Glossary

Abstract Class

An abstract class is a type that cannot be instantiated directly. An abstract class may provide no implementation or an incomplete implementation.

In pyTooling a class is abstract when ExtendedType was applied and either of two things holds:

  • it contains at least one abstract or mustoverride method, or

  • it is decorated with @abstractclass - for a class that has nothing to mark abstract and still exists only to be derived from. The marker describes that one class: a derived class is concrete again unless it is decorated itself. See Abstract Class.

If an abstract class is instantiated, an AbstractClassError is raised.

Abstract Method

An abstract method provides no implementation (no code) and must therefore be overridden by all derived classes. It is marked with @abstractmethod - see Abstract Method.

If an abstract method is called, a NotImplementedError is raised. If it is not overridden, an AbstractClassError is raised when the class is instantiated, because the class is abstract.

Ancestor

Ancestors are all direct and indirect predecessors of a node (parent node and parent nodes thereof a.k.a. grandparents, grand-grandparent, …, root node).

In a tree, a node has only a single parent per node, thus a list of ancestors is a direct line from current node to the root node.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R:::mark1 --> A
  A:::mark2 --> BL & B & BR
  B:::mark2 --> CL & C & CR
  C:::mark2 --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6,font-size:smaller;
  classDef mark1 fill:#69f,stroke:#37f,color:#eee,font-size:smaller;
  classDef mark2 fill:#69f,stroke:#37f,font-size:smaller;
    

Ancestors of the current node are marked in blue.

Annotation
Type Hint

An annotation states the type a variable, a parameter or a return value has. Python does not check it - a type checker like mypy does, and a library may read it.

pyTooling reads them: ExtendedType derives a class’ slots from its annotated fields, so a field is declared once and the slot follows. Since v10.0.0 an annotation is evaluated lazily (PEP 563, PEP 649), so a class may name a type that doesn’t exist yet - including itself.

Wikipedia: Type signature

Base
Base-Class

A base-class is an ancestor class for other classes derived therefrom by inheritance. A class derived from more than one has a primary base-class and, usually, one or more mixin-classes.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  B(BaseClass)
  C(Class)
  I1(Instance);I2(Instance)

  B:::mark1 --> C:::mark2 -..-> I1 & I2

  classDef node font-size:smaller;
  classDef mark1 fill:#69f,stroke:#37f,color:#eee,font-size:smaller;
  classDef mark2 fill:#69f,stroke:#37f,font-size:smaller;
    

Base-class in a class hierarchy.

Basic Authentication

The basic scheme of RFC 7617 authorizes a request with a user name and a password, base64-encoded in the Authorization header. It says nothing about who may do what, so it belongs behind TLS.

RESTClient sends a bearer token by default; a client of an API expecting the basic scheme overrides _RequestHeaders() - see A client for one API.

Wikipedia: Basic access authentication

Bearer Token

The bearer scheme of RFC 6750 authorizes a request with a token in the Authorization header: whoever bears this token may do what it allows, so the token is the credential and is never sent to another host. An OAuth 2.0 flow hands one out.

It is what RESTClient sends, and why a Link header pointing outside the API is rejected rather than followed.

Breadth-First

Breadth-first visits a graph’s or tree’s nodes by distance: everything one edge away, then everything two edges away. It finds the shortest path in an unweighted graph, because a node is reached the first time by the fewest edges.

Vertex.IterateVerticesBFS walks a graph that way. See depth-first for the opposite, and level-order for what breadth-first is called in a tree.

Wikipedia: Breadth-first search

Calendar Version

A calendar version numbers a release by the date it was made - 2026.09 - rather than by what changed in it. It is the scheme a rolling distribution or a dated dataset uses, where “what changed” has no single answer.

CalendarVersion parses one, in the variants Variants lists.

See also

Semantic Version

→ The other scheme: numbering a release by what changed in it.

Website: calver.org

Child

Children are all direct successors of a node.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  EL:::mark2
  E:::mark2
  ER:::mark2
  DR --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Children of the current node are marked in blue.

CLIOption

A CLI option is an argument a program accepts: it is declared once, as a nested class of a program, and describes how that argument is spelled on the command line.

See Program for how options are declared, and CLIParameter for the value one is given.

CLIParameter

