openpathresolver package

Module contents

Find paths based on a structured query or build out a tree in the filesystem.

The open path resolver contains two parts. The path resolver is responsible for finding paths or the elements used to find a path. This can be used either to get where to save a file or where to try to find a file to load.

The workspace resolver is responsible for building out a tree for a given query. For example, if there is a location to save published elements and workspaces for building out the elements, and a user needs to build out the “Widget” element, then the system can automatically build out the file and folder structure needed for the user to do their work.

class openpathresolver.Config(resolvers, path_items)

Bases: object

Store the resolver configs.

The config stores two major components. The resolvers, which are responsible for resolving the placholder values, and the items, which are all of the path parts that are used to find paths or used to create paths.

exception openpathresolver.Error

Bases: Exception

Error for the workspace or path resolvers.

class openpathresolver.FieldKey(key)

Bases: object

A field key is a valid key to a field.

This can be used for path parts keys, the parent key, etc.

# Validation

  • The key must not be empty

  • The first character of the key must be any ASCII alphabetic character or _.

  • The remainder characters must be any ASCII alphanumeric character or _.

  • Sections can be split with .. The above rules then apply to each section.

class openpathresolver.IntegerResolver(padding)

Bases: object

An integer resolver marks a placeholder as an integer with zero padding.

padding

The zero padding for the integer.

class openpathresolver.Owner

Bases: object

The owner of the path.

Inherit = Owner.Inherit
Project = Owner.Project
Root = Owner.Root
User = Owner.User
class openpathresolver.PathItem(key, path, parent, permission, owner, path_type, deferred, metadata)

Bases: object

Input path item arguments.

class openpathresolver.PathType

Bases: object

The type of the path.

Directory = PathType.Directory
File = PathType.File
FileTemplate = PathType.FileTemplate
class openpathresolver.Permission

Bases: object

The permission for a path.

Inherit = Permission.Inherit
ReadOnly = Permission.ReadOnly
ReadWrite = Permission.ReadWrite
class openpathresolver.ResolvedPathItem

Bases: object

The path item that has been validated and resolved in the config.

deferred()

Whether the path is deferred or not.

key()

The key for the path.

metadata()

Metadata for the workspace resolver.

This could contain anything such as the specific user that owns the path, or the source path to copy and paste the file from.

owner()

The owner of the path.

There should be no inherited owner at this point, unless no owner has been defined at all. Then it is recommended to have the workspace resolver decide what the “root” owner should be.

path_type()

The type of the path.

It is assumed that all of the elements except the last will be directories. If the path is a file, then the workspace resolver should use simple logic to create a file (such as copying and pasting from another location). The file template can use a template engine defined in the create workspace’s IO function.

permission()

The permission for the path.

There should be no inherited permissions at this point unless no permissions have been defined at all. Then it is recommended to have the workspace resolver decide what the “root” permission should be.

value()

The fully resolved path.

This may not be a fully absolute path because the root can be defined as a variable.

class openpathresolver.StringResolver(pattern)

Bases: object

A string resolver marks a placeholder as a string with an optional shape.

pattern

The shape of the string.

openpathresolver.create_workspace(config, path_fields, template_fields, io_function)

Build a workspace by creating the files and folders for the given fields.

The create workspace function will use the path_fields to decide if a path should be built or not. In other words, this will create paths that can be resolved with the path fields, but other paths will not be created.

Parameters:
  • config – The config to build the workspace from.

  • path_fields – The fields to fill the path placeholders with. If a path includes a placeholder that does not include a field, then the path will not be built.

  • template_fields – The fields used to fill file templates with.

  • io_function – This function is responsible for actually creating the workspace and defining the rules of the workspace based on the config.

Example

async def main():
    tmp_root = pathlib.Path(tempfile.mkdtemp())

    config = openpathresolver.Config(
        {
            "int": openpathresolver.IntegerResolver(3),
            "str": openpathresolver.StringResolver(r"\w+"),
        },
        [
            openpathresolver.PathItem(
                "path",
                "{root}/path/to/{int}/{str}_{other}",
                None,
                openpathresolver.Permission.Inherit,
                openpathresolver.Owner.Inherit,
                openpathresolver.PathType.Directory,
                deferred=False,
                metadata={},
            )
        ],
    )

    async def io_function(
        config: openpathresolver.Config,  # noqa: ARG001
        template_args: collections.abc.Mapping[str, openpathresolver.TemplateValue],  # noqa: ARG001
        resolved_path_item: openpathresolver.ResolvedPathItem,
    ) -> None:
        resolved_path_item.value().mkdir(exist_ok=True, parents=True)

    await openpathresolver.create_workspace(
        config,
        {"root": tmp_root.as_posix(), "int": 3, "str": "test", "other": "other_test"},
        {},
        io_function,
    )

    assert (tmp_root / "path" / "to" / "003" / "test_other_test").is_dir()

asyncio.run(main())
openpathresolver.find_paths(config, key, fields)

Find paths from a given key and fields.

This differs from the get_path because it will search the filesystem for the paths and the fields do not need to be a superset of the path variables. If a path variable is missing, then that will signify to the system to return all paths that match that variable’s shape. For example, if a user needs to find all of the versions of the “Widget” publish, and the structure of the path looks like “{root}/publishes/{entity}/{version}”, then the only required fields will be root and entity.

