mapteksdk.workflows.parser module

Interface with the Extend Python Script workflow component.

This allows for Python Scripts to declare what inputs the workflow is expected to provide, which outputs the Python Script will provide, along with accessing arguments from the workflow and sending outputs to the workflow.

exception InvalidConnectorNameError

Bases: ValueError

Error raised when a connector name is invalid.

add_note()

Exception.add_note(note) – add a note to the exception

args
with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

exception DuplicateConnectorError

Bases: Exception

Error raised when a duplicate connector is declared.

add_note()

Exception.add_note(note) – add a note to the exception

args
with_traceback()

Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.

class WorkflowArgumentParser(description='', allow_unknown_attributes=False)

Bases: object

Class which allows scripts to accept inputs and write outputs when run via the Extend Python Script workflow component. In particular, scripts which use this class can automatically generate their input and output connectors via the “Generate Connectors” button in the workflow component configuration. Scripts which use this class are also runnable via the command line - values for the input connectors can be passed as command line arguments.

Using this class is highly recommended for scripts intended to be embedded in workflows.

Parameters:
  • description (str) – A description of the script. If –help is passed to the script, this will appear in the help message.

  • allow_unknown_attributes (bool) – New in version 1.4. If unknown attributes should be allowed. If False (default), an error will be raised if an input which does not correspond to a declared input connector is provided. If True, no error will be raised if an input which does not correspond to a declared input connector is provided and the value of this input will be available via the unknown_attribute function.

Notes

This table displays which Python types can be passed to declare_input_connector() or declare_output_connector() for a connector which filters input/output to a specified type. The type displayed in Python type and ConnectorType columns can be used interchangeably for types with a value in both columns. N/A indicates not applicable.

Workflow type

Python type

ConnectorType

String

str

StringConnectorType

Integer

int

IntegerConnectorType

Double

float

DoubleConnectorType

DateTime

datetime.datetime

DateTimeConnectorType

Boolean

bool

BooleanConnectorType

CSV String

list

CSVStringConnectorType

Selection

N/A

WorkflowSelection

Point3D

N/A

Point3DConnectorType

File

pathlib.Path

FileConnectorType

Folder

N/A

DirectoryConnectorType

Other

str

N/A

Examples

Creating 3D Text

Script which creates 3D text with a specified message at a specified path, using a list to pass the colours and a point to pass position of the text. If this script is used in the Extend Python Workflow component it would have three input connectors “text”, “position” and “colour” which would filter values to types “String”, “Point3D” and “CSV String” respectively. Values passed to these connectors in the workflow are used to set the text, position and colour of the created 3D text.

The script can also be run through the command line. If it was in a file called “create_3d_text.py” and was run using: py create_3d_text.py Then it would create a 3D text object in the currently running project with green text reading “Hello World” at [0, 0, 0]. However if were run with the command: create_3d_text.py –text=”Hi” –position=”1, 2, 3” –colour=”255, 0, 0” It will create a 3D text object with text “Hi” at the point [1, 2, 3] and with red text.

>>> from mapteksdk.project import Project
>>> from mapteksdk.workflows import (WorkflowArgumentParser,
...                                  Point3DConnectorType)
>>> from mapteksdk.data import Text3D
>>> parser = WorkflowArgumentParser("Create 3D text.")
>>> parser.declare_input_connector("text", str, default="Hello World",
...                                description="The text of the new 3D text")
>>> parser.declare_input_connector("position",
...                                Point3DConnectorType,
...                                default=[0, 0, 0],
...                                description="[x, y, z] position of text.")
>>> parser.declare_input_connector("colour", list, default=[0, 255, 0],
...                                description="[R, G, B] colour for text.")
>>> parser.parse_arguments()
>>> project = Project()
>>> with project.new(f"cad/{parser['text']}", Text3D) as new_text:
...     new_text.text = parser["text"]
...     new_text.location = parser["position"]
...     new_text.colour = parser["colour"]

Reversing strings

Python scripts which use this module are not required to connect to a project. This example can be performed without a running Project, so it does not construct one. This script takes the string representation of the input and reverses it. For example, the string “Eggs” would be reversed to “sggE” and the number “42.42424” would be reversed to “42424.24”. Note that reversing some types, such as datetime.datetime will not give a valid object of that type.