A CLI parameter is a CLIOption that has been set, together with its value. The options a program accepts are fixed when its class is written; the parameters are chosen per program instance, and are what ToArgumentList() renders.

Console Script
Entry Point

An entry point is a name a distribution publishes for something else to find: the group says what kind of thing it is, and the name maps to an object in the distribution. A console script is the console_scripts group - an installer writes an executable for each of its entries.

DescribePythonPackage() declares them, and since v10.0.0 for any group, not only console scripts - see Handling of entry points.

Python Packaging User Guide

Content-Type
Media Type

A media type names the format of a body - application/json, text/plain - and is what the Content-Type header of RFC 9110 carries, optionally with parameters like ; charset=utf-8. The RFC 6839 structured syntax suffix says a type is written in another one, so application/vnd.github+json is JSON.

MediaType is the enumeration of the types a REST API sends and receives, and Matches() answers whether a header names one, suffix and parameters included.

Wikipedia: Media type

Context Manager

A context manager is an object a with-statement enters and leaves, so what has to happen afterwards happens even when the block raises.

Stopwatch and Span are used that way: entering starts the measurement and leaving ends it - see Using in a with-statement. A timespan measured elsewhere is constructed with its recorded times instead.

CopyLeft

Copyleft is a licensing principle requiring that derived works are distributed under the same license as the original. The GPL family is the best known example.

It is the reason a dependency’s license matters beyond attribution, and why pyTooling.Licensing resolves a license to an SPDX expression rather than to a display name.

Wikipedia: Copyleft

Cygwin

Cygwin is a POSIX-compatible programming and runtime environment for Windows.

Which environment Python runs in is what Platform reports, because a path, an executable’s name and the shell differ between native, Cygwin, MSYS2 and WSL.

DAG

A directed acyclic graph (DAG) is a directed graph without backward edges and therefore free of cycles.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph LR
  A(A); B(B); C(C); D(D); E(E); F(F); G(G); H(H); I(I); J(J); K(K)

  A --> B & C & D
  B --> E & F
  C --> E & G
  D --> G & F
  E --> H
  F --> H & I
  G --> I
  H --> J & K
  I --> K & J

  classDef node fill:#eee,stroke:#777,font-size:smaller;
    

A directed acyclic graph.

Descriptor

A descriptor is an object that defines what reading, writing or deleting an attribute does - the mechanism behind a property, a method, and a slot.

It is why ExtendedType can turn an annotated field into a slot: the slot is a descriptor on the class, and the value lives in the instance’s fixed storage rather than in a __dict__.

Distribution
sdist
Wheel

A distribution is a package as it is published and installed - not the importable directory, but the archive the index serves. A wheel (PEP 427) is the built form, installed by unpacking it; an sdist is the source form, from which a wheel is built first.

DescribePythonPackage() describes what goes into both - see Overview.

Python Packaging User Guide

DG

A directed graph (DG) is a graph where all edges have a direction.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph LR
  A(A); B(B); C(C); D(D); E(E); F(F) ; G(G); H(H); I(I)

  A -.-> B -.-> E
  G --> F
  A --> C --> G --> H --> D
  D -.-> A
  D & F --> B
  I ---> E -.-> F -.-> D

  classDef node fill:#eee,stroke:#777,font-size:smaller;
    

A directed graph with cycles (one cycle is denoted by dotted edges).

Decorator

A decorator is a callable applied to a function, method or class with the @ syntax, returning a replacement for what it was applied to - or the original, when it only records something about it.

pyTooling uses both forms: export() records a name in its module’s __all__ and returns the class unchanged, while readonly() replaces a method with a property. Attributes are decorators too.

Wikipedia: Decorator

Dependency

A dependency is what a package needs of another one to be installed or to run: package A depends on package B, in the versions a requirement accepts. As dependencies have dependencies of their own, they form a graph.

pyTooling.Dependency models it: a PackageVersion depends on versions of other packages, and PackageDependencyGraph collects the packages of one or more storages. See Overview.

See also

Requirement

→ How a requirements file states a dependency.

Depth-First

Depth-first follows one branch of a graph or tree to its end before taking the next. It is how a tree is usually walked, in pre-order or post-order depending on when the node itself is visited.

