Skip to main content

Typesafe resource management in Python

This package creates a definition file by traversing the resource folder and parsing the files

Features

  • Typesafe resource management (needs compatible type checker)
  • Automatic type definition generation
  • Middlewares, loaders api

PyPI: https://pypi.org/project/pathtyped/

pip install pathtyped

Showcase

This code can be found in demo

Your text files

resources/ data.json main.txt speech_0.txt speech_1.txt speech_2.txt


```py
# main.py
from pathtyped import *

rm = ResourceManager(
    f"resources",
    DefinitionFile("", f"resource_definition.py"),
    [remove_known_extensions(r"txt|json"), group_by(r"(speech)_(\d)")],
    [Loaders.text, Loaders.json],
)

from resource_definition import root

resource: root = rm.root  # type: ignore
# The file below does not exist yet
from definition import root

resource: root = resource_manager.root # type: ignore
# defaults.py
# No need to import anything since type str is already imported
# Example
from some_code import YourClass

Generates

# 8587d74aed20f794cdfc800f26c456b7
# Automatically generated by ResourceManager at: 2023-01-15 23:37:27.451164
# DO NOT EDIT THIS FILE MANUALLY. 
# If you want to regenerate this file, change the integrity hash in the first line to something else

# Some generic fixes
list = list[object]
dict = dict[object, object]

# Default import statement:

# Main content:
from typing import NamedTuple

root = NamedTuple("root", [
    ("speech", tuple[
        str,
        str,
        str,
    ],),
    ("data", dict),
    ("main", str),
])

And provides you with type compilation

1673847586091

Documentation

Middlewares

Middlewares are functions that have the ability to modify the tree structure itself as well as change the value of the nodes

They are applied in the order they are passed to the ResourceManager, with each middleware doing a full DFS preorder traversal of the tree

for middleware in middlewares:
    # The @middleware decorator will initiate the dfs preorder traversal
    tree = middleware(self, "<root>", tree)
drawing

This also means that the middleware will be applied to the leaf of the trees that it has returned. This is the most desirable behavior for applying middlewares

@middleware
def strip_numbers_in_string(r: ResourceManager, location: str, tree: EntryTree) -> Optional[EntryTree]:
    """Removes all number property from tree"""
    if isinstance(tree, EntryDict):
        new_tree = EntryDict()
        for key in list(tree.keys()):
            n = re.sub(r"\d+", "", key)
            new_tree[n] = tree[key]
        # If a new dict or list is returned, it will replace the old one
        # Be sure to return a new EntryTree
        return new_tree
    # Returning None indicates that the tree should not be changed
    # You can also modify tree in place and it will be reflected
    return None

Loaders

Loaders are simpler middlewares. They are functions that only take the leaf node and transform it into a useful value.

Most leaf nodes are Path objects

The resource manager will attempt to apply each loader to the leaf node in the order they are passed to the ResourceManager. Returning None indicates that the loader does not know how to handle the leaf node and will pass it to the next loader

for loader in self.loaders:
    if (r := loader(self, obj)) is not None:
        return r

If you want multiple loaders to be applied the same leaf node see the example code at the bottom

# Basic loaders
@loader
def return_suffix(r: ResourceManager, path: Path) -> str:
    return path.suffix

@loader
@extension("mp3")
def pygame_load(r: ResourceManager, path: Path) -> pygame.mixer.Sound:
    return pygame.mixer.Sound(path)

fallback_image = pygame.image.load("fallback.png")

@loader
@extension(r"png|jpg|jpeg")
@fallback(fallback_image) # If the loading raises an Exception
def pygame_image_load(r: ResourceManager, path: Path) -> pygame.Surface:
    return pygame.image.load(path)

# Advanced loaders

# Loader that accepts certain object nodes
# Requires a compatible middleware to generate such leaves
@loader(Script)
def execute(r: ResourceManager, s: Script) -> object:
    return s.execute()

# Two transformations
@loader
def str_node(r: ResourceManager, path: Path) -> str:
    return path.read_text()

@loader(str)
def str_to_int(r: ResourceManager, s: str) -> int:
    if s.isnumeric():
        return int(s)

@loader
def combined(r: ResourceManager, path: Path) -> Union[str, int]:
    res = path
    for l in [str_node, str_to_int]:
        if (t := l(r, res)) is not None:
            res = t
    return res

FAQ

Visual Studio Code shows that the type is any

Change the python.analysis.typeCheckingMode setting to strict and it not allow you to access invalid properties. Make sure that the Python language server is Pylance

{
    "python.analysis.typeCheckingMode": "strict"
}

Cannot import TypeGuard

Project requires Python 3.10 or higher

Contributing

If you have an idea for this library, please make an issue first instead of a PR. I will be happy to discuss it with you

Metadata

Release files for pathtyped 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pathtyped 0.1.4
File Size Uploaded
pathtyped-0.1.4.tar.gz 14.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pathtyped 0.1.4
File Interpreter ABI Platform
pathtyped-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 27.3 kB

Release files / pathtyped-0.1.4.tar.gz

Download URL pathtyped-0.1.4.tar.gz
Size 14.5 kB
Tags Source
SHA-256 checksum
How to use checksums
e2fde390358760fd183b2de4c44830318e4e1a3e35a48faa6f78d14602102978
BLAKE2b-256 checksum
How to use checksums
6e6f3e90a5a16a6b401c0745ebac5db1569c1a00e04119718f8f1a7cafe04639
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.1

Release files / pathtyped-0.1.4-py3-none-any.whl

Download URL pathtyped-0.1.4-py3-none-any.whl
Size 12.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3a6b1c5c0bbe484659c7a729f3144527c32d7bdb47c99ca69ef77800bc078547
BLAKE2b-256 checksum
How to use checksums
40ec68df4cbbdca9fc1d1d5fd70c602be061c27ea5cb2c00ca84043940daeb48
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.1

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page