>>> from mapteksdk.workflows import WorkflowArgumentParser
>>> parser = WorkflowArgumentParser("Reverses the input strings")
>>> parser.declare_input_connector("string",
...                                None,
...                                description="String to reverse.",
...                                default="Something to reverse")
>>> parser.declare_output_connector("reversed",
...                                 None,
...                                 description="The reversed string.")
>>> parser.parse_arguments()
>>> parser.set_output("reversed", parser["string"][::-1])
>>> parser.flush_output() # Calling this is optional.

Dealing with unknown arguments By default, WorkflowArgumentParser will transition the workflow into an error state if it detects an unknown input. However by setting allow_unknown_attributes to True when constructing the object this error will be suppressed and the unknown inputs will be available to the script via the unknown_attribute function. This is useful for scripts where the exact inputs cannot be known before the workflow is run and thus cannot be declared as input connectors.

The following example sums all of the input attributes which are integers. This declares no input connectors and will use all attributes defined when the workflow component is run.

>>> from mapteksdk.workflows import WorkflowArgumentParser
>>> parser = WorkflowArgumentParser(
...   description="Sums all integer input attributes.",
...   allow_unknown_attributes=True)
>>> parser.declare_output_connector(
...   "total",
...   int,
...   connector_name="Total",
...   description="The sum of all integer inputs.")
>>> parser.parse_arguments()
>>> total = 0
>>> for name in parser.unknown_attribute_names:
...   try:
...     total += parser.unknown_attribute(name, int)
...   except ValueError:
...     # The attribute was not an integer, skip it.
...     continue
>>> parser.set_output("total", total)

Filtering attributes As of version 1.4, WorkflowArgumentParser allows outputs to be written without declaring an output connector. This is useful for filtering scripts which do not know what the outputs will be ahead of time.

The following example filters out all attributes which cannot be converted to a floating point number.

>>> from mapteksdk.workflows import WorkflowArgumentParser
>>> parser = WorkflowArgumentParser(
...   description="Filters out all non-numeric attributes.",
...   allow_unknown_attributes=True)
>>> parser.parse_arguments()
>>> for name in parser.unknown_attribute_names:
...   try:
...     parser.set_output(name, parser.unknown_attribute(name, float))
>>>   except ValueError:
...     # The attribute was not numeric, skip it.
...     continue
declare_input_connector(name, input_type, default=None, connector_name=None, description='', *, matching=None)

Declares that this script expects an input connector with the specified name to provide a value of the specified type.

This has no effect if parse_arguments is not called.

Parameters:
  • name (str) – The name of the input connector. This must be a valid Python identifier; however it may include “-” characters. Pass this to get_input() after calling parse_arguments() to get any values passed through this input connector.

  • input_type (type[mapteksdk.workflows.connector_type.ConnectorType] | type) – The data type the input connector will accept. This can either be a simple python data type or a connector type. See table above for how to match types between Workflows and Python.

  • default (Any) – The default value to use for this connector if no value is provided when parse_arguments is called (eg: If the connector was deleted from the workflow node). For non-bool connectors this is None by default. For bool connectors this is ignored - the default is always False.

  • connector_name (str | None) – The user facing name of the connector. If specified, this will be the “Connector Name” and name will be the “Attribute name” of the connector. Unlike name, this can include whitespace characters.

  • description (str) – Description of the input connector. Use this to provide instructions on how to use this input connector. If the input connectors are automatically generated this will be placed in the “Description” field of the input connector. If –help is passed to the script, this will be displayed as part of the help. The description is optional, however it is recommended to provide one.

  • matching (MatchAttribute | None) – Requires Extend Plugins 2021.2 or higher. How attributes are matched on the workflows side. See the documentation for the enumeration for more details. If None (default), the value of default_matching will be used instead.

Raises:
  • ValueError – If input_type is not a ConnectorType subclass or is not a Python type with a corresponding ConnectorType subclass in workflows.connector_types module.

  • ValueError – If default is not the same type as input_type.

  • ValueError – If type is AnyConnectorType and matching is AttributeMatching.ByType.

  • InvalidConnectorNameError – If name is not a valid Python identifier.

  • InvalidConnectorNameError – If declaring a connector using a name reserved for use by the SDK.

  • RuntimeError – If called after parse_args() has been called.

  • DuplicateConnectorError – If two connectors are declared with the same name or, if their name would be the same if “-” characters are replaced with “_” characters.

  • TypeError – If matching is not a value from AttributeMatching or None.