Vertex.IterateVerticesDFS walks a graph that way. See breadth-first for the opposite.

Wikipedia: Depth-first search

Descendant

Descendants are all direct and indirect successors of a node (child nodes and child nodes thereof a.k.a. grandchild, grand-grandchildren, …).

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  EL:::mark2
  E:::mark2
  ER:::mark2
  DR --> ERN1 & ERN2
  E --> F1 & F2
  F1:::mark2
  F2:::mark2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Descendants of the current node are marked in blue.

Edge

An edge is a relation from vertex to vertex in a graph - pyTooling.Graph.Edge, or Link where the relation crosses into another subgraph.

Executable

An executable is a program that this API can also run: Executable adds process handling - starting it, sending it lines, reading its output and waiting for its exit code - to the command line abstraction a program provides.

Extra

An extra is an optional feature of a distribution, named in the install as pyTooling[terminal], which pulls the requirements that feature needs.

pyTooling names an extra after the feature, not after the dependency it happens to pull, so an extra survives a dependency being replaced. DescribePythonPackage() declares them from additionalRequirements.

Exception

An exception is the object a program raises to signal that it cannot continue normally, and the mechanism that transfers control to whatever handles it.

Every exception pyTooling raises derives from ToolingException, and carries the offending value in a note rather than only in its message.

Wikipedia: Exception handling

Generic
Type Variable

A generic type is parametrized by another type, so one class serves every element type without losing what a type checker knows: a type variable stands for the type a use fills in.

pyTooling.Tree.Node, pyTooling.Graph.Graph and LinkedList are generic in several parameters at once - a node’s identifier, its value and its dictionary types are separate variables, so a tree of one shape doesn’t force the other two.

Graph

A graph is a data structure made of vertices (nodes) and vertex-vertex relations called edges.

Special forms of graphs are:

pyTooling.Graph implements one, with Vertex, Edge and Subgraph.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph LR
  A(A); B(B); C(C); D(D); E(E); F(F) ; G(G); H(H); I(I)

  A --> B --> E
  G --> F
  A --> C --> G --> H --> D
  D -.-> A
  D & F -.-> B
  I ---> E --> F --> D

  classDef node fill:#eee,stroke:#777,font-size:smaller;
    

A directed graph with backward-edges denoted by dotted vertex relations.

Grandchild

Grandchildren are direct successors of a node’s children and therefore indirect successors of a node.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR --> ERN1 & ERN2
  E --> F1 & F2
  F1:::mark2
  F2:::mark2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Grandchildren of the current node are marked in blue.

Grandparent

A grandparent is direct predecessor of a node’s parent and therefore indirect predecessor of a node.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B:::mark2 --> CL & C & CR
  C --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Grandparent of the current node are marked in blue.

A hard link is a second directory entry for the same file content. Both entries are equal - neither is the original - and the file content (BLOB) exists as long as at least one of them does.

Unlike a softlink, a hard link cannot point at a directory, cannot cross a filesystem boundary, and cannot dangle.

HTTP Method

The method of an HTTP request says what to do with the resource its URL names - GET, POST, PUT, PATCH, DELETE - and RFC 9110 defines what each means. The standard library’s http.HTTPMethod enumerates them.

Which method a request uses decides whether it may be repeated: see idempotency.

Wikipedia: HTTP methods

Idempotency

A request is idempotent when sending it twice has the same effect as sending it once - RFC 9110 calls GET, PUT and DELETE idempotent, and POST and PATCH not.

It is what decides whether a failing request may be tried again: RESTClient retries the first three and sends the other two once, because a POST whose answer was lost on the way back may have created the resource already - see Retries.

Wikipedia: Idempotence

Inheritance

Inheritance derives a class from another, so the derived class has the fields and methods of its base-class and may add to or replace them.

pyTooling’s ExtendedType takes part in it: a derived class’ slots are the fields it declares plus the ones it inherits, and an abstract method stays abstract until a derived class overrides it.

Wikipedia: Inheritance

Iterator
Generator

An iterator yields its elements one at a time, so a caller can stop after the first and nothing computes the rest. A generator is the usual way to write one - a function with yield.

pyTooling’s traversals are generators: Node.IteratePreOrder, IterateLeafs() and their siblings walk a tree lazily, which is what makes searching a large tree cheap.

