API reference¶
Overview¶
Targets
A user-constructable object. |
|
A |
|
Build a target from a specification. |
Artifacts
A typed view into a directory. |
|
An artifact with dynamically named fields. |
|
An artifact field that does not yet exist. |
|
Recover an existing artifact. |
Context management
A collection of target-construction options. |
|
Return the call stack’s currently active context. |
|
Replace the active context in the current call stack. |
|
Revert to the previously active context. |
|
Return a context manager that makes a context active within its body. |
Schema generation
Return a JSON Schema describing valid artifact specifications. |
|
Return a JSON Schema describing lists of artifact specifications. |
|
Return a JSON Schema describing artifact specification dictionaries. |
Interface generation
A WSGI server that provides access to an Artisan context. |
Readers and writers
A |
|
A |
|
Read a text file using |
|
Read a JSON file using |
|
Read a NumPy array file or a NumPy archive using |
|
Read a CBOR file. |
|
Return the given path, unchanged. |
|
Write a JSON-encodable object or a NumPy array to a CBOR file. |
|
Create a symbolic link. |
Targets¶
-
class
Target
(spec: Target.Spec)¶ A user-constructable object.
All target constructors should accept a specification as their first argument. Specification attributes can be boolean values, integers, floating-point numbers, strings,
None
values,pathlib.Path
objects, artifacts, lists of allowed values, and namespace-like objects with__dict__
attributes containing only allowed values.If
spec
has atype
attribute,Target
’s constructor will dereference it in the current target scope and return an instance of the resulting type. The default target scope contains everyTarget
subclass defined outside of theartisan
library, and uses keys in the form<subclass>.__qualname__
for uniquely named target types andf'{<subclass>.__qualname__} ({<subclass>.__module__})'
for target types with non-unique names.artisan.push_context
orartisan.using_context
can be used to set the active target scope.Target
types can define an innerSpec
class to indicate the expected type ofspec
. If<subclass>.Spec
is not defined explicitly, it will be defined implicitly as a protocol with no required fields. Public, non-callable attributes of<subclass>.Spec
will be used as default values for missingspec
attributes.- Parameters
spec – The target’s specification.
-
class
Namespace
(*args: object, **kwargs: object)¶ A
SimpleNamespace
that prints readably.
-
build
(cls: Type[SomeTarget], spec: object, *args: object, **kwargs: object) → SomeTarget¶ Build a target from a specification.
To support using JSON-encodable objects as specifications, mappings in
spec
are converted to namespaces and artifact-root-relative path strings (strings starting with “@/”) are converted to artifacts if they point to an existing directory, andPath
objects otherwise.args
andkwargs
are forwarded to the target’s constructor.
Artifacts¶
-
class
Artifact
(spec: Artifact.Spec)¶ A typed view into a directory.
Instantiation
When an artifact is instantiated, Artisan will search for a directory with a matching
_meta_.json
file in the active context’s root directory. The search is recursive, but when a directory with a_meta_.json
file is found, its subdirectories will not be searched. If a matching directory does not exist, a new directory will be created, and the active context’s artifact builder will be called to build the artifact there. Ifspec
has a_path_
field, the artifact will be located at that path. The “@” operator, as inArtifactType @ path
, can be used to load an existing artifact without requiring it to match a specification. In the default context, the root directory is the current working directory, and the artifact builder calls__init__
and logs metadata to_meta_.json
.Reading and writing files
Reading from and writing to an artifact’s attributes corresponds to reading from and writing to files in the corresponding directory. Support for new file types can be added by overriding an artifact type’s list of readers (
_readers_
) and/or its list of writers (_writers_
). Readers should be functions that accept a path and return an object representing the data stored at that path. Writers should accept an extensionless path and a data object, write the data to a version of the path with an appropriate extension, and return that extension. To support concurrent reading and writing, files generated by writers are not moved into the artifact’s directory until after the writer returns.When reading from or writing to files, the first reader/writer not to raise an exception when called will be used. For performance, Artisan may skip writers whose data argument type does not match the object being stored. Similarly, Artisan may skip readers whose path argument type is annotated with an incompatible extension requirement, e.g.
Annotated[Path, '.txt']
orAnnotated[Path, '.jpg', '.jpeg']
. TheAnnotated
type constructor can be imported from thetyping
module in Python 3.9+ and thetyping_extensions
module in earlier versions.Attribute-access modes
Artifacts can be instantiated in “read-sync”, “read-async”, or “write” mode. In “read-sync” mode, attribute accesses will only return after the artifact has finished building. In “read-async” mode, attribute accesses will return as soon as a corresponding file or directory exists. In “write” mode, attribute accesses will return immediately, but a
ProxyArtifactField
will be returned if no corresponding file or directory is present. Artifacts are instantiated in “read-sync” mode by default, but ifspec
has a_mode_
attribute, that mode will be used. The default builder always executes artifacts’__init__
methods in “write” mode (an other builders should as well), so it is generally only necessary to specify_mode_
when “read-async” behavior is desired.- Parameters
spec (Artifact.Spec) – The artifact’s specification.
- Variables
_readers_ (ClassVar[List[Callable]]) – The deserialization functions artifacts of this type will try to use when their attributes are being accessed.
_writers_ (ClassVar[List[Callable]]) – The serialization functions artifacts of this type will try to use when their attributes are being assigned to.
_path_ (Path) – The artifact’s path on the filesystem.
_mode_ (Literal['read-sync', 'read-async', 'write']) – The artifact’s attribute-access mode.
-
class
Spec
¶ A protocol denoting valid specifications.
-
__getattr__
(key: str) → Any[source]¶ Return the data stored at
{self._path_}/{key}{inferred_extension}
.
-
__setattr__
(key: str, value: object) → None[source]¶ Write data to
{self._path_}/{key}{inferred_extension}
.The extension is determined based on the type of data stored. For performance, other entries with matching keys are not deleted. Use
__delattr__
to delete those entries.
-
class
DynamicArtifact
(spec: DynamicArtifact.Spec)¶ An artifact with dynamically named fields.
Item access, assignment, deletion, and iteration can be used in place of attribute access, assignment, deletion, and iteration
-
class
Spec
¶ A protocol denoting valid specifications.
-
class
-
class
ProxyArtifactField
(root: Artifact, *keys: str)¶ An artifact field that does not yet exist.
Corresponding files and/or directories will be created when it is written to.
-
__getattr__
(key: str) → ProxyArtifactField[source]¶
-
-
recover
(cls: Type[SomeArtifact], path: os.PathLike | str, mode: str = 'read-sync') → SomeArtifact¶ Recover an existing artifact.
mode
must be “read-sync”, “read-async”, or “write”.
Context management¶
-
class
Context
(*, root=None, scope=None, builder=None)¶ A collection of target-construction options.
- Parameters
root (Path | str | None) – The default directory for artifact creation, and the directory that will be searched for matches when an artifact is instantiated from a specification. By default,
root
is the current working directory.scope (Mapping[str, type] | None) – The mapping used to resolve type names in specifications during target instantiation. By default,
scope
contains all non-Artisan-defined target types.builder (Callable[[Artifact, object], None] | None) – The function called to write files into artifact directories.
builder
accepts two arguments, the artifact to construct and its specification. The default builder callsartifact.__init__(spec)
and logs metadata to a_meta_.json
file. Custom builders can log additional information or offload work to other processes to build artifacts in parallel.
- Variables
root (Path) –
root
as aPath
, ifroot
was provided, or the default, otherwise.scope (Mapping[str, type]) –
scope
, ifscope
was provided, or the default, otherwise.builder (Callable[[Artifact, object], None]) –
builder
, ifbuilder
was provided, or the default, otherwise.
-
push_context
(context=None, *, root=None, scope=None, builder=None)¶ Replace the active context in the current call stack.
pop_context
can be called to revert to the previously active context.- Parameters
context (Context | None) – A context to make active. A new context will be created if one is not provided.
root (Path | str | None) – A value to override
context.root
.scope (Mapping[str, type] | None) – A value to override
context.scope
.builder (Callable[[Artifact, object], None] | None) – A value to override
context.builder
.
-
pop_context
() → None¶ Revert to the previously active context.
A
LookupError
is raised if no context was previously active.
-
using_context
(context=None, *, root=None, scope=None, builder=None)¶ Return a context manager that makes a context active within its body.
- Parameters
context (Context | None) – A context to make active. A new context will be created if one is not provided.
root (Path | str | None) – A value to override
context.root
.scope (Mapping[str, type] | None) – A value to override
context.scope
.builder (Callable[[Artifact, object], None] | None) – A value to override
context.builder
.
Schema generation¶
-
get_spec_schema
() → dict¶ Return a JSON Schema describing valid artifact specifications.
The schema will contain a definition corresponding to the
Spec
type of every entry in the active scope.
-
get_spec_list_schema
() → dict¶ Return a JSON Schema describing lists of artifact specifications.
The schema will contain a definition corresponding to the
Spec
type of every entry in the active scope.
-
get_spec_dict_schema
() → dict¶ Return a JSON Schema describing artifact specification dictionaries.
Objects whose entries are artifact specifications will be valid against the schema. The schema will contain a definition corresponding to the
Spec
type of every entry in the active scope.
Interface generation¶
-
class
API
(*, permissions=None, ui=None, root=None, scope=None, builder=None)¶ A WSGI server that provides access to an Artisan context.
The following request types are supported:
GET /artifacts{/path*}
POST /artifacts
DELETE /artifacts{/path*}
GET /schemas/spec
GET /schemas/spec-list
GET /schemas/spec-dict
GET /ui{/path*}
Analogous
HEAD
andOPTIONS
requests are also supported.- Parameters
permissions – A mapping from passwords to permission sets. Permissions sets can contain “read”, “write”, and/or “delete”. The default permission policy is
{'': ('read', 'write', 'delete')}
, meaning even users who have not provided a password have “read”, “write”, and “delete” permissions.ui – The WSGI server that should handle requests in the form
/ui{/path*}
. The default UI is aWebUI
.root – A path to override the active context’s
root
.scope – A mapping to override the active context’s
scope
.builder – A callable to override the active context’s
builder
.
Readers and writers¶
-
class
PersistentList
(file_: io.BufferedRandom, length: int)¶ A
list
backed by a CBOR file.For performance, a
PersistentList
is invalidated when another object, including anotherPersistentList
, writes to its backing file. An invalidatedPersistentList
is a potentially out-of-date read-only view into the file, and callingappend
orextend
on it will corrupt the file.
-
class
PersistentArray
(filename, dtype='uint8', mode='r+', offset=0, shape=None, order='C')¶ A
numpy.memmap
backed by a CBOR file.The file must contain a row-major multidimensional array as defined in IETF RFC 8746. For performance, a
PersistentArray
is invalidated when another object, including anotherPersistentArray
, writes to its backing file. An invalidatedPersistentArray
is a potentially out-of-date read-only view into the file, and callingappend
orextend
on it will corrupt the file.Due to NumPy issue 4198 (https://github.com/numpy/numpy/issues/4198),
PersistenArray
extendsnp.memmap
by proxy, meaning that it delegates attribute accesses and method calls to an internalnp.memmap
object instead of using Python’s native subclassing mechanism.
-
read_text_file
(path: Annotated[Path, ''.txt'']) → str¶ Read a text file using
Path.read_text
.
-
read_json_file
(path: Annotated[Path, ''.json'']) → Any¶ Read a JSON file using
json.load
.JSON objects are read as namespaces.
-
read_numpy_file
(path: Annotated[Path, ''.npy'', ''.npz'']) → Any¶ Read a NumPy array file or a NumPy archive using
numpy.load
.
-
read_cbor_file
(path: Annotated[Path, ''.cbor'']) → Any¶ Read a CBOR file.
If the file encodes an indefinite-length array, a
PersistentList
will be returned.If the file encodes a 0–12-dimensional row-major array as specified in IETF RFC 8746, and the shape elements and byte string length are encoded as 8-byte unsigned integers, a
PersistentArray
will be returned.Otherwise, a JSON-like object will be returned.
-
read_opaque_file
(path: Path) → Path¶ Return the given path, unchanged.
-
write_object_as_cbor
(path: Path, val: object) → str¶ Write a JSON-encodable object or a NumPy array to a CBOR file.
-
write_path
(path: Path, val: Path) → str¶ Create a symbolic link.