Skip to content

Commit

Permalink
FrozenDict content schema handling (#36)
Browse files Browse the repository at this point in the history
* FrozenDict content schema handling

* Template update

* Version increase

* Update src/schemapack/_internals/utils.py

Co-authored-by: Thomas Zajac <[email protected]>

---------

Co-authored-by: Thomas Zajac <[email protected]>
  • Loading branch information
sbilge and mephenor authored Dec 11, 2024
1 parent 785a3ee commit 16b5810
Show file tree
Hide file tree
Showing 25 changed files with 1,187 additions and 921 deletions.
4 changes: 2 additions & 2 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM mcr.microsoft.com/devcontainers/python:1-3.12-bullseye
FROM mcr.microsoft.com/devcontainers/python:1-3.12-bookworm

ENV PYTHONUNBUFFERED 1

Expand All @@ -8,7 +8,7 @@ ARG USER_GID=$USER_UID
RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then groupmod --gid $USER_GID vscode && usermod --uid $USER_UID --gid $USER_GID vscode; fi

# [Option] Install Node.js
ARG INSTALL_NODE="true"
ARG INSTALL_NODE="false"
ARG NODE_VERSION="lts/*"
RUN if [ "${INSTALL_NODE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi

Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ repos:
- id: debug-statements
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
rev: v0.8.2
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
rev: v1.13.0
hooks:
- id: mypy
args: [--no-warn-unused-ignores]
2 changes: 1 addition & 1 deletion .pyproject_generation/pyproject_custom.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

[project]
name = "schemapack"
version = "2.0.0-alpha.4"
version = "2.0.0-alpha.5"
description = "Make your JSON Schemas sociable and create linked data model."
dependencies = [
"pydantic >=2, <3",
Expand Down
2 changes: 2 additions & 0 deletions .pyproject_generation/pyproject_template.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fixable = [
"UP", # e.g. List -> list
"I", # sort imports
"D", # pydocstyle
"RUF022", # sort items in __all__
]
ignore = [
"E111", # indentation with invalid multiple (for formatter)
Expand All @@ -59,6 +60,7 @@ ignore = [
"D206", # indent-with-spaces (for formatter)
"D300", # triple-single-quotes (for formatter)
"UP040", # type statement (not yet supported by mypy)
"PLC0206", # Extracting value from dictionary without calling `.items()`
]
select = [
"C90", # McCabe Complexity
Expand Down
1 change: 1 addition & 0 deletions .template/mandatory_files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lock/requirements-dev.txt
lock/requirements.txt

Dockerfile
Dockerfile.debian
config_schema.json
example_config.yaml
LICENSE
Expand Down
4 changes: 0 additions & 4 deletions .template/mandatory_files_ignore.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@

.devcontainer/docker-compose.yml

.github/workflows/cd.yaml
.github/workflows/dev_cd.yaml
.github/workflows/check_openapi_spec.yaml

scripts/script_utils/fastapi_app_location.py

Dockerfile
Expand Down
48 changes: 48 additions & 0 deletions Dockerfile.debian
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright 2021 - 2024 Universität Tübingen, DKFZ, EMBL, and Universität zu Köln
# for the German Human Genome-Phenome Archive (GHGA)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

## creating building container
FROM python:3.12-slim-bookworm AS builder
# update and install dependencies
RUN apt update
RUN apt upgrade -y
RUN pip install build
# copy code
COPY . /service
WORKDIR /service
# build wheel
RUN python -m build

# creating running container
FROM python:3.12-slim-bookworm
# update and install dependencies
RUN apt update
RUN apt upgrade -y
# copy and install requirements and wheel
WORKDIR /service
COPY --from=builder /service/lock/requirements.txt /service
RUN pip install --no-deps -r requirements.txt
RUN rm requirements.txt
COPY --from=builder /service/dist/ /service
RUN pip install --no-deps *.whl
RUN rm *.whl
# create new user and execute as that user
RUN useradd --create-home appuser
WORKDIR /home/appuser
USER appuser
# set environment
ENV PYTHONUNBUFFERED=1
# Please adapt to package name:
ENTRYPOINT ["my-microservice"]
4 changes: 2 additions & 2 deletions lock/requirements-dev-template.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# common requirements for development and testing of services

pytest>=8.2
pytest-asyncio>=0.23.6
pytest-asyncio>=0.23.7
pytest-cov>=5
snakeviz>=2.2
logot>=1.3
Expand Down Expand Up @@ -29,4 +29,4 @@ setuptools>=69.5
# required since switch to pyproject.toml and pip-tools
tomli_w>=1.0

uv>=0.1.39
uv>=0.2.13
1,304 changes: 692 additions & 612 deletions lock/requirements-dev.txt

Large diffs are not rendered by default.

592 changes: 324 additions & 268 deletions lock/requirements.txt

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ classifiers = [
"Intended Audience :: Developers",
]
name = "schemapack"
version = "2.0.0-alpha.4"
version = "2.0.0-alpha.5"
description = "Make your JSON Schemas sociable and create linked data model."
dependencies = [
"pydantic >=2, <3",
Expand Down Expand Up @@ -68,6 +68,7 @@ fixable = [
"UP",
"I",
"D",
"RUF022",
]
ignore = [
"E111",
Expand All @@ -87,6 +88,7 @@ ignore = [
"D206",
"D300",
"UP040",
"PLC0206",
]
select = [
"C90",
Expand Down
16 changes: 8 additions & 8 deletions src/schemapack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@
from ._internals.validation import SchemaPackValidator

__all__ = [
"SchemaPackValidator",
"denormalize",
"dump_schemapack",
"dumps_datapack",
"dumps_schemapack",
"export_mermaid",
"load_and_validate",
"load_datapack",
"load_schemapack",
"isolate",
"isolate_class",
"isolate_resource",
"denormalize",
"SchemaPackValidator",
"dumps_datapack",
"dump_schemapack",
"dumps_schemapack",
"load_and_validate",
"load_datapack",
"load_schemapack",
]

__version__ = version(__package__)
4 changes: 2 additions & 2 deletions src/schemapack/_internals/isolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from schemapack.spec.schemapack import SchemaPack


def identify_resource_dependencies( # noqa: C901, PLR0912
def identify_resource_dependencies( # noqa: C901
*,
datapack: DataPack,
class_name: ClassName,
Expand Down Expand Up @@ -92,7 +92,7 @@ def identify_resource_dependencies( # noqa: C901, PLR0912
resource_blacklist: dict[ClassName, set[ResourceId]] = defaultdict(set)
resource_blacklist[class_name].add(resource_id)
if _resource_blacklist:
for class_name, resource_ids in _resource_blacklist.items():
for class_name, resource_ids in _resource_blacklist.items(): # noqa: PLR1704
resource_blacklist[class_name].update(resource_ids)

dependencies_by_class: dict[ClassName, set[ResourceId]] = defaultdict(set)
Expand Down
3 changes: 3 additions & 0 deletions src/schemapack/_internals/spec/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from typing import Annotated, TypeAlias

from arcticfreeze import FrozenDict
from pydantic import Field as _Field

_NonEmptyStr: TypeAlias = Annotated[str, _Field(..., min_length=1)]
Expand All @@ -26,3 +27,5 @@
RelationPropertyName: TypeAlias = _NonEmptyStr
ContentPropertyName: TypeAlias = _NonEmptyStr
IdPropertyName: TypeAlias = _NonEmptyStr
FrozenType: TypeAlias = FrozenDict[str, "str | FrozenType | tuple"]
ThawedType: TypeAlias = dict[str, "str | ThawedType | list"]
17 changes: 16 additions & 1 deletion src/schemapack/_internals/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
import jsonschema.protocols
import jsonschema.validators
import ruamel.yaml
from arcticfreeze import FrozenDict
from pydantic import BaseModel

from schemapack._internals.spec.custom_types import FrozenType, ThawedType
from schemapack.exceptions import ParsingError

yaml = ruamel.yaml.YAML(typ="rt")
Expand Down Expand Up @@ -79,7 +81,8 @@ def assert_valid_json_schema(schema: Mapping[str, Any]) -> None:
cls: type[jsonschema.protocols.Validator] = jsonschema.validators.validator_for(
schema
)

if isinstance(schema, FrozenDict):
schema = thaw_frozendict(schema)
try:
cls.check_schema(schema)
except jsonschema.exceptions.SchemaError as error:
Expand Down Expand Up @@ -109,6 +112,18 @@ def model_to_serializable_dict(
return json.loads(model.model_dump_json(exclude_defaults=True))


def thaw_frozendict(frozen_dict: FrozenType) -> ThawedType:
"""Recursively thaws a FrozenDict into a standard dictionary."""
return {
key: (
thaw_frozendict(val)
if isinstance(val, FrozenDict)
else (list(val) if isinstance(val, tuple) else val)
)
for key, val in frozen_dict.items()
}


def dumps_model(
model: BaseModel,
*,
Expand Down
4 changes: 2 additions & 2 deletions src/schemapack/_internals/validation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
)

__all__ = [
"SchemaPackValidator",
"GlobalValidationPlugin",
"ClassValidationPlugin",
"GlobalValidationPlugin",
"ResourceValidationPlugin",
"SchemaPackValidator",
]
6 changes: 3 additions & 3 deletions src/schemapack/_internals/validation/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@
"ContentSchemaValidationPlugin",
"ExpectedRootValidationPlugin",
"MissingClassSlotValidationPlugin",
"MissingRelationValidationPlugin",
"MissingMandatoryOriginValidationPlugin",
"MissingMandatoryTargetValidationPlugin",
"MissingRelationValidationPlugin",
"MultipleTargetValidationPlugin",
"TargetOverlapValidationPlugin",
"TargetIdValidationPlugin",
"TargetOverlapValidationPlugin",
"UnexpectedRootValidationPlugin",
"UnknownClassSlotValidationPlugin",
"UnknownRelationValidationPlugin",
"UnkownRootResourceValidationPlugin",
"MissingMandatoryOriginValidationPlugin",
]
14 changes: 7 additions & 7 deletions src/schemapack/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@

__all__ = [
"BaseError",
"SpecError",
"CircularRelationError",
"ClassNotFoundError",
"DataPackSpecError",
"ParsingError",
"ResourceNotFoundError",
"SchemaPackSpecError",
"SpecError",
"ValidationAssumptionError",
"ValidationError",
"ValidationErrorRecord",
"DataPackSpecError",
"SchemaPackSpecError",
"CircularRelationError",
"ValidationPluginError",
"ValidationAssumptionError",
"ResourceNotFoundError",
"ClassNotFoundError",
]
2 changes: 1 addition & 1 deletion src/schemapack/plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
)

__all__ = [
"GlobalValidationPlugin",
"ClassValidationPlugin",
"GlobalValidationPlugin",
"ResourceValidationPlugin",
]
4 changes: 2 additions & 2 deletions src/schemapack/spec/custom_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

__all__ = [
"ClassName",
"ResourceId",
"RelationPropertyName",
"ContentPropertyName",
"IdPropertyName",
"RelationPropertyName",
"ResourceId",
]
2 changes: 1 addition & 1 deletion src/schemapack/spec/datapack.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
)

__all__ = [
"SUPPORTED_DATA_PACK_VERSIONS",
"DataPack",
"Resource",
"SupportedDataPackVersions",
"SUPPORTED_DATA_PACK_VERSIONS",
]
2 changes: 1 addition & 1 deletion src/schemapack/spec/schemapack.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@

__all__ = [
"SUPPORTED_SCHEMA_PACK_VERSIONS",
"SchemaPack",
"ClassDefinition",
"IDSpec",
"MandatoryRelationSpec",
"MultipleRelationSpec",
"Relation",
"SchemaPack",
"SupportedSchemaPackVersions",
]
2 changes: 1 addition & 1 deletion src/schemapack/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
read_json_or_yaml_mapping,
)

__all__ = ["read_json_or_yaml_mapping", "model_to_serializable_dict"]
__all__ = ["model_to_serializable_dict", "read_json_or_yaml_mapping"]
Loading

0 comments on commit 16b5810

Please sign in to comment.