Job

A job is the unit a pipeline schedules onto a runner: a sequence of steps running on one machine, with its own result.

pyTooling.CI.Job models one - see Pipeline. A job produced by a matrix is a MatrixJob and carries the values it was produced for.

JSON

The JavaScript Object Notation is a text format for structured data, specified by RFC 8259 and json.org.

pyTooling reads it as a configuration format - JSON - and writes a trace as OTLP/JSON, with the standard library’s json doing the parsing.

Wikipedia: JSON

JSON-Schema

A JSON Schema describes the structure a JSON document must have - which members exist, of which type, and which are required - and is a JSON document itself.

It is to JSON what an XSD is to XML.

JUnit

JUnit XML is the test report format most CI services read, although nobody ever specified it. JUnit didn’t define it: Apache Ant’s junit task wrote these files when it ran JUnit 4 tests, so it is rather an Ant + JUnit format. Ant published no XML schema either, so every *Unit framework writing the format and every service reading it grew its own dialect.

pyTooling writes it, and writes its own format beside it, because JUnit XML cannot express two things a marked test suite has: suites nest, where JUnit flattens them into a dotted classname, and every item carries four names rather than one - see A Report Format of One’s Own.

pyEDAA.Reports reads the dialects into one data model and converts between them - see its Ant and JUnit 4 XML.

Wikipedia: JUnit

Label

A label is what a job asks of the runner it wants - an operating system, an architecture, a capability - and what a self-hosted runner is registered with. A service picks a runner whose labels cover the job’s.

The job model of pyTooling.GitHub reports them.

Leaf

A leaf is a node of a tree that has no children - the other end of the tree from its root.

Node.IsLeaf asks whether a node is one, and IterateLeafs() yields every leaf below a node.

Level-Order

Level-order visits a tree’s nodes level by level: the root, then its children, then their children. It is breadth-first applied to a tree.

Node.IterateLevelOrder walks a tree that way. See pre-order and post-order for the two depth-first orders.

Wikipedia: Level order

License Expression

A license expression states how a work is licensed when one identifier can’t: Apache-2.0 OR MIT offers a choice, GPL-2.0-only WITH Classpath-exception-2.0 names an exception. SPDX defines the syntax.

pyTooling.Licensing models one as a tree - SPDXLicense with AndOperator, OrOperator, WithOperator and OrLaterOperator - so the licenses in an expression are one comprehension away. See Licensing.

Specification: SPDX license expressions

Matrix

A matrix is a job written once and run several times, once per combination of the values it is given - three Python versions on two operating systems are six jobs.

pyTooling.CI.Matrix groups the instances a matrix produced, and each MatrixJob carries the values it was produced for. GitHub reports no matrix as such - the instances are recognized by the bracketed values in a job’s name - see pyTooling.GitHub.

Meta-Class

A meta-class is a class helping to construct classes. Thus, it’s the type of a type - the default one is type.

pyTooling’s is ExtendedType, which derives slots from a class’ annotated fields and implements the abstract class, mixin and singleton behaviour this glossary describes - see Overview.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  T(type)
  ET(MetaClass)
  B(BaseClass)
  M(Mixin)
  C(Class)
  I1(Instance);I2(Instance)

  T --> T
  T:::mark1 --> ET:::mark1 -.class definition.-> B
  B:::mark2 --inheritance--> C:::mark2 -.instantiation..-> I1 & I2
  M --inheritance--> C

  classDef node font-size:smaller;
  classDef mark1 fill:#69f,stroke:#37f,color:#eee,font-size:smaller;
  classDef mark2 fill:#69f,stroke:#37f,font-size:smaller;
    

Relation of meta-classes, classes and instances.

MinGW

Minimalist GNU for Windows is a toolchain building native Windows programs with the GNU compilers. The maintained fork is MinGW-w64, which MSYS2 ships as one of its environments - beside the UCRT one - and which Platform tells apart.

Wikipedia: MinGW

Mixin
Mixin-Class

A mixin class is a class used as a secondary base-class in multiple inheritance. It contributes fields and methods to the class mixing it in, and is not meant to be instantiated on its own.

pyTooling writes one with ExtendedType and the mixin class keyword argument, which lets the mixin-class declare fields although it is not the primary base-class:

class ReportMixin(metaclass=ExtendedType, mixin=True, expects=("_counter", "Write")):
  def Report(self) -> bool:
    return self.Write(f"{self._counter}")

expects is the other half: a mixin-class contributing methods usually needs fields or methods from the class mixing it in, and naming them makes the combined class refuse to be instantiated when one is missing - see Expected Members.

A class deriving from a mixin-class rather than declaring the meta-class itself is marked with @mixin, so a class that is only ever a secondary base-class says so.

MRO

The method resolution order is the sequence Python searches a class’ bases in, which decides which implementation an inherited name resolves to. It is computed once per class (the C3 linearization) and read from __mro__.

It is what makes multiple inheritance predictable: a mixin listed before a base-class wins, and a super() call follows the order rather than the class it is written in.

Wikipedia: C3 linearization

MSYS2

MSYS2 is a software distribution and building platform for Windows, providing a Unix-like shell, a package manager (pacman) and several toolchains - among them MinGW and UCRT - each of which is a separate environment with its own Python.

Which environment a program runs in is what pyTooling.Platform.Platform reports, because a path or an executable’s name differs between them.

Wikipedia: MSYS2

Multiple Inheritance

Multiple inheritance derives a class from more than one base-class. The first is the primary base-class; the others usually contribute behaviour rather than identity - a mixin-class.

pyTooling’s ExtendedType is what makes it work with slots: a mixin-class marked mixin=True may declare fields although it is not the primary base-class, and they become slots of whichever class mixes it in.

Wikipedia: Multiple inheritance

Mustoverride Method

A must-override method provides a partial implementation (incomplete code) and must therefore be fully implemented by all derived classes. It is marked with @mustoverride, and unlike an abstract method its implementation can be called through super - see MustOverwrite Method.

If a must-override method is not overridden, an exception is raised when the class is instantiated, because the class is abstract.

Namespace Package

A namespace package is a package whose parts may come from several distributions, because it has no __init__.py of its own: importing it merges what every distribution contributes.

pyTooling is one. There is no pyTooling/__init__.py, which is why the package’s __version__ lives in pyTooling.Common - named as the packageInformationFile in setup.py - and why another distribution could add a pyTooling.Something of its own.

Native

A native environment is a platform just with the operating system. There is no additional environment layer like MSYS2, Cygwin or WSL, which is what Platform.IsNativePlatform reports.

Node

A node is one element of a tree or a graph, holding a value and its relations to other nodes.

In a tree a node has at most one parent - pyTooling.Tree.Node; in a graph it is called a vertex and is connected by edges.

Nullable

Nullable[T] is how pyTooling spells typing.Optional: every module imports it as from typing import Optional as Nullable, and every signature uses that spelling.

It says the value may be None - nothing more. Whether a parameter is optional is decided by its default, not by its annotation: a Nullable[...] parameter without a default is required and may be given None.

OpenTelemetry
OTLP

OpenTelemetry is the vendor-neutral standard for traces, metrics and logs, and OTLP is its protocol. Its JSON encoding is one document every usual destination reads: a collector accepts it natively, and Jaeger imports it.

A trace exports itself that way - Trace.ToJSON and WriteJSONFile(), see OTLP/JSON Export. pyTooling exports every span as kind INTERNAL, so the trace follows the conventions’ attributes, not their span kinds.

Wikipedia: OpenTelemetry

Overloading

Overloading is providing several implementations of one name, chosen by the arguments they are called with.

Python has no overloading: a second def of a name replaces the first. What it has is overload(), which declares the accepted signatures for a type checker while a single implementation dispatches on them itself.

Overriding

Overriding replaces a method inherited from a base-class with another implementation of the same name. Python needs no keyword for it - a def in the derived class shadows the inherited one, and super reaches the replaced implementation.

pyTooling makes the obligation explicit where there is one: an abstract method has no implementation and must be overridden, a mustoverride method has a partial one that must be, and both are checked when the class is instantiated - see Abstract Method and MustOverwrite Method.

Not to be confused with overloading, which is several implementations of one name in one class.

Parent

A parent is direct predecessor of a node.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C:::mark2 --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Parent of the current node are marked in blue.

Path
Path Flavour