Parameters:
  • config – The config to find the paths from.

  • key – The path item’s key used to find the paths.

  • fields – The fields used to fill the placeholders. If a field is not included, then that represents finding all of the paths of that placeholder type.

Example

tmp_root = pathlib.Path(tempfile.mkdtemp())
expected_paths = []

for index in range(3):
    test_dir = tmp_root / "path" / "to" / f"{index:03d}" / "test_other_test"
    test_dir.mkdir(parents=True, exist_ok=True)
    expected_paths.append(test_dir)

config = openpathresolver.Config(
    {
        "int": openpathresolver.IntegerResolver(3),
        "str": openpathresolver.StringResolver(r"\w+"),
    },
    [
        openpathresolver.PathItem(
            "path",
            "{root}/path/to/{int}/{str}_{other}",
            None,
            openpathresolver.Permission.Inherit,
            openpathresolver.Owner.Inherit,
            openpathresolver.PathType.Directory,
            deferred=False,
            metadata={},
        )
    ],
)

paths = openpathresolver.find_paths(
    config,
    "path",
    {"root": tmp_root.as_posix(), "str": "test", "other": "other_test"},
)

assert sorted(paths) == sorted(expected_paths)
openpathresolver.get_fields(config, key, path)

Try to extract the fields from a key and path.

Parameters:
  • config – The config to get the fields from.

  • key – The path item’s key to get the fields from.

  • path – The path to pull the values from.

Example

config = openpathresolver.Config(
    {
        "int": openpathresolver.IntegerResolver(3),
        "str": openpathresolver.StringResolver(r"\w+?"),
    },
    [
        openpathresolver.PathItem(
            "path",
            "path/to/{int}/{str}_{other}",
            None,
            openpathresolver.Permission.Inherit,
            openpathresolver.Owner.Inherit,
            openpathresolver.PathType.Directory,
            deferred=False,
            metadata={},
        )
    ],
)

fields = openpathresolver.get_fields(
    config, "path", pathlib.Path("path/to/004/test_other_test")
)
assert fields == {
    "int": 4,
    "str": "test",
    "other": "other_test",
}
openpathresolver.get_key(config, path, fields)

Find a key from a path and fields.

Parameters:
  • config – The config to get the key from.

  • path – The path to use to find the key for.

  • fields – The fields used to fill the placeholders in the path.

Example

config = openpathresolver.Config(
    {
        "int": openpathresolver.IntegerResolver(3),
        "str": openpathresolver.StringResolver(r"\w+"),
    },
    [
        openpathresolver.PathItem(
            "path",
            "path/to/{int}/{str}_{other}",
            None,
            openpathresolver.Permission.Inherit,
            openpathresolver.Owner.Inherit,
            openpathresolver.PathType.Directory,
            deferred=False,
            metadata={},
        )
    ],
)

key = openpathresolver.get_key(
    config,
    "path/to/003/test_other_test",
    {
        "int": 3,
        "str": "test",
        "other": "other_test",
    },
)
assert key == "path"
openpathresolver.get_path(config, key, fields)

Resolve a path from a key and fields.

This will get a path to find in the filesystem or save to based on the input key and fields.

Parameters:
  • config – The config to get the path from.

  • key – The path item’s key to generate the path from.

  • fields – The fields used to fill the placeholders in the path.

Example

config = openpathresolver.Config(
    {
        "int": openpathresolver.IntegerResolver(3),
        "str": openpathresolver.StringResolver(r"\w+"),
    },
    [
        openpathresolver.PathItem(
            "path",
            "path/to/{int}/{str}_{other}",
            None,
            openpathresolver.Permission.Inherit,
            openpathresolver.Owner.Inherit,
            openpathresolver.PathType.Directory,
            deferred=False,
            metadata={},
        )
    ],
)

path = openpathresolver.get_path(
    config,
    "path",
    {
        "int": 3,
        "str": "test",
        "other": "other_test",
    },
)
assert path == pathlib.Path("path/to/003/test_other_test")
openpathresolver.get_workspace(config, path_fields)

Get all of the path items that would be created with the create_workspace function.

The only paths that will be returned are paths that can be fully resolved with the given path fields.

Example

tmp_root = pathlib.Path(tempfile.mkdtemp())

config = openpathresolver.Config(
    {
        "int": openpathresolver.IntegerResolver(3),
        "str": openpathresolver.StringResolver(r"\w+"),
    },
    [
        openpathresolver.PathItem(
            "path",
            "{root}/path/to/{int}/{str}_{other}",
            None,
            openpathresolver.Permission.Inherit,
            openpathresolver.Owner.Inherit,
            openpathresolver.PathType.Directory,
            deferred=False,
            metadata={},
        )
    ],
)

result = openpathresolver.get_workspace(
    config,
    {"root": tmp_root.as_posix(), "int": 3, "str": "test", "other": "other_test"},
)
assert sorted(
    [
        tmp_root,
        tmp_root / "path",
        tmp_root / "path" / "to",
        tmp_root / "path" / "to" / "003",
        tmp_root / "path" / "to" / "003" / "test_other_test",
    ]
) == sorted([i.value() for i in result])