appm 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- appm/.mypy_cache/.gitignore +2 -0
- appm/.mypy_cache/3.10/@plugins_snapshot.json +1 -0
- appm/.mypy_cache/3.10/__future__.data.json +1 -0
- appm/.mypy_cache/3.10/__future__.meta.json +1 -0
- appm/.mypy_cache/3.10/_ast.data.json +1 -0
- appm/.mypy_cache/3.10/_ast.meta.json +1 -0
- appm/.mypy_cache/3.10/_bz2.data.json +1 -0
- appm/.mypy_cache/3.10/_bz2.meta.json +1 -0
- appm/.mypy_cache/3.10/_codecs.data.json +1 -0
- appm/.mypy_cache/3.10/_codecs.meta.json +1 -0
- appm/.mypy_cache/3.10/_collections_abc.data.json +1 -0
- appm/.mypy_cache/3.10/_collections_abc.meta.json +1 -0
- appm/.mypy_cache/3.10/_compression.data.json +1 -0
- appm/.mypy_cache/3.10/_compression.meta.json +1 -0
- appm/.mypy_cache/3.10/_contextvars.data.json +1 -0
- appm/.mypy_cache/3.10/_contextvars.meta.json +1 -0
- appm/.mypy_cache/3.10/_decimal.data.json +1 -0
- appm/.mypy_cache/3.10/_decimal.meta.json +1 -0
- appm/.mypy_cache/3.10/_frozen_importlib.data.json +1 -0
- appm/.mypy_cache/3.10/_frozen_importlib.meta.json +1 -0
- appm/.mypy_cache/3.10/_frozen_importlib_external.data.json +1 -0
- appm/.mypy_cache/3.10/_frozen_importlib_external.meta.json +1 -0
- appm/.mypy_cache/3.10/_io.data.json +1 -0
- appm/.mypy_cache/3.10/_io.meta.json +1 -0
- appm/.mypy_cache/3.10/_operator.data.json +1 -0
- appm/.mypy_cache/3.10/_operator.meta.json +1 -0
- appm/.mypy_cache/3.10/_pickle.data.json +1 -0
- appm/.mypy_cache/3.10/_pickle.meta.json +1 -0
- appm/.mypy_cache/3.10/_sitebuiltins.data.json +1 -0
- appm/.mypy_cache/3.10/_sitebuiltins.meta.json +1 -0
- appm/.mypy_cache/3.10/_typeshed/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/_typeshed/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/_typeshed/importlib.data.json +1 -0
- appm/.mypy_cache/3.10/_typeshed/importlib.meta.json +1 -0
- appm/.mypy_cache/3.10/_warnings.data.json +1 -0
- appm/.mypy_cache/3.10/_warnings.meta.json +1 -0
- appm/.mypy_cache/3.10/_weakref.data.json +1 -0
- appm/.mypy_cache/3.10/_weakref.meta.json +1 -0
- appm/.mypy_cache/3.10/_weakrefset.data.json +1 -0
- appm/.mypy_cache/3.10/_weakrefset.meta.json +1 -0
- appm/.mypy_cache/3.10/abc.data.json +1 -0
- appm/.mypy_cache/3.10/abc.meta.json +1 -0
- appm/.mypy_cache/3.10/annotated_types/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/annotated_types/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/appm/__version__.data.json +1 -0
- appm/.mypy_cache/3.10/appm/__version__.meta.json +1 -0
- appm/.mypy_cache/3.10/appm/exceptions.data.json +1 -0
- appm/.mypy_cache/3.10/appm/exceptions.meta.json +1 -0
- appm/.mypy_cache/3.10/appm/utils.data.json +1 -0
- appm/.mypy_cache/3.10/appm/utils.meta.json +1 -0
- appm/.mypy_cache/3.10/ast.data.json +1 -0
- appm/.mypy_cache/3.10/ast.meta.json +1 -0
- appm/.mypy_cache/3.10/base64.data.json +1 -0
- appm/.mypy_cache/3.10/base64.meta.json +1 -0
- appm/.mypy_cache/3.10/builtins.data.json +1 -0
- appm/.mypy_cache/3.10/builtins.meta.json +1 -0
- appm/.mypy_cache/3.10/bz2.data.json +1 -0
- appm/.mypy_cache/3.10/bz2.meta.json +1 -0
- appm/.mypy_cache/3.10/codecs.data.json +1 -0
- appm/.mypy_cache/3.10/codecs.meta.json +1 -0
- appm/.mypy_cache/3.10/collections/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/collections/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/collections/abc.data.json +1 -0
- appm/.mypy_cache/3.10/collections/abc.meta.json +1 -0
- appm/.mypy_cache/3.10/colorsys.data.json +1 -0
- appm/.mypy_cache/3.10/colorsys.meta.json +1 -0
- appm/.mypy_cache/3.10/contextlib.data.json +1 -0
- appm/.mypy_cache/3.10/contextlib.meta.json +1 -0
- appm/.mypy_cache/3.10/contextvars.data.json +1 -0
- appm/.mypy_cache/3.10/contextvars.meta.json +1 -0
- appm/.mypy_cache/3.10/copy.data.json +1 -0
- appm/.mypy_cache/3.10/copy.meta.json +1 -0
- appm/.mypy_cache/3.10/dataclasses.data.json +1 -0
- appm/.mypy_cache/3.10/dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.10/datetime.data.json +1 -0
- appm/.mypy_cache/3.10/datetime.meta.json +1 -0
- appm/.mypy_cache/3.10/decimal.data.json +1 -0
- appm/.mypy_cache/3.10/decimal.meta.json +1 -0
- appm/.mypy_cache/3.10/dis.data.json +1 -0
- appm/.mypy_cache/3.10/dis.meta.json +1 -0
- appm/.mypy_cache/3.10/email/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/email/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/email/_policybase.data.json +1 -0
- appm/.mypy_cache/3.10/email/_policybase.meta.json +1 -0
- appm/.mypy_cache/3.10/email/charset.data.json +1 -0
- appm/.mypy_cache/3.10/email/charset.meta.json +1 -0
- appm/.mypy_cache/3.10/email/contentmanager.data.json +1 -0
- appm/.mypy_cache/3.10/email/contentmanager.meta.json +1 -0
- appm/.mypy_cache/3.10/email/errors.data.json +1 -0
- appm/.mypy_cache/3.10/email/errors.meta.json +1 -0
- appm/.mypy_cache/3.10/email/header.data.json +1 -0
- appm/.mypy_cache/3.10/email/header.meta.json +1 -0
- appm/.mypy_cache/3.10/email/message.data.json +1 -0
- appm/.mypy_cache/3.10/email/message.meta.json +1 -0
- appm/.mypy_cache/3.10/email/policy.data.json +1 -0
- appm/.mypy_cache/3.10/email/policy.meta.json +1 -0
- appm/.mypy_cache/3.10/enum.data.json +1 -0
- appm/.mypy_cache/3.10/enum.meta.json +1 -0
- appm/.mypy_cache/3.10/functools.data.json +1 -0
- appm/.mypy_cache/3.10/functools.meta.json +1 -0
- appm/.mypy_cache/3.10/genericpath.data.json +1 -0
- appm/.mypy_cache/3.10/genericpath.meta.json +1 -0
- appm/.mypy_cache/3.10/gzip.data.json +1 -0
- appm/.mypy_cache/3.10/gzip.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/_abc.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/_abc.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/_bootstrap.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/_bootstrap.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/_bootstrap_external.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/_bootstrap_external.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/abc.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/abc.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/machinery.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/machinery.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/metadata/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/metadata/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/metadata/_meta.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/metadata/_meta.meta.json +1 -0
- appm/.mypy_cache/3.10/importlib/readers.data.json +1 -0
- appm/.mypy_cache/3.10/importlib/readers.meta.json +1 -0
- appm/.mypy_cache/3.10/inspect.data.json +1 -0
- appm/.mypy_cache/3.10/inspect.meta.json +1 -0
- appm/.mypy_cache/3.10/io.data.json +1 -0
- appm/.mypy_cache/3.10/io.meta.json +1 -0
- appm/.mypy_cache/3.10/ipaddress.data.json +1 -0
- appm/.mypy_cache/3.10/ipaddress.meta.json +1 -0
- appm/.mypy_cache/3.10/itertools.data.json +1 -0
- appm/.mypy_cache/3.10/itertools.meta.json +1 -0
- appm/.mypy_cache/3.10/json/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/json/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/json/decoder.data.json +1 -0
- appm/.mypy_cache/3.10/json/decoder.meta.json +1 -0
- appm/.mypy_cache/3.10/json/encoder.data.json +1 -0
- appm/.mypy_cache/3.10/json/encoder.meta.json +1 -0
- appm/.mypy_cache/3.10/keyword.data.json +1 -0
- appm/.mypy_cache/3.10/keyword.meta.json +1 -0
- appm/.mypy_cache/3.10/math.data.json +1 -0
- appm/.mypy_cache/3.10/math.meta.json +1 -0
- appm/.mypy_cache/3.10/numbers.data.json +1 -0
- appm/.mypy_cache/3.10/numbers.meta.json +1 -0
- appm/.mypy_cache/3.10/opcode.data.json +1 -0
- appm/.mypy_cache/3.10/opcode.meta.json +1 -0
- appm/.mypy_cache/3.10/operator.data.json +1 -0
- appm/.mypy_cache/3.10/operator.meta.json +1 -0
- appm/.mypy_cache/3.10/os/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/os/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/os/path.data.json +1 -0
- appm/.mypy_cache/3.10/os/path.meta.json +1 -0
- appm/.mypy_cache/3.10/pathlib.data.json +1 -0
- appm/.mypy_cache/3.10/pathlib.meta.json +1 -0
- appm/.mypy_cache/3.10/pickle.data.json +1 -0
- appm/.mypy_cache/3.10/pickle.meta.json +1 -0
- appm/.mypy_cache/3.10/posixpath.data.json +1 -0
- appm/.mypy_cache/3.10/posixpath.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_config.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_config.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_core_metadata.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_core_metadata.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_core_utils.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_core_utils.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_dataclasses.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_decorators.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_decorators.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_decorators_v1.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_decorators_v1.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_discriminated_union.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_discriminated_union.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_fields.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_fields.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_forward_ref.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_forward_ref.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_generate_schema.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_generate_schema.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_generics.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_generics.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_internal_dataclass.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_internal_dataclass.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_known_annotated_metadata.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_known_annotated_metadata.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_mock_val_ser.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_mock_val_ser.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_model_construction.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_model_construction.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_repr.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_repr.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_schema_generation_shared.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_schema_generation_shared.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_std_types_schema.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_std_types_schema.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_typing_extra.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_typing_extra.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_utils.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_utils.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_validate_call.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_validate_call.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_validators.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_internal/_validators.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_migration.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/_migration.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/annotated_handlers.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/annotated_handlers.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/color.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/color.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/config.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/config.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/dataclasses.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/class_validators.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/class_validators.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/config.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/config.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/copy_internals.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/copy_internals.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/json.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/json.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/parse.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/parse.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/tools.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/deprecated/tools.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/errors.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/errors.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/fields.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/fields.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/functional_serializers.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/functional_serializers.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/functional_validators.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/functional_validators.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/json_schema.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/json_schema.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/main.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/main.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/networks.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/networks.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/plugin/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/plugin/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/plugin/_schema_validator.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/plugin/_schema_validator.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/root_model.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/root_model.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/type_adapter.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/type_adapter.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/types.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/types.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/validate_call.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/validate_call.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/validators.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/validators.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/version.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/version.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic/warnings.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic/warnings.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/_pydantic_core.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/_pydantic_core.meta.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/core_schema.data.json +1 -0
- appm/.mypy_cache/3.10/pydantic_core/core_schema.meta.json +1 -0
- appm/.mypy_cache/3.10/re.data.json +1 -0
- appm/.mypy_cache/3.10/re.meta.json +1 -0
- appm/.mypy_cache/3.10/resource.data.json +1 -0
- appm/.mypy_cache/3.10/resource.meta.json +1 -0
- appm/.mypy_cache/3.10/shutil.data.json +1 -0
- appm/.mypy_cache/3.10/shutil.meta.json +1 -0
- appm/.mypy_cache/3.10/sre_compile.data.json +1 -0
- appm/.mypy_cache/3.10/sre_compile.meta.json +1 -0
- appm/.mypy_cache/3.10/sre_constants.data.json +1 -0
- appm/.mypy_cache/3.10/sre_constants.meta.json +1 -0
- appm/.mypy_cache/3.10/sre_parse.data.json +1 -0
- appm/.mypy_cache/3.10/sre_parse.meta.json +1 -0
- appm/.mypy_cache/3.10/subprocess.data.json +1 -0
- appm/.mypy_cache/3.10/subprocess.meta.json +1 -0
- appm/.mypy_cache/3.10/sys/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/sys/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/tarfile.data.json +1 -0
- appm/.mypy_cache/3.10/tarfile.meta.json +1 -0
- appm/.mypy_cache/3.10/time.data.json +1 -0
- appm/.mypy_cache/3.10/time.meta.json +1 -0
- appm/.mypy_cache/3.10/types.data.json +1 -0
- appm/.mypy_cache/3.10/types.meta.json +1 -0
- appm/.mypy_cache/3.10/typing.data.json +1 -0
- appm/.mypy_cache/3.10/typing.meta.json +1 -0
- appm/.mypy_cache/3.10/typing_extensions.data.json +1 -0
- appm/.mypy_cache/3.10/typing_extensions.meta.json +1 -0
- appm/.mypy_cache/3.10/uuid.data.json +1 -0
- appm/.mypy_cache/3.10/uuid.meta.json +1 -0
- appm/.mypy_cache/3.10/warnings.data.json +1 -0
- appm/.mypy_cache/3.10/warnings.meta.json +1 -0
- appm/.mypy_cache/3.10/weakref.data.json +1 -0
- appm/.mypy_cache/3.10/weakref.meta.json +1 -0
- appm/.mypy_cache/3.10/zipfile/__init__.data.json +1 -0
- appm/.mypy_cache/3.10/zipfile/__init__.meta.json +1 -0
- appm/.mypy_cache/3.10/zlib.data.json +1 -0
- appm/.mypy_cache/3.10/zlib.meta.json +1 -0
- appm/.mypy_cache/3.13/@plugins_snapshot.json +1 -0
- appm/.mypy_cache/3.13/__future__.data.json +1 -0
- appm/.mypy_cache/3.13/__future__.meta.json +1 -0
- appm/.mypy_cache/3.13/_ast.data.json +1 -0
- appm/.mypy_cache/3.13/_ast.meta.json +1 -0
- appm/.mypy_cache/3.13/_bz2.data.json +1 -0
- appm/.mypy_cache/3.13/_bz2.meta.json +1 -0
- appm/.mypy_cache/3.13/_codecs.data.json +1 -0
- appm/.mypy_cache/3.13/_codecs.meta.json +1 -0
- appm/.mypy_cache/3.13/_collections_abc.data.json +1 -0
- appm/.mypy_cache/3.13/_collections_abc.meta.json +1 -0
- appm/.mypy_cache/3.13/_compression.data.json +1 -0
- appm/.mypy_cache/3.13/_compression.meta.json +1 -0
- appm/.mypy_cache/3.13/_contextvars.data.json +1 -0
- appm/.mypy_cache/3.13/_contextvars.meta.json +1 -0
- appm/.mypy_cache/3.13/_decimal.data.json +1 -0
- appm/.mypy_cache/3.13/_decimal.meta.json +1 -0
- appm/.mypy_cache/3.13/_frozen_importlib.data.json +1 -0
- appm/.mypy_cache/3.13/_frozen_importlib.meta.json +1 -0
- appm/.mypy_cache/3.13/_frozen_importlib_external.data.json +1 -0
- appm/.mypy_cache/3.13/_frozen_importlib_external.meta.json +1 -0
- appm/.mypy_cache/3.13/_io.data.json +1 -0
- appm/.mypy_cache/3.13/_io.meta.json +1 -0
- appm/.mypy_cache/3.13/_operator.data.json +1 -0
- appm/.mypy_cache/3.13/_operator.meta.json +1 -0
- appm/.mypy_cache/3.13/_pickle.data.json +1 -0
- appm/.mypy_cache/3.13/_pickle.meta.json +1 -0
- appm/.mypy_cache/3.13/_sitebuiltins.data.json +1 -0
- appm/.mypy_cache/3.13/_sitebuiltins.meta.json +1 -0
- appm/.mypy_cache/3.13/_typeshed/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/_typeshed/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/_typeshed/importlib.data.json +1 -0
- appm/.mypy_cache/3.13/_typeshed/importlib.meta.json +1 -0
- appm/.mypy_cache/3.13/_warnings.data.json +1 -0
- appm/.mypy_cache/3.13/_warnings.meta.json +1 -0
- appm/.mypy_cache/3.13/_weakref.data.json +1 -0
- appm/.mypy_cache/3.13/_weakref.meta.json +1 -0
- appm/.mypy_cache/3.13/_weakrefset.data.json +1 -0
- appm/.mypy_cache/3.13/_weakrefset.meta.json +1 -0
- appm/.mypy_cache/3.13/abc.data.json +1 -0
- appm/.mypy_cache/3.13/abc.meta.json +1 -0
- appm/.mypy_cache/3.13/annotated_types/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/annotated_types/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/appm/__version__.data.json +1 -0
- appm/.mypy_cache/3.13/appm/__version__.meta.json +1 -0
- appm/.mypy_cache/3.13/appm/default.data.json +1 -0
- appm/.mypy_cache/3.13/appm/default.meta.json +1 -0
- appm/.mypy_cache/3.13/appm/exceptions.data.json +1 -0
- appm/.mypy_cache/3.13/appm/exceptions.meta.json +1 -0
- appm/.mypy_cache/3.13/appm/utils.data.json +1 -0
- appm/.mypy_cache/3.13/appm/utils.meta.json +1 -0
- appm/.mypy_cache/3.13/ast.data.json +1 -0
- appm/.mypy_cache/3.13/ast.meta.json +1 -0
- appm/.mypy_cache/3.13/base64.data.json +1 -0
- appm/.mypy_cache/3.13/base64.meta.json +1 -0
- appm/.mypy_cache/3.13/binascii.data.json +1 -0
- appm/.mypy_cache/3.13/binascii.meta.json +1 -0
- appm/.mypy_cache/3.13/builtins.data.json +1 -0
- appm/.mypy_cache/3.13/builtins.meta.json +1 -0
- appm/.mypy_cache/3.13/bz2.data.json +1 -0
- appm/.mypy_cache/3.13/bz2.meta.json +1 -0
- appm/.mypy_cache/3.13/codecs.data.json +1 -0
- appm/.mypy_cache/3.13/codecs.meta.json +1 -0
- appm/.mypy_cache/3.13/collections/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/collections/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/collections/abc.data.json +1 -0
- appm/.mypy_cache/3.13/collections/abc.meta.json +1 -0
- appm/.mypy_cache/3.13/colorsys.data.json +1 -0
- appm/.mypy_cache/3.13/colorsys.meta.json +1 -0
- appm/.mypy_cache/3.13/contextlib.data.json +1 -0
- appm/.mypy_cache/3.13/contextlib.meta.json +1 -0
- appm/.mypy_cache/3.13/contextvars.data.json +1 -0
- appm/.mypy_cache/3.13/contextvars.meta.json +1 -0
- appm/.mypy_cache/3.13/copy.data.json +1 -0
- appm/.mypy_cache/3.13/copy.meta.json +1 -0
- appm/.mypy_cache/3.13/copyreg.data.json +1 -0
- appm/.mypy_cache/3.13/copyreg.meta.json +1 -0
- appm/.mypy_cache/3.13/dataclasses.data.json +1 -0
- appm/.mypy_cache/3.13/dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.13/datetime.data.json +1 -0
- appm/.mypy_cache/3.13/datetime.meta.json +1 -0
- appm/.mypy_cache/3.13/decimal.data.json +1 -0
- appm/.mypy_cache/3.13/decimal.meta.json +1 -0
- appm/.mypy_cache/3.13/dis.data.json +1 -0
- appm/.mypy_cache/3.13/dis.meta.json +1 -0
- appm/.mypy_cache/3.13/email/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/email/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/email/_policybase.data.json +1 -0
- appm/.mypy_cache/3.13/email/_policybase.meta.json +1 -0
- appm/.mypy_cache/3.13/email/charset.data.json +1 -0
- appm/.mypy_cache/3.13/email/charset.meta.json +1 -0
- appm/.mypy_cache/3.13/email/contentmanager.data.json +1 -0
- appm/.mypy_cache/3.13/email/contentmanager.meta.json +1 -0
- appm/.mypy_cache/3.13/email/errors.data.json +1 -0
- appm/.mypy_cache/3.13/email/errors.meta.json +1 -0
- appm/.mypy_cache/3.13/email/header.data.json +1 -0
- appm/.mypy_cache/3.13/email/header.meta.json +1 -0
- appm/.mypy_cache/3.13/email/message.data.json +1 -0
- appm/.mypy_cache/3.13/email/message.meta.json +1 -0
- appm/.mypy_cache/3.13/email/policy.data.json +1 -0
- appm/.mypy_cache/3.13/email/policy.meta.json +1 -0
- appm/.mypy_cache/3.13/enum.data.json +1 -0
- appm/.mypy_cache/3.13/enum.meta.json +1 -0
- appm/.mypy_cache/3.13/fractions.data.json +1 -0
- appm/.mypy_cache/3.13/fractions.meta.json +1 -0
- appm/.mypy_cache/3.13/functools.data.json +1 -0
- appm/.mypy_cache/3.13/functools.meta.json +1 -0
- appm/.mypy_cache/3.13/genericpath.data.json +1 -0
- appm/.mypy_cache/3.13/genericpath.meta.json +1 -0
- appm/.mypy_cache/3.13/glob.data.json +1 -0
- appm/.mypy_cache/3.13/glob.meta.json +1 -0
- appm/.mypy_cache/3.13/gzip.data.json +1 -0
- appm/.mypy_cache/3.13/gzip.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/_abc.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/_abc.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/_bootstrap.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/_bootstrap.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/_bootstrap_external.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/_bootstrap_external.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/abc.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/abc.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/machinery.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/machinery.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/metadata/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/metadata/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/metadata/_meta.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/metadata/_meta.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/readers.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/readers.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/_common.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/_common.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/_functional.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/_functional.meta.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/abc.data.json +1 -0
- appm/.mypy_cache/3.13/importlib/resources/abc.meta.json +1 -0
- appm/.mypy_cache/3.13/inspect.data.json +1 -0
- appm/.mypy_cache/3.13/inspect.meta.json +1 -0
- appm/.mypy_cache/3.13/io.data.json +1 -0
- appm/.mypy_cache/3.13/io.meta.json +1 -0
- appm/.mypy_cache/3.13/ipaddress.data.json +1 -0
- appm/.mypy_cache/3.13/ipaddress.meta.json +1 -0
- appm/.mypy_cache/3.13/itertools.data.json +1 -0
- appm/.mypy_cache/3.13/itertools.meta.json +1 -0
- appm/.mypy_cache/3.13/json/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/json/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/json/decoder.data.json +1 -0
- appm/.mypy_cache/3.13/json/decoder.meta.json +1 -0
- appm/.mypy_cache/3.13/json/encoder.data.json +1 -0
- appm/.mypy_cache/3.13/json/encoder.meta.json +1 -0
- appm/.mypy_cache/3.13/keyword.data.json +1 -0
- appm/.mypy_cache/3.13/keyword.meta.json +1 -0
- appm/.mypy_cache/3.13/math.data.json +1 -0
- appm/.mypy_cache/3.13/math.meta.json +1 -0
- appm/.mypy_cache/3.13/numbers.data.json +1 -0
- appm/.mypy_cache/3.13/numbers.meta.json +1 -0
- appm/.mypy_cache/3.13/opcode.data.json +1 -0
- appm/.mypy_cache/3.13/opcode.meta.json +1 -0
- appm/.mypy_cache/3.13/operator.data.json +1 -0
- appm/.mypy_cache/3.13/operator.meta.json +1 -0
- appm/.mypy_cache/3.13/os/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/os/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/os/path.data.json +1 -0
- appm/.mypy_cache/3.13/os/path.meta.json +1 -0
- appm/.mypy_cache/3.13/pathlib.data.json +1 -0
- appm/.mypy_cache/3.13/pathlib.meta.json +1 -0
- appm/.mypy_cache/3.13/pickle.data.json +1 -0
- appm/.mypy_cache/3.13/pickle.meta.json +1 -0
- appm/.mypy_cache/3.13/posixpath.data.json +1 -0
- appm/.mypy_cache/3.13/posixpath.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_config.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_config.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_core_metadata.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_core_metadata.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_core_utils.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_core_utils.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_dataclasses.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_decorators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_decorators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_decorators_v1.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_decorators_v1.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_discriminated_union.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_discriminated_union.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_docs_extraction.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_docs_extraction.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_fields.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_fields.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_forward_ref.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_forward_ref.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_generate_schema.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_generate_schema.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_generics.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_generics.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_import_utils.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_import_utils.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_internal_dataclass.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_internal_dataclass.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_known_annotated_metadata.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_known_annotated_metadata.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_mock_val_ser.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_mock_val_ser.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_model_construction.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_model_construction.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_namespace_utils.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_namespace_utils.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_repr.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_repr.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_schema_gather.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_schema_gather.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_schema_generation_shared.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_schema_generation_shared.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_serializers.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_serializers.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_signature.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_signature.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_typing_extra.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_typing_extra.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_utils.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_utils.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_validate_call.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_validate_call.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_validators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_internal/_validators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_migration.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/_migration.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/aliases.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/aliases.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/annotated_handlers.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/annotated_handlers.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/color.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/color.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/config.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/config.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/dataclasses.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/class_validators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/class_validators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/config.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/config.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/copy_internals.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/copy_internals.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/json.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/json.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/parse.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/parse.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/tools.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/deprecated/tools.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/errors.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/errors.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/fields.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/fields.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/functional_serializers.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/functional_serializers.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/functional_validators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/functional_validators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/json_schema.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/json_schema.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/main.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/main.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/networks.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/networks.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/plugin/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/plugin/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/plugin/_schema_validator.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/plugin/_schema_validator.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/root_model.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/root_model.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/type_adapter.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/type_adapter.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/types.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/types.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/annotated_types.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/annotated_types.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/class_validators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/class_validators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/color.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/color.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/config.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/config.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/dataclasses.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/dataclasses.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/datetime_parse.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/datetime_parse.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/decorator.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/decorator.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/env_settings.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/env_settings.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/error_wrappers.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/error_wrappers.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/errors.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/errors.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/fields.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/fields.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/json.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/json.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/main.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/main.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/networks.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/networks.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/parse.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/parse.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/schema.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/schema.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/tools.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/tools.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/types.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/types.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/typing.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/typing.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/utils.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/utils.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/validators.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/validators.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/version.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/v1/version.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/validate_call_decorator.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/validate_call_decorator.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/version.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/version.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic/warnings.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic/warnings.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/_pydantic_core.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/_pydantic_core.meta.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/core_schema.data.json +1 -0
- appm/.mypy_cache/3.13/pydantic_core/core_schema.meta.json +1 -0
- appm/.mypy_cache/3.13/re.data.json +1 -0
- appm/.mypy_cache/3.13/re.meta.json +1 -0
- appm/.mypy_cache/3.13/resource.data.json +1 -0
- appm/.mypy_cache/3.13/resource.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/anchor.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/anchor.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/comments.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/comments.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/compat.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/compat.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/composer.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/composer.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/constructor.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/constructor.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/cyaml.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/cyaml.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/docinfo.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/docinfo.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/dumper.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/dumper.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/emitter.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/emitter.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/error.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/error.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/events.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/events.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/loader.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/loader.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/main.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/main.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/nodes.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/nodes.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/parser.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/parser.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/reader.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/reader.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/representer.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/representer.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/resolver.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/resolver.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarbool.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarbool.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarfloat.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarfloat.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarint.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarint.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarstring.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scalarstring.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scanner.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/scanner.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/serializer.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/serializer.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/tag.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/tag.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/timestamp.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/timestamp.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/tokens.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/tokens.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/util.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel/yaml/util.meta.json +1 -0
- appm/.mypy_cache/3.13/ruamel.data.json +1 -0
- appm/.mypy_cache/3.13/ruamel.meta.json +1 -0
- appm/.mypy_cache/3.13/shutil.data.json +1 -0
- appm/.mypy_cache/3.13/shutil.meta.json +1 -0
- appm/.mypy_cache/3.13/sre_compile.data.json +1 -0
- appm/.mypy_cache/3.13/sre_compile.meta.json +1 -0
- appm/.mypy_cache/3.13/sre_constants.data.json +1 -0
- appm/.mypy_cache/3.13/sre_constants.meta.json +1 -0
- appm/.mypy_cache/3.13/sre_parse.data.json +1 -0
- appm/.mypy_cache/3.13/sre_parse.meta.json +1 -0
- appm/.mypy_cache/3.13/subprocess.data.json +1 -0
- appm/.mypy_cache/3.13/subprocess.meta.json +1 -0
- appm/.mypy_cache/3.13/sys/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/sys/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/sys/_monitoring.data.json +1 -0
- appm/.mypy_cache/3.13/sys/_monitoring.meta.json +1 -0
- appm/.mypy_cache/3.13/tarfile.data.json +1 -0
- appm/.mypy_cache/3.13/tarfile.meta.json +1 -0
- appm/.mypy_cache/3.13/textwrap.data.json +1 -0
- appm/.mypy_cache/3.13/textwrap.meta.json +1 -0
- appm/.mypy_cache/3.13/time.data.json +1 -0
- appm/.mypy_cache/3.13/time.meta.json +1 -0
- appm/.mypy_cache/3.13/traceback.data.json +1 -0
- appm/.mypy_cache/3.13/traceback.meta.json +1 -0
- appm/.mypy_cache/3.13/types.data.json +1 -0
- appm/.mypy_cache/3.13/types.meta.json +1 -0
- appm/.mypy_cache/3.13/typing.data.json +1 -0
- appm/.mypy_cache/3.13/typing.meta.json +1 -0
- appm/.mypy_cache/3.13/typing_extensions.data.json +1 -0
- appm/.mypy_cache/3.13/typing_extensions.meta.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/introspection.data.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/introspection.meta.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/typing_objects.data.json +1 -0
- appm/.mypy_cache/3.13/typing_inspection/typing_objects.meta.json +1 -0
- appm/.mypy_cache/3.13/uuid.data.json +1 -0
- appm/.mypy_cache/3.13/uuid.meta.json +1 -0
- appm/.mypy_cache/3.13/warnings.data.json +1 -0
- appm/.mypy_cache/3.13/warnings.meta.json +1 -0
- appm/.mypy_cache/3.13/weakref.data.json +1 -0
- appm/.mypy_cache/3.13/weakref.meta.json +1 -0
- appm/.mypy_cache/3.13/zipfile/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/zipfile/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/zipfile/_path/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/zipfile/_path/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/zlib.data.json +1 -0
- appm/.mypy_cache/3.13/zlib.meta.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/__init__.data.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/__init__.meta.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/_common.data.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/_common.meta.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/_tzpath.data.json +1 -0
- appm/.mypy_cache/3.13/zoneinfo/_tzpath.meta.json +1 -0
- appm/.mypy_cache/CACHEDIR.TAG +3 -0
- appm/__version__.py +1 -1
- appm/default.py +36 -0
- appm/exceptions.py +6 -0
- appm/manager.py +118 -121
- appm/model.py +261 -30
- appm/utils.py +45 -0
- appm-0.0.4.dist-info/METADATA +76 -0
- appm-0.0.4.dist-info/RECORD +769 -0
- appm-0.0.2.dist-info/METADATA +0 -9
- appm-0.0.2.dist-info/RECORD +0 -10
- {appm-0.0.2.dist-info → appm-0.0.4.dist-info}/WHEEL +0 -0
appm/manager.py
CHANGED
@@ -1,68 +1,25 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
import re
|
4
3
|
import shutil
|
5
|
-
from
|
4
|
+
from copy import deepcopy
|
6
5
|
from pathlib import Path
|
7
|
-
from typing import Any
|
6
|
+
from typing import Any
|
8
7
|
|
9
|
-
from ruamel.yaml import YAML
|
8
|
+
from ruamel.yaml import YAML
|
10
9
|
|
11
10
|
from appm.__version__ import __version__
|
11
|
+
from appm.default import DEFAULT_TEMPLATE
|
12
12
|
from appm.exceptions import (
|
13
|
-
FileFormatMismatch,
|
14
|
-
MetadataFileNotFoundErr,
|
15
|
-
ProjectNotFoundErr,
|
16
13
|
UnsupportedFileExtension,
|
17
14
|
)
|
18
|
-
from appm.model import
|
15
|
+
from appm.model import Project
|
16
|
+
from appm.utils import to_flow_style, validate_path
|
19
17
|
|
20
18
|
yaml = YAML()
|
21
19
|
yaml.indent(mapping=2, sequence=4, offset=2)
|
22
20
|
yaml.preserve_quotes = True # optional, if you want to preserve quotes
|
23
21
|
|
24
22
|
|
25
|
-
def to_flow_style(obj: Any) -> Any:
|
26
|
-
"""Recursively convert dict/list to ruamel structures with ALL lists using flow-style."""
|
27
|
-
if isinstance(obj, Mapping):
|
28
|
-
cm = CommentedMap()
|
29
|
-
for k, v in obj.items():
|
30
|
-
cm[k] = to_flow_style(v)
|
31
|
-
return cm
|
32
|
-
if isinstance(obj, Sequence) and not isinstance(obj, str):
|
33
|
-
cs = CommentedSeq()
|
34
|
-
for item in obj:
|
35
|
-
cs.append(to_flow_style(item))
|
36
|
-
cs.fa.set_flow_style()
|
37
|
-
return cs
|
38
|
-
return obj
|
39
|
-
|
40
|
-
|
41
|
-
class ExtManager:
|
42
|
-
def __init__(self, ext: str, decl: ExtDecl) -> None:
|
43
|
-
self.ext = ext
|
44
|
-
self.decl = decl
|
45
|
-
|
46
|
-
@property
|
47
|
-
def pattern(self) -> str:
|
48
|
-
return (
|
49
|
-
r"^"
|
50
|
-
+ self.decl.sep.join([f"({p})" for _, p in self.decl.format])
|
51
|
-
+ r"(.*)$"
|
52
|
-
)
|
53
|
-
|
54
|
-
def match(self, name: str) -> dict[str, str]:
|
55
|
-
match = re.match(self.pattern, name)
|
56
|
-
if not match:
|
57
|
-
raise FileFormatMismatch(f"Name: {name}. Pattern: {self.pattern}")
|
58
|
-
groups = match.groups()
|
59
|
-
result = {}
|
60
|
-
for i, (field, _) in enumerate(self.decl.format):
|
61
|
-
result[field] = groups[i]
|
62
|
-
result["*"] = groups[-1]
|
63
|
-
return result
|
64
|
-
|
65
|
-
|
66
23
|
class ProjectManager:
|
67
24
|
METADATA_NAME: str = "metadata.yaml"
|
68
25
|
|
@@ -72,30 +29,68 @@ class ProjectManager:
|
|
72
29
|
root: str | Path,
|
73
30
|
) -> None:
|
74
31
|
self.root = Path(root)
|
75
|
-
self.metadata =
|
76
|
-
self.handlers = {
|
77
|
-
|
78
|
-
|
79
|
-
|
32
|
+
self.metadata = Project.model_validate(metadata)
|
33
|
+
self.handlers = {ext: handler for ext, handler in self.metadata.file.items()}
|
34
|
+
|
35
|
+
@property
|
36
|
+
def location(self) -> Path:
|
37
|
+
return self.root / self.metadata.project_name
|
80
38
|
|
81
|
-
def match(self, name: str) -> dict[str, str]:
|
39
|
+
def match(self, name: str) -> dict[str, str | None]:
|
40
|
+
"""Match a file name and separate into format defined field components
|
41
|
+
|
42
|
+
The result contains a * which captures all non-captured values.
|
43
|
+
|
44
|
+
Args:
|
45
|
+
name (str): file name
|
46
|
+
|
47
|
+
Raises:
|
48
|
+
UnsupportedFileExtension: the metadata does not define an
|
49
|
+
extension declaration for the file's extension.
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
dict[str, str]: key value dictionary of the field component
|
53
|
+
defined using the format field.
|
54
|
+
"""
|
82
55
|
ext = name.split(".")[-1]
|
83
|
-
if ext
|
84
|
-
|
85
|
-
|
56
|
+
if ext in self.handlers:
|
57
|
+
return self.handlers[ext].match(name)
|
58
|
+
if "*" in self.handlers:
|
59
|
+
return self.handlers["*"].match(name)
|
60
|
+
raise UnsupportedFileExtension(str(ext))
|
86
61
|
|
87
62
|
def get_file_placement(self, name: str) -> str:
|
88
|
-
|
63
|
+
"""Find location where a file should be placed.
|
64
|
+
|
65
|
+
Determination is based on the metadata's layout field,
|
66
|
+
the file extension format definition, and the file name.
|
67
|
+
More concretely, field component - values are matched using the
|
68
|
+
RegEx defined in format. Fields that match layout values will be
|
69
|
+
extracted and path-appended in the order they appear in layout.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
name (str): file name
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
str: file placement directory
|
76
|
+
"""
|
77
|
+
layout = self.metadata.parsed_layout
|
89
78
|
groups = self.match(name)
|
90
|
-
|
91
|
-
return "/".join(values)
|
79
|
+
return layout.get_path(groups)
|
92
80
|
|
93
81
|
def init_project(self) -> None:
|
94
|
-
|
82
|
+
"""Create a project:
|
83
|
+
|
84
|
+
- Determine the project's name from nameing_convention and metadata
|
85
|
+
- Create a folder based on project's root and project name
|
86
|
+
- Create a metadata file in the project's location
|
87
|
+
"""
|
88
|
+
self.location.mkdir(exist_ok=True, parents=True)
|
95
89
|
self.save_metadata()
|
96
90
|
|
97
91
|
def save_metadata(self) -> None:
|
98
|
-
|
92
|
+
"""Save the current metadata to the project location"""
|
93
|
+
metadata_path = self.location / self.METADATA_NAME
|
99
94
|
with metadata_path.open("w") as file:
|
100
95
|
data = self.metadata.model_dump(mode="json")
|
101
96
|
data["version"] = __version__
|
@@ -104,84 +99,86 @@ class ProjectManager:
|
|
104
99
|
file,
|
105
100
|
)
|
106
101
|
|
107
|
-
def copy_file(self, src_path: Path) -> None:
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
102
|
+
def copy_file(self, src_path: str | Path) -> None:
|
103
|
+
"""Copy a file located at `src_path` to an appropriate
|
104
|
+
location in the project.
|
105
|
+
|
106
|
+
Args:
|
107
|
+
src_path (str | Path): path to where src data is found
|
108
|
+
"""
|
109
|
+
src_path = validate_path(src_path)
|
110
|
+
dst_path = self.location / self.get_file_placement(src_path.name)
|
112
111
|
dst_path.mkdir(parents=True, exist_ok=True)
|
113
112
|
shutil.copy2(src_path, dst_path)
|
114
113
|
|
115
|
-
@overload
|
116
114
|
@classmethod
|
117
|
-
def
|
115
|
+
def from_template(
|
118
116
|
cls,
|
119
117
|
root: str | Path,
|
120
|
-
metadata: str | Path,
|
121
118
|
year: int,
|
122
119
|
summary: str,
|
123
120
|
internal: bool = True,
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
@overload
|
129
|
-
@classmethod
|
130
|
-
def from_metadata(
|
131
|
-
cls,
|
132
|
-
root: str | Path,
|
133
|
-
metadata: dict[str, Any],
|
134
|
-
year: int,
|
135
|
-
summary: str,
|
136
|
-
internal: bool = True,
|
137
|
-
researcher: str | None = None,
|
138
|
-
organisation: str | None = None,
|
139
|
-
) -> ProjectManager: ...
|
140
|
-
|
141
|
-
@classmethod
|
142
|
-
def from_metadata(
|
143
|
-
cls,
|
144
|
-
root: str | Path,
|
145
|
-
metadata: str | Path | dict[str, Any],
|
146
|
-
year: int,
|
147
|
-
summary: str,
|
148
|
-
internal: bool = True,
|
149
|
-
researcher: str | None = None,
|
150
|
-
organisation: str | None = None,
|
121
|
+
template: str | Path | dict[str, Any] | None = None,
|
122
|
+
researcherName: str | None = None,
|
123
|
+
organisationName: str | None = None,
|
151
124
|
) -> ProjectManager:
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
125
|
+
"""Create a ProjectManager based on template and meta information
|
126
|
+
|
127
|
+
Args:
|
128
|
+
root (str | Path): parent directory - where project is stored
|
129
|
+
template (str | Path | dict[str, Any]): path to template file or the template content.
|
130
|
+
year (int): meta information - year
|
131
|
+
summary (str): meta information - summary
|
132
|
+
internal (bool, optional): meta information - internal. Defaults to True.
|
133
|
+
researcher (str | None, optional): meta information - researcherName. Defaults to None.
|
134
|
+
organisation (str | None, optional): meta information - organisationName. Defaults to None.
|
135
|
+
|
136
|
+
Returns:
|
137
|
+
ProjectManager: ProjectManager object
|
138
|
+
"""
|
139
|
+
if isinstance(template, str | Path):
|
140
|
+
metadata_path = Path(template)
|
141
|
+
metadata_path = validate_path(template)
|
142
|
+
with metadata_path.open("r") as file:
|
143
|
+
metadata = yaml.load(file)
|
144
|
+
elif isinstance(template, dict):
|
145
|
+
metadata = template
|
146
|
+
elif not template:
|
147
|
+
metadata = deepcopy(DEFAULT_TEMPLATE)
|
158
148
|
else:
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
return cls(root=root, metadata=
|
149
|
+
raise TypeError(
|
150
|
+
f"Unexpected type for template: {type(template)}. Accepts str, dict or None"
|
151
|
+
)
|
152
|
+
metadata["meta"] = {
|
153
|
+
"year": year,
|
154
|
+
"summary": summary,
|
155
|
+
"internal": internal,
|
156
|
+
"researcherName": researcherName,
|
157
|
+
"organisationName": organisationName,
|
158
|
+
}
|
159
|
+
return cls(root=root, metadata=metadata)
|
170
160
|
|
171
161
|
@classmethod
|
172
162
|
def load_project(
|
173
163
|
cls, project_path: Path | str, metadata_name: str | None = None
|
174
164
|
) -> ProjectManager:
|
175
|
-
|
176
|
-
|
177
|
-
|
165
|
+
"""Load a project from project's path
|
166
|
+
|
167
|
+
Args:
|
168
|
+
project_path (Path | str): path to project to open
|
169
|
+
metadata_name (str | None, optional): name for metadata file. If not provided, use "metadata.yaml". Defaults to None.
|
170
|
+
|
171
|
+
Returns:
|
172
|
+
ProjectManager: ProjectManager object
|
173
|
+
"""
|
174
|
+
project_path = validate_path(project_path)
|
178
175
|
metadata_path = (
|
179
176
|
project_path / cls.METADATA_NAME
|
180
177
|
if not metadata_name
|
181
178
|
else project_path / metadata_name
|
182
179
|
)
|
183
|
-
|
184
|
-
|
180
|
+
metadata_path = validate_path(metadata_path)
|
181
|
+
|
185
182
|
with metadata_path.open("r") as file:
|
186
183
|
metadata = yaml.load(file)
|
187
|
-
return cls(metadata=metadata, root=project_path)
|
184
|
+
return cls(metadata=metadata, root=project_path.parent)
|
appm/model.py
CHANGED
@@ -1,28 +1,231 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import re
|
4
|
+
from collections import Counter
|
1
5
|
from typing import Self
|
2
6
|
|
3
7
|
from pydantic import BaseModel, model_validator
|
8
|
+
from ruamel.yaml import YAML
|
4
9
|
|
5
10
|
from appm.__version__ import __version__
|
11
|
+
from appm.exceptions import FileFormatMismatch
|
6
12
|
from appm.utils import slugify
|
7
13
|
|
8
|
-
|
14
|
+
yaml = YAML()
|
9
15
|
|
16
|
+
STRUCTURES = {"year", "summary", "internal", "researcherName", "organisationName"}
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
|
19
|
+
class Field(BaseModel):
|
20
|
+
name: str
|
21
|
+
pattern: str
|
22
|
+
required: bool = True
|
23
|
+
|
24
|
+
@property
|
25
|
+
def regex(self) -> str:
|
26
|
+
return f"(?P<{self.name}>{self.pattern})"
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
def from_tuple(cls, value: tuple[str, str] | list[str]) -> Field:
|
30
|
+
assert len(value) == 2
|
31
|
+
return Field(name=value[0], pattern=value[1])
|
32
|
+
|
33
|
+
|
34
|
+
class Group(BaseModel):
|
35
|
+
components: list[tuple[str, str] | Field | Group]
|
36
|
+
sep: str = "-"
|
37
|
+
|
38
|
+
def validate_components(self) -> Self:
|
39
|
+
if not self.components:
|
40
|
+
raise ValueError(f"Components cannot be empty: {self.components}")
|
41
|
+
self._fields: list[Field | Group] = []
|
42
|
+
self._normalised_fields: list[Field] = []
|
43
|
+
for field in self.components:
|
44
|
+
if isinstance(field, tuple | list):
|
45
|
+
f = Field.from_tuple(field)
|
46
|
+
self._fields.append(f)
|
47
|
+
self._normalised_fields.append(f)
|
48
|
+
elif isinstance(field, Field):
|
49
|
+
self._fields.append(field)
|
50
|
+
self._normalised_fields.append(field)
|
51
|
+
else:
|
52
|
+
self._fields.append(field)
|
53
|
+
self._normalised_fields.extend(field.normalised_fields)
|
54
|
+
return self
|
55
|
+
|
56
|
+
def validate_names(self) -> Self:
|
57
|
+
self._names: list[str] = []
|
58
|
+
self._optional_names: set[str] = set()
|
59
|
+
for field in self.fields:
|
60
|
+
if isinstance(field, Field):
|
61
|
+
self._names.append(field.name)
|
62
|
+
if not field.required:
|
63
|
+
self._optional_names.add(field.name)
|
64
|
+
else:
|
65
|
+
self._names.extend(field.names)
|
66
|
+
self._optional_names.update(field.optional_names)
|
67
|
+
return self
|
68
|
+
|
69
|
+
def validate_regex(self) -> Self:
|
70
|
+
regex_str = []
|
71
|
+
for i, field in enumerate(self.fields):
|
72
|
+
is_optional = isinstance(field, Field) and not field.required
|
73
|
+
pattern = field.regex
|
74
|
+
|
75
|
+
if i == 0:
|
76
|
+
if is_optional:
|
77
|
+
# First field, no separator; make only field optional
|
78
|
+
regex_str.append(f"(?:{pattern})?")
|
79
|
+
else:
|
80
|
+
regex_str.append(pattern)
|
81
|
+
else:
|
82
|
+
if is_optional:
|
83
|
+
# Wrap separator + field together as optional
|
84
|
+
regex_str.append(f"(?:{self.sep}{pattern})?")
|
85
|
+
else:
|
86
|
+
regex_str.append(f"{self.sep}{pattern}")
|
87
|
+
self._regex = "".join(regex_str)
|
88
|
+
return self
|
89
|
+
|
90
|
+
@model_validator(mode="after")
|
91
|
+
def validate_group(self) -> Self:
|
92
|
+
return self.validate_components().validate_names().validate_regex()
|
93
|
+
|
94
|
+
@property
|
95
|
+
def normalised_fields(self) -> list[Field]:
|
96
|
+
return self._normalised_fields
|
97
|
+
|
98
|
+
@property
|
99
|
+
def fields(self) -> list[Field | Group]:
|
100
|
+
return self._fields
|
101
|
+
|
102
|
+
@property
|
103
|
+
def names(self) -> list[str]:
|
104
|
+
return self._names
|
105
|
+
|
106
|
+
@property
|
107
|
+
def optional_names(self) -> set[str]:
|
108
|
+
return self._optional_names
|
109
|
+
|
110
|
+
@property
|
111
|
+
def regex(self) -> str:
|
112
|
+
return self._regex
|
113
|
+
|
114
|
+
|
115
|
+
class Extension(Group):
|
116
|
+
default: dict[str, str] | None = None
|
14
117
|
|
15
118
|
@property
|
16
|
-
def
|
17
|
-
return
|
119
|
+
def default_names(self) -> set[str]:
|
120
|
+
return set() if not self.default else set(self.default.keys())
|
18
121
|
|
122
|
+
@property
|
123
|
+
def all_names(self) -> set[str]:
|
124
|
+
return set(self.names) | self.default_names
|
125
|
+
|
126
|
+
def validate_regex(self) -> Self:
|
127
|
+
self = super().validate_regex()
|
128
|
+
self._regex = f"^{self._regex}(?P<rest>.*)$"
|
129
|
+
return self
|
130
|
+
|
131
|
+
def validate_unique_names(self) -> Self:
|
132
|
+
count = Counter(self.names)
|
133
|
+
non_uniques = {k: v for k, v in count.items() if v > 1}
|
134
|
+
if non_uniques:
|
135
|
+
raise ValueError(f"Non-unique field name: {non_uniques}")
|
136
|
+
return self
|
137
|
+
|
138
|
+
def validate_reserved_name(self) -> Self:
|
139
|
+
if "rest" in self.names:
|
140
|
+
raise ValueError("Field component must not contain reserved key: rest")
|
141
|
+
return self
|
19
142
|
|
20
|
-
|
143
|
+
def validate_first_field_must_be_required(self) -> Self:
|
144
|
+
if not (field := self.normalised_fields[0]).required:
|
145
|
+
raise ValueError(f"First component must be required: {field.name}")
|
146
|
+
return self
|
147
|
+
|
148
|
+
@model_validator(mode="after")
|
149
|
+
def validate_extension(self) -> Self:
|
150
|
+
return (
|
151
|
+
self.validate_components()
|
152
|
+
.validate_names()
|
153
|
+
.validate_regex()
|
154
|
+
.validate_unique_names()
|
155
|
+
.validate_reserved_name()
|
156
|
+
.validate_first_field_must_be_required()
|
157
|
+
)
|
158
|
+
|
159
|
+
def match(self, name: str) -> dict[str, str | None]:
|
160
|
+
m = re.match(self.regex, name)
|
161
|
+
if not m:
|
162
|
+
raise FileFormatMismatch(f"Name: {name}. Pattern: {self.regex}")
|
163
|
+
result = m.groupdict()
|
164
|
+
if self.default:
|
165
|
+
for k, v in self.default.items():
|
166
|
+
if result.get(k) is None:
|
167
|
+
result[k] = v
|
168
|
+
return result
|
169
|
+
|
170
|
+
|
171
|
+
type File = dict[str, Extension]
|
172
|
+
|
173
|
+
|
174
|
+
class Layout(BaseModel):
|
175
|
+
structure: list[str]
|
176
|
+
mapping: dict[str, dict[str, str]] | None = None
|
177
|
+
|
178
|
+
@classmethod
|
179
|
+
def from_list(cls, value: list[str]) -> Layout:
|
180
|
+
return cls(structure=value)
|
181
|
+
|
182
|
+
@property
|
183
|
+
def structure_set(self) -> set[str]:
|
184
|
+
return self._structure_set
|
185
|
+
|
186
|
+
@model_validator(mode="after")
|
187
|
+
def validate_layout(self) -> Self:
|
188
|
+
self._structure_set = set(self.structure)
|
189
|
+
if self.mapping:
|
190
|
+
if not set(self.mapping.keys()).issubset(self._structure_set):
|
191
|
+
raise ValueError(
|
192
|
+
f"Mapping keys must be a subset of structure. Mapping keys: {set(self.mapping.keys())}, structure: {self.structure}"
|
193
|
+
)
|
194
|
+
return self
|
195
|
+
|
196
|
+
def get_path(self, components: dict[str, str | None]) -> str:
|
197
|
+
result: list[str] = []
|
198
|
+
for key in self.structure:
|
199
|
+
value = components.get(key, None)
|
200
|
+
if self.mapping and key in self.mapping and value in self.mapping[key]:
|
201
|
+
value = self.mapping[key][value]
|
202
|
+
if value is None:
|
203
|
+
raise ValueError(
|
204
|
+
f"None value for key: {key}. Either set a default for Extension definition, change Extension pattern to capture key value, or rename file."
|
205
|
+
)
|
206
|
+
result.append(value)
|
207
|
+
return "/".join(result)
|
208
|
+
|
209
|
+
|
210
|
+
class NamingConv(BaseModel):
|
21
211
|
sep: str = "_"
|
22
|
-
structure: list[str] = [
|
212
|
+
structure: list[str] = [
|
213
|
+
"year",
|
214
|
+
"summary",
|
215
|
+
"internal",
|
216
|
+
"researcherName",
|
217
|
+
"organisationName",
|
218
|
+
]
|
23
219
|
|
24
220
|
@model_validator(mode="after")
|
25
|
-
def
|
221
|
+
def validate_naming_convention(self) -> Self:
|
222
|
+
"""Validate structure value
|
223
|
+
|
224
|
+
structure:
|
225
|
+
- cannot be empty
|
226
|
+
- cannot have repeated component(s)
|
227
|
+
- cannot have a field component that is not one of the metadata fields.
|
228
|
+
"""
|
26
229
|
counter: dict[str, int] = {}
|
27
230
|
if len(self.structure) == 0:
|
28
231
|
raise ValueError("Invalid naming structure - empty structure")
|
@@ -37,40 +240,68 @@ class NamingConventionDecl(BaseModel):
|
|
37
240
|
return self
|
38
241
|
|
39
242
|
|
40
|
-
class
|
41
|
-
layout: list[str]
|
42
|
-
file:
|
43
|
-
naming_convention:
|
243
|
+
class Template(BaseModel):
|
244
|
+
layout: Layout | list[str]
|
245
|
+
file: File
|
246
|
+
naming_convention: NamingConv = NamingConv()
|
247
|
+
version: str = __version__
|
44
248
|
|
45
|
-
|
46
|
-
|
47
|
-
|
249
|
+
def validate_layout(self) -> Self:
|
250
|
+
if isinstance(self.layout, list):
|
251
|
+
self._layout = Layout.from_list(self.layout)
|
252
|
+
else:
|
253
|
+
self._layout = self.layout
|
254
|
+
return self
|
48
255
|
|
49
|
-
|
50
|
-
|
256
|
+
def validate_file_non_empty(self) -> Self:
|
257
|
+
if not self.file:
|
258
|
+
raise ValueError("Empty extension")
|
259
|
+
return self
|
260
|
+
|
261
|
+
def validate_file_name_subset_layout(self) -> Self:
|
51
262
|
for ext, decl in self.file.items():
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
263
|
+
for field in self.parsed_layout.structure_set:
|
264
|
+
if field not in decl.all_names:
|
265
|
+
raise ValueError(
|
266
|
+
f"Component fields must be a superset of layout fields: {field}. Ext: {ext}"
|
267
|
+
)
|
268
|
+
if field in decl.optional_names and field not in decl.default_names:
|
269
|
+
raise ValueError(
|
270
|
+
f"Optional field that is also a layout field must have a default value: {field}. Ext: {ext}"
|
271
|
+
)
|
57
272
|
return self
|
58
273
|
|
274
|
+
@property
|
275
|
+
def parsed_layout(self) -> Layout:
|
276
|
+
return self._layout
|
277
|
+
|
278
|
+
@model_validator(mode="after")
|
279
|
+
def validate_template(self) -> Self:
|
280
|
+
return (
|
281
|
+
self.validate_layout()
|
282
|
+
.validate_file_non_empty()
|
283
|
+
.validate_file_name_subset_layout()
|
284
|
+
)
|
285
|
+
|
59
286
|
|
60
|
-
class
|
287
|
+
class Metadata(BaseModel):
|
61
288
|
year: int
|
62
289
|
summary: str
|
63
|
-
internal: bool
|
64
|
-
|
65
|
-
|
66
|
-
|
290
|
+
internal: bool = True
|
291
|
+
researcherName: str | None = None
|
292
|
+
organisationName: str | None = None
|
293
|
+
|
294
|
+
|
295
|
+
class Project(Template):
|
296
|
+
meta: Metadata
|
67
297
|
|
68
298
|
@property
|
69
|
-
def
|
299
|
+
def project_name(self) -> str:
|
300
|
+
"""Project name based on metadata and naming convention definiton"""
|
70
301
|
fields = self.naming_convention.structure
|
71
302
|
name: list[str] = []
|
72
303
|
for field in fields:
|
73
|
-
value = getattr(self, field)
|
304
|
+
value = getattr(self.meta, field)
|
74
305
|
if value is not None:
|
75
306
|
if isinstance(value, str):
|
76
307
|
name.append(slugify(value))
|
appm/utils.py
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
import re
|
2
|
+
from collections.abc import Mapping, Sequence
|
3
|
+
from pathlib import Path
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from ruamel.yaml import CommentedMap, CommentedSeq
|
7
|
+
|
8
|
+
from appm.exceptions import NotAFileErr, NotFoundErr
|
2
9
|
|
3
10
|
|
4
11
|
def slugify(text: str) -> str:
|
@@ -25,3 +32,41 @@ def slugify(text: str) -> str:
|
|
25
32
|
# Replace spaces with hyphens
|
26
33
|
text = re.sub(r"[\s\-]+", "-", text)
|
27
34
|
return text.strip("-")
|
35
|
+
|
36
|
+
|
37
|
+
def to_flow_style(obj: Any) -> Any:
|
38
|
+
"""Recursively convert dict/list to ruamel structures with ALL lists using flow-style."""
|
39
|
+
if isinstance(obj, Mapping):
|
40
|
+
cm = CommentedMap()
|
41
|
+
for k, v in obj.items():
|
42
|
+
cm[k] = to_flow_style(v)
|
43
|
+
return cm
|
44
|
+
if isinstance(obj, Sequence) and not isinstance(obj, str):
|
45
|
+
cs = CommentedSeq()
|
46
|
+
for item in obj:
|
47
|
+
cs.append(to_flow_style(item))
|
48
|
+
cs.fa.set_flow_style()
|
49
|
+
return cs
|
50
|
+
return obj
|
51
|
+
|
52
|
+
|
53
|
+
def validate_path(path: str | Path, is_file: bool = False) -> Path:
|
54
|
+
"""Verify that path describes an existing file/folder
|
55
|
+
|
56
|
+
Args:
|
57
|
+
path (str | Path): path to validate
|
58
|
+
is_file (bool): whether path is a file. Defaults to False.
|
59
|
+
|
60
|
+
Raises:
|
61
|
+
NotFoundErr: path item doesnt exist
|
62
|
+
NotAFileErr: path doesn't describe a file
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
Path: validated path
|
66
|
+
"""
|
67
|
+
_path = Path(path)
|
68
|
+
if not _path.exists():
|
69
|
+
raise NotFoundErr(str(path))
|
70
|
+
if is_file and not _path.is_file():
|
71
|
+
raise NotAFileErr(str(path))
|
72
|
+
return _path
|