A path names a place in a hierarchy as a sequence of elements, not as a string: pyTooling.GenericPath holds the elements, and a flavour says what the hierarchy looks like - its ELEMENT_DELIMITER, its ROOT_DELIMITER and the ELEMENT_TYPE its elements have.

pyTooling.GenericPath.URL.Path is the flavour of a URL. Composing with / and removing a trailing delimiter are the flavour-independent part, so a new flavour states its three declarations and inherits the rest.

Note

A path that starts at the root is absolute, and one that starts where it is read is relative - in the path sense, which is not this glossary’s relative, a sibling’s descendant in a tree.

Pipeline

A pipeline is one run of a CI service’s automation for one commit: the jobs it schedules, the steps they run, and the result they produce together.

pyTooling.CI.Pipeline models one - with called workflows, matrices, jobs and steps below it, each knowing its parent. See Pipeline.

Post-Order

Post-order is a depth-first traversal of a tree visiting a node after its children.

It is the order to use when a node’s result depends on its children’s - computing a size, or deleting a subtree.

See Pre-Order for the opposite.

Pre-Order

Pre-order is a depth-first traversal of a tree visiting a node before its children.

It is the order to use when a child’s handling depends on its parent’s - rendering an indented outline, or resolving a path from the root down.

See Post-Order for the opposite.

Program

A program is an executable command line application, abstracted as a Python class by Program: its name per operating system, and the arguments it accepts as CLI options.

A program only assembles a command line, whereas an executable also runs it.

Property
Read-only Property

A property is an attribute computed by a method: reading it calls a getter, and assigning it calls a setter - or fails, if there is none.

pyTooling writes a read-only property with @readonly, which is a property with a getter and nothing else, and which hands out the getter’s type rather than Any - see @readonly. Assignment behaviour is documented on the getter, because that is the doc-string Sphinx renders.

PyPI

The Python Package Index is the public repository pip installs from by default.

It is also what the dependency-table directive queries to resolve a dependency’s version and license.

Wikipedia: Python Package Index

PyPy

PyPy is an alternative Python implementation with a just-in-time compiler, generally faster than CPython for long-running pure-Python code and slower for anything dominated by C extensions.

pyTooling’s pipelines test against it, which is why the code avoids assuming CPython’s reference-counting behaviour - an object is not necessarily collected the moment its last name goes away.

Wikipedia: PyPy

Relative

Relatives are siblings and their descendants.

Left relatives are left siblings and all their descendants, whereas right relatives are right siblings and all their descendants.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL:::mark2 --> ELN1 & ELN2
  ELN1:::mark2
  ELN2:::mark2
  D:::cur --> EL & E & ER
  DR:::mark2 --> ERN1 & ERN2
  ERN1:::mark2
  ERN2:::mark2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Relatives of the current node are marked in blue.

Requirement
Requirements File

A requirement is a distribution another one needs, with the versions it accepts - pyTooling ~= 8.19 - and optionally an environment marker saying when it applies at all. A requirements file lists them, and may include another with -r.

RequirementsFile reads such a file as a tree: every file knows its parent, its root and the chain between, AllRequirements yields them in the order the files state them with the nearer statement winning, and a cycle raises rather than being read twice. See Python Packages.

See also

Dependency

→ What a requirement states, and the graph the dependencies form.

REST
REST-API

Representational State Transfer is an architectural style for web APIs: a resource is addressed by a URL, and the HTTP method says what to do with it - read it, create it, replace it, delete it. It is described in chapter 5 of Roy Fielding’s dissertation rather than by a standard, so what an API calls REST varies.

A REST API usually answers in JSON. pyTooling.GitHub reads the payloads GitHub’s REST API answers with for a workflow run.

Wikipedia: REST

Root

All nodes in a tree have one common ancestor called root.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R:::mark1 --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark1 fill:#69f,stroke:#37f,color:#eee;
    

Root of the current node are marked in blue.

Runner
Runner Group

A runner is the machine a job runs on - hosted by the service or self-hosted - and a runner group is how several of them are administered together, with who may use them.

The job model of pyTooling.GitHub reports which one a job ran on; the labels it asked for say what it wanted.

Schema

