From cd6a2729d985cafecbfc635247ed6d496686852c Mon Sep 17 00:00:00 2001 From: Nina Bernick Date: Thu, 25 Jul 2024 16:22:20 -0700 Subject: [PATCH 1/3] move validators to top level --- .gitignore | 1 + docs/HOWTO-working-with-platformics.md | 2 +- platformics/codegen/generator.py | 4 ++-- platformics/codegen/templates/api/types/class_name.py.j2 | 4 ++-- .../codegen/templates/{api => }/validators/class_name.py.j2 | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) rename platformics/codegen/templates/{api => }/validators/class_name.py.j2 (97%) diff --git a/.gitignore b/.gitignore index ea70c94..5023691 100644 --- a/.gitignore +++ b/.gitignore @@ -255,6 +255,7 @@ test_app/cerbos/* test_app/support/* test_app/test_infra/* test_app/.moto_recording +test_app/validators/* # temp files /tmp/* diff --git a/docs/HOWTO-working-with-platformics.md b/docs/HOWTO-working-with-platformics.md index c6b45d7..939a833 100644 --- a/docs/HOWTO-working-with-platformics.md +++ b/docs/HOWTO-working-with-platformics.md @@ -32,11 +32,11 @@ Notable files and subdirectories: * `api/` - entrypoint for GQL API service * `helpers/` - generated GQL types and helper functions for GROUPBY queries * `types/` - generated GQL types - * `validators/` - generated Pydantic validators for create and update inputs * `mutations.py` - generated mutations (create, update, delete) for each entity type * `queries.py` - generated queries (list and aggregate) for each entity type * `schema.graphql` - GQL format schema * `schema.json` - JSON format schema +* `validators/` - generated Pydantic validators for create and update inputs * `cerbos/` - generated access policies for user actions for each entity type * `database/` - code related to establishing DB connections / sessions * `migrations/` - alembic migrations diff --git a/platformics/codegen/generator.py b/platformics/codegen/generator.py index 75f6666..c1ef716 100644 --- a/platformics/codegen/generator.py +++ b/platformics/codegen/generator.py @@ -14,7 +14,6 @@ DIR_CODEGEN = [ "support", "api/types", - "api/validators", "api/helpers", "database/models", "database/migrations", @@ -22,6 +21,7 @@ "cerbos/policies", "cerbos/policies/_schemas", "test_infra/factories", + "validators", ] @@ -163,7 +163,7 @@ def generate(schemafile: str, output_prefix: str, render_files: bool, template_o ) generate_entity_subclass_files( output_prefix, - "api/validators/class_name.py", + "validators/class_name.py", environment, wrapped_view, render_files=render_files, diff --git a/platformics/codegen/templates/api/types/class_name.py.j2 b/platformics/codegen/templates/api/types/class_name.py.j2 index fbc9190..79e084c 100644 --- a/platformics/codegen/templates/api/types/class_name.py.j2 +++ b/platformics/codegen/templates/api/types/class_name.py.j2 @@ -19,10 +19,10 @@ import strawberry import datetime from platformics.api.core.query_builder import get_db_rows, get_aggregate_db_rows {%- if cls.create_fields %} -from api.validators.{{cls.snake_name}} import {{cls.name}}CreateInputValidator +from validators.{{cls.snake_name}} import {{cls.name}}CreateInputValidator {%- endif %} {%- if cls.mutable_fields %} -from api.validators.{{cls.snake_name}} import {{cls.name}}UpdateInputValidator +from validators.{{cls.snake_name}} import {{cls.name}}UpdateInputValidator {%- endif %} {%- if render_files %} from platformics.api.files import File, FileWhereClause diff --git a/platformics/codegen/templates/api/validators/class_name.py.j2 b/platformics/codegen/templates/validators/class_name.py.j2 similarity index 97% rename from platformics/codegen/templates/api/validators/class_name.py.j2 rename to platformics/codegen/templates/validators/class_name.py.j2 index 8e434d7..164adf4 100644 --- a/platformics/codegen/templates/api/validators/class_name.py.j2 +++ b/platformics/codegen/templates/validators/class_name.py.j2 @@ -2,7 +2,7 @@ Pydantic validator for {{cls.name}} Auto-generated by running 'make codegen'. Do not edit. -Make changes to the template codegen/templates/api/validators/class_name.py.j2 instead. +Make changes to the template codegen/templates/validators/class_name.py.j2 instead. """ # ruff: noqa: E501 Line too long From 54c0c0e9ff42ab8b579506a80d0db842d21ea92e Mon Sep 17 00:00:00 2001 From: Nina Bernick Date: Thu, 25 Jul 2024 16:51:48 -0700 Subject: [PATCH 2/3] rename api to graphql_api --- .gitignore | 2 +- .pre-commit-config.yaml | 2 +- platformics/codegen/generator.py | 12 ++-- .../helpers/class_name.py.j2 | 4 +- .../{api => graphql_api}/mutations.py.j2 | 6 +- .../{api => graphql_api}/queries.py.j2 | 8 +-- .../types/class_name.py.j2 | 66 +++++++++---------- platformics/database/models/file.py | 2 +- platformics/{api => graphql_api}/core/deps.py | 2 +- .../core/error_handler.py | 2 +- .../{api => graphql_api}/core/errors.py | 0 .../{api => graphql_api}/core/gql_loaders.py | 4 +- .../core/query_builder.py | 4 +- .../core/query_input_types.py | 0 .../core/strawberry_extensions.py | 0 platformics/{api => graphql_api}/files.py | 14 ++-- .../{api => graphql_api}/relay/__init__.py | 0 .../{api => graphql_api}/relay/exceptions.py | 0 .../{api => graphql_api}/relay/fields.py | 2 +- .../{api => graphql_api}/relay/types.py | 2 +- platformics/{api => graphql_api}/setup.py | 4 +- .../tests/test_hashability.py | 2 +- .../{api => graphql_api}/types/entities.py | 2 +- .../{api => graphql_api}/uvicorn_worker.py | 0 pyproject.toml | 4 +- test_app/Makefile | 10 +-- test_app/conftest.py | 12 ++-- test_app/etc/supervisord.conf | 2 +- test_app/main.py | 8 +-- 29 files changed, 88 insertions(+), 88 deletions(-) rename platformics/codegen/templates/{api => graphql_api}/helpers/class_name.py.j2 (92%) rename platformics/codegen/templates/{api => graphql_api}/mutations.py.j2 (67%) rename platformics/codegen/templates/{api => graphql_api}/queries.py.j2 (70%) rename platformics/codegen/templates/{api => graphql_api}/types/class_name.py.j2 (89%) rename platformics/{api => graphql_api}/core/deps.py (98%) rename platformics/{api => graphql_api}/core/error_handler.py (97%) rename platformics/{api => graphql_api}/core/errors.py (100%) rename platformics/{api => graphql_api}/core/gql_loaders.py (97%) rename platformics/{api => graphql_api}/core/query_builder.py (98%) rename platformics/{api => graphql_api}/core/query_input_types.py (100%) rename platformics/{api => graphql_api}/core/strawberry_extensions.py (100%) rename platformics/{api => graphql_api}/files.py (97%) rename platformics/{api => graphql_api}/relay/__init__.py (100%) rename platformics/{api => graphql_api}/relay/exceptions.py (100%) rename platformics/{api => graphql_api}/relay/fields.py (99%) rename platformics/{api => graphql_api}/relay/types.py (99%) rename platformics/{api => graphql_api}/setup.py (92%) rename platformics/{api => graphql_api}/tests/test_hashability.py (98%) rename platformics/{api => graphql_api}/types/entities.py (97%) rename platformics/{api => graphql_api}/uvicorn_worker.py (100%) diff --git a/.gitignore b/.gitignore index 5023691..9f6d7c1 100644 --- a/.gitignore +++ b/.gitignore @@ -249,7 +249,7 @@ pyrightconfig.json .env.localdev # Codegen on test app -test_app/api/* +test_app/graphql_api/* test_app/database/* test_app/cerbos/* test_app/support/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4743721..56753e3 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,7 @@ repos: rev: "v1.10.0" hooks: - id: mypy - exclude: "platformics/thirdparty|platformics/api/relay" + exclude: "platformics/thirdparty|platformics/graphql_api/relay" additional_dependencies: ["types-PyYAML", "types-dateparser", "types-requests"] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 diff --git a/platformics/codegen/generator.py b/platformics/codegen/generator.py index c1ef716..53a421d 100644 --- a/platformics/codegen/generator.py +++ b/platformics/codegen/generator.py @@ -13,8 +13,8 @@ DIR_CODEGEN = [ "support", - "api/types", - "api/helpers", + "graphql_api/types", + "graphql_api/helpers", "database/models", "database/migrations", "database/migrations/versions", @@ -106,8 +106,8 @@ def generate_entity_import_files( "database/models/__init__.py", "database/migrations/env.py", "database/migrations/script.py.mako", - "api/queries.py", - "api/mutations.py", + "graphql_api/queries.py", + "graphql_api/mutations.py", ] classes = view.entities for filename in import_templates: @@ -156,7 +156,7 @@ def generate(schemafile: str, output_prefix: str, render_files: bool, template_o ) generate_entity_subclass_files( output_prefix, - "api/types/class_name.py", + "graphql_api/types/class_name.py", environment, wrapped_view, render_files=render_files, @@ -184,7 +184,7 @@ def generate(schemafile: str, output_prefix: str, render_files: bool, template_o ) generate_entity_subclass_files( output_prefix, - "api/helpers/class_name.py", + "graphql_api/helpers/class_name.py", environment, wrapped_view, render_files=render_files, diff --git a/platformics/codegen/templates/api/helpers/class_name.py.j2 b/platformics/codegen/templates/graphql_api/helpers/class_name.py.j2 similarity index 92% rename from platformics/codegen/templates/api/helpers/class_name.py.j2 rename to platformics/codegen/templates/graphql_api/helpers/class_name.py.j2 index 9d9057c..49b2791 100644 --- a/platformics/codegen/templates/api/helpers/class_name.py.j2 +++ b/platformics/codegen/templates/graphql_api/helpers/class_name.py.j2 @@ -2,7 +2,7 @@ Define GraphQL types and helper functions for supporting GROUPBY queries. Auto-gereanted by running 'make codegen'. Do not edit. -Make changes to the template codegen/templates/api/groupby_helpers.py.j2 instead. +Make changes to the template codegen/templates/graphql_api/groupby_helpers.py.j2 instead. """ {% set related_fields = cls.related_fields | unique(attribute='related_class.name') | list %} {% set ignored_fields = ["File", "Entity", cls.name] %} @@ -23,7 +23,7 @@ from support.enums import {%- for field in cls.related_fields %} {%- if field.related_class.name not in ignored_fields and not field.multivalued and not field.is_virtual_relationship %} -from api.helpers.{{ field.related_class.snake_name }} import {{ field.related_class.name }}GroupByOptions, build_{{ field.related_class.snake_name }}_groupby_output +from graphql_api.helpers.{{ field.related_class.snake_name }} import {{ field.related_class.name }}GroupByOptions, build_{{ field.related_class.snake_name }}_groupby_output {%- endif %} {%- endfor %} diff --git a/platformics/codegen/templates/api/mutations.py.j2 b/platformics/codegen/templates/graphql_api/mutations.py.j2 similarity index 67% rename from platformics/codegen/templates/api/mutations.py.j2 rename to platformics/codegen/templates/graphql_api/mutations.py.j2 index f03570b..95d1101 100644 --- a/platformics/codegen/templates/api/mutations.py.j2 +++ b/platformics/codegen/templates/graphql_api/mutations.py.j2 @@ -2,17 +2,17 @@ GraphQL mutations for files and entities Auto-generated by running 'make codegen'. Do not edit. -Make changes to the template codegen/templates/api/mutations.py.j2 instead. +Make changes to the template codegen/templates/graphql_api/mutations.py.j2 instead. """ import strawberry from typing import Sequence {%- if render_files %} -from platformics.api.files import File, create_file, upload_file, upload_temporary_file, mark_upload_complete, concatenate_files, SignedURL, MultipartUploadResponse +from platformics.graphql_api.files import File, create_file, upload_file, upload_temporary_file, mark_upload_complete, concatenate_files, SignedURL, MultipartUploadResponse {%- endif %} {%- for class in classes %} -from api.types.{{ class.snake_name }} import {{ class.name }}, {%- if class.create_fields %}create_{{ class.snake_name }}, {%- endif %}{%- if class.mutable_fields %}update_{{ class.snake_name }}, {%- endif %}delete_{{ class.snake_name }} +from graphql_api.types.{{ class.snake_name }} import {{ class.name }}, {%- if class.create_fields %}create_{{ class.snake_name }}, {%- endif %}{%- if class.mutable_fields %}update_{{ class.snake_name }}, {%- endif %}delete_{{ class.snake_name }} {%- endfor %} @strawberry.type diff --git a/platformics/codegen/templates/api/queries.py.j2 b/platformics/codegen/templates/graphql_api/queries.py.j2 similarity index 70% rename from platformics/codegen/templates/api/queries.py.j2 rename to platformics/codegen/templates/graphql_api/queries.py.j2 index 5ba7be6..e8aa849 100644 --- a/platformics/codegen/templates/api/queries.py.j2 +++ b/platformics/codegen/templates/graphql_api/queries.py.j2 @@ -2,17 +2,17 @@ Supported GraphQL queries for files and entities Auto-generated by running 'make codegen'. Do not edit. -Make changes to the template codegen/templates/api/queries.py.j2 instead. +Make changes to the template codegen/templates/graphql_api/queries.py.j2 instead. """ import strawberry -from platformics.api import relay +from platformics.graphql_api import relay from typing import Sequence, List {%- if render_files %} -from platformics.api.files import File, resolve_files +from platformics.graphql_api.files import File, resolve_files {%- endif %} {%- for class in classes %} -from api.types.{{ class.snake_name }} import {{ class.name }}, resolve_{{ class.plural_snake_name }}, {{ class.name }}Aggregate, resolve_{{ class.plural_snake_name }}_aggregate +from graphql_api.types.{{ class.snake_name }} import {{ class.name }}, resolve_{{ class.plural_snake_name }}, {{ class.name }}Aggregate, resolve_{{ class.plural_snake_name }}_aggregate {%- endfor %} diff --git a/platformics/codegen/templates/api/types/class_name.py.j2 b/platformics/codegen/templates/graphql_api/types/class_name.py.j2 similarity index 89% rename from platformics/codegen/templates/api/types/class_name.py.j2 rename to platformics/codegen/templates/graphql_api/types/class_name.py.j2 index 79e084c..9c62d43 100644 --- a/platformics/codegen/templates/api/types/class_name.py.j2 +++ b/platformics/codegen/templates/graphql_api/types/class_name.py.j2 @@ -2,7 +2,7 @@ GraphQL type for {{cls.name}} Auto-generated by running 'make codegen'. Do not edit. -Make changes to the template codegen/templates/api/types/class_name.py.j2 instead. +Make changes to the template codegen/templates/graphql_api/types/class_name.py.j2 instead. """ # ruff: noqa: E501 Line too long @@ -17,7 +17,7 @@ import platformics.database.models as base_db import database.models as db import strawberry import datetime -from platformics.api.core.query_builder import get_db_rows, get_aggregate_db_rows +from platformics.graphql_api.core.query_builder import get_db_rows, get_aggregate_db_rows {%- if cls.create_fields %} from validators.{{cls.snake_name}} import {{cls.name}}CreateInputValidator {%- endif %} @@ -25,27 +25,27 @@ from validators.{{cls.snake_name}} import {{cls.name}}CreateInputValidator from validators.{{cls.snake_name}} import {{cls.name}}UpdateInputValidator {%- endif %} {%- if render_files %} -from platformics.api.files import File, FileWhereClause +from platformics.graphql_api.files import File, FileWhereClause {%- endif %} -from api.helpers.{{ cls.snake_name }} import {{ cls.name }}GroupByOptions, build_{{ cls.snake_name }}_groupby_output -from platformics.api.types.entities import EntityInterface +from graphql_api.helpers.{{ cls.snake_name }} import {{ cls.name }}GroupByOptions, build_{{ cls.snake_name }}_groupby_output +from platformics.graphql_api.types.entities import EntityInterface {%- for related_field in related_fields %} {%- if related_field.related_class.name not in ignored_fields and related_field.multivalued %} -from api.types.{{related_field.related_class.snake_name}} import ({{related_field.related_class.name}}Aggregate, format_{{related_field.related_class.snake_name}}_aggregate_output) +from graphql_api.types.{{related_field.related_class.snake_name}} import ({{related_field.related_class.name}}Aggregate, format_{{related_field.related_class.snake_name}}_aggregate_output) {%- endif %} {%- endfor %} from cerbos.sdk.client import CerbosClient from cerbos.sdk.model import Principal, Resource from fastapi import Depends -from platformics.api.core.errors import PlatformicsError -from platformics.api.core.deps import get_cerbos_client, get_db_session, require_auth_principal, is_system_user -from platformics.api.core.query_input_types import aggregator_map, orderBy, EnumComparators, DatetimeComparators, IntComparators, FloatComparators, StrComparators, UUIDComparators, BoolComparators -from platformics.api.core.strawberry_extensions import DependencyExtension +from platformics.graphql_api.core.errors import PlatformicsError +from platformics.graphql_api.core.deps import get_cerbos_client, get_db_session, require_auth_principal, is_system_user +from platformics.graphql_api.core.query_input_types import aggregator_map, orderBy, EnumComparators, DatetimeComparators, IntComparators, FloatComparators, StrComparators, UUIDComparators, BoolComparators +from platformics.graphql_api.core.strawberry_extensions import DependencyExtension from platformics.security.authorization import CerbosAction, get_resource_query from sqlalchemy import inspect from sqlalchemy.engine.row import RowMapping from sqlalchemy.ext.asyncio import AsyncSession -from platformics.api import relay +from platformics.graphql_api import relay from strawberry.field import StrawberryField from strawberry.types import Info from support.limit_offset import LimitOffsetClause @@ -68,7 +68,7 @@ T = typing.TypeVar("T") if TYPE_CHECKING: {%- for related_field in related_fields %} {%- if related_field.related_class.name not in ignored_fields %} - from api.types.{{related_field.related_class.snake_name}} import ({{related_field.related_class.name}}OrderByClause, {{related_field.related_class.name}}WhereClause, {{related_field.related_class.name}}) + from graphql_api.types.{{related_field.related_class.snake_name}} import ({{related_field.related_class.name}}OrderByClause, {{related_field.related_class.name}}WhereClause, {{related_field.related_class.name}}) {%- endif %} {%- endfor %} pass @@ -94,22 +94,22 @@ These are batching functions for loading related objects to avoid N+1 queries. {%- if related_field.inverse and related_field.related_class.name not in ignored_fields %} {%- if related_field.multivalued %} @relay.connection( - relay.ListConnection[Annotated["{{ related_field.type }}", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]] # type:ignore + relay.ListConnection[Annotated["{{ related_field.type }}", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]] # type:ignore ) async def load_{{ related_field.related_class.snake_name }}_rows( root: "{{ cls.name }}", info: Info, - where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")] | None = None, - order_by: Optional[list[Annotated["{{ related_field.type }}OrderByClause", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]]] = [], -) -> Sequence[Annotated["{{ related_field.type }}", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]]: + where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")] | None = None, + order_by: Optional[list[Annotated["{{ related_field.type }}OrderByClause", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]]] = [], +) -> Sequence[Annotated["{{ related_field.type }}", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]]: {%- else %} @strawberry.field async def load_{{ related_field.related_class.snake_name }}_rows( root: "{{ cls.name }}", info: Info, - where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")] | None = None, - order_by: Optional[list[Annotated["{{ related_field.type }}OrderByClause", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]]] = [], -) -> Optional[Annotated["{{ related_field.type }}", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]]: + where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")] | None = None, + order_by: Optional[list[Annotated["{{ related_field.type }}OrderByClause", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]]] = [], +) -> Optional[Annotated["{{ related_field.type }}", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]]: {%- endif %} dataloader = info.context["sqlalchemy_loader"] mapper = inspect(db.{{ cls.name }}) @@ -132,8 +132,8 @@ async def load_{{ related_field.related_class.snake_name }}_rows( async def load_{{ related_field.related_class.snake_name }}_aggregate_rows( root: "{{ cls.name }}", info: Info, - where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")] | None = None, -) -> Optional[Annotated["{{ related_field.related_class.name }}Aggregate", strawberry.lazy("api.types.{{ related_field.related_class.snake_name }}")]]: + where: Annotated["{{ related_field.type }}WhereClause", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")] | None = None, +) -> Optional[Annotated["{{ related_field.related_class.name }}Aggregate", strawberry.lazy("graphql_api.types.{{ related_field.related_class.snake_name }}")]]: selections = info.selected_fields[0].selections[0].selections dataloader = info.context["sqlalchemy_loader"] mapper = inspect(db.{{ cls.name }}) @@ -159,8 +159,8 @@ def load_files_from(attr_name: str) -> Callable: async def load_files( root: "{{ cls.name }}", info: Info, - where: Annotated["FileWhereClause", strawberry.lazy("platformics.api.files")] | None = None, - ) -> Optional[Annotated["File", strawberry.lazy("platformics.api.files")]]: + where: Annotated["FileWhereClause", strawberry.lazy("platformics.graphql_api.files")] | None = None, + ) -> Optional[Annotated["File", strawberry.lazy("platformics.graphql_api.files")]]: """ Given a list of {{ cls.name }} IDs for a certain file type, return related Files """ @@ -208,7 +208,7 @@ class {{ cls.name }}WhereClause(TypedDict): {%- elif attr.type == "date" %} {{ attr.name }}: Optional[DatetimeComparators] | None {%- elif attr.inverse %} - {{ attr.name }}: Optional[Annotated["{{ attr.type }}WhereClause", strawberry.lazy("api.types.{{ attr.related_class.snake_name }}")]] | None + {{ attr.name }}: Optional[Annotated["{{ attr.type }}WhereClause", strawberry.lazy("graphql_api.types.{{ attr.related_class.snake_name }}")]] | None {%- elif attr.type == cls.name %} {{ attr.name }}_id: Optional[UUIDComparators] | None {%- endif %} @@ -222,7 +222,7 @@ class {{ cls.name }}OrderByClause(TypedDict): {%- for attr in cls.visible_fields %} {%- if attr.type != "File" and not attr.multivalued %} {%- if attr.inverse %} - {{ attr.name }}: Optional[Annotated["{{ attr.type }}OrderByClause", strawberry.lazy("api.types.{{ attr.related_class.snake_name }}")]] | None + {{ attr.name }}: Optional[Annotated["{{ attr.type }}OrderByClause", strawberry.lazy("graphql_api.types.{{ attr.related_class.snake_name }}")]] | None {%- else %} {{ attr.name }}: Optional[orderBy] | None {%- endif %} @@ -260,13 +260,13 @@ class {{ cls.name }}(EntityInterface): {{ attr.name }}: {{ getType("datetime.datetime", attr.required) }} {%- elif attr.type == "File" %} {{ attr.name }}_id: Optional[strawberry.ID] - {{ attr.name }}: Optional[Annotated["File", strawberry.lazy("platformics.api.files")]] = load_files_from("{{ attr.name }}") # type: ignore + {{ attr.name }}: Optional[Annotated["File", strawberry.lazy("platformics.graphql_api.files")]] = load_files_from("{{ attr.name }}") # type: ignore {%- elif attr.type == cls.name %} {{ attr.name }}_id: Optional[strawberry.ID] {%- elif attr.inverse %} - {{ attr.name }}: {{ "Sequence" if attr.multivalued else "Optional" }}[Annotated["{{ attr.type }}", strawberry.lazy("api.types.{{ attr.related_class.snake_name }}")]] = load_{{ attr.related_class.snake_name }}_rows # type:ignore + {{ attr.name }}: {{ "Sequence" if attr.multivalued else "Optional" }}[Annotated["{{ attr.type }}", strawberry.lazy("graphql_api.types.{{ attr.related_class.snake_name }}")]] = load_{{ attr.related_class.snake_name }}_rows # type:ignore {%- if attr.multivalued %} - {{ attr.name }}_aggregate : Optional[Annotated["{{ attr.related_class.name }}Aggregate", strawberry.lazy("api.types.{{ attr.related_class.snake_name }}")]] = load_{{ attr.related_class.snake_name }}_aggregate_rows # type:ignore + {{ attr.name }}_aggregate : Optional[Annotated["{{ attr.related_class.name }}Aggregate", strawberry.lazy("graphql_api.types.{{ attr.related_class.snake_name }}")]] = load_{{ attr.related_class.snake_name }}_aggregate_rows # type:ignore {%- endif %} {%- endif %} {%- endfor %} @@ -420,7 +420,7 @@ async def resolve_{{ cls.plural_snake_name }}( limit_offset: Optional[LimitOffsetClause] = None, ) -> typing.Sequence[{{ cls.name }}]: """ - Resolve {{ cls.name }} objects. Used for queries (see api/queries.py). + Resolve {{ cls.name }} objects. Used for queries (see graphql_api/queries.py). """ limit = limit_offset["limit"] if limit_offset and "limit" in limit_offset else None offset = limit_offset["offset"] if limit_offset and "offset" in limit_offset else None @@ -483,7 +483,7 @@ async def resolve_{{ cls.plural_snake_name }}_aggregate( # TODO: add support for groupby, limit/offset ) -> {{ cls.name }}Aggregate: """ - Aggregate values for {{ cls.name }} objects. Used for queries (see api/queries.py). + Aggregate values for {{ cls.name }} objects. Used for queries (see graphql_api/queries.py). """ # Get the selected aggregate functions and columns to operate on, and groupby options if any were provided. # TODO: not sure why selected_fields is a list @@ -509,7 +509,7 @@ async def create_{{ cls.snake_name }}( is_system_user: bool = Depends(is_system_user), ) -> db.{{ cls.name }}: """ - Create a new {{ cls.name }} object. Used for mutations (see api/mutations.py). + Create a new {{ cls.name }} object. Used for mutations (see graphql_api/mutations.py). """ validated = {{cls.name}}CreateInputValidator(**input.__dict__) params = validated.model_dump() @@ -569,7 +569,7 @@ async def update_{{ cls.snake_name }}( is_system_user: bool = Depends(is_system_user), ) -> Sequence[db.{{ cls.name }}]: """ - Update {{ cls.name }} objects. Used for mutations (see api/mutations.py). + Update {{ cls.name }} objects. Used for mutations (see graphql_api/mutations.py). """ validated = {{cls.name}}UpdateInputValidator(**input.__dict__) params = validated.model_dump() @@ -642,7 +642,7 @@ async def delete_{{ cls.snake_name }}( principal: Principal = Depends(require_auth_principal), ) -> Sequence[db.{{ cls.name }}]: """ - Delete {{ cls.name }} objects. Used for mutations (see api/mutations.py). + Delete {{ cls.name }} objects. Used for mutations (see graphql_api/mutations.py). """ # Fetch entities for deletion, if we have access to them entities = await get_db_rows(db.{{ cls.name }}, session, cerbos_client, principal, where, [], CerbosAction.DELETE) diff --git a/platformics/database/models/file.py b/platformics/database/models/file.py index 0ac4d77..490f0bd 100644 --- a/platformics/database/models/file.py +++ b/platformics/database/models/file.py @@ -52,7 +52,7 @@ def set_s3_client(s3_client: S3Client) -> None: entity_field_name: Mapped[str] = mapped_column(String, nullable=False) entity: Mapped[Entity] = relationship(Entity, foreign_keys=entity_id) - # TODO: Changes here need to be reflected in api/files.py + # TODO: Changes here need to be reflected in graphql_api/files.py status: Mapped[FileStatus] = mapped_column(Enum(FileStatus, native_enum=False), nullable=False) protocol: Mapped[FileAccessProtocol] = mapped_column(Enum(FileAccessProtocol, native_enum=False), nullable=False) namespace: Mapped[str] = mapped_column(String, nullable=False) diff --git a/platformics/api/core/deps.py b/platformics/graphql_api/core/deps.py similarity index 98% rename from platformics/api/core/deps.py rename to platformics/graphql_api/core/deps.py index 0642cb6..6f0bc3a 100644 --- a/platformics/api/core/deps.py +++ b/platformics/graphql_api/core/deps.py @@ -10,7 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from starlette.requests import Request -from platformics.api.core.error_handler import PlatformicsError +from platformics.graphql_api.core.error_handler import PlatformicsError from platformics.database.connect import AsyncDB, init_async_db from platformics.security.token_auth import get_token_claims from platformics.settings import APISettings diff --git a/platformics/api/core/error_handler.py b/platformics/graphql_api/core/error_handler.py similarity index 97% rename from platformics/api/core/error_handler.py rename to platformics/graphql_api/core/error_handler.py index f4ac2a4..a610699 100644 --- a/platformics/api/core/error_handler.py +++ b/platformics/graphql_api/core/error_handler.py @@ -5,7 +5,7 @@ from pydantic import ValidationError from strawberry.extensions.base_extension import SchemaExtension -from platformics.api.core.errors import PlatformicsError +from platformics.graphql_api.core.errors import PlatformicsError class ExceptionHandler(ABC): diff --git a/platformics/api/core/errors.py b/platformics/graphql_api/core/errors.py similarity index 100% rename from platformics/api/core/errors.py rename to platformics/graphql_api/core/errors.py diff --git a/platformics/api/core/gql_loaders.py b/platformics/graphql_api/core/gql_loaders.py similarity index 97% rename from platformics/api/core/gql_loaders.py rename to platformics/graphql_api/core/gql_loaders.py index 98cfd7a..4d5a228 100644 --- a/platformics/api/core/gql_loaders.py +++ b/platformics/graphql_api/core/gql_loaders.py @@ -8,8 +8,8 @@ from strawberry.dataloader import DataLoader import platformics.database.models as db -from platformics.api.core.errors import PlatformicsError -from platformics.api.core.query_builder import get_aggregate_db_query, get_db_query, get_db_rows +from platformics.graphql_api.core.errors import PlatformicsError +from platformics.graphql_api.core.query_builder import get_aggregate_db_query, get_db_query, get_db_rows from platformics.database.connect import AsyncDB from platformics.security.authorization import CerbosAction diff --git a/platformics/api/core/query_builder.py b/platformics/graphql_api/core/query_builder.py similarity index 98% rename from platformics/api/core/query_builder.py rename to platformics/graphql_api/core/query_builder.py index 58aa1d4..652d605 100644 --- a/platformics/api/core/query_builder.py +++ b/platformics/graphql_api/core/query_builder.py @@ -17,8 +17,8 @@ from typing_extensions import TypedDict import platformics.database.models as db -from platformics.api.core.errors import PlatformicsError -from platformics.api.core.query_input_types import aggregator_map, operator_map, orderBy +from platformics.graphql_api.core.errors import PlatformicsError +from platformics.graphql_api.core.query_input_types import aggregator_map, operator_map, orderBy from platformics.database.models.base import Base from platformics.security.authorization import CerbosAction, get_resource_query diff --git a/platformics/api/core/query_input_types.py b/platformics/graphql_api/core/query_input_types.py similarity index 100% rename from platformics/api/core/query_input_types.py rename to platformics/graphql_api/core/query_input_types.py diff --git a/platformics/api/core/strawberry_extensions.py b/platformics/graphql_api/core/strawberry_extensions.py similarity index 100% rename from platformics/api/core/strawberry_extensions.py rename to platformics/graphql_api/core/strawberry_extensions.py diff --git a/platformics/api/files.py b/platformics/graphql_api/files.py similarity index 97% rename from platformics/api/files.py rename to platformics/graphql_api/files.py index 8929ea1..3bd2901 100644 --- a/platformics/api/files.py +++ b/platformics/graphql_api/files.py @@ -24,7 +24,7 @@ from strawberry.types import Info from typing_extensions import TypedDict -from platformics.api.core.deps import ( +from platformics.graphql_api.core.deps import ( get_cerbos_client, get_db_session, get_s3_client, @@ -33,10 +33,10 @@ require_auth_principal, require_system_user, ) -from platformics.api.core.query_builder import get_db_rows -from platformics.api.core.query_input_types import EnumComparators, IntComparators, StrComparators, UUIDComparators -from platformics.api.core.strawberry_extensions import DependencyExtension -from platformics.api.types.entities import Entity +from platformics.graphql_api.core.query_builder import get_db_rows +from platformics.graphql_api.core.query_input_types import EnumComparators, IntComparators, StrComparators, UUIDComparators +from platformics.graphql_api.core.strawberry_extensions import DependencyExtension +from platformics.graphql_api.types.entities import Entity from platformics.security.authorization import CerbosAction, get_resource_query from platformics.settings import APISettings from platformics.support.file_enums import FileAccessProtocol, FileStatus @@ -134,7 +134,7 @@ async def load_entities( root: "File", info: Info, where: EntityWhereClause | None = None, -) -> typing.Optional[typing.Annotated["Entity", strawberry.lazy("platformics.api.types.entities")]]: +) -> typing.Optional[typing.Annotated["Entity", strawberry.lazy("platformics.graphql_api.types.entities")]]: """ Dataloader to fetch related entities, given file IDs. """ @@ -158,7 +158,7 @@ class File: id: strawberry.ID entity_id: strawberry.ID entity_field_name: str - entity: typing.Optional[typing.Annotated["Entity", strawberry.lazy("platformics.api.types.entities")]] = ( + entity: typing.Optional[typing.Annotated["Entity", strawberry.lazy("platformics.graphql_api.types.entities")]] = ( load_entities ) status: FileStatus diff --git a/platformics/api/relay/__init__.py b/platformics/graphql_api/relay/__init__.py similarity index 100% rename from platformics/api/relay/__init__.py rename to platformics/graphql_api/relay/__init__.py diff --git a/platformics/api/relay/exceptions.py b/platformics/graphql_api/relay/exceptions.py similarity index 100% rename from platformics/api/relay/exceptions.py rename to platformics/graphql_api/relay/exceptions.py diff --git a/platformics/api/relay/fields.py b/platformics/graphql_api/relay/fields.py similarity index 99% rename from platformics/api/relay/fields.py rename to platformics/graphql_api/relay/fields.py index 1b06b6a..317977f 100644 --- a/platformics/api/relay/fields.py +++ b/platformics/graphql_api/relay/fields.py @@ -39,7 +39,7 @@ from strawberry.utils.typing import eval_type from typing_extensions import Annotated, get_origin -from platformics.api.relay.exceptions import ( +from platformics.graphql_api.relay.exceptions import ( RelayWrongAnnotationError, RelayWrongResolverAnnotationError, ) diff --git a/platformics/api/relay/types.py b/platformics/graphql_api/relay/types.py similarity index 99% rename from platformics/api/relay/types.py rename to platformics/graphql_api/relay/types.py index 06683d2..d688245 100644 --- a/platformics/api/relay/types.py +++ b/platformics/graphql_api/relay/types.py @@ -38,7 +38,7 @@ from strawberry.utils.typing import eval_type, is_classvar from typing_extensions import Annotated, Literal, Self, TypeAlias, get_args, get_origin -from platformics.api.relay.exceptions import NodeIDAnnotationError +from platformics.graphql_api.relay.exceptions import NodeIDAnnotationError if TYPE_CHECKING: from strawberry.utils.await_maybe import AwaitableOrValue diff --git a/platformics/api/setup.py b/platformics/graphql_api/setup.py similarity index 92% rename from platformics/api/setup.py rename to platformics/graphql_api/setup.py index 6c76589..43110aa 100644 --- a/platformics/api/setup.py +++ b/platformics/graphql_api/setup.py @@ -12,8 +12,8 @@ from strawberry.schema.config import StrawberryConfig from strawberry.schema.name_converter import HasGraphQLName, NameConverter -from platformics.api.core.deps import get_auth_principal, get_cerbos_client, get_db_module, get_engine, get_s3_client -from platformics.api.core.gql_loaders import EntityLoader +from platformics.graphql_api.core.deps import get_auth_principal, get_cerbos_client, get_db_module, get_engine, get_s3_client +from platformics.graphql_api.core.gql_loaders import EntityLoader from platformics.database.connect import AsyncDB from platformics.database.models.file import File from platformics.settings import APISettings diff --git a/platformics/api/tests/test_hashability.py b/platformics/graphql_api/tests/test_hashability.py similarity index 98% rename from platformics/api/tests/test_hashability.py rename to platformics/graphql_api/tests/test_hashability.py index 6be251e..2947363 100644 --- a/platformics/api/tests/test_hashability.py +++ b/platformics/graphql_api/tests/test_hashability.py @@ -7,7 +7,7 @@ import strawberry -from platformics.api.core.gql_loaders import get_input_hash +from platformics.graphql_api.core.gql_loaders import get_input_hash @strawberry.enum diff --git a/platformics/api/types/entities.py b/platformics/graphql_api/types/entities.py similarity index 97% rename from platformics/api/types/entities.py rename to platformics/graphql_api/types/entities.py index 0880eac..3c44f8f 100644 --- a/platformics/api/types/entities.py +++ b/platformics/graphql_api/types/entities.py @@ -3,7 +3,7 @@ import strawberry from strawberry.types import Info -from platformics.api import relay +from platformics.graphql_api import relay @strawberry.type diff --git a/platformics/api/uvicorn_worker.py b/platformics/graphql_api/uvicorn_worker.py similarity index 100% rename from platformics/api/uvicorn_worker.py rename to platformics/graphql_api/uvicorn_worker.py diff --git a/pyproject.toml b/pyproject.toml index 8bc9e61..b6bb969 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,7 @@ warn_unreachable = true explicit_package_bases = true ignore_missing_imports = true exclude = [ - "platformics/api/relay", + "platformics/graphql_api/relay", "platformics/thirdparty" ] # We'd like to turn this on soon but we're not there yet. @@ -71,7 +71,7 @@ exclude = [ # do not look at shopify and turn anything originating from it into Any [[tool.mypy.overrides]] -module = ["platformics.api.relay.*"] +module = ["platformics.graphql_api.relay.*"] follow_imports = "skip" [[tool.mypy.overrides]] diff --git a/test_app/Makefile b/test_app/Makefile index dca3634..1b0bd4e 100644 --- a/test_app/Makefile +++ b/test_app/Makefile @@ -43,11 +43,11 @@ init: $(MAKE) alembic-upgrade-head $(docker_compose_run) $(APP_CONTAINER) black . # $(docker_compose_run) $(CONTAINER) ruff check --fix . - $(docker_compose_run) $(APP_CONTAINER) sh -c 'strawberry export-schema main:schema > /app/api/schema.graphql' + $(docker_compose_run) $(APP_CONTAINER) sh -c 'strawberry export-schema main:schema > /app/graphql_api/schema.graphql' docker compose up -d $(MAKE) seed-moto sleep 5 # wait for the app to reload after having files updated. - docker compose exec $(APP_CONTAINER) python3 -m sgqlc.introspection --exclude-deprecated --exclude-description http://localhost:9009/graphql api/schema.json + docker compose exec $(APP_CONTAINER) python3 -m sgqlc.introspection --exclude-deprecated --exclude-description http://localhost:9009/graphql graphql_api/schema.json .PHONY: seed-moto seed-moto: ## Seed the moto db by running the ./bin/seed_moto.sh script @@ -56,7 +56,7 @@ seed-moto: ## Seed the moto db by running the ./bin/seed_moto.sh script .PHONY: clean clean: ## Remove all codegen'd artifacts. - rm -rf api + rm -rf graphql_api rm -rf cerbos rm -rf support rm -rf database @@ -106,8 +106,8 @@ token: ## Copy an auth token for this local dev env to the system clipboard .PHONY: update-cli update-cli: ## Update the GQL types used by the CLI - $(docker_compose) exec $(APP_CONTAINER) python3 -m sgqlc.introspection --exclude-deprecated --exclude-description http://localhost:8042/graphql api/schema.json - $(docker_compose) exec $(APP_CONTAINER) sgqlc-codegen schema api/schema.json cli/gql_schema.py + $(docker_compose) exec $(APP_CONTAINER) python3 -m sgqlc.introspection --exclude-deprecated --exclude-description http://localhost:8042/graphql graphql_api/schema.json + $(docker_compose) exec $(APP_CONTAINER) sgqlc-codegen schema graphql_api/schema.json cli/gql_schema.py .PHONY: fix-poetry-lock fix-poetry-lock: ## Fix poetry lockfile after merge conflict & repairing pyproject.toml diff --git a/test_app/conftest.py b/test_app/conftest.py index 0c6dfd1..7111501 100644 --- a/test_app/conftest.py +++ b/test_app/conftest.py @@ -6,7 +6,7 @@ import os import typing from typing import Optional -from platformics.api.core.error_handler import HandleErrors +from platformics.graphql_api.core.error_handler import HandleErrors import boto3 import pytest @@ -16,14 +16,14 @@ from httpx import AsyncClient from moto import mock_s3 from mypy_boto3_s3.client import S3Client -from platformics.api.core.deps import ( +from platformics.graphql_api.core.deps import ( get_auth_principal, get_db_session, get_engine, get_s3_client, require_auth_principal, ) -from platformics.api.setup import get_app +from platformics.graphql_api.setup import get_app from platformics.database.connect import AsyncDB, SyncDB, init_async_db, init_sync_db from platformics.database.models.base import Base from platformics.test_infra.factories.base import FileFactory, SessionStorage @@ -34,9 +34,9 @@ from starlette.requests import Request from platformics.settings import APISettings from database import models -from platformics.api.setup import get_strawberry_config -from api.mutations import Mutation -from api.queries import Query +from platformics.graphql_api.setup import get_strawberry_config +from graphql_api.mutations import Mutation +from graphql_api.queries import Query import strawberry __all__ = [ diff --git a/test_app/etc/supervisord.conf b/test_app/etc/supervisord.conf index e965071..02b5847 100644 --- a/test_app/etc/supervisord.conf +++ b/test_app/etc/supervisord.conf @@ -33,7 +33,7 @@ startretries = 9999 [program:graphql_api] directory=/app -command=gunicorn --reload -k platformics.api.uvicorn_worker.ReloadingWorker -c /app/etc/gunicorn_conf.py main:app +command=gunicorn --reload -k platformics.graphql_api.uvicorn_worker.ReloadingWorker -c /app/etc/gunicorn_conf.py main:app environment=PYTHONUNBUFFERED=1,PYTHONPATH=. stderr_logfile = /dev/stderr stderr_logfile_maxbytes=0 diff --git a/test_app/main.py b/test_app/main.py index db4ccd7..cf856fb 100644 --- a/test_app/main.py +++ b/test_app/main.py @@ -4,13 +4,13 @@ import strawberry import uvicorn -from platformics.api.setup import get_app, get_strawberry_config -from platformics.api.core.error_handler import HandleErrors +from platformics.graphql_api.setup import get_app, get_strawberry_config +from platformics.graphql_api.core.error_handler import HandleErrors from platformics.settings import APISettings from database import models -from api.mutations import Mutation -from api.queries import Query +from graphql_api.mutations import Mutation +from graphql_api.queries import Query settings = APISettings.model_validate({}) # Workaround for https://github.com/pydantic/pydantic/issues/3753 schema = strawberry.Schema(query=Query, mutation=Mutation, config=get_strawberry_config(), extensions=[HandleErrors()]) From ac937a08d4a3453e127d82510a4480f6bf8fbaf2 Mon Sep 17 00:00:00 2001 From: Nina Bernick Date: Thu, 25 Jul 2024 16:55:49 -0700 Subject: [PATCH 3/3] remove docker-compose-dev --- docker-compose-dev.yml | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 docker-compose-dev.yml diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml deleted file mode 100644 index 2128258..0000000 --- a/docker-compose-dev.yml +++ /dev/null @@ -1,42 +0,0 @@ -version: "3.8" - -services: - dev-app: - image: "platformics-dev-app" - build: - context: "." - dockerfile: "Dockerfile.dev" - args: - - BUILDKIT_INLINE_CACHE=1 - restart: always - ports: - - "9008:9008" - - "9009:9009" - environment: - - PYTHONPATH=. - - CERBOS_URL=http://cerbos:3692 - - PLATFORMICS_DATABASE_HOST=platformics-db.platformics - - PLATFORMICS_DATABASE_PORT=5432 - - PLATFORMICS_DATABASE_USER=postgres - - PLATFORMICS_DATABASE_PASSWORD=password_postgres - - PLATFORMICS_DATABASE_NAME=platformics - - DEFAULT_UPLOAD_BUCKET=local-bucket - - DEFAULT_UPLOAD_PROTOCOL=s3 - - OUTPUT_S3_PREFIX=platformics - - BOTO_ENDPOINT_URL=http://motoserver.platformics:4000 - - AWS_REGION=us-west-2 - - AWS_ACCESS_KEY_ID=test - - AWS_SECRET_ACCESS_KEY=test - # TODO - these are keypairs for testing only! Do not use in prod!! - - JWK_PUBLIC_KEY_FILE=/app/etc/public_key.pem - - JWK_PRIVATE_KEY_FILE=/app/etc/private_key.pem - volumes: - - ./test_app:/app - - .:/platformics - - ./platformics:/app/platformics - command: ["/usr/local/bin/supervisord", "-c", "/app/etc/supervisord.conf"] -networks: - default: - name: platformics - driver: overlay - attachable: true