Notes

Using from workflows

Python scripts can be added to workflows by dragging and dropping the script onto the workflow. The connectors declared by this function (and declare_output_connectors) will be automatically added to the workflow component.

Using via the command line

A script using this class is not restricted to being run in workflows - it can also be run via the command line or a code editor. Inputs can be passed into input connectors as command line arguments. The general form of one of these command line arguments is:

>>> --name=value

Or if the name is only a single character long:

>>> -n=value

The main exception is for bool connectors. For them omit the equals sign and value - the presence of the argument name indicates True and its absence indicates False.

Examples

Command line examples Given a script called “script.py” which uses this module and Python interpreter set to be run via the “py” command, the following examples show how to pass an argument to the script.

Connector with name=”name” of type str. The quotation marks around the string are necessary to include the spaces as part of the string instead of as separate arguments.

>>> py script.py --name="Tim the enchanter"

Connector with name=”n” of type str. For connectors with single letter names the name is prefixed with one dash instead of two.

>>> py script.py -n="King Arthur"

Connector with name=”pre-sorted” of type bool. Note that for bool connectors no value is passed.

>>> py script.py --pre-sorted # Gives pre-sorted=True
>>> py script.py              # Gives pre-sorted=False

Connector with name=”count” of type int

>>> py script.py --count=42

Connector with name=”tolerance” of type float.

>>> py script.py --tolerance=3.14159

Connector with name=”time” of type datetime.datetime. Note that the date must be entered in ISO-8601 compliant format.

>>> py script.py --time="2020-07-10T12:54:07"

Connector with name=”origin” of type list.

>>> py script.py origin="1, 1, 1"
declare_output_connector(name, output_type, connector_name=None, description=None)

Declares that this script will provide a value for an output connector.

You should call set_output once for each connector declared with this function. Failing to provide a value for an output connector will cause the Workflow to halt.

Parameters:
  • name (str) – The name of the output connector. This must be a valid Python identifier however it may include - characters.

  • output_type (type[mapteksdk.workflows.connector_type.ConnectorType] | type) – The type of the output. This can either be a simple python type or a connector type. See the table in declare_input_connector to choose the correct Python type to match the workflows type.

  • connector_name (str | None) – The user facing name of the connector. If specified, this will be the “Connector Name” and name will be the “Attribute name” of the connector. Unlike name, this can include whitespace characters.

  • description (str | None) – Description of the output connector. If the connectors are automatically generated, this will be placed in the Description field of the connector. If None (default) the description will be the empty string.

Raises:
  • ValueError – If input_type is not a ConnectorType subclass or is not a Python type with a corresponding ConnectorType subclass in workflows.connector_types module.

  • InvalidConnectorNameError – If the connector name is invalid.

  • RuntimeError – If called after parse_args() has been called.

Notes

Changed in version 1.4. Prior to version 1.4, all outputs had to be declared by this function. In version 1.4 outputs can be set without declaring a corresponding output connector. Providing outputs without declaring a connector is useful for scripts where their outputs cannot be known before the workflow / script is run.

parse_arguments(arguments=None)

Indicates that the script has finished configuring the connectors and allows values to be read from the input connectors. This will also allow values to be written to the output connectors.

If there is an error parsing the arguments, a SystemExit will be raised. This ensures your script will not run with invalid inputs.

Parameters:

arguments (list[str] | None) – List of arguments to parse. If None (default) then the arguments are parsed from sys.argv[:1]. Inputs from workflows can only be accepted if this parameter is not specified.

Raises:
  • SystemExit – If the value passed to a connector is not compatible with the type specified when declare_argument was called for that connector.

  • SystemExit – If an unknown argument appears.

Warning

When you click the “Generate Connectors” button in the workflow component, the Python Script will be executed until this function is called (And thus to completion if this is never called). You should make sure that no code which has side effects is called before calling this function.

You should always call this function before calling Project().

Printing to standard output before calling this function will cause the workflow component to fail to generate connectors.

Notes

Usually this function will be called as: workflows.parse_arguments()

get_input(name)

Returns the value passed to the connector with the specified name.

For convenience, this function can also be called via subscripting this object.

Parameters:

name (str) – The name of the argument to retrieve the value for.

Returns:

Value for argument name.

Return type:

type

Raises:

KeyError – If there is no argument with name (Potentially because parse_arguments has not been called).

property unknown_attribute_names: tuple[str, ...]

A tuple containing the names of the unknown attributes.

This will always be empty if this object was not constructed to allow unknown arguments.

Notes

New in version 1.4.

unknown_attribute(name: str, dtype: type[T]) T
unknown_attribute(name: str) str

Read the value of an unknown attribute.

Unknown attributes are input attributes of the workflow component which do not correspond to any of the declared input connectors.

Allowing unknown attributes is useful for writing scripts where the inputs cannot be determined before the workflow or script is run (e.g. scripts which filter the input attributes).

Parameters:
  • name – The name of the attribute.

  • dtype – The expected Python type of the attribute (e.g. int). This is str by default.

Returns:

The value of the unknown attribute converted to the specified type.

Return type:

dtype

Raises:
  • KeyError – If there is no unknown attribute with the specified name. This will always be raised if this object was not constructed to allow unknown attributes.

  • ValueError – If the value cannot be converted to the specified type.

Notes

New in version 1.4.

set_output(name, value)

Sets the value to be written to an output.

This should be called once for each declared output connector. Failing to do so will cause the workflow to halt.

Note that the value will not appear in the workflow until the script successfully exits.

Parameters:
  • name (str) – Name of the output. This should match the name of an output connector.

  • value (Any) – Value to provide for the output. This should be a simple type, such as an int, float, str, list or datetime.

Raises:
  • TypeError – If name does not correspond to an output attribute and its type cannot be sent to the workflow.

  • ValueError – If value cannot be converted to the type passed in to declare_output_connector for name.

  • RuntimeError – If you attempt to call this twice for the same connector.

  • RuntimeError – If called after calling flush_output.

Notes

Changed in version 1.4. This function no longer raises an error if name does not correspond to a declared output connector.

flush_output()

Flushes the output making it available to the output connectors. Call this function once you have called set_output() for each output connector.

After this function has been called, you cannot write any more values to the output connectors.

Raises:

RuntimeError – If this function is called more than once.

property default_matching: MatchAttribute | None

The default matching type used by declare_input_connector().

If this is set to a value from the MatchAttribute enum, if the matching parameter of generate_connectors is None the value of this property will be used instead.

If this is None (default) the connector will use the default matching type as defined by the workflow component (this is currently MatchAttribute.BY_TYPE).

Raises:

TypeError – If set to a value which is not part of the MatchAttribute.BY_TYPE enum.

Examples

This property can be used to set all connectors to match attribute by name. The matching argument can be used to specify a different value for specific connectors.

>>> from mapteksdk.workflows import (WorkflowArgumentParser,
...                                  MatchAttribute, StringConnectorType)
>>> parser = WorkflowArgumentParser("Example showing matching by name.")
>>> parser.default_matching = MatchAttribute.BY_NAME
>>> # These two connectors will now match by name instead of by type.
>>> parser.declare_input_connector("input_path", StringConnectorType)
>>> parser.declare_input_connector("output_path", StringConnectorType)
... # The third connector specifies a different matching scheme
... # and will not match.
>>> parser.declare_input_connector("attribute",
...                                StringConnectorType,
...                                matching=MatchAttribute.DO_NOT_MATCH,
...                                default="grade")
>>> parser.parse_arguments()
>>> # Do something useful with the arguments.
describe_connectors(destination)

Describes the input and output connectors.

This is used by the Extend Python Workflow Component to generate the connectors — it is not recommended to use this function in scripts.

This results in an Object with three fields: Description : The description of the Python script. Input : Description of the input connectors. Output : Description of the output connectors.

Parameters:

destination (TextIOWrapper) – The stream to write the description to.

property items: list[str]

The items array set by a Data Editor workflow component.

Set this to None to indicate no change should be made to the items array.

Raises:

RuntimeError – If accessed before parse_arguments() or if set after flush_output().

Warning

This requires Python Plugin version 2021.1 to be effective.

Notes

When using Python Plugin versions less than 2021.1, the workflow component will ignore the items list. This property will always start as an empty list and changes will not be propagated back to the workflow.

Lists and dicts should not be added to this list. They will cause errors on the workflow side.