From 5d692fe353d79edf544e9100716c22eef07e010e Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Tue, 23 Jul 2024 16:09:40 +0200 Subject: [PATCH 01/14] Update dependencies --- .../api/v1_api/ontology_type_validation.py | 4 +- muse_for_anything/db/cli.py | 10 - muse_for_anything/db/models/model_helpers.py | 25 +- .../db/models/object_relation_tables.py | 75 +- .../db/models/ontology_objects.py | 99 +- muse_for_anything/db/models/taxonomies.py | 70 +- muse_for_anything/db/models/users.py | 35 +- muse_for_anything/oso_helpers.py | 130 +- poetry.lock | 1191 +++++++++-------- pyproject.toml | 54 +- 10 files changed, 925 insertions(+), 768 deletions(-) diff --git a/muse_for_anything/api/v1_api/ontology_type_validation.py b/muse_for_anything/api/v1_api/ontology_type_validation.py index 5e2a8eb..0c6afd0 100644 --- a/muse_for_anything/api/v1_api/ontology_type_validation.py +++ b/muse_for_anything/api/v1_api/ontology_type_validation.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from muse_for_anything.db.models.taxonomies import Taxonomy -from flask.globals import _request_ctx_stack +from flask.globals import request_ctx from werkzeug.urls import url_parse from werkzeug.routing import MapAdapter @@ -152,7 +152,7 @@ def visit(self, data, walker: SchemaWalker) -> None: else: url = url_parse(data["$ref"]) - ctx = _request_ctx_stack.top + ctx = request_ctx if ctx is None: raise DataVisitorException( "No request context to check schema url against!" diff --git a/muse_for_anything/db/cli.py b/muse_for_anything/db/cli.py index 757ff26..c26ec41 100644 --- a/muse_for_anything/db/cli.py +++ b/muse_for_anything/db/cli.py @@ -4,7 +4,6 @@ import click from flask import Blueprint, Flask, current_app -from flask.cli import with_appcontext from ..util.logging import get_logger @@ -22,7 +21,6 @@ @DB_CLI.command("create-db") -@with_appcontext def create_db(): """Create all db tables.""" create_db_function(current_app) @@ -36,7 +34,6 @@ def create_db_function(app: Flask): @DB_CLI.command("create-admin-user") @click.option("-f", "--force", is_flag=True, default=False) -@with_appcontext def create_admin_user_cli(force: bool = False): """Create an admin user with username and password 'admin'.""" result = create_admin_user(current_app, force) @@ -70,7 +67,6 @@ def create_admin_user(app: Flask, force: bool = False): @click.password_option("--password") @click.option("-r", "--role", default=None) @click.option("-f", "--force", is_flag=True, default=False) -@with_appcontext def create_user_cli( username: str, password: str, role: Optional[str] = None, force: bool = False ): @@ -120,7 +116,6 @@ def create_user( @DB_CLI.command("delete-user") @click.option("-u", "--username") -@with_appcontext def delete_user_cli(username: str): """Delete the user with the given username.""" click.confirm( @@ -151,7 +146,6 @@ def delete_user(app: Flask, username: str): @DB_CLI.command("list-roles") @click.option("-u", "--username", default=None) -@with_appcontext def list_roles_cli(username: Optional[str]): """List all user roles. @@ -171,7 +165,6 @@ def list_roles_cli(username: Optional[str]): @DB_CLI.command("add-role") @click.option("-u", "--username") @click.option("-r", "--role") -@with_appcontext def add_user_role_cli(username: str, role: str): """Add a role to an existing user.""" user: Optional[User] = User.query.filter(User.username == username).first() @@ -187,7 +180,6 @@ def add_user_role_cli(username: str, role: str): @DB_CLI.command("remove-role") @click.option("-u", "--username") @click.option("-r", "--role") -@with_appcontext def remove_user_role_cli(username: str, role: str): """Remove a role from an existing user.""" user: Optional[User] = User.query.filter(User.username == username).first() @@ -202,7 +194,6 @@ def remove_user_role_cli(username: str, role: str): @DB_CLI.command("drop-db") -@with_appcontext def drop_db(): """Drop all db tables.""" drop_db_function(current_app) @@ -222,7 +213,6 @@ def register_cli_blueprint(app: Flask): @DB_CLI.command("export-namespace") @click.option("-n", "--namespace") -@with_appcontext def map_namespace_to_owl_cli(namespace: int): """ Export the specified namespace to an OWL file. diff --git a/muse_for_anything/db/models/model_helpers.py b/muse_for_anything/db/models/model_helpers.py index 7c2df31..b8c8cfb 100644 --- a/muse_for_anything/db/models/model_helpers.py +++ b/muse_for_anything/db/models/model_helpers.py @@ -1,7 +1,10 @@ from datetime import datetime from typing import Any, Sequence +from sqlalchemy import DateTime from sqlalchemy.sql.elements import literal from sqlalchemy.sql.schema import Column +from sqlalchemy.types import Unicode, UnicodeText +from sqlalchemy.orm import Mapped, mapped_column from ...util.import_helpers import get_all_classes_of_module @@ -24,32 +27,28 @@ def exists(cls, query_filter: Sequence[Any] = tuple()): class IdMixin: """Add an 'id' column that is the primary key for this table.""" - id: Column = DB.Column(DB.Integer, primary_key=True) + id: Mapped[int] = mapped_column(primary_key=True) class NameDescriptionMixin: """Add a 'name' and 'description' column to the table.""" - name: Column = DB.Column( - DB.Unicode, nullable=False, index=True, info={"collate": "NOCASE"} - ) - description: Column = DB.Column(DB.UnicodeText, nullable=True, index=True) + name: Mapped[str] = mapped_column(DB.Unicode, nullable=False, index=True, info={"collate": "NOCASE"}) + description: Mapped[str] = mapped_column(DB.UnicodeText, nullable=True, index=True) class UniqueNameDescriptionMixin: """Add a 'name' (with a unique constraint) and 'description' column to the table.""" - name: Column = DB.Column( - DB.Unicode, nullable=False, unique=True, index=True, info={"collate": "NOCASE"} - ) - description: Column = DB.Column(DB.UnicodeText, nullable=True, index=True) + name: Mapped[str] = mapped_column(DB.Unicode, nullable=False, unique=True, index=True, info={"collate": "NOCASE"}) + description: Mapped[str] = mapped_column(DB.UnicodeText, nullable=True, index=True) class CreateDeleteMixin: """Add the columns 'created_on' and 'deleted_on' to track creation and deletion of immutable database entries.""" - created_on: Column = DB.Column(DB.DateTime, default=datetime.utcnow, nullable=False) - deleted_on: Column = DB.Column(DB.DateTime, nullable=True) + created_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow, nullable=False) + deleted_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=True) @property def is_deleted(self) -> bool: @@ -59,9 +58,7 @@ def is_deleted(self) -> bool: class ChangesMixin(CreateDeleteMixin): """Add the columns 'created_on', 'updated_on' and 'deleted_on' to track changes to the database entries.""" - updated_on: Column = DB.Column( - DB.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False - ) + updated_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) __all__ = list(get_all_classes_of_module(__name__)) diff --git a/muse_for_anything/db/models/object_relation_tables.py b/muse_for_anything/db/models/object_relation_tables.py index 2d3423e..7431259 100644 --- a/muse_for_anything/db/models/object_relation_tables.py +++ b/muse_for_anything/db/models/object_relation_tables.py @@ -1,8 +1,8 @@ """Module containing relation tables.""" from typing import Any, Dict, Optional, cast -from sqlalchemy.sql.schema import ForeignKey, Column, Index -from sqlalchemy.orm import relationship +from sqlalchemy.sql.schema import ForeignKey, Index +from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.ext.declarative import declared_attr from ..db import DB, MODEL @@ -30,24 +30,19 @@ class OntologyTypeVersionToTypeVersion(MODEL, IdMixin): __tablename__ = "TypeVersionToTypeVersion" # the type version importing - type_version_source_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectTypeVersion.id), nullable=False - ) + type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + # the imported type version - type_version_target_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectTypeVersion.id), nullable=False - ) + type_version_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) # relationships - type_version_source: OntologyObjectTypeVersion = relationship( - OntologyObjectTypeVersion, + type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="imported_types", primaryjoin=OntologyObjectTypeVersion.id == type_version_source_id, ) - type_version_target: OntologyObjectTypeVersion = relationship( - OntologyObjectTypeVersion, + type_version_target: Mapped[OntologyObjectTypeVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="imported_by_types", primaryjoin=OntologyObjectTypeVersion.id == type_version_target_id, @@ -67,23 +62,17 @@ class OntologyTypeVersionToType(MODEL, IdMixin): __tablename__ = "TypeVersionToType" - type_version_source_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectTypeVersion.id), nullable=False - ) - type_target_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectType.id), nullable=False - ) + type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + type_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectType.id"), nullable=False) # relationships - type_version_source: OntologyObjectTypeVersion = relationship( - OntologyObjectTypeVersion, + type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_types", primaryjoin=OntologyObjectTypeVersion.id == type_version_source_id, ) - type_target: OntologyObjectType = relationship( - OntologyObjectType, + type_target: Mapped[OntologyObjectType] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_by_types", primaryjoin=OntologyObjectType.id == type_target_id, @@ -103,23 +92,17 @@ class OntologyTypeVersionToTaxonomy(MODEL, IdMixin): __tablename__ = "TypeVersionToTaxonomy" - type_version_source_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectTypeVersion.id), nullable=False - ) - taxonomy_target_id: Column = DB.Column( - DB.Integer, ForeignKey(Taxonomy.id), nullable=False - ) + type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + taxonomy_target_id: Mapped[int] = mapped_column(ForeignKey("Taxonomy.id"), nullable=False) # relationships - type_version_source: OntologyObjectTypeVersion = relationship( - OntologyObjectTypeVersion, + type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_taxonomies", primaryjoin=OntologyObjectTypeVersion.id == type_version_source_id, ) - taxonomy_target: Taxonomy = relationship( - Taxonomy, + taxonomy_target: Mapped[Taxonomy] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_by_types", primaryjoin=Taxonomy.id == taxonomy_target_id, @@ -139,23 +122,17 @@ class OntologyObjectVersionToObject(MODEL, IdMixin): __tablename__ = "ObjectVersionToObject" - object_version_source_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectVersion.id), nullable=False - ) - object_target_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObject.id), nullable=False - ) + object_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + object_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObject.id"), nullable=False) # relationships - object_version_source: OntologyObjectVersion = relationship( - OntologyObjectVersion, + object_version_source: Mapped[OntologyObjectVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_objects", primaryjoin=OntologyObjectVersion.id == object_version_source_id, ) - object_target: OntologyObject = relationship( - OntologyObject, + object_target: Mapped[OntologyObject] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_by_objects", primaryjoin=OntologyObject.id == object_target_id, @@ -175,23 +152,17 @@ class OntologyObjectVersionToTaxonomyItem(MODEL, IdMixin): __tablename__ = "ObjectVersionToTaxonomyItem" - object_version_source_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectVersion.id), nullable=False - ) - taxonomy_item_target_id: Column = DB.Column( - DB.Integer, ForeignKey(TaxonomyItem.id), nullable=False - ) + object_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectVersion.id"), nullable=False) + taxonomy_item_target_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) # relationships - object_version_source: OntologyObjectVersion = relationship( - OntologyObjectVersion, + object_version_source: Mapped[OntologyObjectVersion] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_taxonomy_items", primaryjoin=OntologyObjectVersion.id == object_version_source_id, ) - taxonomy_item_target: TaxonomyItem = relationship( - TaxonomyItem, + taxonomy_item_target: Mapped[TaxonomyItem] = relationship( lazy="select", # is nearly always in cache anyway back_populates="referenced_by_objects", primaryjoin=TaxonomyItem.id == taxonomy_item_target_id, diff --git a/muse_for_anything/db/models/ontology_objects.py b/muse_for_anything/db/models/ontology_objects.py index 7aee99e..b10b751 100644 --- a/muse_for_anything/db/models/ontology_objects.py +++ b/muse_for_anything/db/models/ontology_objects.py @@ -1,9 +1,10 @@ """Module containing ontology object table definitions.""" from typing import Any, Dict, List, Optional, cast -from sqlalchemy.sql.schema import ForeignKey, Column, Index -from sqlalchemy.orm import relationship +from sqlalchemy.sql.schema import ForeignKey, Index +from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.ext.declarative import declared_attr +from sqlalchemy.types import Text from ..db import DB, MODEL from .model_helpers import ( @@ -22,16 +23,13 @@ class OntologyObjectType(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Type" - namespace_id: Column = DB.Column(DB.Integer, ForeignKey(Namespace.id), nullable=False) - current_version_id: Column = DB.Column( - DB.Integer, ForeignKey("TypeVersion.id"), nullable=True - ) - is_toplevel_type: Column = DB.Column(DB.Boolean, nullable=False) - + namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) + current_version_id: Mapped[int] = mapped_column(ForeignKey("TypeVesion.id"), nullable=True) + is_toplevel_type: Mapped[int] = mapped_column(nullable=False) + # relationships - namespace: Namespace = relationship(Namespace, innerjoin=True, lazy="selectin") - current_version: "OntologyObjectTypeVersion" = relationship( - "OntologyObjectTypeVersion", + namespace: Mapped[Namespace] = relationship(innerjoin=True, lazy="selectin") + current_version: Mapped["OntologyObjectTypeVersion"] = relationship( post_update=True, innerjoin=True, lazy="joined", @@ -44,14 +42,12 @@ class OntologyObjectType(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): back_populates="ontology_type", primaryjoin="OntologyObjectType.id == OntologyObjectTypeVersion.object_type_id", ) - ontology_objects: "OntologyObject" = relationship( - "OntologyObject", + ontology_objects: Mapped["OntologyObject"] = relationship( lazy="select", back_populates="ontology_type", ) - referenced_by_types: List["rel.OntologyTypeVersionToType"] = relationship( - "OntologyTypeVersionToType", + referenced_by_types: Mapped[List["rel.OntologyTypeVersionToType"]] = relationship( lazy="select", order_by="OntologyTypeVersionToType.id", back_populates="type_target", @@ -114,12 +110,10 @@ class OntologyObjectTypeVersion(MODEL, IdMixin, CreateDeleteMixin): __tablename__ = "TypeVersion" - id: Column = DB.Column(DB.Integer, primary_key=True) - object_type_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectType.id), nullable=False - ) - version: Column = DB.Column(DB.Integer, nullable=False) - data: Column = DB.Column(DB.JSON, nullable=False) + id: Mapped[int] = mapped_column(primary_key=True) + object_type_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectType.id"), nullable=False) + version: Mapped[int] = mapped_column(nullable=False) + data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @declared_attr def __table_args__(cls): @@ -133,43 +127,37 @@ def __table_args__(cls): ) # relationships - ontology_type: OntologyObjectType = relationship( - OntologyObjectType, + ontology_type: Mapped[OntologyObjectType] = relationship( lazy="select", # should already be in chache in most cases back_populates="versions", primaryjoin=OntologyObjectType.id == object_type_id, ) - ontology_object_versions: "OntologyObjectVersion" = relationship( - "OntologyObjectVersion", + ontology_object_versions: Mapped["OntologyObjectVersion"] = relationship( lazy="select", back_populates="ontology_type_version", ) - imported_types: List["rel.OntologyTypeVersionToTypeVersion"] = relationship( - "OntologyTypeVersionToTypeVersion", + imported_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = relationship( lazy="select", order_by="OntologyTypeVersionToTypeVersion.id", back_populates="type_version_source", primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTypeVersion.type_version_source_id", ) - imported_by_types: List["rel.OntologyTypeVersionToTypeVersion"] = relationship( - "OntologyTypeVersionToTypeVersion", + imported_by_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = relationship( lazy="select", order_by="OntologyTypeVersionToTypeVersion.id", back_populates="type_version_target", primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTypeVersion.type_version_target_id", ) - referenced_types: List["rel.OntologyTypeVersionToType"] = relationship( - "OntologyTypeVersionToType", + referenced_types: Mapped[List["rel.OntologyTypeVersionToType"]] = relationship( lazy="select", order_by="OntologyTypeVersionToType.id", back_populates="type_version_source", primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToType.type_version_source_id", ) - referenced_taxonomies: List["rel.OntologyTypeVersionToTaxonomy"] = relationship( - "OntologyTypeVersionToTaxonomy", + referenced_taxonomies: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = relationship( lazy="select", order_by="OntologyTypeVersionToTaxonomy.id", back_populates="type_version_source", @@ -218,24 +206,18 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Object" - namespace_id: Column = DB.Column(DB.Integer, ForeignKey(Namespace.id), nullable=False) - object_type_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectType.id), nullable=False - ) - current_version_id: Column = DB.Column( - DB.Integer, ForeignKey("ObjectVersion.id"), nullable=True - ) + namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) + object_type_id: Mapped[int] = mapped_column(ForeignKey("OnotologyObjectType.id"), nullable=False) + current_version_id: Mapped[int] = mapped_column(ForeignKey("ObjectVersion.id"), nullable=True) # relationships - namespace: Namespace = relationship(Namespace, innerjoin=True, lazy="selectin") - ontology_type: OntologyObjectType = relationship( - OntologyObjectType, + namespace: Mapped[Namespace] = relationship(innerjoin=True, lazy="selectin") + ontology_type: Mapped[OntologyObjectType] = relationship( innerjoin=True, lazy="selectin", # load the type in a seperate query (and maybe benefit from session chache) back_populates="ontology_objects", ) - current_version: "OntologyObjectVersion" = relationship( - "OntologyObjectVersion", + current_version: Mapped["OntologyObjectVersion"] = relationship( post_update=True, innerjoin=True, lazy="joined", @@ -249,8 +231,7 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): primaryjoin="OntologyObject.id == OntologyObjectVersion.object_id", ) - referenced_by_objects: List["rel.OntologyObjectVersionToObject"] = relationship( - "OntologyObjectVersionToObject", + referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = relationship( lazy="select", order_by="OntologyObjectVersionToObject.id", back_populates="object_target", @@ -304,14 +285,10 @@ class OntologyObjectVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMi __tablename__ = "ObjectVersion" - object_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObject.id), nullable=False - ) - version: Column = DB.Column(DB.Integer, nullable=False) - object_type_version_id: Column = DB.Column( - DB.Integer, ForeignKey(OntologyObjectTypeVersion.id), nullable=False - ) - data: Column = DB.Column(DB.JSON, nullable=False) + object_id: Mapped[int] = mapped_column(ForeignKey("OntologyObject.id"), nullable=False) + version: Mapped[int] = mapped_column(nullable=False) + object_type_version_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @declared_attr def __table_args__(cls): @@ -322,30 +299,26 @@ def __table_args__(cls): ) # relationships - ontology_object: OntologyObject = relationship( - OntologyObject, + ontology_object: Mapped[OntologyObject] = relationship( innerjoin=True, lazy="select", # should already be in session cache back_populates="versions", primaryjoin=OntologyObject.id == object_id, ) - ontology_type_version: OntologyObjectTypeVersion = relationship( - OntologyObjectTypeVersion, + ontology_type_version: Mapped[OntologyObjectTypeVersion] = relationship( innerjoin=True, lazy="selectin", # selectin uses a second (or more) queries and is more memory efficient compared to direct join back_populates="ontology_object_versions", ) - referenced_objects: List["rel.OntologyObjectVersionToObject"] = relationship( - "OntologyObjectVersionToObject", + referenced_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = relationship( lazy="select", order_by="OntologyObjectVersionToObject.id", back_populates="object_version_source", primaryjoin="OntologyObjectVersion.id == OntologyObjectVersionToObject.object_version_source_id", ) - referenced_taxonomy_items: List["rel.OntologyObjectVersionToTaxonomyItem"] = relationship( - "OntologyObjectVersionToTaxonomyItem", + referenced_taxonomy_items: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = relationship( lazy="select", order_by="OntologyObjectVersionToTaxonomyItem.id", back_populates="object_version_source", diff --git a/muse_for_anything/db/models/taxonomies.py b/muse_for_anything/db/models/taxonomies.py index c51120a..4f136d1 100644 --- a/muse_for_anything/db/models/taxonomies.py +++ b/muse_for_anything/db/models/taxonomies.py @@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional, cast from sqlalchemy.orm.query import Query from sqlalchemy.sql.schema import ForeignKey, Column, Index -from sqlalchemy.orm import relationship, selectinload +from sqlalchemy.orm import Mapped, mapped_column, relationship, selectinload from sqlalchemy.ext.declarative import declared_attr from ..db import DB, MODEL @@ -23,20 +23,18 @@ class Taxonomy(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Taxonomy" - namespace_id: Column = DB.Column(DB.Integer, ForeignKey(Namespace.id), nullable=False) + namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) # relationships namespace = relationship(Namespace, innerjoin=True, lazy="selectin") - items: List["TaxonomyItem"] = relationship( - "TaxonomyItem", + items: Mapped[List["TaxonomyItem"]] = relationship( lazy="select", # do not always load this order_by="TaxonomyItem.id", back_populates="taxonomy", primaryjoin="Taxonomy.id == TaxonomyItem.taxonomy_id", ) - current_items: List["TaxonomyItem"] = relationship( - "TaxonomyItem", + current_items: Mapped[List["TaxonomyItem"]] = relationship( viewonly=True, # lazy="select", # do not always load this order_by="TaxonomyItem.id", @@ -44,8 +42,7 @@ class Taxonomy(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): primaryjoin="and_(Taxonomy.id == TaxonomyItem.taxonomy_id, TaxonomyItem.deleted_on == None)", ) - referenced_by_types: List["rel.OntologyTypeVersionToTaxonomy"] = relationship( - "OntologyTypeVersionToTaxonomy", + referenced_by_types: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = relationship( lazy="select", order_by="OntologyTypeVersionToTaxonomy.id", back_populates="taxonomy_target", @@ -83,64 +80,54 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): __tablename__ = "TaxonomyItem" - taxonomy_id: Column = DB.Column(DB.Integer, ForeignKey(Taxonomy.id), nullable=False) - current_version_id: Column = DB.Column( - DB.Integer, ForeignKey("TaxonomyItemVersion.id"), nullable=True - ) + taxonomy_id: Mapped[int] = mapped_column(ForeignKey("Taxonomy.id"), nullable=False) + current_version_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItemVersion.id"), nullable=True) # relationships - taxonomy: Taxonomy = relationship( - Taxonomy, + taxonomy: Mapped[Taxonomy] = relationship( innerjoin=True, lazy="selectin", back_populates="items", sync_backref=False, ) - current_version: "TaxonomyItemVersion" = relationship( - "TaxonomyItemVersion", + current_version: Mapped["TaxonomyItemVersion"] = relationship( post_update=True, innerjoin=True, lazy="joined", primaryjoin="TaxonomyItem.current_version_id == TaxonomyItemVersion.id", ) - versions: List["TaxonomyItemVersion"] = relationship( - "TaxonomyItemVersion", + versions: Mapped[List["TaxonomyItemVersion"]] = relationship( lazy="select", order_by="TaxonomyItemVersion.version", back_populates="taxonomy_item", primaryjoin="TaxonomyItem.id == TaxonomyItemVersion.taxonomy_item_id", ) - related: List["TaxonomyItemRelation"] = relationship( - "TaxonomyItemRelation", + related: Mapped[List["TaxonomyItemRelation"]] = relationship( lazy="select", order_by="TaxonomyItemRelation.id", back_populates="taxonomy_item_source", primaryjoin="TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_source_id", ) - ancestors: List["TaxonomyItemRelation"] = relationship( - "TaxonomyItemRelation", + ancestors: Mapped[List["TaxonomyItemRelation"]] = relationship( lazy="select", order_by="TaxonomyItemRelation.id", back_populates="taxonomy_item_target", primaryjoin="TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_target_id", ) - current_related: List["TaxonomyItemRelation"] = relationship( - "TaxonomyItemRelation", + current_related: Mapped[List["TaxonomyItemRelation"]] = relationship( viewonly=True, lazy="selectin", # deals better with multiple levels of hierarchy order_by="TaxonomyItemRelation.id", primaryjoin="and_(TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_source_id, TaxonomyItemRelation.deleted_on == None)", ) - current_ancestors: List["TaxonomyItemRelation"] = relationship( - "TaxonomyItemRelation", + current_ancestors: Mapped[List["TaxonomyItemRelation"]] = relationship( viewonly=True, lazy="selectin", # deals better with multiple levels of hierarchy order_by="TaxonomyItemRelation.id", primaryjoin="and_(TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_target_id, TaxonomyItemRelation.deleted_on == None)", ) - referenced_by_objects: List["rel.OntologyObjectVersionToTaxonomyItem"] = relationship( - "OntologyObjectVersionToTaxonomyItem", + referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = relationship( lazy="select", order_by="OntologyObjectVersionToTaxonomyItem.id", back_populates="taxonomy_item_target", @@ -187,12 +174,10 @@ class TaxonomyItemVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMixi __tablename__ = "TaxonomyItemVersion" - taxonomy_item_id: Column = DB.Column( - DB.Integer, ForeignKey(TaxonomyItem.id), nullable=False - ) - version: Column = DB.Column(DB.Integer, nullable=False) - sort_key: Column = DB.Column(DB.Float, nullable=True) - + taxonomy_item_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) + version: Mapped[int] = mapped_column(nullable=False) + sort_key: Mapped[float] = mapped_column(nullable=True) + @declared_attr def __table_args__(cls): return ( @@ -211,8 +196,7 @@ def __table_args__(cls): ) # relationships - taxonomy_item: TaxonomyItem = relationship( - TaxonomyItem, + taxonomy_item: Mapped[TaxonomyItem] = relationship( innerjoin=True, lazy="select", # normally loaded from the taxonmy item -> less queries needed back_populates="versions", @@ -240,24 +224,18 @@ class TaxonomyItemRelation(MODEL, IdMixin, CreateDeleteMixin): __tablename__ = "TaxonomyItemRelation" - taxonomy_item_source_id: Column = DB.Column( - DB.Integer, ForeignKey(TaxonomyItem.id), nullable=False - ) + taxonomy_item_source_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) - taxonomy_item_target_id: Column = DB.Column( - DB.Integer, ForeignKey(TaxonomyItem.id), nullable=False - ) + taxonomy_item_target_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) # relationships - taxonomy_item_source: TaxonomyItem = relationship( - TaxonomyItem, + taxonomy_item_source: Mapped[TaxonomyItem] = relationship( lazy="select", # is nearly always in cache anyway back_populates="related", primaryjoin=TaxonomyItem.id == taxonomy_item_source_id, ) - taxonomy_item_target: TaxonomyItem = relationship( - TaxonomyItem, + taxonomy_item_target: Mapped[TaxonomyItem] = relationship( lazy="select", # is nearly always in cache anyway back_populates="ancestors", primaryjoin=TaxonomyItem.id == taxonomy_item_target_id, diff --git a/muse_for_anything/db/models/users.py b/muse_for_anything/db/models/users.py index c3ec22b..cd6297a 100644 --- a/muse_for_anything/db/models/users.py +++ b/muse_for_anything/db/models/users.py @@ -3,9 +3,10 @@ from typing import List, Optional, Set, Union from flask_babel import gettext -from sqlalchemy.orm import relationship +from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.sql.elements import literal -from sqlalchemy.sql.schema import Column, ForeignKey +from sqlalchemy.sql.schema import ForeignKey +from sqlalchemy.types import Text from .model_helpers import CreateDeleteMixin, ExistsMixin, IdMixin from .namespace import Namespace @@ -55,19 +56,17 @@ class User(MODEL, IdMixin, CreateDeleteMixin, ExistsMixin): __tablename__ = "User" - username: Column = DB.Column(DB.String(120), unique=True, index=True) - e_mail: Column = DB.Column(DB.Text, unique=True, index=True, nullable=True) - password: Column = DB.Column(DB.String(120)) + username: Mapped[str] = mapped_column(DB.String(120), unique=True, index=True) + e_mail: Mapped[Text] = mapped_column(DB.Text, unique=True, index=True, nullable=True) + password: Mapped[str] = mapped_column(DB.String(120)) # references - roles: List["UserRole"] = relationship( - "UserRole", + roles: Mapped[List["UserRole"]] = relationship( lazy="joined", back_populates="user", ) - grants: List["UserGrant"] = relationship( - "UserGrant", + grants: Mapped[List["UserGrant"]] = relationship( lazy="select", back_populates="user", ) @@ -159,12 +158,11 @@ class UserRole(MODEL, IdMixin): __tablename__ = "UserRole" - user_id: Column = DB.Column(DB.Integer, ForeignKey(User.id), nullable=False) - role: Column = DB.Column(DB.String(64)) + user_id: Mapped[int] = mapped_column(ForeignKey("User.id"), nullable=False) + role: Mapped[str] = mapped_column(DB.String(64)) # references - user: User = relationship( - User, + user: Mapped[User] = relationship( innerjoin=True, lazy="selectin", back_populates="roles", @@ -249,13 +247,12 @@ class UserGrant(MODEL, IdMixin): __tablename__ = "UserGrant" - user_id: Column = DB.Column(DB.Integer, ForeignKey(User.id), nullable=True) - role: Column = DB.Column(DB.String(64), index=True) - resource_type: Column = DB.Column(DB.String(64), index=True) - resource_id: Column = DB.Column(DB.Integer(), index=True) + user_id: Mapped[int] = mapped_column(ForeignKey("User.id"), nullable=True) + role: Mapped[str] = mapped_column(DB.String(64), index=True) + resource_type: Mapped[str] = mapped_column(DB.String(64), index=True) + resource_id: Mapped[int] = mapped_column(index=True) - user: User = relationship( - User, + user: Mapped[User] = relationship( innerjoin=True, lazy="selectin", back_populates="grants", diff --git a/muse_for_anything/oso_helpers.py b/muse_for_anything/oso_helpers.py index 342b5e7..2cd11fb 100644 --- a/muse_for_anything/oso_helpers.py +++ b/muse_for_anything/oso_helpers.py @@ -1,14 +1,15 @@ """Module for setting up oso support for flask app.""" from dataclasses import dataclass -from typing import Any, Dict, Optional, Sequence, Type +from typing import Any, Callable, Dict, NoReturn, Optional, Sequence, Type -from flask import Flask -from flask.globals import g, request -from flask_oso import FlaskOso +from flask import Flask, current_app, g, request +from flask.globals import request_ctx, g, request +from flask.wrappers import Request, Response from oso import Oso from polar.exceptions import OsoError from sqlalchemy.exc import ArgumentError +from werkzeug.exceptions import Forbidden from muse_for_anything.db.models.namespace import Namespace from muse_for_anything.db.models.ontology_objects import ( @@ -56,25 +57,81 @@ class OsoResource: arguments: Optional[Dict[str, Any]] = None -class CustomFlaskOso(FlaskOso): +class CustomFlaskOso(): _oso: Oso _app: Flask _allowed_methods: Optional[Sequence[str]] - def __init__(self, *, oso: Optional[Oso] = None, app: Optional[Flask] = None): - super().__init__(oso=oso, app=app) + def __init__(self, oso: Optional[Oso] = None, app: Optional[Flask] = None) -> None: + self._app = app + self._oso = None + + def unauthorized() -> NoReturn: + raise Forbidden("Unauthorized") + + self._unauthorized_action = unauthorized + + self._get_actor = lambda: g.current_user + + if self._app is not None: + self.init_app(self._app) + if oso is not None: + self.set_oso(oso) + self._allowed_methods = None + def set_oso(self, oso: Oso) -> None: + if oso == self._oso: + return + self._oso = oso + self._oso.register_class(Request) + def init_app(self, app: Flask): - super().init_app(app) + app.teardown_appcontext(self.teardown) + app.before_request(self._provide_oso) app.before_request(self._clear_old_cache) + def teardown(self, exception): + pass + + def _provide_oso(self) -> None: + top = _app_context() + if not hasattr(top, "oso_flask_oso"): + top.oso_flask_oso = self + def _clear_old_cache( self, ): self._allowed_methods = None + def set_get_actor(self, func:Callable[[], Any]) -> None: + self._get_actor = func + + def set_unauthorize_action(self, func:Callable[[], Any]) -> None: + self._unauthorized_action = func + + def require_authorization(self, app:Optional[Flask] = None) -> None: + if app is None: + app = self._app + if app is None: + raise OsoError( + "Cannot require authorization without Flask app object" + ) + app.after_request(self._require_authorization) + + def perform_route_authorization(self, app: Optional[Flask] = None) -> None: + if app is None: + app = self._app + if app is None: + raise OsoError( + "Cannot perform route authorization without Flask app object" + ) + app.before_request(self.perform_route_authorization) + + def skip_authorization(self, reason: Optional[str] = None) -> None: + _authorize_called() + def _get_resource(self): if g.current_resource: return g.current_resource @@ -111,7 +168,51 @@ def authorize( ): if resource is None: resource = self._get_resource() - super().authorize(resource, actor=actor, action=action) + if actor is None: + try: + actor = self.current_actor + except AttributeError as e: + raise OsoError( + "Getting the current actor failed. " + "You may need to override the current actor function with " + "FlaskOso#set_get_actor" + ) from e + if action is None: + action = request.method + if resource is request: + resource = request._get_currect_object() + if self.oso is None: + raise OsoError("Cannot perform authorization without oso instance") + + allowed = self.oso.is_allowed(actor, action, resource) + _authorize_called() + + if not allowed: + self._unauthorized_action() + + @property + def app(self) -> Flask: + return self._app or current_app + + @property + def oso(self) -> Optional[Oso]: + return self._oso + + @property + def current_actor(self) -> Any: + return self._get_actor() + + def _perform_route_authorization(self) -> None: + if not request.url_rule: + return + self.authorize(resource=request) + + def _require_authorization(self, response: Response) -> Response: + if not request.url_rule: + return Response + if not getattr(_app_context(), "oso_flask_authorize_called", False): + raise OsoError("Authorize not called.") + return response def is_admin( self, @@ -172,6 +273,17 @@ def get_allowed_actions( FLASK_OSO = CustomFlaskOso(oso=OSO) +def _authorize_called() -> None: + _app_context().oso_flask_authorize_called = True + +def _app_context(): + top = request_ctx + if top is None: + raise OsoError( + "Application context doesn't exist. Did you use oso outside the context of a request? " + "See https://flask.palletsprojects.com/en/1.1.x/appcontext/#manually-push-a-context" + ) + return top def register_oso(app: Flask): """Register oso to enable access management for this app.""" diff --git a/poetry.lock b/poetry.lock index 12dd35b..82568d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -13,13 +13,13 @@ files = [ [[package]] name = "alembic" -version = "1.13.1" +version = "1.13.2" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.1-py3-none-any.whl", hash = "sha256:2edcc97bed0bd3272611ce3a98d98279e9c209e7186e43e75bbb1b2bdfdbcc43"}, - {file = "alembic-1.13.1.tar.gz", hash = "sha256:4932c8558bf68f2ee92b9bbcb8218671c627064d5b08939437af6d77dc05e595"}, + {file = "alembic-1.13.2-py3-none-any.whl", hash = "sha256:6b8733129a6224a9a711e17c99b08462dbf7cc9670ba8f2e2ae9af860ceb1953"}, + {file = "alembic-1.13.2.tar.gz", hash = "sha256:1ff0ae32975f4fd96028c39ed9bb3c867fe3af956bd7bb37343b54c9fe7445ef"}, ] [package.dependencies] @@ -32,37 +32,26 @@ tz = ["backports.zoneinfo"] [[package]] name = "apispec" -version = "5.2.2" +version = "6.6.1" description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "apispec-5.2.2-py3-none-any.whl", hash = "sha256:f5f0d6b452c3e4a0e0922dce8815fac89dc4dbc758acef21fb9e01584d6602a5"}, - {file = "apispec-5.2.2.tar.gz", hash = "sha256:6ea6542e1ebffe9fd95ba01ef3f51351eac6c200a974562c7473059b9cd20aa7"}, + {file = "apispec-6.6.1-py3-none-any.whl", hash = "sha256:6460315cb38ac6a2ff42d9e2b8dc0435c37d4428d3abeda96ff97b5dc8eb6b94"}, + {file = "apispec-6.6.1.tar.gz", hash = "sha256:f5caa47cee75fe03b9c50b5594048b4c052eeca2c212e0dac12dbb6175d9a659"}, ] [package.dependencies] -marshmallow = {version = ">=3.13.0", optional = true, markers = "extra == \"marshmallow\""} +marshmallow = {version = ">=3.18.0", optional = true, markers = "extra == \"marshmallow\""} +packaging = ">=21.3" [package.extras] -dev = ["PyYAML (>=3.10)", "flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "marshmallow (>=3.13.0)", "mock", "mypy (==0.950)", "prance[osv] (>=0.11)", "pre-commit (>=2.4,<3.0)", "pytest", "tox", "types-PyYAML"] -docs = ["marshmallow (>=3.13.0)", "pyyaml (==6.0)", "sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "sphinx-rtd-theme (==1.0.0)"] -lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "mypy (==0.950)", "pre-commit (>=2.4,<3.0)", "types-PyYAML"] -marshmallow = ["marshmallow (>=3.13.0)"] -tests = ["PyYAML (>=3.10)", "marshmallow (>=3.13.0)", "mock", "prance[osv] (>=0.11)", "pytest"] -validation = ["prance[osv] (>=0.11)"] +dev = ["apispec[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["apispec[marshmallow]", "pyyaml (==6.0.1)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-rtd-theme (==2.0.0)"] +marshmallow = ["marshmallow (>=3.18.0)"] +tests = ["apispec[marshmallow,yaml]", "openapi-spec-validator (==0.7.1)", "pytest"] yaml = ["PyYAML (>=3.10)"] -[[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, -] - [[package]] name = "attrs" version = "23.2.0" @@ -84,13 +73,13 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p [[package]] name = "babel" -version = "2.14.0" +version = "2.15.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Babel-2.14.0-py3-none-any.whl", hash = "sha256:efb1a25b7118e67ce3a259bed20545c29cb68be8ad2c784c83689981b7a57287"}, - {file = "Babel-2.14.0.tar.gz", hash = "sha256:6919867db036398ba21eb5c7a0f6b28ab8cbc3ae7a73a44ebe34ae74a4e7d363"}, + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] [package.extras] @@ -98,60 +87,73 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "bcrypt" -version = "3.2.2" +version = "4.2.0" description = "Modern password hashing for your software and your servers" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"}, - {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"}, - {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"}, - {file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"}, - {file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"}, - {file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"}, + {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"}, + {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"}, + {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"}, + {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"}, + {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"}, + {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"}, + {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"}, + {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"}, + {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"}, + {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"}, + {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"}, + {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"}, + {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"}, + {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"}, + {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"}, ] -[package.dependencies] -cffi = ">=1.1" - [package.extras] tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] [[package]] name = "black" -version = "23.12.1" +version = "24.4.2" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, + {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, + {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, + {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, + {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, + {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, + {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, + {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, + {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, + {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, + {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, + {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, + {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, + {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, + {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, + {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, ] [package.dependencies] @@ -171,24 +173,24 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "blinker" -version = "1.7.0" +version = "1.8.2" description = "Fast, simple object-to-object and broadcast signaling" optional = false python-versions = ">=3.8" files = [ - {file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"}, - {file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"}, + {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"}, + {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"}, ] [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.7.4" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, + {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, ] [[package]] @@ -381,48 +383,62 @@ files = [ [[package]] name = "docutils" -version = "0.18.1" +version = "0.20.1" description = "Docutils -- Python Documentation Utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" files = [ - {file = "docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c"}, - {file = "docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06"}, + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, ] +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "flake8" -version = "3.9.2" +version = "7.1.0" description = "the modular source code checker: pep8 pyflakes and co" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.8.1" files = [ - {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, - {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, + {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, + {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, ] [package.dependencies] -mccabe = ">=0.6.0,<0.7.0" -pycodestyle = ">=2.7.0,<2.8.0" -pyflakes = ">=2.3.0,<2.4.0" +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.12.0,<2.13.0" +pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "flake8-bugbear" -version = "21.11.29" +version = "24.4.26" description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8.1" files = [ - {file = "flake8-bugbear-21.11.29.tar.gz", hash = "sha256:8b04cb2fafc6a78e1a9d873bd3988e4282f7959bb6b0d7c1ae648ec09b937a7b"}, - {file = "flake8_bugbear-21.11.29-py36.py37.py38-none-any.whl", hash = "sha256:179e41ddae5de5e3c20d1f61736feeb234e70958fbb56ab3c28a67739c8e9a82"}, + {file = "flake8_bugbear-24.4.26-py3-none-any.whl", hash = "sha256:cb430dd86bc821d79ccc0b030789a9c87a47a369667f12ba06e80f11305e8258"}, + {file = "flake8_bugbear-24.4.26.tar.gz", hash = "sha256:ff8d4ba5719019ebf98e754624c30c05cef0dadcf18a65d91c7567300e52a130"}, ] [package.dependencies] attrs = ">=19.2.0" -flake8 = ">=3.0.0" +flake8 = ">=6.0.0" [package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit"] +dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "pytest", "tox"] [[package]] name = "flake8-docstrings" @@ -441,13 +457,13 @@ pydocstyle = ">=2.1" [[package]] name = "flask" -version = "2.3.3" +version = "3.0.3" description = "A simple framework for building complex web applications." optional = false python-versions = ">=3.8" files = [ - {file = "flask-2.3.3-py3-none-any.whl", hash = "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"}, - {file = "flask-2.3.3.tar.gz", hash = "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc"}, + {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"}, + {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"}, ] [package.dependencies] @@ -456,7 +472,7 @@ click = ">=8.1.3" itsdangerous = ">=2.1.2" Jinja2 = ">=3.1.2" python-dotenv = {version = "*", optional = true, markers = "extra == \"dotenv\""} -Werkzeug = ">=2.3.7" +Werkzeug = ">=3.0.0" [package.extras] async = ["asgiref (>=3.2)"] @@ -464,38 +480,34 @@ dotenv = ["python-dotenv"] [[package]] name = "flask-babel" -version = "2.0.0" -description = "Adds i18n/l10n support to Flask applications" +version = "4.0.0" +description = "Adds i18n/l10n support for Flask applications." optional = false -python-versions = "*" +python-versions = ">=3.8,<4.0" files = [ - {file = "Flask-Babel-2.0.0.tar.gz", hash = "sha256:f9faf45cdb2e1a32ea2ec14403587d4295108f35017a7821a2b1acb8cfd9257d"}, - {file = "Flask_Babel-2.0.0-py3-none-any.whl", hash = "sha256:e6820a052a8d344e178cdd36dd4bb8aea09b4bda3d5f9fa9f008df2c7f2f5468"}, + {file = "flask_babel-4.0.0-py3-none-any.whl", hash = "sha256:638194cf91f8b301380f36d70e2034c77ee25b98cb5d80a1626820df9a6d4625"}, + {file = "flask_babel-4.0.0.tar.gz", hash = "sha256:dbeab4027a3f4a87678a11686496e98e1492eb793cbdd77ab50f4e9a2602a593"}, ] [package.dependencies] -Babel = ">=2.3" -Flask = "*" -Jinja2 = ">=2.5" -pytz = "*" - -[package.extras] -dev = ["Pallets-Sphinx-Themes", "bumpversion", "ghp-import", "pytest", "pytest-mock", "sphinx"] +Babel = ">=2.12" +Flask = ">=2.0" +Jinja2 = ">=3.1" +pytz = ">=2022.7" [[package]] name = "flask-cors" -version = "3.0.10" +version = "4.0.1" description = "A Flask extension adding a decorator for CORS support" optional = false python-versions = "*" files = [ - {file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"}, - {file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"}, + {file = "Flask_Cors-4.0.1-py2.py3-none-any.whl", hash = "sha256:f2a704e4458665580c074b714c4627dd5a306b333deb9074d0b1794dfa2fb677"}, + {file = "flask_cors-4.0.1.tar.gz", hash = "sha256:eeb69b342142fdbf4766ad99357a7f3876a2ceb77689dc10ff912aac06c389e4"}, ] [package.dependencies] Flask = ">=0.9" -Six = "*" [[package]] name = "flask-jwt-extended" @@ -517,86 +529,91 @@ Werkzeug = ">=0.14" asymmetric-crypto = ["cryptography (>=3.3.1)"] [[package]] -name = "flask-migrate" -version = "3.1.0" -description = "SQLAlchemy database migrations for Flask applications using Alembic." +name = "flask-login" +version = "0.6.3" +description = "User authentication and session management for Flask." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Flask-Migrate-3.1.0.tar.gz", hash = "sha256:57d6060839e3a7f150eaab6fe4e726d9e3e7cffe2150fb223d73f92421c6d1d9"}, - {file = "Flask_Migrate-3.1.0-py3-none-any.whl", hash = "sha256:a6498706241aba6be7a251078de9cf166d74307bca41a4ca3e403c9d39e2f897"}, + {file = "Flask-Login-0.6.3.tar.gz", hash = "sha256:5e23d14a607ef12806c699590b89d0f0e0d67baeec599d75947bf9c147330333"}, + {file = "Flask_Login-0.6.3-py3-none-any.whl", hash = "sha256:849b25b82a436bf830a054e74214074af59097171562ab10bfa999e6b78aae5d"}, ] [package.dependencies] -alembic = ">=0.7" -Flask = ">=0.9" -Flask-SQLAlchemy = ">=1.0" +Flask = ">=1.0.4" +Werkzeug = ">=1.0.1" [[package]] -name = "flask-oso" -version = "0.26.0" -description = "oso flask integration" +name = "flask-migrate" +version = "4.0.7" +description = "SQLAlchemy database migrations for Flask applications using Alembic." optional = false python-versions = ">=3.6" files = [ - {file = "flask_oso-0.26.0-py3-none-any.whl", hash = "sha256:86694a0d4643f05c8342c2d616048c1a44c2cf762d8327c6fbd84a0fa8f7a7ba"}, + {file = "Flask-Migrate-4.0.7.tar.gz", hash = "sha256:dff7dd25113c210b069af280ea713b883f3840c1e3455274745d7355778c8622"}, + {file = "Flask_Migrate-4.0.7-py3-none-any.whl", hash = "sha256:5c532be17e7b43a223b7500d620edae33795df27c75811ddf32560f7d48ec617"}, ] [package.dependencies] -flask = ">=0.12.0" -oso = ">=0.26.0,<0.27.0" +alembic = ">=1.9.0" +Flask = ">=0.9" +Flask-SQLAlchemy = ">=1.0" [[package]] name = "flask-smorest" -version = "0.39.0" +version = "0.44.0" description = "Flask/Marshmallow-based REST API framework" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "flask-smorest-0.39.0.tar.gz", hash = "sha256:b72b068283176c8dc7bb0e3cfbc2721fc5c9efdcf719eac76604d78223adb99c"}, - {file = "flask_smorest-0.39.0-py3-none-any.whl", hash = "sha256:0b31c01f5fd3f7c2bc7f9e700e387e326939529edeabbe45963d352caca99f12"}, + {file = "flask-smorest-0.44.0.tar.gz", hash = "sha256:13f6e39d807c8847a56dc40656c2bbc0a2b2a430d8a4bb4a21836046757f7cef"}, + {file = "flask_smorest-0.44.0-py3-none-any.whl", hash = "sha256:a35d088d0f62e9ff7e94ed996601e04fcc17cbacfb43b52543b596b933db4f72"}, ] [package.dependencies] -apispec = {version = ">=5.1.0,<6", extras = ["marshmallow"]} -flask = ">=2.0,<3" -marshmallow = ">=3.13.0,<4" +apispec = {version = ">=6.0.0,<7", extras = ["marshmallow"]} +flask = ">=3.0.2,<4" +marshmallow = ">=3.18.0,<4" webargs = ">=8.0.0,<9" -werkzeug = ">=2.0,<3" +werkzeug = ">=3.0.1,<4" [package.extras] -dev = ["PyYAML (==6.0)", "apispec (==5.2.2)", "coverage (==6.4.3)", "flake8 (==5.0.4)", "flake8-bugbear (==22.7.1)", "flask (==2.2.2)", "marshmallow (==3.17.0)", "pre-commit (==2.20.0)", "pytest (==7.1.2)", "pytest-cov (==3.0.0)", "webargs (==8.2.0)", "werkzeug (==2.2.2)"] -lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.7.1)", "pre-commit (==2.20.0)"] -tests = ["PyYAML (==6.0)", "apispec (==5.2.2)", "coverage (==6.4.3)", "flask (==2.2.2)", "marshmallow (==3.17.0)", "pytest (==7.1.2)", "pytest-cov (==3.0.0)", "webargs (==8.2.0)", "werkzeug (==2.2.2)"] +dev = ["PyYAML (==6.0.1)", "apispec (==6.4.0)", "coverage (==7.4.3)", "flask (==3.0.2)", "marshmallow (==3.20.2)", "pre-commit (==3.6.2)", "pytest (==8.0.2)", "pytest-cov (==4.1.0)", "webargs (==8.4.0)", "werkzeug (==3.0.1)"] +lint = ["pre-commit (==3.6.2)"] +tests = ["PyYAML (==6.0.1)", "apispec (==6.4.0)", "coverage (==7.4.3)", "flask (==3.0.2)", "marshmallow (==3.20.2)", "pytest (==8.0.2)", "pytest-cov (==4.1.0)", "webargs (==8.4.0)", "werkzeug (==3.0.1)"] [[package]] name = "flask-sqlalchemy" -version = "2.5.1" -description = "Adds SQLAlchemy support to your Flask application." +version = "3.1.1" +description = "Add SQLAlchemy support to your Flask application." optional = false -python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*" +python-versions = ">=3.8" files = [ - {file = "Flask-SQLAlchemy-2.5.1.tar.gz", hash = "sha256:2bda44b43e7cacb15d4e05ff3cc1f8bc97936cc464623424102bfc2c35e95912"}, - {file = "Flask_SQLAlchemy-2.5.1-py2.py3-none-any.whl", hash = "sha256:f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390"}, + {file = "flask_sqlalchemy-3.1.1-py3-none-any.whl", hash = "sha256:4ba4be7f419dc72f4efd8802d69974803c37259dd42f3913b0dcf75c9447e0a0"}, + {file = "flask_sqlalchemy-3.1.1.tar.gz", hash = "sha256:e4b68bb881802dda1a7d878b2fc84c06d1ee57fb40b874d3dc97dabfa36b8312"}, ] [package.dependencies] -Flask = ">=0.10" -SQLAlchemy = ">=0.8.0" +flask = ">=2.2.5" +sqlalchemy = ">=2.0.16" [[package]] name = "flask-static-digest" -version = "0.2.1" -description = "Flask extension for md5 tagging and gzipping static files." +version = "0.4.1" +description = "Flask extension for md5 tagging and compressing (gzip / brotli) static files." optional = false python-versions = ">=3.6" files = [ - {file = "Flask-Static-Digest-0.2.1.tar.gz", hash = "sha256:7528b08a2c12dc3a828096b66ee2612f323d50be36d01f2817b767fbb1ceca6e"}, + {file = "Flask_Static_Digest-0.4.1-py3-none-any.whl", hash = "sha256:72bed5f614bcb57a81d2ebf6aa9ee3158a6057114b441ee791340b2c0df962b1"}, + {file = "flask_static_digest-0.4.1.tar.gz", hash = "sha256:a6b38e953a4cfaac092e0ae40feea82a4f098bfac50969cefc48d4a9e7492e14"}, ] [package.dependencies] Flask = ">=1.0" +[package.extras] +brotli = ["Brotli (>=1.0.9)"] + [[package]] name = "greenlet" version = "3.0.3" @@ -670,13 +687,13 @@ test = ["objgraph", "psutil"] [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -714,24 +731,24 @@ files = [ [[package]] name = "itsdangerous" -version = "2.1.2" +version = "2.2.0" description = "Safely pass data to untrusted environments and back." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"}, - {file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"}, + {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"}, + {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"}, ] [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -742,34 +759,48 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jsonschema" -version = "3.2.0" +version = "4.23.0" description = "An implementation of JSON Schema validation for Python" optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, - {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, + {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, + {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, ] [package.dependencies] -attrs = ">=17.4.0" -pyrsistent = ">=0.14.0" -setuptools = "*" -six = ">=1.11.0" +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" [package.extras] -format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] -format-nongpl = ["idna", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "webcolors"] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" [[package]] name = "mako" -version = "1.3.0" +version = "1.3.5" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.0-py3-none-any.whl", hash = "sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9"}, - {file = "Mako-1.3.0.tar.gz", hash = "sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b"}, + {file = "Mako-1.3.5-py3-none-any.whl", hash = "sha256:260f1dbc3a519453a9c856dedfe4beb4e50bd5a26d96386cb6c80856556bb91a"}, + {file = "Mako-1.3.5.tar.gz", hash = "sha256:48dbc20568c1d276a2698b36d968fa76161bf127194907ea6fc594fa81f943bc"}, ] [package.dependencies] @@ -806,81 +837,90 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "2.1.5" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] [[package]] name = "marshmallow" -version = "3.20.2" +version = "3.21.3" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, - {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, + {file = "marshmallow-3.21.3-py3-none-any.whl", hash = "sha256:86ce7fb914aa865001a4b2092c4c2872d13bc347f3d42673272cabfdbad386f1"}, + {file = "marshmallow-3.21.3.tar.gz", hash = "sha256:4f57c5e050a54d66361e826f94fba213eb10b67b2fdb02c3e0343ce207ba1662"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -903,24 +943,24 @@ union = ["marshmallow-union"] [[package]] name = "mccabe" -version = "0.6.1" +version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false -python-versions = "*" +python-versions = ">=3.6" files = [ - {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, - {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] [[package]] name = "mdit-py-plugins" -version = "0.4.0" +version = "0.4.1" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" files = [ - {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, - {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, + {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, + {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, ] [package.dependencies] @@ -955,17 +995,17 @@ files = [ [[package]] name = "myst-parser" -version = "2.0.0" +version = "3.0.1" description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," optional = false python-versions = ">=3.8" files = [ - {file = "myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14"}, - {file = "myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead"}, + {file = "myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1"}, + {file = "myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87"}, ] [package.dependencies] -docutils = ">=0.16,<0.21" +docutils = ">=0.18,<0.22" jinja2 = "*" markdown-it-py = ">=3.0,<4.0" mdit-py-plugins = ">=0.4,<1.0" @@ -975,54 +1015,58 @@ sphinx = ">=6,<8" [package.extras] code-style = ["pre-commit (>=3.0,<4.0)"] linkify = ["linkify-it-py (>=2.0,<3.0)"] -rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4.2,<0.5.0)", "sphinx-book-theme (==1.0.0rc2)", "sphinx-copybutton", "sphinx-design2", "sphinx-pyscript", "sphinx-tippy (>=0.3.1)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.8.2,<0.9.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] -testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] -testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] +rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-book-theme (>=1.1,<2.0)", "sphinx-copybutton", "sphinx-design", "sphinx-pyscript", "sphinx-tippy (>=0.4.3)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.9.0,<0.10.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"] [[package]] name = "oso" -version = "0.26.4" +version = "0.27.3" description = "oso is an open source policy engine for authorization that's embedded in your application" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "oso-0.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c88e25d6afc74e1363270778105544c78a6c84d8caa340d4343546af8b58066c"}, - {file = "oso-0.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cfe11384df31c7d3989e93f83a96a27a3c4b969e533126270a9f0dd53e20d81c"}, - {file = "oso-0.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e585ac2f0fe3af823b9a715b2a882979e9b0381fccc0824560edc2c80eac2b4"}, - {file = "oso-0.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bea557e9eb256b5f3ac4f6a462ac37d742446ca462dcef743a47f02401b4248a"}, - {file = "oso-0.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:4e4cd78b4e840dab1e6553df5d35cb1c82fc37fb5f62ad2b000dc81dec052d11"}, - {file = "oso-0.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:23fc859aa9cfae2d5d625ebcc0f254aa2eb753c90e3677faf6dd5c8c2ee570c3"}, - {file = "oso-0.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01599277a0d7d2ff1d30adcdef6eb2b573745975ce47e3d2fa30ec63a6b05e29"}, - {file = "oso-0.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027eb000b8ee4ec323c76c0d837cb711360a6e4ec9cb8924a5b0bd27624abb5d"}, - {file = "oso-0.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1d75b156d336a9ee24134db0186172e645845b290e13fe1fb0497656cb533b55"}, - {file = "oso-0.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:4c8c657c730c00737eae78755a0817840658e6ec9de0c8c6db43b23fbdb1faf2"}, - {file = "oso-0.26.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d3ddeb87d1f29b84e48fed52424ee232d5e03587fb2f3ee52de177fcb3528b0d"}, - {file = "oso-0.26.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a62569aed6a535c9657a24fcf9be0f6b1ba957c2126011800baf6a4848ac11fd"}, - {file = "oso-0.26.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:4a33eb9d8c49b59d72be4b3189e522316a00fba2d774b124d390a4a4a59c2f19"}, - {file = "oso-0.26.4-cp36-cp36m-win_amd64.whl", hash = "sha256:46864b9e7eec0d47909c05c03367a13be84ac793397eb44e62feca6d0d17b58b"}, - {file = "oso-0.26.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c9b900cd8aaf43c4c26aaeb8d5930880bf3892128e8b974bf6e85e27a816cfbc"}, - {file = "oso-0.26.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d860caf8e0602170f8ffafc222b642523387d5b286ba3f25023b28952c3318"}, - {file = "oso-0.26.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54c97ac152310e179a16f029dfbdcd9322f2dbe662eb32bba199f2036ecfc61e"}, - {file = "oso-0.26.4-cp37-cp37m-win_amd64.whl", hash = "sha256:cb1437a9259f6ac8e17aa65c5febb610bf007b1f062b46af82ddad561493e68d"}, - {file = "oso-0.26.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bbc83a68d1db43c820a8601ecd02cbafbba51bbc8e59034c779ec5e31d6f2242"}, - {file = "oso-0.26.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ce834536fed6533ed30f47e5f0a456de46c8955f290fe990b7a92ac52756c6f4"}, - {file = "oso-0.26.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07d60833376e02e9a55aa06983154778ad2d3a6185a99a647fcb60f9eff56b83"}, - {file = "oso-0.26.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:37202a0f61c7c3aed9842bceb9cb433c72736964a030122b6452236127a6200c"}, - {file = "oso-0.26.4-cp38-cp38-win_amd64.whl", hash = "sha256:ef13f42b9833447d9146a83d9ac8f47a38c595687376df064bcc75ee31b329bd"}, - {file = "oso-0.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9c5331037610ed59fa52ec34cca9929d1bb27432f56aa4afbaec992245bf104e"}, - {file = "oso-0.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3911f17555495d491ac5d2cc396ad53234e6aa1d8281f0c13c74cd4ea50f2ca6"}, - {file = "oso-0.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:778efe600365a08d12b565f7dd6fe77e59fed76365c189ab6ab5aef702a4464c"}, - {file = "oso-0.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b148eab888522e2b22ce374145590b68874eb52b4dccfde22b24cc419476b97c"}, - {file = "oso-0.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:cc3c849c4c2897d032736466e7b4c16e2db5fc507505afc2e516871969a6d946"}, - {file = "oso-0.26.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:dbc3d9db93b413a3fc4c2181d80f159217b58f965084e90df068aed89ad79507"}, - {file = "oso-0.26.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17704a101490e231e19961b9dc4cacdc372ca0055904a4a9ebaf0f68e13077b4"}, - {file = "oso-0.26.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:55d6174b4b1f37131b692b2c45d2e76dffb5dc7e5c89feee293a14239e04c018"}, - {file = "oso-0.26.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2ae2b2a4840d5d1323cac769d5638f59c1e9256e024214af8bd40ac26b73c69e"}, - {file = "oso-0.26.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cefe157ad30db3511dde870e166765b8a175f527024772e3abc3f05408fe240d"}, - {file = "oso-0.26.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d9edfea472673490d45d46a55819ef37d11603ed122c7e2f08359e9d96fd6006"}, - {file = "oso-0.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fa17769d5218ce390ccc9d01283295331801e1162f46fcb6297ffb8428085399"}, - {file = "oso-0.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8504f2d212406ce3068bb7038706ce7db49c2cfd3f3a876cfb73be837d15417a"}, - {file = "oso-0.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:db2e298432fbc308f93ad7935775beb1892b5b7f03981777544fceeefc50cbe4"}, + {file = "oso-0.27.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d23322bf611efd6ea2e944cb347768a4d275b3aa6344452e78c04593db7d8529"}, + {file = "oso-0.27.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:af257d0c86ee28e305608b13237f4ad0d17883b9d1018c1a01b0aad685a149c1"}, + {file = "oso-0.27.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9bd1f8262340e28ede72441bd48f04bb6cfa8c29f29e74ef30ada0e6ce2039d"}, + {file = "oso-0.27.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bcb1442b516c3e4291e84723b249b6ed5b6366c12449a648239fd0badd41f883"}, + {file = "oso-0.27.3-cp310-cp310-win_amd64.whl", hash = "sha256:2ff4e5aa675a1fd95dbf166acda6ccd36205fd52167a4b1d3b1f155143ee8d4d"}, + {file = "oso-0.27.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cba1e783367b8f8c09e5cb33bba90f41c7d7c2d4e7a0cd67a01d8eb8f42ae896"}, + {file = "oso-0.27.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0dec2b7fd5593fb4e36290d348f3e058bfdf26ce4afa6de7557deddc031469d"}, + {file = "oso-0.27.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93fbede3a6d5090780e25eca33fd77a52f63c0ed1f88ad0f2e96890ac7c3fe17"}, + {file = "oso-0.27.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de70282fe24bf80f24edcb03003760c5439dfe36a7805763e9ff0d7923da0d19"}, + {file = "oso-0.27.3-cp311-cp311-win_amd64.whl", hash = "sha256:a5c3ba2ea5961b8ebcb68cf4cda3c4a4b3ec50449768d90f805db5f07fac6783"}, + {file = "oso-0.27.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8233c2abab7f751b9e4c31c9ec860af3c936e627ce475285b74dfa4812e4f279"}, + {file = "oso-0.27.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a2a4e3dc889bec8d286898fea2f533e596663c0b788106d984c754a0c6b01fa5"}, + {file = "oso-0.27.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f93315bbb1988c58db0c9ae12c24aefb5e3d15ef2f80126a36cbbbfe060ef2b"}, + {file = "oso-0.27.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e54ef0e7066e152e065f6659f5cf1ff0cd823e9fd6b700a8d231a864e4224746"}, + {file = "oso-0.27.3-cp312-cp312-win_amd64.whl", hash = "sha256:afec309535235b374e741827a853bf5caa33f1926e3375a1fe45ba291f638175"}, + {file = "oso-0.27.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:790f0074421284a6c669ab5259ce5805b4d010fb1c3ddc23d781bbde64eba88b"}, + {file = "oso-0.27.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:868cf500bb529ea3abb38d8f1745ce50e64dfe8980d6a4730c1b4068b31be4cb"}, + {file = "oso-0.27.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1da316a8d8b87deaf3feef64e687297cb70de701fe318e57fce1acb445488869"}, + {file = "oso-0.27.3-cp37-cp37m-win_amd64.whl", hash = "sha256:84d5024a4b3383269b42fa770e4ac33bbc7664e822e6bf58737bd5dd8e16bdcd"}, + {file = "oso-0.27.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:89a1c86dd08635912c0152951581ee8d2be144d95eee695f26101dd0489adffc"}, + {file = "oso-0.27.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a793d6c2abf6df13923368e641accc7610011386da208f33021d72b2430f9927"}, + {file = "oso-0.27.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa4c8808202d14281f1bbff9b333fa70809af19e19e99a64c95f6ddad6f54dbe"}, + {file = "oso-0.27.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ab6eb413b1e24cde8b395129ce2ad727e460c392cb6dd08bda1ec8f574197ca"}, + {file = "oso-0.27.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cd6b82af3732f0f4561ce425fa1191c6dda8f2a0ecc4c8923a15f7473c0b50b"}, + {file = "oso-0.27.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:06995b79a0b19ac22a81cdb3463aa7bb9b5231ec304f1c1fe8fb708866f7a33b"}, + {file = "oso-0.27.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6b974b69336402e735e3407e2d588e3a35426da1d7e654a2661e6d3ade3d276f"}, + {file = "oso-0.27.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d68ad10bb6a8894894b8290839b5379a257aed421f544eda580e5b8cf0cd501b"}, + {file = "oso-0.27.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e6dfdb9de0e3480d7e6153400430be6a07ba99e306a1e179ad3c2d948f7c89b"}, + {file = "oso-0.27.3-cp39-cp39-win_amd64.whl", hash = "sha256:3b257b8644f01e2963ecbc0e25deeb0dbb2cc38995654962ee4b620f45c2ebc7"}, + {file = "oso-0.27.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:908dff4f3259a9610d8b10549590dcd7ed0f5bae083a3ce708fe19525c8cd394"}, + {file = "oso-0.27.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed4ef7a602361f3a3c3fe32f173344b7be563502ddf83bb836c0c569cbaa7d91"}, + {file = "oso-0.27.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fde31f80606795995d7a62f6dcebf230e01213862e272ff40cd22de976233d4e"}, + {file = "oso-0.27.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5d2e9b2ccd74ff654e3ba508025e954d8d775a491897a39212a27fa6d0313571"}, + {file = "oso-0.27.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:430c8a72c146ec72ccf0ddf1f421cb25a0a252ca2a8de0396f0a75f5b5a27026"}, + {file = "oso-0.27.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:a52814c2539e5ea37e1c4313fcb2a2e4788b48252c2e0e4913f349134d3b6692"}, + {file = "oso-0.27.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b8578a24acac8e0e923feffa15b45b87c7f79f87d6613d5d6a4a39ba80edb765"}, + {file = "oso-0.27.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4523cd2aa7ff2128b437be12fec95e2886f8fa838944fad468c6e3bd7971117d"}, + {file = "oso-0.27.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:19a7328ca118dd19cdf1fa2c7fab6ae50c55b6932c426821c7f07cf0004e5641"}, + {file = "oso-0.27.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7de72883e9eb44809e774dd30ee37857778faed35e6558fd20b235ef2030c19"}, + {file = "oso-0.27.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2d81f130180cc93d443bb563c7b5be2195e632ff4d054b3eebea5666a69001"}, + {file = "oso-0.27.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:def6a4490c3b98be05f03d59e0f5b7aeee6f4ac88acff9ea07f58ad95eb0c1b8"}, ] [package.dependencies] @@ -1034,13 +1078,13 @@ jwt = ["authlib"] [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -1056,51 +1100,70 @@ files = [ [[package]] name = "pip-licenses" -version = "3.5.5" +version = "4.5.1" description = "Dump the software license list of Python packages installed with pip." optional = false -python-versions = "~=3.7" +python-versions = "~=3.8" files = [ - {file = "pip-licenses-3.5.5.tar.gz", hash = "sha256:748cfd7aca6e05032f9fa85691301295f4d943e87955be6914ca49abe3c075a4"}, - {file = "pip_licenses-3.5.5-py3-none-any.whl", hash = "sha256:6129c116bab2b202d90d6e3a96092df4ad84c0c4d57bb70192fc03f8bf06d181"}, + {file = "pip-licenses-4.5.1.tar.gz", hash = "sha256:fad5f56fbaa56b8e414434e36c32394a9412ff10ddf2cef92b51951bdf193869"}, + {file = "pip_licenses-4.5.1-py3-none-any.whl", hash = "sha256:7c982bc6837f47d32d4016b43d9174c0ce723b450710a2111a3ebbb910f152b7"}, ] [package.dependencies] -PTable = "*" +prettytable = ">=2.3.0" +tomli = ">=2" [package.extras] -test = ["docutils", "pytest-cov", "pytest-pycodestyle", "pytest-runner"] +test = ["docutils", "mypy", "pytest-cov", "pytest-pycodestyle", "pytest-runner", "tomli-w"] [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "prettytable" +version = "3.10.2" +description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "prettytable-3.10.2-py3-none-any.whl", hash = "sha256:1cbfdeb4bcc73976a778a0fb33cb6d752e75396f16574dcb3e2d6332fd93c76a"}, + {file = "prettytable-3.10.2.tar.gz", hash = "sha256:29ec6c34260191d42cd4928c28d56adec360ac2b1208a26c7e4f14b90cc8bc84"}, +] + +[package.dependencies] +wcwidth = "*" + +[package.extras] +tests = ["pytest", "pytest-cov", "pytest-lazy-fixtures"] + [[package]] name = "psycopg2" version = "2.9.9" @@ -1123,47 +1186,26 @@ files = [ {file = "psycopg2-2.9.9.tar.gz", hash = "sha256:d1454bde93fb1e224166811694d600e746430c006fbb031ea06ecc2ea41bf156"}, ] -[[package]] -name = "ptable" -version = "0.9.2" -description = "A simple Python library for easily displaying tabular data in a visually appealing ASCII table format" -optional = false -python-versions = "*" -files = [ - {file = "PTable-0.9.2.tar.gz", hash = "sha256:aa7fc151cb40f2dabcd2275ba6f7fd0ff8577a86be3365cd3fb297cbe09cc292"}, -] - -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] - [[package]] name = "pycodestyle" -version = "2.7.0" +version = "2.12.0" description = "Python style guide checker" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"}, - {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"}, + {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, + {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, ] [[package]] name = "pycparser" -version = "2.21" +version = "2.22" description = "C parser in Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, - {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] @@ -1185,28 +1227,27 @@ toml = ["tomli (>=1.2.3)"] [[package]] name = "pyflakes" -version = "2.3.1" +version = "3.2.0" description = "passive checker of Python programs" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.8" files = [ - {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"}, - {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, ] [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] @@ -1228,93 +1269,50 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pymysql" -version = "1.1.0" +version = "1.1.1" description = "Pure Python MySQL Driver" optional = true python-versions = ">=3.7" files = [ - {file = "PyMySQL-1.1.0-py3-none-any.whl", hash = "sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"}, - {file = "PyMySQL-1.1.0.tar.gz", hash = "sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96"}, + {file = "PyMySQL-1.1.1-py3-none-any.whl", hash = "sha256:4de15da4c61dc132f4fb9ab763063e693d521a80fd0e87943b9a453dd4c19d6c"}, + {file = "pymysql-1.1.1.tar.gz", hash = "sha256:e127611aaf2b417403c60bf4dc570124aeb4a57f5f37b8e95ae399a42f904cd0"}, ] [package.extras] ed25519 = ["PyNaCl (>=1.4.0)"] rsa = ["cryptography"] -[[package]] -name = "pyrsistent" -version = "0.20.0" -description = "Persistent/Functional/Immutable data structures" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyrsistent-0.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c3aba3e01235221e5b229a6c05f585f344734bd1ad42a8ac51493d74722bbce"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1beb78af5423b879edaf23c5591ff292cf7c33979734c99aa66d5914ead880f"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21cc459636983764e692b9eba7144cdd54fdec23ccdb1e8ba392a63666c60c34"}, - {file = "pyrsistent-0.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5ac696f02b3fc01a710427585c855f65cd9c640e14f52abe52020722bb4906b"}, - {file = "pyrsistent-0.20.0-cp310-cp310-win32.whl", hash = "sha256:0724c506cd8b63c69c7f883cc233aac948c1ea946ea95996ad8b1380c25e1d3f"}, - {file = "pyrsistent-0.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:8441cf9616d642c475684d6cf2520dd24812e996ba9af15e606df5f6fd9d04a7"}, - {file = "pyrsistent-0.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f3b1bcaa1f0629c978b355a7c37acd58907390149b7311b5db1b37648eb6958"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cdd7ef1ea7a491ae70d826b6cc64868de09a1d5ff9ef8d574250d0940e275b8"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cae40a9e3ce178415040a0383f00e8d68b569e97f31928a3a8ad37e3fde6df6a"}, - {file = "pyrsistent-0.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6288b3fa6622ad8a91e6eb759cfc48ff3089e7c17fb1d4c59a919769314af224"}, - {file = "pyrsistent-0.20.0-cp311-cp311-win32.whl", hash = "sha256:7d29c23bdf6e5438c755b941cef867ec2a4a172ceb9f50553b6ed70d50dfd656"}, - {file = "pyrsistent-0.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:59a89bccd615551391f3237e00006a26bcf98a4d18623a19909a2c48b8e986ee"}, - {file = "pyrsistent-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:09848306523a3aba463c4b49493a760e7a6ca52e4826aa100ee99d8d39b7ad1e"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a14798c3005ec892bbada26485c2eea3b54109cb2533713e355c806891f63c5e"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b14decb628fac50db5e02ee5a35a9c0772d20277824cfe845c8a8b717c15daa3"}, - {file = "pyrsistent-0.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e2c116cc804d9b09ce9814d17df5edf1df0c624aba3b43bc1ad90411487036d"}, - {file = "pyrsistent-0.20.0-cp312-cp312-win32.whl", hash = "sha256:e78d0c7c1e99a4a45c99143900ea0546025e41bb59ebc10182e947cf1ece9174"}, - {file = "pyrsistent-0.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:4021a7f963d88ccd15b523787d18ed5e5269ce57aa4037146a2377ff607ae87d"}, - {file = "pyrsistent-0.20.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:79ed12ba79935adaac1664fd7e0e585a22caa539dfc9b7c7c6d5ebf91fb89054"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f920385a11207dc372a028b3f1e1038bb244b3ec38d448e6d8e43c6b3ba20e98"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f5c2d012671b7391803263419e31b5c7c21e7c95c8760d7fc35602353dee714"}, - {file = "pyrsistent-0.20.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3992833fbd686ee783590639f4b8343a57f1f75de8633749d984dc0eb16c86"}, - {file = "pyrsistent-0.20.0-cp38-cp38-win32.whl", hash = "sha256:881bbea27bbd32d37eb24dd320a5e745a2a5b092a17f6debc1349252fac85423"}, - {file = "pyrsistent-0.20.0-cp38-cp38-win_amd64.whl", hash = "sha256:6d270ec9dd33cdb13f4d62c95c1a5a50e6b7cdd86302b494217137f760495b9d"}, - {file = "pyrsistent-0.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ca52d1ceae015859d16aded12584c59eb3825f7b50c6cfd621d4231a6cc624ce"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b318ca24db0f0518630e8b6f3831e9cba78f099ed5c1d65ffe3e023003043ba0"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed2c3216a605dc9a6ea50c7e84c82906e3684c4e80d2908208f662a6cbf9022"}, - {file = "pyrsistent-0.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e14c95c16211d166f59c6611533d0dacce2e25de0f76e4c140fde250997b3ca"}, - {file = "pyrsistent-0.20.0-cp39-cp39-win32.whl", hash = "sha256:f058a615031eea4ef94ead6456f5ec2026c19fb5bd6bfe86e9665c4158cf802f"}, - {file = "pyrsistent-0.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:58b8f6366e152092194ae68fefe18b9f0b4f89227dfd86a07770c3d86097aebf"}, - {file = "pyrsistent-0.20.0-py3-none-any.whl", hash = "sha256:c55acc4733aad6560a7f5f818466631f07efc001fd023f34a6c203f8b6df0f0b"}, - {file = "pyrsistent-0.20.0.tar.gz", hash = "sha256:4c48f78f62ab596c679086084d0dd13254ae4f3d6c72a83ffdf5ebdef8f265a4"}, -] - [[package]] name = "pytest" -version = "6.2.5" +version = "8.3.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, + {file = "pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c"}, + {file = "pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6"}, ] [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -toml = "*" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "python-dotenv" -version = "1.0.0" +version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.8" files = [ - {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"}, - {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"}, + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] [package.extras] @@ -1322,13 +1320,13 @@ cli = ["click (>=5.0)"] [[package]] name = "pytz" -version = "2023.3.post1" +version = "2024.1" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, + {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] [[package]] @@ -1343,6 +1341,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1350,8 +1349,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1368,6 +1375,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1375,20 +1383,36 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1402,21 +1426,113 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "setuptools" -version = "69.0.3" -description = "Easily download, build, install, upgrade, and uninstall Python packages" +name = "rpds-py" +version = "0.19.0" +description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:fb37bd599f031f1a6fb9e58ec62864ccf3ad549cf14bac527dbfa97123edcca4"}, + {file = "rpds_py-0.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3384d278df99ec2c6acf701d067147320b864ef6727405d6470838476e44d9e8"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e54548e0be3ac117595408fd4ca0ac9278fde89829b0b518be92863b17ff67a2"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8eb488ef928cdbc05a27245e52de73c0d7c72a34240ef4d9893fdf65a8c1a955"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5da93debdfe27b2bfc69eefb592e1831d957b9535e0943a0ee8b97996de21b5"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79e205c70afddd41f6ee79a8656aec738492a550247a7af697d5bd1aee14f766"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:959179efb3e4a27610e8d54d667c02a9feaa86bbabaf63efa7faa4dfa780d4f1"}, + {file = "rpds_py-0.19.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a6e605bb9edcf010f54f8b6a590dd23a4b40a8cb141255eec2a03db249bc915b"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9133d75dc119a61d1a0ded38fb9ba40a00ef41697cc07adb6ae098c875195a3f"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd36b712d35e757e28bf2f40a71e8f8a2d43c8b026d881aa0c617b450d6865c9"}, + {file = "rpds_py-0.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:354f3a91718489912f2e0fc331c24eaaf6a4565c080e00fbedb6015857c00582"}, + {file = "rpds_py-0.19.0-cp310-none-win32.whl", hash = "sha256:ebcbf356bf5c51afc3290e491d3722b26aaf5b6af3c1c7f6a1b757828a46e336"}, + {file = "rpds_py-0.19.0-cp310-none-win_amd64.whl", hash = "sha256:75a6076289b2df6c8ecb9d13ff79ae0cad1d5fb40af377a5021016d58cd691ec"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6d45080095e585f8c5097897313def60caa2046da202cdb17a01f147fb263b81"}, + {file = "rpds_py-0.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5c9581019c96f865483d031691a5ff1cc455feb4d84fc6920a5ffc48a794d8a"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1540d807364c84516417115c38f0119dfec5ea5c0dd9a25332dea60b1d26fc4d"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e65489222b410f79711dc3d2d5003d2757e30874096b2008d50329ea4d0f88c"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9da6f400eeb8c36f72ef6646ea530d6d175a4f77ff2ed8dfd6352842274c1d8b"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37f46bb11858717e0efa7893c0f7055c43b44c103e40e69442db5061cb26ed34"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:071d4adc734de562bd11d43bd134330fb6249769b2f66b9310dab7460f4bf714"}, + {file = "rpds_py-0.19.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9625367c8955e4319049113ea4f8fee0c6c1145192d57946c6ffcd8fe8bf48dd"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e19509145275d46bc4d1e16af0b57a12d227c8253655a46bbd5ec317e941279d"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d438e4c020d8c39961deaf58f6913b1bf8832d9b6f62ec35bd93e97807e9cbc"}, + {file = "rpds_py-0.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90bf55d9d139e5d127193170f38c584ed3c79e16638890d2e36f23aa1630b952"}, + {file = "rpds_py-0.19.0-cp311-none-win32.whl", hash = "sha256:8d6ad132b1bc13d05ffe5b85e7a01a3998bf3a6302ba594b28d61b8c2cf13aaf"}, + {file = "rpds_py-0.19.0-cp311-none-win_amd64.whl", hash = "sha256:7ec72df7354e6b7f6eb2a17fa6901350018c3a9ad78e48d7b2b54d0412539a67"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5095a7c838a8647c32aa37c3a460d2c48debff7fc26e1136aee60100a8cd8f68"}, + {file = "rpds_py-0.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f2f78ef14077e08856e788fa482107aa602636c16c25bdf59c22ea525a785e9"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7cc6cb44f8636fbf4a934ca72f3e786ba3c9f9ba4f4d74611e7da80684e48d2"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf902878b4af334a09de7a45badbff0389e7cf8dc2e4dcf5f07125d0b7c2656d"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:688aa6b8aa724db1596514751ffb767766e02e5c4a87486ab36b8e1ebc1aedac"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57dbc9167d48e355e2569346b5aa4077f29bf86389c924df25c0a8b9124461fb"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4cf5a9497874822341c2ebe0d5850fed392034caadc0bad134ab6822c0925b"}, + {file = "rpds_py-0.19.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a790d235b9d39c70a466200d506bb33a98e2ee374a9b4eec7a8ac64c2c261fa"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d16089dfa58719c98a1c06f2daceba6d8e3fb9b5d7931af4a990a3c486241cb"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bc9128e74fe94650367fe23f37074f121b9f796cabbd2f928f13e9661837296d"}, + {file = "rpds_py-0.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c8f77e661ffd96ff104bebf7d0f3255b02aa5d5b28326f5408d6284c4a8b3248"}, + {file = "rpds_py-0.19.0-cp312-none-win32.whl", hash = "sha256:5f83689a38e76969327e9b682be5521d87a0c9e5a2e187d2bc6be4765f0d4600"}, + {file = "rpds_py-0.19.0-cp312-none-win_amd64.whl", hash = "sha256:06925c50f86da0596b9c3c64c3837b2481337b83ef3519e5db2701df695453a4"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:52e466bea6f8f3a44b1234570244b1cff45150f59a4acae3fcc5fd700c2993ca"}, + {file = "rpds_py-0.19.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e21cc693045fda7f745c790cb687958161ce172ffe3c5719ca1764e752237d16"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b31f059878eb1f5da8b2fd82480cc18bed8dcd7fb8fe68370e2e6285fa86da6"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1dd46f309e953927dd018567d6a9e2fb84783963650171f6c5fe7e5c41fd5666"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34a01a4490e170376cd79258b7f755fa13b1a6c3667e872c8e35051ae857a92b"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcf426a8c38eb57f7bf28932e68425ba86def6e756a5b8cb4731d8e62e4e0223"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68eea5df6347d3f1378ce992d86b2af16ad7ff4dcb4a19ccdc23dea901b87fb"}, + {file = "rpds_py-0.19.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dab8d921b55a28287733263c0e4c7db11b3ee22aee158a4de09f13c93283c62d"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6fe87efd7f47266dfc42fe76dae89060038f1d9cb911f89ae7e5084148d1cc08"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:535d4b52524a961d220875688159277f0e9eeeda0ac45e766092bfb54437543f"}, + {file = "rpds_py-0.19.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:8b1a94b8afc154fbe36978a511a1f155f9bd97664e4f1f7a374d72e180ceb0ae"}, + {file = "rpds_py-0.19.0-cp38-none-win32.whl", hash = "sha256:7c98298a15d6b90c8f6e3caa6457f4f022423caa5fa1a1ca7a5e9e512bdb77a4"}, + {file = "rpds_py-0.19.0-cp38-none-win_amd64.whl", hash = "sha256:b0da31853ab6e58a11db3205729133ce0df26e6804e93079dee095be3d681dc1"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:5039e3cef7b3e7a060de468a4a60a60a1f31786da94c6cb054e7a3c75906111c"}, + {file = "rpds_py-0.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab1932ca6cb8c7499a4d87cb21ccc0d3326f172cfb6a64021a889b591bb3045c"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2afd2164a1e85226fcb6a1da77a5c8896c18bfe08e82e8ceced5181c42d2179"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1c30841f5040de47a0046c243fc1b44ddc87d1b12435a43b8edff7e7cb1e0d0"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f757f359f30ec7dcebca662a6bd46d1098f8b9fb1fcd661a9e13f2e8ce343ba1"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15e65395a59d2e0e96caf8ee5389ffb4604e980479c32742936ddd7ade914b22"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb0f6eb3a320f24b94d177e62f4074ff438f2ad9d27e75a46221904ef21a7b05"}, + {file = "rpds_py-0.19.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b228e693a2559888790936e20f5f88b6e9f8162c681830eda303bad7517b4d5a"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2575efaa5d949c9f4e2cdbe7d805d02122c16065bfb8d95c129372d65a291a0b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5c872814b77a4e84afa293a1bee08c14daed1068b2bb1cc312edbf020bbbca2b"}, + {file = "rpds_py-0.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850720e1b383df199b8433a20e02b25b72f0fded28bc03c5bd79e2ce7ef050be"}, + {file = "rpds_py-0.19.0-cp39-none-win32.whl", hash = "sha256:ce84a7efa5af9f54c0aa7692c45861c1667080814286cacb9958c07fc50294fb"}, + {file = "rpds_py-0.19.0-cp39-none-win_amd64.whl", hash = "sha256:1c26da90b8d06227d7769f34915913911222d24ce08c0ab2d60b354e2d9c7aff"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:75969cf900d7be665ccb1622a9aba225cf386bbc9c3bcfeeab9f62b5048f4a07"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8445f23f13339da640d1be8e44e5baf4af97e396882ebbf1692aecd67f67c479"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5a7c1062ef8aea3eda149f08120f10795835fc1c8bc6ad948fb9652a113ca55"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:462b0c18fbb48fdbf980914a02ee38c423a25fcc4cf40f66bacc95a2d2d73bc8"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3208f9aea18991ac7f2b39721e947bbd752a1abbe79ad90d9b6a84a74d44409b"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3444fe52b82f122d8a99bf66777aed6b858d392b12f4c317da19f8234db4533"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb4bac7185a9f0168d38c01d7a00addece9822a52870eee26b8d5b61409213"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6b130bd4163c93798a6b9bb96be64a7c43e1cec81126ffa7ffaa106e1fc5cef5"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a707b158b4410aefb6b054715545bbb21aaa5d5d0080217290131c49c2124a6e"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:dc9ac4659456bde7c567107556ab065801622396b435a3ff213daef27b495388"}, + {file = "rpds_py-0.19.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:81ea573aa46d3b6b3d890cd3c0ad82105985e6058a4baed03cf92518081eec8c"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f148c3f47f7f29a79c38cc5d020edcb5ca780020fab94dbc21f9af95c463581"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0906357f90784a66e89ae3eadc2654f36c580a7d65cf63e6a616e4aec3a81be"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f629ecc2db6a4736b5ba95a8347b0089240d69ad14ac364f557d52ad68cf94b0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6feacd1d178c30e5bc37184526e56740342fd2aa6371a28367bad7908d454fc"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae8b6068ee374fdfab63689be0963333aa83b0815ead5d8648389a8ded593378"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d57546bad81e0da13263e4c9ce30e96dcbe720dbff5ada08d2600a3502e526"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b6683a37338818646af718c9ca2a07f89787551057fae57c4ec0446dc6224b"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e8481b946792415adc07410420d6fc65a352b45d347b78fec45d8f8f0d7496f0"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bec35eb20792ea64c3c57891bc3ca0bedb2884fbac2c8249d9b731447ecde4fa"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:aa5476c3e3a402c37779e95f7b4048db2cb5b0ed0b9d006983965e93f40fe05a"}, + {file = "rpds_py-0.19.0-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:19d02c45f2507b489fd4df7b827940f1420480b3e2e471e952af4d44a1ea8e34"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3e2fd14c5d49ee1da322672375963f19f32b3d5953f0615b175ff7b9d38daed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:93a91c2640645303e874eada51f4f33351b84b351a689d470f8108d0e0694210"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b9fc03bf76a94065299d4a2ecd8dfbae4ae8e2e8098bbfa6ab6413ca267709"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5a4b07cdf3f84310c08c1de2c12ddadbb7a77568bcb16e95489f9c81074322ed"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba0ed0dc6763d8bd6e5de5cf0d746d28e706a10b615ea382ac0ab17bb7388633"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:474bc83233abdcf2124ed3f66230a1c8435896046caa4b0b5ab6013c640803cc"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:329c719d31362355a96b435f4653e3b4b061fcc9eba9f91dd40804ca637d914e"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef9101f3f7b59043a34f1dccbb385ca760467590951952d6701df0da9893ca0c"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:0121803b0f424ee2109d6e1f27db45b166ebaa4b32ff47d6aa225642636cd834"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8344127403dea42f5970adccf6c5957a71a47f522171fafaf4c6ddb41b61703a"}, + {file = "rpds_py-0.19.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:443cec402ddd650bb2b885113e1dcedb22b1175c6be223b14246a714b61cd521"}, + {file = "rpds_py-0.19.0.tar.gz", hash = "sha256:4fdc9afadbeb393b4bbbad75481e0ea78e4469f2e1d713a90811700830b553a9"}, ] -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "six" version = "1.16.0" @@ -1441,68 +1557,69 @@ files = [ [[package]] name = "sphinx" -version = "6.2.1" +version = "7.4.7" description = "Python documentation generator" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "Sphinx-6.2.1.tar.gz", hash = "sha256:6d56a34697bb749ffa0152feafc4b19836c755d90a7c59b72bc7dfd371b9cc6b"}, - {file = "sphinx-6.2.1-py3-none-any.whl", hash = "sha256:97787ff1fa3256a3eef9eda523a63dbf299f7b47e053cfcf684a1c2a8380c912"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.20" +alabaster = ">=0.7.14,<0.8.0" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.13" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" +sphinxcontrib-serializinghtml = ">=1.1.9" +tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-click" -version = "4.4.0" +version = "6.0.0" description = "Sphinx extension that automatically documents click applications" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "sphinx-click-4.4.0.tar.gz", hash = "sha256:cc67692bd28f482c7f01531c61b64e9d2f069bfcf3d24cbbb51d4a84a749fa48"}, - {file = "sphinx_click-4.4.0-py3-none-any.whl", hash = "sha256:2821c10a68fc9ee6ce7c92fad26540d8d8c8f45e6d7258f0e4fb7529ae8fab49"}, + {file = "sphinx_click-6.0.0-py3-none-any.whl", hash = "sha256:1e0a3c83bcb7c55497751b19d07ebe56b5d7b85eb76dd399cf9061b497adc317"}, + {file = "sphinx_click-6.0.0.tar.gz", hash = "sha256:f5d664321dc0c6622ff019f1e1c84e58ce0cecfddeb510e004cf60c2a3ab465b"}, ] [package.dependencies] -click = ">=7.0" +click = ">=8.0" docutils = "*" -sphinx = ">=2.0" +sphinx = ">=4.0" [[package]] name = "sphinx-rtd-theme" -version = "1.3.0" +version = "2.0.0" description = "Read the Docs theme for Sphinx" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.6" files = [ - {file = "sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0"}, - {file = "sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931"}, + {file = "sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586"}, + {file = "sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b"}, ] [package.dependencies] -docutils = "<0.19" -sphinx = ">=1.6,<8" +docutils = "<0.21" +sphinx = ">=5,<8" sphinxcontrib-jquery = ">=4,<5" [package.extras] @@ -1510,56 +1627,50 @@ dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.7" +version = "1.0.8" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, - {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, + {file = "sphinxcontrib_applehelp-1.0.8-py3-none-any.whl", hash = "sha256:cb61eb0ec1b61f349e5cc36b2028e9e7ca765be05e49641c97241274753067b4"}, + {file = "sphinxcontrib_applehelp-1.0.8.tar.gz", hash = "sha256:c40a4f96f3776c4393d933412053962fac2b84f4c99a7982ba42e09576a70619"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.5" +version = "1.0.6" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, - {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, + {file = "sphinxcontrib_devhelp-1.0.6-py3-none-any.whl", hash = "sha256:6485d09629944511c893fa11355bda18b742b83a2b181f9a009f7e500595c90f"}, + {file = "sphinxcontrib_devhelp-1.0.6.tar.gz", hash = "sha256:9893fd3f90506bc4b97bdb977ceb8fbd823989f4316b28c3841ec128544372d3"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.4" +version = "2.0.6" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, - {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, + {file = "sphinxcontrib_htmlhelp-2.0.6-py3-none-any.whl", hash = "sha256:1b9af5a2671a61410a868fce050cab7ca393c218e6205cbc7f590136f207395c"}, + {file = "sphinxcontrib_htmlhelp-2.0.6.tar.gz", hash = "sha256:c6597da06185f0e3b4dc952777a04200611ef563882e0c244d27a15ee22afa73"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -1592,21 +1703,19 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.6" +version = "1.0.8" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, - {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, + {file = "sphinxcontrib_qthelp-1.0.8-py3-none-any.whl", hash = "sha256:323d6acc4189af76dfe94edd2a27d458902319b60fcca2aeef3b2180c106a75f"}, + {file = "sphinxcontrib_qthelp-1.0.8.tar.gz", hash = "sha256:db3f8fa10789c7a8e76d173c23364bdf0ebcd9449969a9e6a3dd31b8b7469f03"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-redoc" @@ -1627,91 +1736,107 @@ sphinx = ">=1.5" [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.9" +version = "1.1.10" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" files = [ - {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, - {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, + {file = "sphinxcontrib_serializinghtml-1.1.10-py3-none-any.whl", hash = "sha256:326369b8df80a7d2d8d7f99aa5ac577f51ea51556ed974e7716cfd4fca3f6cb7"}, + {file = "sphinxcontrib_serializinghtml-1.1.10.tar.gz", hash = "sha256:93f3f5dc458b91b192fe10c397e324f262cf163d79f3282c158e8436a2c4511f"}, ] -[package.dependencies] -Sphinx = ">=5" - [package.extras] lint = ["docutils-stubs", "flake8", "mypy"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sqlalchemy" -version = "1.4.51" +version = "2.0.31" description = "Database Abstraction Library" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad"}, - {file = "SQLAlchemy-1.4.51.tar.gz", hash = "sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9"}, +python-versions = ">=3.7" +files = [ + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f2a213c1b699d3f5768a7272de720387ae0122f1becf0901ed6eaa1abd1baf6c"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9fea3d0884e82d1e33226935dac990b967bef21315cbcc894605db3441347443"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3ad7f221d8a69d32d197e5968d798217a4feebe30144986af71ada8c548e9fa"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2bee229715b6366f86a95d497c347c22ddffa2c7c96143b59a2aa5cc9eebbc"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cd5b94d4819c0c89280b7c6109c7b788a576084bf0a480ae17c227b0bc41e109"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:750900a471d39a7eeba57580b11983030517a1f512c2cb287d5ad0fcf3aebd58"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win32.whl", hash = "sha256:7bd112be780928c7f493c1a192cd8c5fc2a2a7b52b790bc5a84203fb4381c6be"}, + {file = "SQLAlchemy-2.0.31-cp310-cp310-win_amd64.whl", hash = "sha256:5a48ac4d359f058474fadc2115f78a5cdac9988d4f99eae44917f36aa1476327"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f68470edd70c3ac3b6cd5c2a22a8daf18415203ca1b036aaeb9b0fb6f54e8298"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e2c38c2a4c5c634fe6c3c58a789712719fa1bf9b9d6ff5ebfce9a9e5b89c1ca"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd15026f77420eb2b324dcb93551ad9c5f22fab2c150c286ef1dc1160f110203"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2196208432deebdfe3b22185d46b08f00ac9d7b01284e168c212919891289396"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:352b2770097f41bff6029b280c0e03b217c2dcaddc40726f8f53ed58d8a85da4"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56d51ae825d20d604583f82c9527d285e9e6d14f9a5516463d9705dab20c3740"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win32.whl", hash = "sha256:6e2622844551945db81c26a02f27d94145b561f9d4b0c39ce7bfd2fda5776dac"}, + {file = "SQLAlchemy-2.0.31-cp311-cp311-win_amd64.whl", hash = "sha256:ccaf1b0c90435b6e430f5dd30a5aede4764942a695552eb3a4ab74ed63c5b8d3"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3b74570d99126992d4b0f91fb87c586a574a5872651185de8297c6f90055ae42"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f77c4f042ad493cb8595e2f503c7a4fe44cd7bd59c7582fd6d78d7e7b8ec52c"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1591329333daf94467e699e11015d9c944f44c94d2091f4ac493ced0119449"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74afabeeff415e35525bf7a4ecdab015f00e06456166a2eba7590e49f8db940e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b9c01990d9015df2c6f818aa8f4297d42ee71c9502026bb074e713d496e26b67"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:66f63278db425838b3c2b1c596654b31939427016ba030e951b292e32b99553e"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win32.whl", hash = "sha256:0b0f658414ee4e4b8cbcd4a9bb0fd743c5eeb81fc858ca517217a8013d282c96"}, + {file = "SQLAlchemy-2.0.31-cp312-cp312-win_amd64.whl", hash = "sha256:fa4b1af3e619b5b0b435e333f3967612db06351217c58bfb50cee5f003db2a5a"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f43e93057cf52a227eda401251c72b6fbe4756f35fa6bfebb5d73b86881e59b0"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d337bf94052856d1b330d5fcad44582a30c532a2463776e1651bd3294ee7e58b"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c06fb43a51ccdff3b4006aafee9fcf15f63f23c580675f7734245ceb6b6a9e05"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:b6e22630e89f0e8c12332b2b4c282cb01cf4da0d26795b7eae16702a608e7ca1"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:79a40771363c5e9f3a77f0e28b3302801db08040928146e6808b5b7a40749c88"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win32.whl", hash = "sha256:501ff052229cb79dd4c49c402f6cb03b5a40ae4771efc8bb2bfac9f6c3d3508f"}, + {file = "SQLAlchemy-2.0.31-cp37-cp37m-win_amd64.whl", hash = "sha256:597fec37c382a5442ffd471f66ce12d07d91b281fd474289356b1a0041bdf31d"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dc6d69f8829712a4fd799d2ac8d79bdeff651c2301b081fd5d3fe697bd5b4ab9"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:23b9fbb2f5dd9e630db70fbe47d963c7779e9c81830869bd7d137c2dc1ad05fb"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a21c97efcbb9f255d5c12a96ae14da873233597dfd00a3a0c4ce5b3e5e79704"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a6a9837589c42b16693cf7bf836f5d42218f44d198f9343dd71d3164ceeeac"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc251477eae03c20fae8db9c1c23ea2ebc47331bcd73927cdcaecd02af98d3c3"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2fd17e3bb8058359fa61248c52c7b09a97cf3c820e54207a50af529876451808"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win32.whl", hash = "sha256:c76c81c52e1e08f12f4b6a07af2b96b9b15ea67ccdd40ae17019f1c373faa227"}, + {file = "SQLAlchemy-2.0.31-cp38-cp38-win_amd64.whl", hash = "sha256:4b600e9a212ed59355813becbcf282cfda5c93678e15c25a0ef896b354423238"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b6cf796d9fcc9b37011d3f9936189b3c8074a02a4ed0c0fbbc126772c31a6d4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78fe11dbe37d92667c2c6e74379f75746dc947ee505555a0197cfba9a6d4f1a4"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc47dc6185a83c8100b37acda27658fe4dbd33b7d5e7324111f6521008ab4fe"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a41514c1a779e2aa9a19f67aaadeb5cbddf0b2b508843fcd7bafdf4c6864005"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:afb6dde6c11ea4525318e279cd93c8734b795ac8bb5dda0eedd9ebaca7fa23f1"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3f9faef422cfbb8fd53716cd14ba95e2ef655400235c3dfad1b5f467ba179c8c"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win32.whl", hash = "sha256:fc6b14e8602f59c6ba893980bea96571dd0ed83d8ebb9c4479d9ed5425d562e9"}, + {file = "SQLAlchemy-2.0.31-cp39-cp39-win_amd64.whl", hash = "sha256:3cb8a66b167b033ec72c3812ffc8441d4e9f5f78f5e31e54dcd4c90a4ca5bebc"}, + {file = "SQLAlchemy-2.0.31-py3-none-any.whl", hash = "sha256:69f3e3c08867a8e4856e92d7afb618b95cdee18e0bc1647b77599722c9a28911"}, + {file = "SQLAlchemy-2.0.31.tar.gz", hash = "sha256:b607489dd4a54de56984a0c7656247504bd5523d9d0ba799aef59d4add009484"}, ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.13\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} +typing-extensions = ">=4.6.0" [package.extras] aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] +aioodbc = ["aioodbc", "greenlet (!=0.4.17)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] +asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"] +mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"] mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] +mypy = ["mypy (>=0.910)"] +mysql = ["mysqlclient (>=1.4.0)"] mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] +oracle = ["cx_oracle (>=8)"] +oracle-oracledb = ["oracledb (>=1.0.1)"] postgresql = ["psycopg2 (>=2.7)"] postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] +postgresql-pg8000 = ["pg8000 (>=1.29.1)"] +postgresql-psycopg = ["psycopg (>=3.0.7)"] postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] +postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"] +pymysql = ["pymysql"] sqlcipher = ["sqlcipher3_binary"] -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -files = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] - [[package]] name = "tomli" version = "2.0.1" @@ -1725,31 +1850,43 @@ files = [ [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + [[package]] name = "webargs" version = "8.4.0" @@ -1774,13 +1911,13 @@ tests = ["Django (>=2.2.0)", "Flask (>=0.12.5)", "aiohttp (>=3.0.8)", "bottle (> [[package]] name = "werkzeug" -version = "2.3.8" +version = "3.0.1" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.8" files = [ - {file = "werkzeug-2.3.8-py3-none-any.whl", hash = "sha256:bba1f19f8ec89d4d607a3bd62f1904bd2e609472d93cd85e9d4e178f472c3748"}, - {file = "werkzeug-2.3.8.tar.gz", hash = "sha256:554b257c74bbeb7a0d254160a4f8ffe185243f52a52035060b761ca62d977f03"}, + {file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"}, + {file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"}, ] [package.dependencies] @@ -1796,4 +1933,4 @@ pymysql = ["PyMySQL"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "6baf20773f3c4dbe2c313217230660174184a9b5c374197e8934425cfd91deef" +content-hash = "08e5fe91bda8f623c9270a733539d03a582de54b09c2b99ce8401e125c813d85" diff --git a/pyproject.toml b/pyproject.toml index cdd7d31..4feddeb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,36 +8,38 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.10" -flask = { extras = ["dotenv"], version = "^2.0.0" } -invoke = "^2.0.0" -Flask-JWT-Extended = "^4.0.0" -Flask-Cors = "^3.0.10" -Flask-SQLAlchemy = "^2.5.1" -SQLAlchemy = "^1.4.40" -Flask-Migrate = "^3.0.0" -flask-babel = "^2.0.0" -flask-smorest = "^0.39.0" -Flask-Static-Digest = "^0.2.1" -flask-oso = "^0.26.0" +flask = { extras = ["dotenv"], version = "^3.0.0" } +invoke = "^2.2.0" +Flask-JWT-Extended = "^4.6.0" +Flask-Cors = "^4.0.0" +Flask-SQLAlchemy = "^3.1.1" +SQLAlchemy = "^2.0.23" +Flask-Login = "^0.6.3" +Flask-Migrate = "^4.0.5" +flask-babel = "^4.0.0" +flask-smorest = "^0.44.0" +Flask-Static-Digest = "^0.4.1" +oso = "^0.27.3" tomli = "^2.0.0" marshmallow-jsonschema = "^0.13.0" -jsonschema = "3.2.0" -bcrypt = "^3.2.0" -psycopg2 = { version = "^2.9.3", optional = true } -PyMySQL = { version = "^1.0.2", optional = true } +jsonschema = "4.23.0" +bcrypt = "^4.0.0" +werkzeug = "3.0.1" +psycopg2 = { version = "^2.9.9", optional = true } +PyMySQL = { version = "^1.1.1", optional = true } -[tool.poetry.dev-dependencies] -black = "^23.1.0" -flake8 = "^3.9.2" -pytest = "^6.2.4" -flake8-docstrings = "^1.6.0" -flake8-bugbear = "^21.4.3" -Sphinx = "^6.0.0" +[tool.poetry.group.dev.dependencies] +black = "^24.4.2" +flake8 = "^7.1.0" +pytest = "^8.3.1" +flake8-docstrings = "^1.7.0" +flake8-bugbear = "^24.4.26" +Sphinx = "^7.4.7" sphinxcontrib-redoc = "^1.6.0" -sphinx-click = "^4.4.0" -myst-parser = "^2.0.0" -sphinx-rtd-theme = "^1.2.2" -pip-licenses = "^3.5.3" +sphinx-click = "^6.0.0" +myst-parser = "^3.0.1" +sphinx-rtd-theme = "^2.0.0" +pip-licenses = "^4.5.1" [tool.poetry.extras] psycopg2 = ["psycopg2"] From ae9a5359790e57a72127000d293582b158145e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Tue, 23 Jul 2024 16:38:57 +0200 Subject: [PATCH 02/14] Fix using of non timezone aware datetime object for timezone aware db columns The DB column change may require a migration! --- muse_for_anything/api/v1_api/namespace.py | 4 ++-- .../api/v1_api/ontology_objects.py | 4 ++-- .../api/v1_api/ontology_types.py | 4 ++-- muse_for_anything/api/v1_api/taxonomy.py | 4 ++-- .../api/v1_api/taxonomy_items.py | 6 ++--- muse_for_anything/db/models/model_helpers.py | 23 +++++++++++++++---- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/muse_for_anything/api/v1_api/namespace.py b/muse_for_anything/api/v1_api/namespace.py index f5821de..2a69840 100644 --- a/muse_for_anything/api/v1_api/namespace.py +++ b/muse_for_anything/api/v1_api/namespace.py @@ -1,6 +1,6 @@ """Module containing the namespace API endpoints of the v1 API.""" -from datetime import datetime +from datetime import datetime, timezone from http import HTTPStatus from typing import Any, List, Optional @@ -396,7 +396,7 @@ def delete(self, namespace: str): # only actually delete when not already deleted if found_namespace.deleted_on is None: # soft delete namespace - found_namespace.deleted_on = datetime.utcnow() + found_namespace.deleted_on = datetime.now(timezone.utc) DB.session.add(found_namespace) DB.session.commit() diff --git a/muse_for_anything/api/v1_api/ontology_objects.py b/muse_for_anything/api/v1_api/ontology_objects.py index 2f9b60e..04f77bb 100644 --- a/muse_for_anything/api/v1_api/ontology_objects.py +++ b/muse_for_anything/api/v1_api/ontology_objects.py @@ -1,6 +1,6 @@ """Module containing the object API endpoints of the v1 API.""" -from datetime import datetime +from datetime import datetime, timezone from http import HTTPStatus from typing import Any, List, Optional @@ -651,7 +651,7 @@ def delete(self, namespace: str, object_id: str): # only actually delete when not already deleted if found_object.deleted_on is None: # soft delete object - found_object.deleted_on = datetime.utcnow() + found_object.deleted_on = datetime.now(timezone.utc) # TODO soft delete komposition objects (also implement undelete…) DB.session.add(found_object) DB.session.commit() diff --git a/muse_for_anything/api/v1_api/ontology_types.py b/muse_for_anything/api/v1_api/ontology_types.py index ef873e1..ece023f 100644 --- a/muse_for_anything/api/v1_api/ontology_types.py +++ b/muse_for_anything/api/v1_api/ontology_types.py @@ -1,6 +1,6 @@ """Module containing the type API endpoints of the v1 API.""" -from datetime import datetime +from datetime import datetime, timezone from http import HTTPStatus from typing import Any, List, Optional @@ -513,7 +513,7 @@ def delete(self, namespace: str, object_type: str): # only actually delete when not already deleted if found_object_type.deleted_on is None: # soft delete namespace - found_object_type.deleted_on = datetime.utcnow() + found_object_type.deleted_on = datetime.now(timezone.utc) DB.session.add(found_object_type) DB.session.commit() diff --git a/muse_for_anything/api/v1_api/taxonomy.py b/muse_for_anything/api/v1_api/taxonomy.py index efe6042..51f00fe 100644 --- a/muse_for_anything/api/v1_api/taxonomy.py +++ b/muse_for_anything/api/v1_api/taxonomy.py @@ -1,6 +1,6 @@ """Module containing the taxonomy API endpoints of the v1 API.""" -from datetime import datetime +from datetime import datetime, timezone from http import HTTPStatus from typing import Any, List, Optional @@ -498,7 +498,7 @@ def delete(self, namespace: str, taxonomy: str): # only actually delete when not already deleted if found_taxonomy.deleted_on is None: # soft delete namespace - found_taxonomy.deleted_on = datetime.utcnow() + found_taxonomy.deleted_on = datetime.now(timezone.utc) DB.session.add(found_taxonomy) DB.session.commit() diff --git a/muse_for_anything/api/v1_api/taxonomy_items.py b/muse_for_anything/api/v1_api/taxonomy_items.py index dc24257..629b21b 100644 --- a/muse_for_anything/api/v1_api/taxonomy_items.py +++ b/muse_for_anything/api/v1_api/taxonomy_items.py @@ -1,6 +1,6 @@ """Module containing the taxonomy items API endpoints of the v1 API.""" -from datetime import datetime +from datetime import datetime, timezone from http import HTTPStatus from typing import Any, Dict, List, Optional, Sequence, Tuple, cast @@ -423,7 +423,7 @@ def delete(self, namespace: str, taxonomy: str, taxonomy_item: str): # restore # only actually delete when not already deleted if found_taxonomy_item.deleted_on is None: # delete taxonomy item - deleted_timestamp = datetime.utcnow() + deleted_timestamp = datetime.now(timezone.utc) found_taxonomy_item.deleted_on = deleted_timestamp # also delete incoming and outgoing relations to remove them # from relations of existing items @@ -913,7 +913,7 @@ def delete( # only actually delete when not already deleted if found_relation.deleted_on is None: # delete taxonomy item relation - found_relation.deleted_on = datetime.utcnow() + found_relation.deleted_on = datetime.now(timezone.utc) DB.session.add(found_relation) DB.session.commit() diff --git a/muse_for_anything/db/models/model_helpers.py b/muse_for_anything/db/models/model_helpers.py index b8c8cfb..64fe18c 100644 --- a/muse_for_anything/db/models/model_helpers.py +++ b/muse_for_anything/db/models/model_helpers.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Sequence from sqlalchemy import DateTime from sqlalchemy.sql.elements import literal @@ -33,21 +33,29 @@ class IdMixin: class NameDescriptionMixin: """Add a 'name' and 'description' column to the table.""" - name: Mapped[str] = mapped_column(DB.Unicode, nullable=False, index=True, info={"collate": "NOCASE"}) + name: Mapped[str] = mapped_column( + DB.Unicode, nullable=False, index=True, info={"collate": "NOCASE"} + ) description: Mapped[str] = mapped_column(DB.UnicodeText, nullable=True, index=True) class UniqueNameDescriptionMixin: """Add a 'name' (with a unique constraint) and 'description' column to the table.""" - name: Mapped[str] = mapped_column(DB.Unicode, nullable=False, unique=True, index=True, info={"collate": "NOCASE"}) + name: Mapped[str] = mapped_column( + DB.Unicode, nullable=False, unique=True, index=True, info={"collate": "NOCASE"} + ) description: Mapped[str] = mapped_column(DB.UnicodeText, nullable=True, index=True) class CreateDeleteMixin: """Add the columns 'created_on' and 'deleted_on' to track creation and deletion of immutable database entries.""" - created_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow, nullable=False) + created_on: Mapped[datetime] = mapped_column( + DateTime(timezone=True), + default_factory=lambda: datetime.now(timezone.utc), + nullable=False, + ) deleted_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=True) @property @@ -58,7 +66,12 @@ def is_deleted(self) -> bool: class ChangesMixin(CreateDeleteMixin): """Add the columns 'created_on', 'updated_on' and 'deleted_on' to track changes to the database entries.""" - updated_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False) + updated_on: Mapped[datetime] = mapped_column( + DateTime(timezone=True), + default_factory=lambda: datetime.now(timezone.utc), + onupdate=lambda: datetime.now(timezone.utc), + nullable=False, + ) __all__ = list(get_all_classes_of_module(__name__)) From 4ab6fe61123dd4c6767f2d64b864407492e4a1e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Tue, 23 Jul 2024 16:40:54 +0200 Subject: [PATCH 03/14] Format with current black version --- muse_for_anything/api/util.py | 1 + .../api/v1_api/generators/namespace.py | 4 +- .../api/v1_api/generators/object.py | 4 +- .../api/v1_api/generators/object_version.py | 8 +- .../api/v1_api/generators/taxonomy.py | 4 +- .../api/v1_api/generators/taxonomy_item.py | 4 +- .../generators/taxonomy_item_relation.py | 4 +- .../generators/taxonomy_item_version.py | 4 +- .../api/v1_api/generators/user_management.py | 8 +- .../api/v1_api/models/ontology.py | 32 ++++++-- .../api/v1_api/ontology_object_validation.py | 12 +-- .../api/v1_api/ontology_type_validation.py | 12 +-- .../api/v1_api/request_helpers.py | 4 +- muse_for_anything/api/v1_api/root.py | 9 ++- muse_for_anything/api/v1_api/schema.py | 10 +-- muse_for_anything/db/__init__.py | 6 +- .../db/models/object_relation_tables.py | 42 ++++++++--- .../db/models/ontology_objects.py | 74 ++++++++++++------- muse_for_anything/db/models/taxonomies.py | 30 +++++--- muse_for_anything/oso_helpers.py | 51 +++++++------ muse_for_anything/password_helpers.py | 20 ++--- muse_for_anything/util/config/__init__.py | 1 + muse_for_anything/util/debug_routes/routes.py | 1 - 23 files changed, 218 insertions(+), 127 deletions(-) diff --git a/muse_for_anything/api/util.py b/muse_for_anything/api/util.py index 3f48866..1cb6875 100644 --- a/muse_for_anything/api/util.py +++ b/muse_for_anything/api/util.py @@ -1,4 +1,5 @@ """Module containing utilities for flask smorest APIs.""" + from typing import Any, Dict from flask import url_for from flask_smorest import Blueprint diff --git a/muse_for_anything/api/v1_api/generators/namespace.py b/muse_for_anything/api/v1_api/generators/namespace.py index 643642f..53aec04 100644 --- a/muse_for_anything/api/v1_api/generators/namespace.py +++ b/muse_for_anything/api/v1_api/generators/namespace.py @@ -335,7 +335,9 @@ def generate_api_object( return return NamespaceData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, created_on=resource.created_on, diff --git a/muse_for_anything/api/v1_api/generators/object.py b/muse_for_anything/api/v1_api/generators/object.py index 38e39c3..7507620 100644 --- a/muse_for_anything/api/v1_api/generators/object.py +++ b/muse_for_anything/api/v1_api/generators/object.py @@ -248,7 +248,9 @@ def generate_api_object( return return ObjectData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, created_on=resource.created_on, diff --git a/muse_for_anything/api/v1_api/generators/object_version.py b/muse_for_anything/api/v1_api/generators/object_version.py index 12264d9..dcd0ccf 100644 --- a/muse_for_anything/api/v1_api/generators/object_version.py +++ b/muse_for_anything/api/v1_api/generators/object_version.py @@ -158,9 +158,7 @@ def update_key( return key -class ObjectVersionSelfLinkGenerator( - LinkGenerator, resource_type=OntologyObjectVersion -): +class ObjectVersionSelfLinkGenerator(LinkGenerator, resource_type=OntologyObjectVersion): def generate_link( self, resource: OntologyObjectVersion, @@ -199,7 +197,9 @@ def generate_api_object( return return ObjectData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, created_on=resource.created_on, diff --git a/muse_for_anything/api/v1_api/generators/taxonomy.py b/muse_for_anything/api/v1_api/generators/taxonomy.py index e288f1b..aaad29b 100644 --- a/muse_for_anything/api/v1_api/generators/taxonomy.py +++ b/muse_for_anything/api/v1_api/generators/taxonomy.py @@ -194,7 +194,9 @@ def generate_api_object( return return TaxonomyData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, created_on=resource.created_on, diff --git a/muse_for_anything/api/v1_api/generators/taxonomy_item.py b/muse_for_anything/api/v1_api/generators/taxonomy_item.py index 32535f9..9beeb1b 100644 --- a/muse_for_anything/api/v1_api/generators/taxonomy_item.py +++ b/muse_for_anything/api/v1_api/generators/taxonomy_item.py @@ -447,7 +447,9 @@ def generate_api_object( ] return TaxonomyItemData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, sort_key=resource.sort_key, diff --git a/muse_for_anything/api/v1_api/generators/taxonomy_item_relation.py b/muse_for_anything/api/v1_api/generators/taxonomy_item_relation.py index 39afb20..66d872e 100644 --- a/muse_for_anything/api/v1_api/generators/taxonomy_item_relation.py +++ b/muse_for_anything/api/v1_api/generators/taxonomy_item_relation.py @@ -318,7 +318,9 @@ def generate_api_object( return return TaxonomyItemRelationData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), source_item=LinkGenerator.get_link_of(resource.taxonomy_item_source), target_item=LinkGenerator.get_link_of(resource.taxonomy_item_target), created_on=resource.created_on, diff --git a/muse_for_anything/api/v1_api/generators/taxonomy_item_version.py b/muse_for_anything/api/v1_api/generators/taxonomy_item_version.py index a37c657..f7ddf1b 100644 --- a/muse_for_anything/api/v1_api/generators/taxonomy_item_version.py +++ b/muse_for_anything/api/v1_api/generators/taxonomy_item_version.py @@ -282,7 +282,9 @@ def generate_api_object( ] return TaxonomyItemData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), name=resource.name, description=resource.description, sort_key=resource.sort_key, diff --git a/muse_for_anything/api/v1_api/generators/user_management.py b/muse_for_anything/api/v1_api/generators/user_management.py index 4211c73..98f9ec1 100644 --- a/muse_for_anything/api/v1_api/generators/user_management.py +++ b/muse_for_anything/api/v1_api/generators/user_management.py @@ -253,7 +253,9 @@ def generate_link( return link = LinkGenerator.get_link_of(CollectionResource(UserRole, resource=resource)) link.rel = (CREATE_REL, POST_REL, REQUIRES_FRESH_LOGIN_REL) - link.schema = url_for(SCHEMA_RESOURCE, schema_id=USER_ROLE_POST_SCHEMA, _external=True) + link.schema = url_for( + SCHEMA_RESOURCE, schema_id=USER_ROLE_POST_SCHEMA, _external=True + ) return link @@ -271,7 +273,9 @@ def generate_api_object( return return UserData( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True), + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ), username=resource.username, e_mail=resource.e_mail, ) diff --git a/muse_for_anything/api/v1_api/models/ontology.py b/muse_for_anything/api/v1_api/models/ontology.py index 591c4e6..412b482 100644 --- a/muse_for_anything/api/v1_api/models/ontology.py +++ b/muse_for_anything/api/v1_api/models/ontology.py @@ -48,7 +48,9 @@ class DeletedPageSchemaMixin: deleted = ma.fields.Boolean(required=False, allow_none=True, missing=False) -class NamespacePageParamsSchema(SearchPageSchemaMixin, DeletedPageSchemaMixin, CursorPageArgumentsSchema): +class NamespacePageParamsSchema( + SearchPageSchemaMixin, DeletedPageSchemaMixin, CursorPageArgumentsSchema +): pass @@ -128,11 +130,15 @@ class FileExportData(BaseApiObject): content_type: str = "application/xml" -class ObjectTypePageParamsSchema(CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin): +class ObjectTypePageParamsSchema( + CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin +): pass -class ObjectTypeVersionsPageParamsSchema(CursorPageArgumentsSchema, DeletedPageSchemaMixin): +class ObjectTypeVersionsPageParamsSchema( + CursorPageArgumentsSchema, DeletedPageSchemaMixin +): pass @@ -171,15 +177,21 @@ class ObjectData(BaseApiObject, ChangesDataMixin, NameDescriptionMixin): data: Any -class ObjectsCursorPageArgumentsSchema(CursorPageArgumentsSchema, DeletedPageSchemaMixin, SearchPageSchemaMixin): +class ObjectsCursorPageArgumentsSchema( + CursorPageArgumentsSchema, DeletedPageSchemaMixin, SearchPageSchemaMixin +): type_id = ma.fields.String(data_key="type-id", allow_none=True, load_only=True) -class ObjectVersionsCursorPageArgumentsSchema(CursorPageArgumentsSchema, DeletedPageSchemaMixin): +class ObjectVersionsCursorPageArgumentsSchema( + CursorPageArgumentsSchema, DeletedPageSchemaMixin +): pass -class TaxonomyPageParamsSchema(CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin): +class TaxonomyPageParamsSchema( + CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin +): pass @@ -200,11 +212,15 @@ class TaxonomyData(BaseApiObject, ChangesDataMixin, NameDescriptionMixin): items: Sequence[ApiLink] = tuple() -class TaxonomyItemPageParamsSchema(CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin): +class TaxonomyItemPageParamsSchema( + CursorPageArgumentsSchema, SearchPageSchemaMixin, DeletedPageSchemaMixin +): pass -class TaxonomyItemVersionsPageParamsSchema(CursorPageArgumentsSchema, DeletedPageSchemaMixin): +class TaxonomyItemVersionsPageParamsSchema( + CursorPageArgumentsSchema, DeletedPageSchemaMixin +): pass diff --git a/muse_for_anything/api/v1_api/ontology_object_validation.py b/muse_for_anything/api/v1_api/ontology_object_validation.py index 8e2be3f..2a587e7 100644 --- a/muse_for_anything/api/v1_api/ontology_object_validation.py +++ b/muse_for_anything/api/v1_api/ontology_object_validation.py @@ -62,12 +62,12 @@ def resolve_type_version_schema_url(url_string: str): version: str = params.get("version") if endpoint == "api-v1.TypeVersionView": - found_type_version: Optional[ - OntologyObjectTypeVersion - ] = OntologyObjectTypeVersion.query.filter( - OntologyObjectTypeVersion.version == int(version), - OntologyObjectTypeVersion.object_type_id == int(object_type), - ).first() + found_type_version: Optional[OntologyObjectTypeVersion] = ( + OntologyObjectTypeVersion.query.filter( + OntologyObjectTypeVersion.version == int(version), + OntologyObjectTypeVersion.object_type_id == int(object_type), + ).first() + ) if found_type_version is None: raise DataVisitorException(f"Invalid schema ref! Schema '{url}' not found!") diff --git a/muse_for_anything/api/v1_api/ontology_type_validation.py b/muse_for_anything/api/v1_api/ontology_type_validation.py index 0c6afd0..5b34d21 100644 --- a/muse_for_anything/api/v1_api/ontology_type_validation.py +++ b/muse_for_anything/api/v1_api/ontology_type_validation.py @@ -211,12 +211,12 @@ def extract_type_reference( namespace=namespace, object_type=object_type, version=version ) - found_type_version: Optional[ - OntologyObjectTypeVersion - ] = OntologyObjectTypeVersion.query.filter( - OntologyObjectTypeVersion.version == version_number, - OntologyObjectTypeVersion.object_type_id == object_type_id, - ).first() + found_type_version: Optional[OntologyObjectTypeVersion] = ( + OntologyObjectTypeVersion.query.filter( + OntologyObjectTypeVersion.version == version_number, + OntologyObjectTypeVersion.object_type_id == object_type_id, + ).first() + ) if ( found_type_version is None diff --git a/muse_for_anything/api/v1_api/request_helpers.py b/muse_for_anything/api/v1_api/request_helpers.py index a1bdf68..3c8e83b 100644 --- a/muse_for_anything/api/v1_api/request_helpers.py +++ b/muse_for_anything/api/v1_api/request_helpers.py @@ -293,7 +293,9 @@ def default_generate_api_object( query_params: Optional[Dict[str, str]] = None, ) -> Optional[BaseApiObject]: return BaseApiObject( - self=LinkGenerator.get_link_of(resource, query_params=query_params, ignore_deleted=True) + self=LinkGenerator.get_link_of( + resource, query_params=query_params, ignore_deleted=True + ) ) def generate_api_object( diff --git a/muse_for_anything/api/v1_api/root.py b/muse_for_anything/api/v1_api/root.py index 3177bc7..add3220 100644 --- a/muse_for_anything/api/v1_api/root.py +++ b/muse_for_anything/api/v1_api/root.py @@ -149,7 +149,14 @@ def get(self): rel=("collection", "page"), resource_type="ont-object", key=("namespaceId",), - query_key=("item-count", "cursor", "sort", "type-id", "search", "deleted"), + query_key=( + "item-count", + "cursor", + "sort", + "type-id", + "search", + "deleted", + ), ), KeyedApiLink( href=template_url_for( diff --git a/muse_for_anything/api/v1_api/schema.py b/muse_for_anything/api/v1_api/schema.py index a8f5458..e3c4ef0 100644 --- a/muse_for_anything/api/v1_api/schema.py +++ b/muse_for_anything/api/v1_api/schema.py @@ -313,11 +313,11 @@ def _get_object_type_version(self, schema_id: str) -> OntologyObjectTypeVersion: ) type_version_id = int(schema_id) - found_object_type_version: Optional[ - OntologyObjectTypeVersion - ] = OntologyObjectTypeVersion.query.filter( - OntologyObjectTypeVersion.id == type_version_id - ).first() + found_object_type_version: Optional[OntologyObjectTypeVersion] = ( + OntologyObjectTypeVersion.query.filter( + OntologyObjectTypeVersion.id == type_version_id + ).first() + ) if found_object_type_version is None: abort(HTTPStatus.NOT_FOUND, message=gettext("Schema id not found.")) diff --git a/muse_for_anything/db/__init__.py b/muse_for_anything/db/__init__.py index e997ade..8776d00 100644 --- a/muse_for_anything/db/__init__.py +++ b/muse_for_anything/db/__init__.py @@ -11,9 +11,9 @@ def register_db(app: Flask): """Register the sqlalchemy db and alembic migrations with the flask app.""" if not app.config.get("SQLALCHEMY_DATABASE_URI"): - app.config[ - "SQLALCHEMY_DATABASE_URI" - ] = f"sqlite:///{app.instance_path}/{app.import_name}.db" + app.config["SQLALCHEMY_DATABASE_URI"] = ( + f"sqlite:///{app.instance_path}/{app.import_name}.db" + ) DB.init_app(app) app.logger.info(f'Connected to db "{app.config["SQLALCHEMY_DATABASE_URI"]}".') diff --git a/muse_for_anything/db/models/object_relation_tables.py b/muse_for_anything/db/models/object_relation_tables.py index 7431259..317b099 100644 --- a/muse_for_anything/db/models/object_relation_tables.py +++ b/muse_for_anything/db/models/object_relation_tables.py @@ -30,10 +30,14 @@ class OntologyTypeVersionToTypeVersion(MODEL, IdMixin): __tablename__ = "TypeVersionToTypeVersion" # the type version importing - type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) - + type_version_source_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) + # the imported type version - type_version_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + type_version_target_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) # relationships type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( @@ -62,8 +66,12 @@ class OntologyTypeVersionToType(MODEL, IdMixin): __tablename__ = "TypeVersionToType" - type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) - type_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectType.id"), nullable=False) + type_version_source_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) + type_target_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectType.id"), nullable=False + ) # relationships type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( @@ -92,8 +100,12 @@ class OntologyTypeVersionToTaxonomy(MODEL, IdMixin): __tablename__ = "TypeVersionToTaxonomy" - type_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) - taxonomy_target_id: Mapped[int] = mapped_column(ForeignKey("Taxonomy.id"), nullable=False) + type_version_source_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) + taxonomy_target_id: Mapped[int] = mapped_column( + ForeignKey("Taxonomy.id"), nullable=False + ) # relationships type_version_source: Mapped[OntologyObjectTypeVersion] = relationship( @@ -122,8 +134,12 @@ class OntologyObjectVersionToObject(MODEL, IdMixin): __tablename__ = "ObjectVersionToObject" - object_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) - object_target_id: Mapped[int] = mapped_column(ForeignKey("OntologyObject.id"), nullable=False) + object_version_source_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) + object_target_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObject.id"), nullable=False + ) # relationships object_version_source: Mapped[OntologyObjectVersion] = relationship( @@ -152,8 +168,12 @@ class OntologyObjectVersionToTaxonomyItem(MODEL, IdMixin): __tablename__ = "ObjectVersionToTaxonomyItem" - object_version_source_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectVersion.id"), nullable=False) - taxonomy_item_target_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) + object_version_source_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectVersion.id"), nullable=False + ) + taxonomy_item_target_id: Mapped[int] = mapped_column( + ForeignKey("TaxonomyItem.id"), nullable=False + ) # relationships object_version_source: Mapped[OntologyObjectVersion] = relationship( diff --git a/muse_for_anything/db/models/ontology_objects.py b/muse_for_anything/db/models/ontology_objects.py index b10b751..fab712e 100644 --- a/muse_for_anything/db/models/ontology_objects.py +++ b/muse_for_anything/db/models/ontology_objects.py @@ -24,9 +24,11 @@ class OntologyObjectType(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Type" namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) - current_version_id: Mapped[int] = mapped_column(ForeignKey("TypeVesion.id"), nullable=True) + current_version_id: Mapped[int] = mapped_column( + ForeignKey("TypeVesion.id"), nullable=True + ) is_toplevel_type: Mapped[int] = mapped_column(nullable=False) - + # relationships namespace: Mapped[Namespace] = relationship(innerjoin=True, lazy="selectin") current_version: Mapped["OntologyObjectTypeVersion"] = relationship( @@ -111,7 +113,9 @@ class OntologyObjectTypeVersion(MODEL, IdMixin, CreateDeleteMixin): __tablename__ = "TypeVersion" id: Mapped[int] = mapped_column(primary_key=True) - object_type_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectType.id"), nullable=False) + object_type_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectType.id"), nullable=False + ) version: Mapped[int] = mapped_column(nullable=False) data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @@ -143,11 +147,13 @@ def __table_args__(cls): back_populates="type_version_source", primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTypeVersion.type_version_source_id", ) - imported_by_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = relationship( - lazy="select", - order_by="OntologyTypeVersionToTypeVersion.id", - back_populates="type_version_target", - primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTypeVersion.type_version_target_id", + imported_by_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = ( + relationship( + lazy="select", + order_by="OntologyTypeVersionToTypeVersion.id", + back_populates="type_version_target", + primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTypeVersion.type_version_target_id", + ) ) referenced_types: Mapped[List["rel.OntologyTypeVersionToType"]] = relationship( @@ -157,11 +163,13 @@ def __table_args__(cls): primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToType.type_version_source_id", ) - referenced_taxonomies: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = relationship( - lazy="select", - order_by="OntologyTypeVersionToTaxonomy.id", - back_populates="type_version_source", - primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTaxonomy.type_version_source_id", + referenced_taxonomies: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = ( + relationship( + lazy="select", + order_by="OntologyTypeVersionToTaxonomy.id", + back_populates="type_version_source", + primaryjoin="OntologyObjectTypeVersion.id == OntologyTypeVersionToTaxonomy.type_version_source_id", + ) ) @property @@ -207,8 +215,12 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Object" namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) - object_type_id: Mapped[int] = mapped_column(ForeignKey("OnotologyObjectType.id"), nullable=False) - current_version_id: Mapped[int] = mapped_column(ForeignKey("ObjectVersion.id"), nullable=True) + object_type_id: Mapped[int] = mapped_column( + ForeignKey("OnotologyObjectType.id"), nullable=False + ) + current_version_id: Mapped[int] = mapped_column( + ForeignKey("ObjectVersion.id"), nullable=True + ) # relationships namespace: Mapped[Namespace] = relationship(innerjoin=True, lazy="selectin") @@ -231,11 +243,13 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): primaryjoin="OntologyObject.id == OntologyObjectVersion.object_id", ) - referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = relationship( - lazy="select", - order_by="OntologyObjectVersionToObject.id", - back_populates="object_target", - primaryjoin="OntologyObject.id == OntologyObjectVersionToObject.object_target_id", + referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = ( + relationship( + lazy="select", + order_by="OntologyObjectVersionToObject.id", + back_populates="object_target", + primaryjoin="OntologyObject.id == OntologyObjectVersionToObject.object_target_id", + ) ) @property @@ -285,9 +299,13 @@ class OntologyObjectVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMi __tablename__ = "ObjectVersion" - object_id: Mapped[int] = mapped_column(ForeignKey("OntologyObject.id"), nullable=False) + object_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObject.id"), nullable=False + ) version: Mapped[int] = mapped_column(nullable=False) - object_type_version_id: Mapped[int] = mapped_column(ForeignKey("OntologyObjectTypeVersion.id"), nullable=False) + object_type_version_id: Mapped[int] = mapped_column( + ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ) data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @declared_attr @@ -318,11 +336,13 @@ def __table_args__(cls): primaryjoin="OntologyObjectVersion.id == OntologyObjectVersionToObject.object_version_source_id", ) - referenced_taxonomy_items: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = relationship( - lazy="select", - order_by="OntologyObjectVersionToTaxonomyItem.id", - back_populates="object_version_source", - primaryjoin="OntologyObjectVersion.id == OntologyObjectVersionToTaxonomyItem.object_version_source_id", + referenced_taxonomy_items: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = ( + relationship( + lazy="select", + order_by="OntologyObjectVersionToTaxonomyItem.id", + back_populates="object_version_source", + primaryjoin="OntologyObjectVersion.id == OntologyObjectVersionToTaxonomyItem.object_version_source_id", + ) ) @property diff --git a/muse_for_anything/db/models/taxonomies.py b/muse_for_anything/db/models/taxonomies.py index 4f136d1..8884bdf 100644 --- a/muse_for_anything/db/models/taxonomies.py +++ b/muse_for_anything/db/models/taxonomies.py @@ -81,7 +81,9 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): __tablename__ = "TaxonomyItem" taxonomy_id: Mapped[int] = mapped_column(ForeignKey("Taxonomy.id"), nullable=False) - current_version_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItemVersion.id"), nullable=True) + current_version_id: Mapped[int] = mapped_column( + ForeignKey("TaxonomyItemVersion.id"), nullable=True + ) # relationships taxonomy: Mapped[Taxonomy] = relationship( @@ -127,11 +129,13 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): primaryjoin="and_(TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_target_id, TaxonomyItemRelation.deleted_on == None)", ) - referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = relationship( - lazy="select", - order_by="OntologyObjectVersionToTaxonomyItem.id", - back_populates="taxonomy_item_target", - primaryjoin="TaxonomyItem.id == OntologyObjectVersionToTaxonomyItem.taxonomy_item_target_id", + referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = ( + relationship( + lazy="select", + order_by="OntologyObjectVersionToTaxonomyItem.id", + back_populates="taxonomy_item_target", + primaryjoin="TaxonomyItem.id == OntologyObjectVersionToTaxonomyItem.taxonomy_item_target_id", + ) ) @property @@ -174,10 +178,12 @@ class TaxonomyItemVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMixi __tablename__ = "TaxonomyItemVersion" - taxonomy_item_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) + taxonomy_item_id: Mapped[int] = mapped_column( + ForeignKey("TaxonomyItem.id"), nullable=False + ) version: Mapped[int] = mapped_column(nullable=False) sort_key: Mapped[float] = mapped_column(nullable=True) - + @declared_attr def __table_args__(cls): return ( @@ -224,9 +230,13 @@ class TaxonomyItemRelation(MODEL, IdMixin, CreateDeleteMixin): __tablename__ = "TaxonomyItemRelation" - taxonomy_item_source_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) + taxonomy_item_source_id: Mapped[int] = mapped_column( + ForeignKey("TaxonomyItem.id"), nullable=False + ) - taxonomy_item_target_id: Mapped[int] = mapped_column(ForeignKey("TaxonomyItem.id"), nullable=False) + taxonomy_item_target_id: Mapped[int] = mapped_column( + ForeignKey("TaxonomyItem.id"), nullable=False + ) # relationships taxonomy_item_source: Mapped[TaxonomyItem] = relationship( diff --git a/muse_for_anything/oso_helpers.py b/muse_for_anything/oso_helpers.py index 2cd11fb..679d93c 100644 --- a/muse_for_anything/oso_helpers.py +++ b/muse_for_anything/oso_helpers.py @@ -57,7 +57,7 @@ class OsoResource: arguments: Optional[Dict[str, Any]] = None -class CustomFlaskOso(): +class CustomFlaskOso: _oso: Oso _app: Flask @@ -66,19 +66,19 @@ class CustomFlaskOso(): def __init__(self, oso: Optional[Oso] = None, app: Optional[Flask] = None) -> None: self._app = app self._oso = None - + def unauthorized() -> NoReturn: raise Forbidden("Unauthorized") - + self._unauthorized_action = unauthorized - + self._get_actor = lambda: g.current_user - + if self._app is not None: self.init_app(self._app) if oso is not None: self.set_oso(oso) - + self._allowed_methods = None def set_oso(self, oso: Oso) -> None: @@ -94,7 +94,7 @@ def init_app(self, app: Flask): def teardown(self, exception): pass - + def _provide_oso(self) -> None: top = _app_context() if not hasattr(top, "oso_flask_oso"): @@ -105,30 +105,26 @@ def _clear_old_cache( ): self._allowed_methods = None - def set_get_actor(self, func:Callable[[], Any]) -> None: + def set_get_actor(self, func: Callable[[], Any]) -> None: self._get_actor = func - - def set_unauthorize_action(self, func:Callable[[], Any]) -> None: + + def set_unauthorize_action(self, func: Callable[[], Any]) -> None: self._unauthorized_action = func - - def require_authorization(self, app:Optional[Flask] = None) -> None: + + def require_authorization(self, app: Optional[Flask] = None) -> None: if app is None: app = self._app if app is None: - raise OsoError( - "Cannot require authorization without Flask app object" - ) + raise OsoError("Cannot require authorization without Flask app object") app.after_request(self._require_authorization) - + def perform_route_authorization(self, app: Optional[Flask] = None) -> None: if app is None: app = self._app if app is None: - raise OsoError( - "Cannot perform route authorization without Flask app object" - ) + raise OsoError("Cannot perform route authorization without Flask app object") app.before_request(self.perform_route_authorization) - + def skip_authorization(self, reason: Optional[str] = None) -> None: _authorize_called() @@ -183,21 +179,21 @@ def authorize( resource = request._get_currect_object() if self.oso is None: raise OsoError("Cannot perform authorization without oso instance") - + allowed = self.oso.is_allowed(actor, action, resource) _authorize_called() - + if not allowed: self._unauthorized_action() - + @property def app(self) -> Flask: return self._app or current_app - + @property def oso(self) -> Optional[Oso]: return self._oso - + @property def current_actor(self) -> Any: return self._get_actor() @@ -206,7 +202,7 @@ def _perform_route_authorization(self) -> None: if not request.url_rule: return self.authorize(resource=request) - + def _require_authorization(self, response: Response) -> Response: if not request.url_rule: return Response @@ -273,9 +269,11 @@ def get_allowed_actions( FLASK_OSO = CustomFlaskOso(oso=OSO) + def _authorize_called() -> None: _app_context().oso_flask_authorize_called = True + def _app_context(): top = request_ctx if top is None: @@ -285,6 +283,7 @@ def _app_context(): ) return top + def register_oso(app: Flask): """Register oso to enable access management for this app.""" from .db.models.namespace import Namespace diff --git a/muse_for_anything/password_helpers.py b/muse_for_anything/password_helpers.py index e80f9c8..e56fb78 100644 --- a/muse_for_anything/password_helpers.py +++ b/muse_for_anything/password_helpers.py @@ -447,8 +447,8 @@ def check_current_settings(self) -> bool: end = time_ns() results.append(end - start) - min_time = min(results) / (10 ** 9) - max_time = max(results) / (10 ** 9) + min_time = min(results) / (10**9) + max_time = max(results) / (10**9) if min_time < 0.1: if self._app: @@ -536,12 +536,12 @@ def calibrate(self, echo_results: bool = False) -> Dict[str, Dict[int, List[int] timings.append(end - start) results_bcrypt[rounds] = timings if echo_results: - min_time = min(timings) / (10 ** 9) - max_time = max(timings) / (10 ** 9) + min_time = min(timings) / (10**9) + max_time = max(timings) / (10**9) click.echo( f"Log Rounds {rounds: 4}: Min {min_time:<8.3} s Max {max_time:<8.3} s" ) - if max(timings) > 1 * (10 ** 9): + if max(timings) > 1 * (10**9): break if echo_results: @@ -567,12 +567,12 @@ def calibrate(self, echo_results: bool = False) -> Dict[str, Dict[int, List[int] timings.append(end - start) results_pbkdf2[rounds] = timings if echo_results: - min_time = min(timings) / (10 ** 9) - max_time = max(timings) / (10 ** 9) + min_time = min(timings) / (10**9) + max_time = max(timings) / (10**9) click.echo( f"Rounds {rounds:13_}: Min {min_time:<6.3} s Max {max_time:<6.3} s" ) - if max(timings) > 1 * (10 ** 9): + if max(timings) > 1 * (10**9): break results = { @@ -613,8 +613,8 @@ def generate_calibration_data(): data = FLASK_PASSWORD.calibrate(True) click.echo("\nDetermining good settings from calibration results:\n") - min_threshold_ns = 0.2 * (10 ** 9) - max_threshold_ns = 1.2 * (10 ** 9) + min_threshold_ns = 0.2 * (10**9) + max_threshold_ns = 1.2 * (10**9) for key, name in (("bcrypt", "Bcrypt"), ("pbkdf2", "PBKDF2")): calibration_data = data.get(key) diff --git a/muse_for_anything/util/config/__init__.py b/muse_for_anything/util/config/__init__.py index 02261b2..31fd610 100644 --- a/muse_for_anything/util/config/__init__.py +++ b/muse_for_anything/util/config/__init__.py @@ -1,4 +1,5 @@ """Module containing default config values.""" + from logging import INFO, WARNING from os import urandom diff --git a/muse_for_anything/util/debug_routes/routes.py b/muse_for_anything/util/debug_routes/routes.py index 2618d64..f047ae7 100644 --- a/muse_for_anything/util/debug_routes/routes.py +++ b/muse_for_anything/util/debug_routes/routes.py @@ -4,7 +4,6 @@ from .root import DEBUG_BLP - @DEBUG_BLP.route("/routes") def routes(): """Render all registered routes.""" From 60cff315d0ae8bee015e8d46c4a6ac42fec56747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Tue, 23 Jul 2024 16:50:27 +0200 Subject: [PATCH 04/14] Fix missing import url_parse --- .../api/v1_api/ontology_type_validation.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/muse_for_anything/api/v1_api/ontology_type_validation.py b/muse_for_anything/api/v1_api/ontology_type_validation.py index 5b34d21..65c8f90 100644 --- a/muse_for_anything/api/v1_api/ontology_type_validation.py +++ b/muse_for_anything/api/v1_api/ontology_type_validation.py @@ -1,27 +1,25 @@ """Module containing validation functions for object types.""" from dataclasses import dataclass -from muse_for_anything.db.models.taxonomies import Taxonomy -from flask.globals import request_ctx -from werkzeug.urls import url_parse -from werkzeug.routing import MapAdapter - from http import HTTPStatus - -from muse_for_anything.api.json_schema.schema_tools import SchemaWalker from typing import Any, Callable, Deque, Dict, Optional, Sequence, Set, Tuple -from flask_babel import gettext -from jsonschema import Draft7Validator +from urllib.parse import urlparse +from flask.globals import request_ctx +from flask_babel import gettext from flask_smorest import abort +from jsonschema import Draft7Validator +from werkzeug.routing import MapAdapter +from muse_for_anything.api.json_schema.schema_tools import SchemaWalker from muse_for_anything.db.models.ontology_objects import ( OntologyObjectType, OntologyObjectTypeVersion, ) -from .models.schema import TYPE_SCHEMA -from ..json_schema import DataWalker, DataWalkerVisitor, DataVisitorException +from muse_for_anything.db.models.taxonomies import Taxonomy +from ..json_schema import DataVisitorException, DataWalker, DataWalkerVisitor +from .models.schema import TYPE_SCHEMA SCHEMA_VALIDATOR = Draft7Validator(TYPE_SCHEMA) @@ -150,14 +148,19 @@ def visit(self, data, walker: SchemaWalker) -> None: f"Unknown local schema reference '{ref}'! No schema with matching id!" ) else: - url = url_parse(data["$ref"]) + url = urlparse(data["$ref"]) ctx = request_ctx if ctx is None: raise DataVisitorException( "No request context to check schema url against!" ) - url_adapter: MapAdapter = ctx.url_adapter + url_adapter: Optional[MapAdapter] = ctx.url_adapter + if url_adapter is None: + raise DataVisitorException( + "No url adapter found in request context! Unable to check URL." + f"URL: '{url}'" + ) if url.netloc != url_adapter.get_host(None): raise DataVisitorException( "Only references to schemas on the same MUSE4Anything instance allowed! " From ea869d3b99228df8ffa9893c9a300e91318360cc Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Thu, 25 Jul 2024 12:09:42 +0200 Subject: [PATCH 05/14] Fix url_parse and request_ctx --- .../api/v1_api/ontology_object_validation.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/muse_for_anything/api/v1_api/ontology_object_validation.py b/muse_for_anything/api/v1_api/ontology_object_validation.py index 2a587e7..e4a9dd7 100644 --- a/muse_for_anything/api/v1_api/ontology_object_validation.py +++ b/muse_for_anything/api/v1_api/ontology_object_validation.py @@ -2,9 +2,10 @@ from dataclasses import dataclass +from urllib.parse import urlparse + from muse_for_anything.db.models.taxonomies import TaxonomyItem -from flask.globals import _request_ctx_stack -from werkzeug.urls import url_parse +from flask.globals import request_ctx from werkzeug.routing import MapAdapter from http import HTTPStatus @@ -36,12 +37,17 @@ class ObjectMetadata: def resolve_type_version_schema_url(url_string: str): """Resolver url references without creating any http request by directly querying the database.""" # TODO use url cache - url = url_parse(url_string) + url = urlparse(url_string) # url should already be from a validated type! - ctx = _request_ctx_stack.top + ctx = request_ctx if ctx is None: raise DataVisitorException("No request context to check schema url against!") - url_adapter: MapAdapter = ctx.url_adapter + url_adapter: Optional[MapAdapter] = ctx.url_adapter + if url_adapter is None: + raise DataVisitorException( + "No url adapter found in request context! Unable to check URL." + f"URL: '{url}'" + ) if url.netloc != url_adapter.get_host(None): raise DataVisitorException( "Only references to schemas on the same MUSE4Anything instance allowed! " From f19c5b85dfef03b48b7176ea64b4b8c09cb4399a Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Thu, 25 Jul 2024 12:12:07 +0200 Subject: [PATCH 06/14] Fix locale_selector for Babel --- muse_for_anything/babel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/muse_for_anything/babel.py b/muse_for_anything/babel.py index c85be82..f461f83 100644 --- a/muse_for_anything/babel.py +++ b/muse_for_anything/babel.py @@ -11,7 +11,6 @@ BABEL = Babel() -@BABEL.localeselector def get_locale(): if "lang" in g: # check LanguageAccept option in g context @@ -47,4 +46,4 @@ def inject_lang_from_header(): def register_babel(app: Flask): """Register babel to enable translations for this app.""" - BABEL.init_app(app) + BABEL.init_app(app, locale_selector=get_locale) From 5714d02f4893fb591b7853a598d7593a0ad88d14 Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Thu, 25 Jul 2024 12:26:57 +0200 Subject: [PATCH 07/14] Update SQLAlchemy models --- .../db/models/object_relation_tables.py | 20 ++++++++--------- .../db/models/ontology_objects.py | 22 +++++++++++++------ muse_for_anything/db/models/taxonomies.py | 20 ++++++++++++----- muse_for_anything/db/models/users.py | 4 ++-- 4 files changed, 42 insertions(+), 24 deletions(-) diff --git a/muse_for_anything/db/models/object_relation_tables.py b/muse_for_anything/db/models/object_relation_tables.py index 317b099..74d9f11 100644 --- a/muse_for_anything/db/models/object_relation_tables.py +++ b/muse_for_anything/db/models/object_relation_tables.py @@ -31,12 +31,12 @@ class OntologyTypeVersionToTypeVersion(MODEL, IdMixin): # the type version importing type_version_source_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectTypeVersion.id), nullable=False ) # the imported type version type_version_target_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectTypeVersion.id), nullable=False ) # relationships @@ -67,10 +67,10 @@ class OntologyTypeVersionToType(MODEL, IdMixin): __tablename__ = "TypeVersionToType" type_version_source_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectTypeVersion.id), nullable=False ) type_target_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectType.id"), nullable=False + ForeignKey(OntologyObjectType.id), nullable=False ) # relationships @@ -101,10 +101,10 @@ class OntologyTypeVersionToTaxonomy(MODEL, IdMixin): __tablename__ = "TypeVersionToTaxonomy" type_version_source_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectTypeVersion.id), nullable=False ) taxonomy_target_id: Mapped[int] = mapped_column( - ForeignKey("Taxonomy.id"), nullable=False + ForeignKey(Taxonomy.id), nullable=False ) # relationships @@ -135,10 +135,10 @@ class OntologyObjectVersionToObject(MODEL, IdMixin): __tablename__ = "ObjectVersionToObject" object_version_source_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectVersion.id), nullable=False ) object_target_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObject.id"), nullable=False + ForeignKey(OntologyObject.id), nullable=False ) # relationships @@ -169,10 +169,10 @@ class OntologyObjectVersionToTaxonomyItem(MODEL, IdMixin): __tablename__ = "ObjectVersionToTaxonomyItem" object_version_source_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectVersion.id"), nullable=False + ForeignKey(OntologyObjectVersion.id), nullable=False ) taxonomy_item_target_id: Mapped[int] = mapped_column( - ForeignKey("TaxonomyItem.id"), nullable=False + ForeignKey(TaxonomyItem.id), nullable=False ) # relationships diff --git a/muse_for_anything/db/models/ontology_objects.py b/muse_for_anything/db/models/ontology_objects.py index fab712e..4de603a 100644 --- a/muse_for_anything/db/models/ontology_objects.py +++ b/muse_for_anything/db/models/ontology_objects.py @@ -23,9 +23,9 @@ class OntologyObjectType(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Type" - namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) + namespace_id: Mapped[int] = mapped_column(ForeignKey(Namespace.id), nullable=False) current_version_id: Mapped[int] = mapped_column( - ForeignKey("TypeVesion.id"), nullable=True + ForeignKey("TypeVersion.id"), nullable=True ) is_toplevel_type: Mapped[int] = mapped_column(nullable=False) @@ -50,6 +50,7 @@ class OntologyObjectType(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): ) referenced_by_types: Mapped[List["rel.OntologyTypeVersionToType"]] = relationship( + "OntologyTypeVersionToType", lazy="select", order_by="OntologyTypeVersionToType.id", back_populates="type_target", @@ -114,7 +115,7 @@ class OntologyObjectTypeVersion(MODEL, IdMixin, CreateDeleteMixin): id: Mapped[int] = mapped_column(primary_key=True) object_type_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectType.id"), nullable=False + ForeignKey(OntologyObjectType.id), nullable=False ) version: Mapped[int] = mapped_column(nullable=False) data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @@ -142,6 +143,7 @@ def __table_args__(cls): ) imported_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = relationship( + "OntologyTypeVersionToTypeVersion", lazy="select", order_by="OntologyTypeVersionToTypeVersion.id", back_populates="type_version_source", @@ -149,6 +151,7 @@ def __table_args__(cls): ) imported_by_types: Mapped[List["rel.OntologyTypeVersionToTypeVersion"]] = ( relationship( + "OntologyTypeVersionToTypeVersion", lazy="select", order_by="OntologyTypeVersionToTypeVersion.id", back_populates="type_version_target", @@ -157,6 +160,7 @@ def __table_args__(cls): ) referenced_types: Mapped[List["rel.OntologyTypeVersionToType"]] = relationship( + "OntologyTypeVersionToType", lazy="select", order_by="OntologyTypeVersionToType.id", back_populates="type_version_source", @@ -165,6 +169,7 @@ def __table_args__(cls): referenced_taxonomies: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = ( relationship( + "OntologyTypeVersionToTaxonomy", lazy="select", order_by="OntologyTypeVersionToTaxonomy.id", back_populates="type_version_source", @@ -214,9 +219,9 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Object" - namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) + namespace_id: Mapped[int] = mapped_column(ForeignKey(Namespace.id), nullable=False) object_type_id: Mapped[int] = mapped_column( - ForeignKey("OnotologyObjectType.id"), nullable=False + ForeignKey(OntologyObjectType.id), nullable=False ) current_version_id: Mapped[int] = mapped_column( ForeignKey("ObjectVersion.id"), nullable=True @@ -245,6 +250,7 @@ class OntologyObject(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = ( relationship( + "OntologyObjectVersionToObject", lazy="select", order_by="OntologyObjectVersionToObject.id", back_populates="object_target", @@ -300,11 +306,11 @@ class OntologyObjectVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMi __tablename__ = "ObjectVersion" object_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObject.id"), nullable=False + ForeignKey(OntologyObject.id), nullable=False ) version: Mapped[int] = mapped_column(nullable=False) object_type_version_id: Mapped[int] = mapped_column( - ForeignKey("OntologyObjectTypeVersion.id"), nullable=False + ForeignKey(OntologyObjectTypeVersion.id), nullable=False ) data: Mapped[Text] = mapped_column(DB.JSON, nullable=False) @@ -330,6 +336,7 @@ def __table_args__(cls): ) referenced_objects: Mapped[List["rel.OntologyObjectVersionToObject"]] = relationship( + "OntologyObjectVersionToObject", lazy="select", order_by="OntologyObjectVersionToObject.id", back_populates="object_version_source", @@ -338,6 +345,7 @@ def __table_args__(cls): referenced_taxonomy_items: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = ( relationship( + "OntologyObjectVersionToTaxonomyItem", lazy="select", order_by="OntologyObjectVersionToTaxonomyItem.id", back_populates="object_version_source", diff --git a/muse_for_anything/db/models/taxonomies.py b/muse_for_anything/db/models/taxonomies.py index 8884bdf..29a3539 100644 --- a/muse_for_anything/db/models/taxonomies.py +++ b/muse_for_anything/db/models/taxonomies.py @@ -23,18 +23,20 @@ class Taxonomy(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): __tablename__ = "Taxonomy" - namespace_id: Mapped[int] = mapped_column(ForeignKey("Namespace.id"), nullable=False) + namespace_id: Mapped[int] = mapped_column(ForeignKey(Namespace.id), nullable=False) # relationships namespace = relationship(Namespace, innerjoin=True, lazy="selectin") items: Mapped[List["TaxonomyItem"]] = relationship( + "TaxonomyItem", lazy="select", # do not always load this order_by="TaxonomyItem.id", back_populates="taxonomy", primaryjoin="Taxonomy.id == TaxonomyItem.taxonomy_id", ) current_items: Mapped[List["TaxonomyItem"]] = relationship( + "TaxonomyItem", viewonly=True, # lazy="select", # do not always load this order_by="TaxonomyItem.id", @@ -43,6 +45,7 @@ class Taxonomy(MODEL, IdMixin, NameDescriptionMixin, ChangesMixin): ) referenced_by_types: Mapped[List["rel.OntologyTypeVersionToTaxonomy"]] = relationship( + "OntologyTypeVersionToTaxonomy", lazy="select", order_by="OntologyTypeVersionToTaxonomy.id", back_populates="taxonomy_target", @@ -80,7 +83,7 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): __tablename__ = "TaxonomyItem" - taxonomy_id: Mapped[int] = mapped_column(ForeignKey("Taxonomy.id"), nullable=False) + taxonomy_id: Mapped[int] = mapped_column(ForeignKey(Taxonomy.id), nullable=False) current_version_id: Mapped[int] = mapped_column( ForeignKey("TaxonomyItemVersion.id"), nullable=True ) @@ -93,36 +96,42 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): sync_backref=False, ) current_version: Mapped["TaxonomyItemVersion"] = relationship( + "TaxonomyItemVersion", post_update=True, innerjoin=True, lazy="joined", primaryjoin="TaxonomyItem.current_version_id == TaxonomyItemVersion.id", ) versions: Mapped[List["TaxonomyItemVersion"]] = relationship( + "TaxonomyItemVersion", lazy="select", order_by="TaxonomyItemVersion.version", back_populates="taxonomy_item", primaryjoin="TaxonomyItem.id == TaxonomyItemVersion.taxonomy_item_id", ) related: Mapped[List["TaxonomyItemRelation"]] = relationship( + "TaxonomyItemRelation", lazy="select", order_by="TaxonomyItemRelation.id", back_populates="taxonomy_item_source", primaryjoin="TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_source_id", ) ancestors: Mapped[List["TaxonomyItemRelation"]] = relationship( + "TaxonomyItemRelation", lazy="select", order_by="TaxonomyItemRelation.id", back_populates="taxonomy_item_target", primaryjoin="TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_target_id", ) current_related: Mapped[List["TaxonomyItemRelation"]] = relationship( + "TaxonomyItemRelation", viewonly=True, lazy="selectin", # deals better with multiple levels of hierarchy order_by="TaxonomyItemRelation.id", primaryjoin="and_(TaxonomyItem.id == TaxonomyItemRelation.taxonomy_item_source_id, TaxonomyItemRelation.deleted_on == None)", ) current_ancestors: Mapped[List["TaxonomyItemRelation"]] = relationship( + "TaxonomyItemRelation", viewonly=True, lazy="selectin", # deals better with multiple levels of hierarchy order_by="TaxonomyItemRelation.id", @@ -131,6 +140,7 @@ class TaxonomyItem(MODEL, IdMixin, ChangesMixin): referenced_by_objects: Mapped[List["rel.OntologyObjectVersionToTaxonomyItem"]] = ( relationship( + "OntologyObjectVersionToTaxonomyItem", lazy="select", order_by="OntologyObjectVersionToTaxonomyItem.id", back_populates="taxonomy_item_target", @@ -179,7 +189,7 @@ class TaxonomyItemVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMixi __tablename__ = "TaxonomyItemVersion" taxonomy_item_id: Mapped[int] = mapped_column( - ForeignKey("TaxonomyItem.id"), nullable=False + ForeignKey(TaxonomyItem.id), nullable=False ) version: Mapped[int] = mapped_column(nullable=False) sort_key: Mapped[float] = mapped_column(nullable=True) @@ -231,11 +241,11 @@ class TaxonomyItemRelation(MODEL, IdMixin, CreateDeleteMixin): __tablename__ = "TaxonomyItemRelation" taxonomy_item_source_id: Mapped[int] = mapped_column( - ForeignKey("TaxonomyItem.id"), nullable=False + ForeignKey(TaxonomyItem.id), nullable=False ) taxonomy_item_target_id: Mapped[int] = mapped_column( - ForeignKey("TaxonomyItem.id"), nullable=False + ForeignKey(TaxonomyItem.id), nullable=False ) # relationships diff --git a/muse_for_anything/db/models/users.py b/muse_for_anything/db/models/users.py index cd6297a..d4c7e38 100644 --- a/muse_for_anything/db/models/users.py +++ b/muse_for_anything/db/models/users.py @@ -158,7 +158,7 @@ class UserRole(MODEL, IdMixin): __tablename__ = "UserRole" - user_id: Mapped[int] = mapped_column(ForeignKey("User.id"), nullable=False) + user_id: Mapped[int] = mapped_column(ForeignKey(User.id), nullable=False) role: Mapped[str] = mapped_column(DB.String(64)) # references @@ -247,7 +247,7 @@ class UserGrant(MODEL, IdMixin): __tablename__ = "UserGrant" - user_id: Mapped[int] = mapped_column(ForeignKey("User.id"), nullable=True) + user_id: Mapped[int] = mapped_column(ForeignKey(User.id), nullable=True) role: Mapped[str] = mapped_column(DB.String(64), index=True) resource_type: Mapped[str] = mapped_column(DB.String(64), index=True) resource_id: Mapped[int] = mapped_column(index=True) From 03d91bb353a0ffade7b70006c2a966bd4faef7bf Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Thu, 25 Jul 2024 13:09:49 +0200 Subject: [PATCH 08/14] Fixed default for updated_on and created_on --- muse_for_anything/db/models/model_helpers.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/muse_for_anything/db/models/model_helpers.py b/muse_for_anything/db/models/model_helpers.py index 64fe18c..e66bd66 100644 --- a/muse_for_anything/db/models/model_helpers.py +++ b/muse_for_anything/db/models/model_helpers.py @@ -52,8 +52,8 @@ class CreateDeleteMixin: """Add the columns 'created_on' and 'deleted_on' to track creation and deletion of immutable database entries.""" created_on: Mapped[datetime] = mapped_column( - DateTime(timezone=True), - default_factory=lambda: datetime.now(timezone.utc), + DB.DateTime, + default=lambda: datetime.now(timezone.utc), nullable=False, ) deleted_on: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=True) @@ -67,8 +67,8 @@ class ChangesMixin(CreateDeleteMixin): """Add the columns 'created_on', 'updated_on' and 'deleted_on' to track changes to the database entries.""" updated_on: Mapped[datetime] = mapped_column( - DateTime(timezone=True), - default_factory=lambda: datetime.now(timezone.utc), + DB.DateTime, + default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False, ) From 1f3261122b17ca60056560b477e3026c1b78ee54 Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Fri, 26 Jul 2024 10:18:26 +0200 Subject: [PATCH 09/14] Add timezoned columns again --- muse_for_anything/db/models/model_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/muse_for_anything/db/models/model_helpers.py b/muse_for_anything/db/models/model_helpers.py index e66bd66..a82f542 100644 --- a/muse_for_anything/db/models/model_helpers.py +++ b/muse_for_anything/db/models/model_helpers.py @@ -52,7 +52,7 @@ class CreateDeleteMixin: """Add the columns 'created_on' and 'deleted_on' to track creation and deletion of immutable database entries.""" created_on: Mapped[datetime] = mapped_column( - DB.DateTime, + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False, ) @@ -67,7 +67,7 @@ class ChangesMixin(CreateDeleteMixin): """Add the columns 'created_on', 'updated_on' and 'deleted_on' to track changes to the database entries.""" updated_on: Mapped[datetime] = mapped_column( - DB.DateTime, + DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc), nullable=False, From 05c9538ae419202bf63ae7dc3cc35bc8782ba78f Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Fri, 26 Jul 2024 10:41:00 +0200 Subject: [PATCH 10/14] Format with current black version --- .../api/v1_api/ontology_object_validation.py | 8 ++++---- muse_for_anything/db/models/ontology_objects.py | 4 +--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/muse_for_anything/api/v1_api/ontology_object_validation.py b/muse_for_anything/api/v1_api/ontology_object_validation.py index e4a9dd7..eb09023 100644 --- a/muse_for_anything/api/v1_api/ontology_object_validation.py +++ b/muse_for_anything/api/v1_api/ontology_object_validation.py @@ -44,10 +44,10 @@ def resolve_type_version_schema_url(url_string: str): raise DataVisitorException("No request context to check schema url against!") url_adapter: Optional[MapAdapter] = ctx.url_adapter if url_adapter is None: - raise DataVisitorException( - "No url adapter found in request context! Unable to check URL." - f"URL: '{url}'" - ) + raise DataVisitorException( + "No url adapter found in request context! Unable to check URL." + f"URL: '{url}'" + ) if url.netloc != url_adapter.get_host(None): raise DataVisitorException( "Only references to schemas on the same MUSE4Anything instance allowed! " diff --git a/muse_for_anything/db/models/ontology_objects.py b/muse_for_anything/db/models/ontology_objects.py index 4de603a..bdcfa74 100644 --- a/muse_for_anything/db/models/ontology_objects.py +++ b/muse_for_anything/db/models/ontology_objects.py @@ -305,9 +305,7 @@ class OntologyObjectVersion(MODEL, IdMixin, NameDescriptionMixin, CreateDeleteMi __tablename__ = "ObjectVersion" - object_id: Mapped[int] = mapped_column( - ForeignKey(OntologyObject.id), nullable=False - ) + object_id: Mapped[int] = mapped_column(ForeignKey(OntologyObject.id), nullable=False) version: Mapped[int] = mapped_column(nullable=False) object_type_version_id: Mapped[int] = mapped_column( ForeignKey(OntologyObjectTypeVersion.id), nullable=False From 5b03b6e33447113b40acedc43dd4a0f8f58a8f99 Mon Sep 17 00:00:00 2001 From: Jan Weber Date: Fri, 26 Jul 2024 16:41:56 +0200 Subject: [PATCH 11/14] Add todos for safety check with request context --- muse_for_anything/api/v1_api/ontology_object_validation.py | 1 + muse_for_anything/oso_helpers.py | 1 + 2 files changed, 2 insertions(+) diff --git a/muse_for_anything/api/v1_api/ontology_object_validation.py b/muse_for_anything/api/v1_api/ontology_object_validation.py index eb09023..7c152c5 100644 --- a/muse_for_anything/api/v1_api/ontology_object_validation.py +++ b/muse_for_anything/api/v1_api/ontology_object_validation.py @@ -40,6 +40,7 @@ def resolve_type_version_schema_url(url_string: str): url = urlparse(url_string) # url should already be from a validated type! ctx = request_ctx + # TODO Safety check will probably never trigger if ctx is None: raise DataVisitorException("No request context to check schema url against!") url_adapter: Optional[MapAdapter] = ctx.url_adapter diff --git a/muse_for_anything/oso_helpers.py b/muse_for_anything/oso_helpers.py index 679d93c..891c1fc 100644 --- a/muse_for_anything/oso_helpers.py +++ b/muse_for_anything/oso_helpers.py @@ -276,6 +276,7 @@ def _authorize_called() -> None: def _app_context(): top = request_ctx + # TODO Safety check will probably never trigger if top is None: raise OsoError( "Application context doesn't exist. Did you use oso outside the context of a request? " From 5385ddffb2dc392a5e91f068935097bbd8603df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Fri, 26 Jul 2024 17:06:43 +0200 Subject: [PATCH 12/14] Fix resource_ctx usage and fix typing problems in flask oso --- .../api/v1_api/ontology_object_validation.py | 6 ++-- .../api/v1_api/ontology_type_validation.py | 5 ++-- muse_for_anything/oso_helpers.py | 28 +++++++++++-------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/muse_for_anything/api/v1_api/ontology_object_validation.py b/muse_for_anything/api/v1_api/ontology_object_validation.py index 7c152c5..15950d2 100644 --- a/muse_for_anything/api/v1_api/ontology_object_validation.py +++ b/muse_for_anything/api/v1_api/ontology_object_validation.py @@ -39,9 +39,9 @@ def resolve_type_version_schema_url(url_string: str): # TODO use url cache url = urlparse(url_string) # url should already be from a validated type! - ctx = request_ctx - # TODO Safety check will probably never trigger - if ctx is None: + try: + ctx = request_ctx._get_current_object() + except RuntimeError: raise DataVisitorException("No request context to check schema url against!") url_adapter: Optional[MapAdapter] = ctx.url_adapter if url_adapter is None: diff --git a/muse_for_anything/api/v1_api/ontology_type_validation.py b/muse_for_anything/api/v1_api/ontology_type_validation.py index 65c8f90..8d8a3e8 100644 --- a/muse_for_anything/api/v1_api/ontology_type_validation.py +++ b/muse_for_anything/api/v1_api/ontology_type_validation.py @@ -150,8 +150,9 @@ def visit(self, data, walker: SchemaWalker) -> None: else: url = urlparse(data["$ref"]) - ctx = request_ctx - if ctx is None: + try: + ctx = request_ctx._get_current_object() + except RuntimeError: raise DataVisitorException( "No request context to check schema url against!" ) diff --git a/muse_for_anything/oso_helpers.py b/muse_for_anything/oso_helpers.py index 891c1fc..f83b764 100644 --- a/muse_for_anything/oso_helpers.py +++ b/muse_for_anything/oso_helpers.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from typing import Any, Callable, Dict, NoReturn, Optional, Sequence, Type -from flask import Flask, current_app, g, request +from flask import Flask, current_app from flask.globals import request_ctx, g, request from flask.wrappers import Request, Response from oso import Oso @@ -59,8 +59,8 @@ class OsoResource: class CustomFlaskOso: - _oso: Oso - _app: Flask + _oso: Optional[Oso] + _app: Optional[Flask] _allowed_methods: Optional[Sequence[str]] def __init__(self, oso: Optional[Oso] = None, app: Optional[Flask] = None) -> None: @@ -205,7 +205,7 @@ def _perform_route_authorization(self) -> None: def _require_authorization(self, response: Response) -> Response: if not request.url_rule: - return Response + return response if not getattr(_app_context(), "oso_flask_authorize_called", False): raise OsoError("Authorize not called.") return response @@ -222,7 +222,9 @@ def is_admin( if actor is None: actor = self._get_current_actor() - oso: Oso = self.oso + oso = self.oso + if oso is None: + raise ValueError("No instance of oso set!") return oso.query_rule("is_admin", resource) def is_allowed( @@ -241,7 +243,9 @@ def is_allowed( if action is None: action = request.method - oso: Oso = self.oso + oso = self.oso + if oso is None: + raise ValueError("No instance of oso set!") return oso.is_allowed(actor, action, resource) def get_allowed_actions( @@ -258,7 +262,9 @@ def get_allowed_actions( if actor is None: actor = self._get_current_actor() - oso: Oso = self.oso + oso = self.oso + if oso is None: + raise ValueError("No instance of oso set!") result = oso.get_allowed_actions(actor, resource, allow_wildcard=allow_wildcard) if should_cache_result: self._allowed_methods = result @@ -275,14 +281,14 @@ def _authorize_called() -> None: def _app_context(): - top = request_ctx - # TODO Safety check will probably never trigger - if top is None: + try: + context = request_ctx._get_current_object() + except RuntimeError: raise OsoError( "Application context doesn't exist. Did you use oso outside the context of a request? " "See https://flask.palletsprojects.com/en/1.1.x/appcontext/#manually-push-a-context" ) - return top + return context def register_oso(app: Flask): From 9aa86fc56049df2179c525bb645aee1c26a9c059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Mon, 29 Jul 2024 10:52:28 +0200 Subject: [PATCH 13/14] Fix alembic migrations not working --- migrations/env.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/migrations/env.py b/migrations/env.py index 84702be..90d268f 100644 --- a/migrations/env.py +++ b/migrations/env.py @@ -3,10 +3,8 @@ import logging from logging.config import fileConfig -from sqlalchemy import engine_from_config -from sqlalchemy import pool - from alembic import context +from sqlalchemy import engine_from_config, pool # this is the Alembic Config object, which provides # access to the values within the .ini file in use. @@ -23,9 +21,8 @@ # target_metadata = mymodel.Base.metadata from flask import current_app -current_app.config[ - "SQLITE_FOREIGN_KEYS" -] = False # do NOT use foreign key checking when updating DB +# do NOT use foreign key checking when updating DB +current_app.config["SQLITE_FOREIGN_KEYS"] = False config.set_main_option( "sqlalchemy.url", str(current_app.extensions["migrate"].db.engine.url).replace("%", "%%"), @@ -84,13 +81,17 @@ def process_revision_directives(context, revision, directives): ) with connectable.connect() as connection: + extra_kwargs = dict(current_app.extensions["migrate"].configure_args) + # remove duplicate args from extra config + extra_kwargs.pop("compare_type", None) + extra_kwargs.pop("render_as_batch", None) context.configure( connection=connection, target_metadata=target_metadata, process_revision_directives=process_revision_directives, render_as_batch=True, compare_type=True, - **current_app.extensions["migrate"].configure_args + **extra_kwargs, ) with context.begin_transaction(): From 476abf5ac799ad3714d2f5e159f808ea6f285c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=BChler?= Date: Mon, 29 Jul 2024 10:56:51 +0200 Subject: [PATCH 14/14] Run black 24 on migration and conf.py --- docs/conf.py | 6 +++--- migrations/versions/a18bebd2bb1a_initial_migration.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4981d13..11b2e81 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -91,9 +91,9 @@ autosectionlabel_prefix_document = False autosectionlabel_maxdepth = None -intersphinx_mapping: Optional[ - Dict[str, Tuple[str, Union[Optional[str], Tuple[str]]]] -] = None +intersphinx_mapping: Optional[Dict[str, Tuple[str, Union[Optional[str], Tuple[str]]]]] = ( + None +) intersphinx_timeout = 30 source_suffix = { diff --git a/migrations/versions/a18bebd2bb1a_initial_migration.py b/migrations/versions/a18bebd2bb1a_initial_migration.py index 5963d15..a8147f9 100644 --- a/migrations/versions/a18bebd2bb1a_initial_migration.py +++ b/migrations/versions/a18bebd2bb1a_initial_migration.py @@ -3,6 +3,7 @@ Revision ID: a18bebd2bb1a Create Date: 2021-09-19 20:16:31.258752 """ + from alembic import op import sqlalchemy as sa