A schema is a formal description of the structure a document must have, written in a language of its own, so that a document can be checked against it instead of by reading it. XSD is one for XML, JSON-Schema one for JSON.

pyTooling publishes the schemas of the file formats it writes - see Overview - so a consumer of such a file can validate it without owning pyTooling.

Schema Validation

Schema validation checks a document against its schema and reports where the document deviates - a missing element, an attribute of the wrong type, children in the wrong order.

A file pyTooling writes names its schema, so validating it is one command:

xmllint --schema TestReport-v0.1.xsd --noout TestReport.xml
Semantic Version

A semantic version numbers a release by what changed in it: major.minor.patch, where the major part is raised for a breaking change, the minor for a compatible feature and the patch for a fix. A consumer can therefore state what it accepts.

SemanticVersion parses one, in the variants Variants lists, and version range states what a requirement accepts.

See also

Calendar Version

→ The other scheme: numbering a release by the date it was made.

Website: semver.org

Wikipedia: Software versioning

Sentinel

A sentinel is a value that stands for “nothing to say here” where None is a legitimate value, or where the real value can’t be written yet.

ThisClass is one: a class variable holding the class declaring it can’t be written in the class body, because the class doesn’t exist while its body runs, so the sentinel stands in it and ExtendedType replaces it with the finished class.

Sibling

Siblings are all direct child nodes of a node’s parent node except itself.

        %%{init: { "flowchart": { "nodeSpacing": 15, "rankSpacing": 30, "curve": "linear", "useMaxWidth": false } } }%%
graph TD
  R(Root)
  A(...)
  BL(Node); B(GrandParent); BR(Node)
  CL(Uncle); C(Parent); CR(Aunt)
  DL(Sibling); D(Node);  DR(Sibling)
  ELN1(Niece); ELN2(Nephew)
  EL(Child);   E(Child); ER(Child);
  ERN1(Niece);ERN2(Nephew)
  F1(GrandChild); F2(GrandChild)

  R --> A
  A --> BL & B & BR
  B --> CL & C & CR
  C --> DL & D & DR
  DL:::mark2 --> ELN1 & ELN2
  D:::cur --> EL & E & ER
  DR:::mark2 --> ERN1 & ERN2
  E --> F1 & F2

  classDef node fill:#eee,stroke:#777,font-size:smaller;
  classDef cur fill:#9e9,stroke:#6e6;
  classDef mark2 fill:#69f,stroke:#37f;
    

Siblings of the current node are marked in blue.

Singleton

The singleton design pattern ensures only a single instance of a class to exist. If another instance is going to be created, a previously cached instance of that class will be returned.

pyTooling writes one with ExtendedType and singleton=True, or with the @singleton decorator - see Singleton.

Slots

__slots__ fixes the set of instance attributes a class allows, so instances need no __dict__. That saves memory per instance and turns a typo into an error instead of a new attribute.

pyTooling’s ExtendedType meta-class derives the slots from the class’ annotated fields, so a class gets them by declaring its fields rather than by repeating their names.

A symbolic link is a file whose content is a path to another file or directory.

Unlike a hardlink it may point at a directory, may cross filesystems, and may dangle - the target can be removed or never have existed, which is why following one is an operation that can fail.

Span

A span is one timespan of a trace: when it began, when it ended, what it is called, and the attributes it carries. Spans nest, so a span holds the spans of whatever ran inside it.

pyTooling.Tracing.Span is one. A span is timed by the with-statement that enters and leaves it, or constructed with times recorded elsewhere - see Recorded Timespans.

SPDX

The Software Package Data Exchange is the standard for stating what a work is licensed under: an identifier per license (Apache-2.0, MIT-0), an exception list, and a syntax for combining them - a license expression.

pyTooling.Licensing is built on it: SPDX_INDEX maps every identifier it knows to a License, and a package’s license is published as an expression rather than as a classifier. See Licensing.

Wikipedia: SPDX

Step

A step is one command or action of a job, run in the job’s order on the job’s runner, with its own result.

pyTooling.CI.Step models one. A step that never started has no timing to report.

Subgraph

A subgraph is a part of a graph handled as a unit - a cluster the drawing keeps together, or a component the algorithm walks on its own.

pyTooling.Graph.Subgraph is one, and it is the difference between the two relations a graph has: an Edge stays inside a graph, while a Link crosses from one subgraph into another.

