⚙ Technical documentation

transformer – Main API

This module exports the functions that should cover most use-cases of any Transformer user.

transformer.dumps(scenario_paths, plugins=(), with_default_plugins=True)[source]

Transforms the provided scenario_paths using the provided plugins, and returns the resulting locustfile code as a string.

See also: dump()

Parameters:
  • scenario_paths (Iterable[Union[str, Path]]) – paths to scenario files (HAR) or directories
  • plugins (Sequence[str]) – names of plugins to use
  • with_default_plugins (bool) – whether the default plugins should be used in addition to those provided (recommended: True)
Return type:

str

transformer.dump(file, scenario_paths, plugins=(), with_default_plugins=True)[source]

Transforms the provided scenario_paths using the provided plugins, and writes the resulting locustfile code in the provided file.

See also: dumps()

Parameters:
  • file (Textio) – an object with a writelines method (as specified by io.TextIOBase), e.g. sys.stdout or the result of open.
  • scenario_paths (Iterable[Union[str, Path]]) – paths to scenario files (HAR) or directories.
  • plugins (Sequence[str]) – names of plugins to use.
  • with_default_plugins (bool) – whether the default plugins should be used in addition to those provided (recommended: True).
Return type:

None

transformer.plugins – Plugin System

This module exposes the API needed to create your own Transformer plugins.

See also

🚀 Writing plugins
The rationale for contracts, and a description of the most important ones.
@transformer.plugins.plugin(contract)[source]

Associates a function to a Contract, making that function a Transformer plugin that will be detected as such by resolve.

Parameters:contract (Contract) – the contract to associate to the decorated function.
Raises:InvalidContractError – if contract is not a valid Contract.
class transformer.plugins.Contract[source]

Enumeration of all supported plugin contracts. Each specific contract defines a way for plugins to be used in Transformer.

Any Python function may become a Transformer plugin by announcing that it implements at least one contract, using the @plugin decorator.

OnTask = 1

The OnTask contract.

OnScenario = 2

The OnScenario contract.

OnPythonProgram = 4

The OnPythonProgram contract.

OnTaskSequence = 8

Deprecated.

transformer.plugins.Plugin

Subtype of functions (callable) that are registered as Transformer plugins. Mostly useful in type annotations.

transformer.request – HTTP requests read from HAR

Representation of HAR Request objects.

class transformer.request.HttpMethod[source]

Enumeration of supported HTTP method types.

DELETE = 5

DELETE

GET = 1

GET

OPTIONS = 4

OPTIONS

PATCH = 6

PATCH

POST = 2

POST

PUT = 3

PUT

class transformer.request.QueryPair(name, value)[source]

A pair of query parameters, as recorded in a HAR file (queryString).

class transformer.request.Request(timestamp, method, url, har_entry, headers=mappingproxy({}), post_data=None, query=(), name=None)[source]

An HTTP request, as recorded in a HAR file (request).

Note that post_data, if present, will be a dict of the same format as recorded in the HAR file (postData – although it is not consistently followed by HAR generators).

timestamp

datetime – Time at which the request was recorded.

method

HttpMethod – HTTP method of the request.

url

urllib.parse.SplitResult – URL targeted by the request.

har_entry

dict – A single record from entries as recorded in a HAR file corresponding to the request, provided for read-only access.

headers

requests.structures.CaseInsensitiveDict (reference) – HTTP headers sent with the request.

post_data = None

Optional dict – If method is POST, the corresponding data payload.

query = []

List of QueryPair – Key-value arguments sent as part of the url’s query string.

name = None

Optional str – Value provided for locust.clients.HttpSession’s “dynamic” name parameter. See Grouping requests to URLs with dynamic parameters for details.

classmethod all_from_har(har)[source]

Generates requests for all entries in a given HAR top-level object.

Return type:Iterator[Request]
classmethod from_har_entry(entry)[source]

Creates a request from a HAR entry.

Raises:
  • KeyError – if entry is not a valid HAR “entry” object.
  • ValueError – if the request.startedDateTime value cannot be interpreted as a timestamp.
Return type:

Request

task_name()[source]

Generates a simple name to be used as name by the task of this request.

Return type:str

transformer.python – Python Syntax Tree

Transformer’s Python Syntax Tree framework allows you to create and manipulate Python source code without bothering with irrelevant, style-related details.

It is the main API for writing OnPythonProgram plugins.

A non-goal of this framework is customization of style: users should rely on an external tool (such as black) if they need style customization of their generated locustfile.

See also

Syntax tree
High-level description of Transformer’s “syntax tree” internal object.
transformer.python.Program

