API
Base Classes
- class tctools.common.Tool(*args)
Tools base class.
argparseis done in the constructor, CLI arguments should be passed there.Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- LOGGER_NAME: str | None = None
- FILTER_DEFAULT: list[str]
- CONFIG_KEY: str | None = None
- PATH_VARIABLES: list[str] = []
- classmethod get_argument_parser() ArgumentParser
- classmethod set_arguments(parser)
Create application-specific arguments.
- make_config() dict[str, Any]
Get configuration from possible files.
- abstract run() int
Main tool execution.
- get_logger()
Get logger for this class.
- class tctools.common.TcTool(*args)
Base class for tools sharing TwinCAT functionality.
Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- PATH_VARIABLES: list[str] = ['target']
- classmethod set_arguments(parser)
Create application-specific arguments.
- classmethod set_main_argument(parser)
First argument that’s supplied.
Separate method to allow overriding it.
- static get_xml_header(file: str) str | None
Get raw XML header as string.
- get_xml_tree(path: str | Path) _ElementTree
Get parsed XML path.
- classmethod find_files(targets: str | list[str], filters: None | list[str] = None, recursive: bool = True, skip_check: bool = False) dict[Path, list[Path]]
Find a set of files, based on one or more targets and an optional filter.
The entire set will never contain duplicate files
Returned dict looks like:
{ "given pattern 1": [file_1, folder/file2, etc.], "given pattern 2": ... , }
- find_target_files() Generator[Path, None, None]
Use argparse arguments to get a set of target files.
XML Sorter
- class tctools.xml_sort.xml_sort_class.XmlSorter(*args)
Tool to sort XML files.
Use one instance for a sequence of files.
Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- LOGGER_NAME: str | None = 'xml_sorter'
- FILTER_DEFAULT: list[str] = ['*.tsproj', '*.xti', '*.plcproj']
- CONFIG_KEY: str | None = 'xml_sort'
- classmethod set_arguments(parser)
Create application-specific arguments.
- run() int
Main tool execution.
- sort_file(path: str)
Sort a single path.
- sort_node_recursively(node: _Element)
Sort a node and any sub-nodes, and their sub-nodes.
Sorting is done in-place, the object is passed in by reference.
- static sort_attributes(node: _Element) bool
Sort the attributes of a node.
- Returns:
True if any changes were really made
- static get_node_sorting_key(node: _Element) str
Get the string by which sub-nodes will be sorted.
Sorting will be done on the literal node XML subtree string.
- static get_tag(node: _Element) str
Get tag without URL prefix from node.
- static get_attrib(node: _Element) dict[str, str]
Yield node attributes, with namespace stripped.
Formatter
- class tctools.format.format_class.Formatter(*args)
Helper to check formatting in PLC files.
Instantiate once for a sequence of files.
Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- LOGGER_NAME: str | None = 'formatter'
- FILTER_DEFAULT: list[str] = ['*.TcPOU', '*.TcGVL', '*.TcDUT']
- CONFIG_KEY: str | None = 'format'
- classmethod set_arguments(parser)
Create application-specific arguments.
- classmethod register_rule(new_rule: type[FormattingRule])
Incorporate a new formatting rule (accounting for its priority).
- run() int
Main tool execution.
- format_file(path: str)
Format (or check) a specific path.
The path is read as text and code inside XML tags is detected manually. Other lines of XML remain untouched.
- static split_code_segments(content: list[str])
Copy content, split into XML and code sections.
Function is a generator, each pair is yielded.
Note: line endings are not modified! I.e., segments should be appended together directly, without extra newlines.
- Param:
File content as list
- Returns:
list[Segment]
- format_segment(content: list[str], kind: Kind)
Format a specific segment of code.
- Parameters:
content – Text to reformat (changed in place!)
kind – type of the content
- apply_rule(rule, content, kind: Kind | None = None)
Run a rule over some content and handle results.
- class tctools.format.format_class.XmlMachine
Helper class to identify code bits inside an XML path.
- parse(content: list[str])
Progress machine line by line.
- class tctools.format.format_rules.FormattingRule(properties: OrderedDict)
TcFormatter rule base class.
Extend and implement this class to check for and correct a specific error/style/etc.
- Variables:
PRIORITY – Lower priority means a rule gets applied earlier.
WHOLE_FILE – If True, rule is applied to the entire file instead of just code blocks.
- PRIORITY = 100
- WHOLE_FILE = False
- property actual_indent_size: int
Tab width for style=tabs or indent size for style=spaces.
- get_property(name: str, default: Any = None, value_type: type | None = None) Any
Get item from
_properties, parsing as needed.- Parameters:
name
default – Value to dfault if name doesn’t exist
value_type – Class of the returned value (e.g.
bool)
- abstract format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- add_correction(message: str, line_nr: int)
Register a formatting correction.
See
Correction.
- consume_corrections() list[tuple[int, str]]
Return listed corrections and reset list.
- class tctools.format.format_rules.FormatTabs(*args)
Check usage of tab character.
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- class tctools.format.format_rules.FormatTrailingWhitespace(*args)
Remove trailing whitespace.
- PRIORITY = 90
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- class tctools.format.format_rules.FormatInsertFinalNewline(*args)
Asserting a final empty newline in a file.
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- class tctools.format.format_rules.FormatEndOfLine(*args)
Asserting line endings are as expected.
- WHOLE_FILE = True
- PRIORITY = 50
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- class tctools.format.format_rules.FormatVariablesAlign(*args)
Assert whitespace align in variable declarations.
Target formatting will create columns on the “:” and the “//” of comments.
- PRIORITY = 110
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- format_argument_list(content: list[str])
Format entire declaration section
- class tctools.format.format_rules.FormatConditionalParentheses(*args)
Formatter to make uses of parentheses inside IF, CASE and WHILE consistent.
First regex is used to find potential corrections, which are then investigated by a loop to make sure parentheses remain matching and no essential parentheses are removed.
- format(content: list[str], kind: Kind | None = None)
Fun rule to format text.
- Parameters:
content – Text to format (changed in place!)
kind – Kind of content
- static find_and_match_braces(text: str, brace_left: str = '(', brace_right: str = ')') tuple[int, int]
Step through braces in a string.
Note that levels can step into negative.
- Returns:
tuple of (strpos, level), where strpos is the zero-index position of the brace itself and level is the nested level it indicates
Git Info
- class tctools.git_info.git_info_class.GitInfo(*args)
Class to insert Git version info into a template.
We use template keys in the source file like
{{key}}. This is done to avoid conflicts with TwinCAT source files. e.g.<key>might collide with XML brackets in$keythe dollar sign is a key for string constants.Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- LOGGER_NAME: str | None = 'git_info'
- CONFIG_KEY: str | None = 'git_info'
- PATH_VARIABLES: list[str] = ['template', 'tolerate_dirty']
- classmethod set_arguments(parser)
Create application-specific arguments.
- run() int
Produce an info file based on template.
This is largely a copy of https://github.com/RobertoRoos/git-substitute. This DRY violation is accepted to prevent a code dependency.
Patch PLC
- class tctools.patch_plc.patch_plc_class.PatchPlc(*args)
Function code for PLc project patching.
Pass e.g.
sys.args[1:](skipping the script part of the arguments).- Parameters:
args – See
set_arguments()
- LOGGER_NAME: str | None = 'patch_plc'
- FILTER_DEFAULT: list[str] = ['*.TcPOU', '*.TcGVL', '*.TcDUT', '*.TcGTLO', '*.TcIO', '*.TcTLEO', '*.TcTTO']
- CONFIG_KEY: str | None = 'patch_plc'
- classmethod set_arguments(parser)
Create application-specific arguments.
- classmethod set_main_argument(parser)
First argument that’s supplied.
Separate method to allow overriding it.
- run() int
Perform actual patching.
- operation_merge(current_sources: FileItems, new_sources: dict[Path, FileItems]) int | None
See help info for merge.
- operation_remove(current_sources: FileItems, new_sources: dict[Path, FileItems])
See help info for remove.
- operation_reset(current_sources: FileItems, new_sources: dict[Path, FileItems])
See help info for reset.
- determine_source_folders(source_files: Iterable[Path]) FileItems
Collect all folders (incl. intermediate folders) of files.
Also turn files into a neat relative path, w.r.t. the project file. Relies on self._project_file.
- skip_file_duplicates(new_sources: FileItems, current_sources: FileItems)
Avoid duplicate file names (regardless of full path).
current_sourcesis modified in-place.
- get_project_sources(tree) FileItems
Get all files and folders currently in a PLC project.
- sources_to_remove(current: FileItems, new_sources: dict[Path, FileItems]) FileItems
From a set of sources and CLI input, determine the sources to remove.
Important: only the keys of new_sources are considered! I.e., the files to remove need not exist on the filesystem.
listens to self.args.recursive.
- xml_add_sources(sources: FileItems)
Modify the files and folders elements in-place.
- xml_remove_source(to_remove: FileItems)
Modify the files and folders elements in-place.
- log_sources(source: FileItems, add: bool)
Log a set of sources in its entirety.
Logged a INFO level when dry or check (otherwise the output is kind of meaningless), otherwise at DEBUG.
- static path_to_str(path: PurePath) str
Turn any path into a windows-path string.
This is useful mostly for the paths inside the PLC project XML.