Wikipedia: Glossary of graph theory: subgraph

Test Suite
Testcase
Marker

A testcase is one test - one thing that either holds or doesn’t - and a test suite groups testcases and further suites, so a run is a tree rather than a list.

pyTooling marks them instead of naming them: @testsuite and @testcase are the markers, and they carry the title a report shows, which frees the class’ and method’s names from having to read as prose. See Finding Testcases and Testsuites.

Trace

A trace is the record of one execution: a tree of spans with their times, and the attributes describing what each of them was.

pyTooling.Tracing.Trace is the root span of such a tree, and exports itself as OTLP JSON - see Overview.

Wikipedia: Tracing

TOML

Tom’s Obvious, Minimal Language is a text format for configuration files, specified at toml.io. It is what pyproject.toml is written in, and the standard library reads it with tomllib.

As a pyTooling configuration format it is planned.

Wikipedia: TOML

Tree

A tree is a data structure made of nodes and parent-child relations. All nodes in a tree share one common ancestor called root.

A tree is a special form of a directed acyclic graph (DAG).

pyTooling.Tree implements one, and the family words this glossary defines - ancestor, descendant, sibling, relative - are the names of its iterators and properties.

UCRT

The Universal C Runtime is the C runtime library Windows ships itself, so a program linked against it needs no runtime of its own. It is the newer of the two MSYS2 toolchains - UCRT64 beside the MinGW one - and Platform reports which of them Python runs in.

Wikipedia: Microsoft Windows library files: UCRT

URI

A Uniform Resource Identifier names a resource, and is specified by RFC 3986. It is the general form: a URL is a URI that says where the resource is, a URN one that says what it is without saying where.

Wikipedia: Uniform Resource Identifier

URL

A Uniform Resource Locator is a URI that says where a resource is: a scheme, an authority - host, port and optionally user and password -, a path, a query and a fragment, as RFC 3986 writes them.

URL parses one, composes it with a resource below it using the / operator, and reports what it rejects as a URLError. Its path is a path flavour of pyTooling.GenericPath, so it is a sequence of elements rather than a string.

Wikipedia: Uniform Resource Locator

URN

A Uniform Resource Name is a URI in the urn: scheme, specified by RFC 8141. It names a resource persistently without saying where to get it - urn:isbn:0451450523 is a book, not a download.

Wikipedia: Uniform Resource Name

Version Range

A version range states which versions a requirement accepts - >=1.2.0,<2.0.0 - as a set with a lower and an upper bound, either of which may be open or absent.

VersionRange is one, and a version expression is what a requirements file writes, in the four dialects VersionRange describes. An intersection keeps both operands’ bound handling, so an excluded bound stays excluded.

Vertex

A vertex is a node in a graph - pyTooling.Graph.Vertex. Vertices in a graph are connected using edges.

Workflow

A workflow is an automation file a CI service runs - and, below a pipeline, a called workflow: one workflow started by another, whose jobs belong to the caller’s run.

pyTooling.CI.Workflow groups them, nested as deeply as they are called. GitHub reports no nesting as such - a called workflow is recognized by the Caller / Job shape of a job’s name, see pyTooling.GitHub.

WSL

The Windows Subsystem for Linux runs a Linux distribution on Windows. Python running in it is Python on Linux - Platform reports Linux, and says it is WSL beside it, because the file system and the executables around it are the host’s.

Wikipedia: Windows Subsystem for Linux

XML

The Extensible Markup Language is a text format for structured data, specified by the W3C’s XML recommendation.

pyTooling.Testing.ReportWriter writes a test report as one nested XML document, and the XSD describing it is shipped with pyTooling. As a configuration format XML is planned.

Wikipedia: XML

XML-Schema
XSD

An XML Schema Definition describes the structure an XML document must have - the elements, their attributes and their order - and is an XML document itself. It is specified by the W3C’s XML Schema.

pyTooling publishes one per file format it writes, each rendered with its types drawn as a graph - see Overview.

Wikipedia: XML Schema

YAML

YAML Ain’t Markup Language is an indentation-based text format for structured data, specified at yaml.org.

pyTooling reads it as a configuration format - YAML.

Wikipedia: YAML