A Sequence of Statement objects. Useful as alias in type signatures.

class transformer.python.Line(text, indent_level=0)[source]

Bases: object

A line of text and its associated indentation level.

This class allows not to constantly copy strings to add a new indentation level at every scope of the syntax tree.

text

str – Text contained by this line.

indent_level

int – Indentation level of text in the line.

clone()[source]

Creates an exact but disconnected copy of self. Useful in tests.

Return type:Line
class transformer.python.Statement(comments=())[source]

Bases: object

Python distinguishes between statements and expressions: basically, statements cannot be assigned to a variable, whereas expressions can.

For our purpose, another distinction is important: statements may span over multiple lines (and not just for style), whereas all expressions can be expressed in a single line.

This class serves as abstract base for all implementors of lines() and handles comment processing for them.

Parameters:comments (Sequence[str]) – Comment lines attached to this statement.
comments

Comment lines attached to this statement.

This is a property to ensure that modifications of this list preserve the invariant “one element = one line”.

Return type:List[str]
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

comment_lines(indent_level)[source]

Converts self.comments from str to Line with # prefixes.

Return type:List[Line]
attach_comment(line)[source]

Attach a comment to line: inline if self.comments is just one line, on dedicated new lines above otherwise.

Return type:List[Line]
class transformer.python.OpaqueBlock(block, comments=())[source]

Bases: transformer.python.Statement

A block of code already represented as a string. This helps moving existing code (e.g. in plugins) from our ad-hoc “blocks of code” framework to the syntax tree framework defined in this module. It also allows to express Python constructs that would otherwise not yet be representable with this AST framework.

Parameters:block (str) – String representing a block of Python code.
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Function(name, params, statements, comments=())[source]

Bases: transformer.python.Statement

A function definition (def ...).

Parameters:
  • name (str) – Name of this function.
  • params (Sequence[str]) – Names of each parameter of this function.
  • statements (Sequence[Statement]) – Body of this function.
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Decoration(decorator, target, comments=())[source]

Bases: transformer.python.Statement

A function or class definition to which is applied a decorator (e.g. @task).

Parameters:
  • decorator (str) – Name of the decorator applied to target.
  • target (Statement) – Function or class definition to which is applied decorator.
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Class(name, statements, superclasses=(), comments=())[source]

Bases: transformer.python.Statement

A class definition.

Parameters:
  • name (str) – Name of this class.
  • statements (Sequence[Statement]) – Fields of this class: methods, attributes, etc.
  • superclasses (Sequence[str]) – Names of each superclass of this class. In fact anything in the “function argument” format can be used here, like keyword-arguments (but in a string!).
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Expression[source]

Bases: object

See the documentation of Statement for why Expression is a separate class. An expression is still a statement in Python (e.g. functions can be called anywhere), but this Expression class is not a Statement because we can’t attach comments to arbitrary expressions (e.g. between braces). If you need to use an Expression as a Statement, see the Standalone wrapper class.

This class serves as abstract base for all our implementors of __str__().

class transformer.python.Standalone(expr, comments=())[source]

Bases: transformer.python.Statement

Wraps an Expression so that it can be used as a Statement.

Parameters:expr (Expression) – The wrapped expression.
lines(indent_level=0, comments=True)[source]

An Expression E used as a Statement is serialized as the result of str(E) on its own Line.

Return type:List[Line]
class transformer.python.Literal(value)[source]

Bases: transformer.python.Expression

All literal Python expressions (integers, strings, lists, etc.).

Everything will be serialized using repr(), except Expression objects that could be contained in a composite value like list: they will be serialized with str(), as is probably expected. Thus:

>>> str(Literal([1, {"a": FString("-{x}")}]))
"[1, {'a': f'-{x}'}]"

instead of something like [1, {'a': FString('-{x}')}].

See also

FString

Parameters:value (Any) – The Python literal represented by this node.
class transformer.python.FString(s)[source]

Bases: transformer.python.Literal

f-strings are strings that capture values from their environment.

They cannot be handled in Literal because they are a “trick” of the Python parser: before the program runs, they lose their f prefix and their template is evaluated, so when Literal is instantiated, they are only a normal string that tried to capture values from Transformer’s context (instead of the locustfile’s context).

Parameters:s (str) – The template of this f-string, for example a{x}b for the f-string f"a{x}b".
class transformer.python.Symbol(name)[source]

Bases: transformer.python.Expression

The name of something (variable, function, etc.). Avoids any kind of string quoting and escaping that would happen with Literal.

>>> str(Literal("x"))
"'x'"
>>> str(Symbol("x"))
'x'

The provided argument’s type is explicitly checked and a TypeError may be raised to avoid confusion when a user expects e.g. Symbol(True) to work like Symbol("True").

Parameters:name (str) – Textual representation of this symbol. Will be forwarded without modification to the locustfile.
class transformer.python.FunctionCall(name, positional_args=(), named_args=mappingproxy({}))[source]

Bases: transformer.python.Expression

The invocation of a function or method.

Parameters:
  • name (str) – Name of the function that is called.
  • positional_args (Sequence[Expression]) – Positional arguments associated with this call, if any.
  • named_args (Mapping[str, Expression]) – Keyword-arguments associated with this call, if any.
class transformer.python.BinaryOp(lhs, op, rhs)[source]

Bases: transformer.python.Expression

The invocation of a binary operator.

To avoid any precedence error in the generated code, operands that are also BinaryOps are always surrounded by braces (even when not necessary, as in “1 + (2 + 3)”, as a more subtle behavior would increase the complexity of the implementation without much benefit.

Parameters:
  • lhs (Expression) – Left-hand side operand of this operation.
  • op (str) – Name of the operator, like +.
  • rhs (Expression) – Right-hand side operand of this operation.
class transformer.python.Assignment(lhs, rhs, comments=())[source]

Bases: transformer.python.Statement

The assignment of a value to a variable.

For our purposes, we don’t treat multiple assignment via tuples differently. We also don’t support chained assignments such as a = b = 1.

Parameters:
  • lhs (str) – Variable name (or names) the rhs is assigned to.
  • rhs (Expression) – Expression which value is assigned to lhs.
lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.IfElse(condition_blocks, else_block=None, comments=())[source]

Bases: transformer.python.Statement

The if/elif/else construct, where elif and else are optional and elif can be repeated.

Parameters:
  • condition_blocks (Sequence[Tuple[Expression, Sequence[Statement]]]) – Pairs of condition and statements. Each pair is composed of an expression representing a condition, and a list of statements corresponding to that condition. This represents an if/elif/…/elif sequence, where there is always an “if” clause and an arbitrary number of “elif” clauses.
  • else_block (Optional[Sequence[Statement]]) – Statements representing the “else” clause, if any.
Raises:

ValueError – If there is not at least one element in condition_blocks.

lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Import(targets, source=None, alias=None, comments=())[source]

Bases: transformer.python.Statement

The import statement in all its forms: import X, import X as A, from M import X, from M import X as A, and from M import X, Y.

Combined imports like from M import X, Y are split for simplicity.

Parameters:
  • targets (Sequence[str]) – What is imported: X in import X and from M import X.
  • source (Optional[str]) – From where targets are imported, if applicable: M in from M import X.
  • alias (Optional[str]) – Alias for a single-element targets: A in import X as A and from M import X as A.
Raises:

ValueError – If targets is empty, or if alias is specified even though there are multiple targets.

lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.Return(value, comments=())[source]

Bases: transformer.python.Statement

The return statement.

lines(indent_level=0, comments=True)[source]

All Line objects necessary to represent this Statement, along with the appropriate indentation level.

Parameters:
  • indent_level (int) – How much indentation to apply to the least indented line of this statement.
  • comments (bool) – Whether existing comments attached to self should be included in the result.
Return type:

List[Line]

class transformer.python.ExpressionView(target, converter, name)[source]

Bases: transformer.python.Expression

A “proxy” for an object that is not an Expression.

ExpressionView allows to mix non-Expression objects in the syntax tree, along with a function capable of transforming these objects into actual Expression objects at any time. This is useful when these objects are easier to manipulate than their Expression equivalent.

For example: any Request object can be converted into an equivalent Expression, but Request has a simpler API than Expression for request-oriented operations like accessing the URL, etc. ExpressionView can “wrap” a Request to pretend that the Request is an Expression (with all associated benefits of being part of the syntax tree), but still support the Request API.

target

() T – A function (without parameters) returning the wrapped, non-Expression object.

The benefit of target being a function (instead of a direct reference to the wrapped object) is that it allows to specify some mutable field of an object. See for example Task2, which contains an ExpressionView wrapping its own request attribute. If the value of that attribute changes, the ExpressionView will refer to the new value (found by accessing the attribute via self), not the old value (which would still be referenced by a non-callable target).

converter

T Expression – A function capable of transforming the result of target into an Expression. The result of converter is computed each time this ExpressionView has to behave like an Expression, for example when passed as argument to str.

name

str – Purely descriptive: makes the inspection of data structures containing ExpressionView objects more comfortable.