diff --git a/.gitignore b/.gitignore index b637a1901..d5ab06eab 100644 --- a/.gitignore +++ b/.gitignore @@ -128,7 +128,6 @@ src/prisma/types.py src/prisma/enums.py src/prisma/client.py src/prisma/models.py -src/prisma/fields.py src/prisma/actions.py src/prisma/metadata.py src/prisma/partials.py diff --git a/pyproject.toml b/pyproject.toml index 7f08b82c0..8882bb1d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,6 @@ docstring-code-format = true "prisma.enums".msg = "This is a generated file, it should only be imported at runtime in other generated files." "prisma.types".msg = "This is a generated file, it should only be imported at runtime in other generated files." "prisma.client".msg = "This is a generated file, it should only be imported at runtime in other generated files." -"prisma.fields".msg = "This is a generated file, it should only be imported at runtime in other generated files." "prisma.models".msg = "This is a generated file, it should only be imported at runtime in other generated files." "prisma.actions".msg = "This is a generated file, it should only be imported at runtime in other generated files." "prisma.metadata".msg = "This is a generated file, it should only be imported at runtime in other generated files." diff --git a/src/prisma/generator/templates/fields.py.jinja b/src/prisma/_fields.py similarity index 84% rename from src/prisma/generator/templates/fields.py.jinja rename to src/prisma/_fields.py index 54fd41c53..496c26dfa 100644 --- a/src/prisma/generator/templates/fields.py.jinja +++ b/src/prisma/_fields.py @@ -1,12 +1,23 @@ -{% include '_header.py.jinja' %} -{% from '_utils.py.jinja' import recursive_types with context %} -# -- template fields.py.jinja -- -from typing_extensions import override -from ._compat import PYDANTIC_V2, CoreSchema, core_schema +from __future__ import annotations import base64 +from typing import ( + TYPE_CHECKING, + Any, + Dict, + List, + Union, + Iterator, + overload, +) +from typing_extensions import override + from pydantic import Json as _PydanticJson +from ._compat import PYDANTIC_V2, CoreSchema, core_schema + +if TYPE_CHECKING: + from .types import Serializable # noqa: TID251 __all__ = ( 'Json', @@ -35,14 +46,14 @@ # inherit from _PydanticJson so that pydantic will automatically # transform the json string into python objects. class Json(BaseJson): - data: 'Serializable' + data: Serializable - def __init__(self, data: 'Serializable') -> None: + def __init__(self, data: Serializable) -> None: self.data = data super().__init__() @classmethod - def keys(cls, **data: 'Serializable') -> 'Json': + def keys(cls, **data: Serializable) -> Json: return cls(data) if TYPE_CHECKING: @@ -68,15 +79,15 @@ def keys(cls, **data: 'Serializable') -> 'Json': # cast(Dict[str, Any], user.json_obj) # prisma.validate(ExpectedType, user.json_obj) # NOTE: not implemented yet @overload # type: ignore - def __getitem__(self, i: slice) -> List['Serializable']: + def __getitem__(self, i: slice) -> List[Serializable]: ... @overload - def __getitem__(self, i: '_JsonKeys') -> 'Serializable': + def __getitem__(self, i: _JsonKeys) -> Serializable: ... @override - def __getitem__(self, i: Union['_JsonKeys', slice]) -> 'Serializable': # pyright: ignore[reportIncompatibleMethodOverride] + def __getitem__(self, i: Union[_JsonKeys, slice]) -> Serializable: # pyright: ignore[reportIncompatibleMethodOverride] ... @@ -87,12 +98,12 @@ def __init__(self, raw: bytes) -> None: self._raw = raw @classmethod - def encode(cls, value: bytes) -> 'Base64': + def encode(cls, value: bytes) -> Base64: """Encode bytes into valid Base64""" return cls(base64.b64encode(value)) @classmethod - def fromb64(cls, value: Union[str, bytes]) -> 'Base64': + def fromb64(cls, value: Union[str, bytes]) -> Base64: """ Create an instance of the `Base64` class from data that has already been encoded into a valid base 64 structure. @@ -123,6 +134,7 @@ def decode_str(self, encoding: str = 'utf-8') -> str: # Support OpenAPI schema generation if PYDANTIC_V2: + @classmethod def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: Any) -> Any: json_schema = handler(core_schema) @@ -131,6 +143,7 @@ def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: Any) -> json_schema['format'] = 'byte' return json_schema else: + @classmethod def __modify_schema__(cls, field_schema: Dict[str, object]) -> None: field_schema['type'] = 'string' @@ -138,6 +151,7 @@ def __modify_schema__(cls, field_schema: Dict[str, object]) -> None: # Support converting objects into Base64 at the Pydantic level if PYDANTIC_V2: + @classmethod def __get_pydantic_core_schema__( cls, @@ -148,17 +162,16 @@ def __get_pydantic_core_schema__( return core_schema.no_info_before_validator_function( cls._validate, schema=core_schema.any_schema(), - serialization=core_schema.plain_serializer_function_ser_schema( - lambda instance: str(instance) - ) + serialization=core_schema.plain_serializer_function_ser_schema(lambda instance: str(instance)), ) else: + @classmethod def __get_validators__(cls) -> Iterator[object]: yield cls._validate @classmethod - def _validate(cls, value: object) -> 'Base64': + def _validate(cls, value: object) -> Base64: if isinstance(value, Base64): return value @@ -169,9 +182,7 @@ def _validate(cls, value: object) -> 'Base64': if isinstance(value, bytes): return cls(value) - raise ValueError( - f'Could not convert type: {type(value)} to a Base64 object; Expected a string or bytes object' - ) + raise ValueError(f'Could not convert type: {type(value)} to a Base64 object; Expected a string or bytes object') @override def __str__(self) -> str: @@ -187,6 +198,3 @@ def __eq__(self, other: Any) -> bool: return self._raw == other._raw return False - - -from .types import Serializable diff --git a/src/prisma/fields.py b/src/prisma/fields.py new file mode 100644 index 000000000..8e1f80c64 --- /dev/null +++ b/src/prisma/fields.py @@ -0,0 +1 @@ +from ._fields import * diff --git a/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_async[fields.py].raw b/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_async[fields.py].raw deleted file mode 100644 index 4078ae710..000000000 --- a/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_async[fields.py].raw +++ /dev/null @@ -1,231 +0,0 @@ -''' -# -*- coding: utf-8 -*- -# code generated by Prisma. DO NOT EDIT. -# pyright: reportUnusedImport=false -# fmt: off - -# global imports for type checking -from builtins import bool as _bool -from builtins import int as _int -from builtins import float as _float -from builtins import str as _str -import sys -import decimal -import datetime -from typing import ( - TYPE_CHECKING, - Optional, - Iterable, - Iterator, - Sequence, - Callable, - ClassVar, - NoReturn, - TypeVar, - Generic, - Mapping, - Tuple, - Union, - List, - Dict, - Type, - Any, - Set, - overload, - cast, -) -from typing_extensions import TypedDict, Literal - - -LiteralString = str -# -- template fields.py.jinja -- -from typing_extensions import override -from ._compat import PYDANTIC_V2, CoreSchema, core_schema - -import base64 -from pydantic import Json as _PydanticJson - - -__all__ = ( - 'Json', - 'Base64', -) - - -if TYPE_CHECKING: - BaseJson = str -else: - BaseJson = _PydanticJson - -_JsonKeys = Union[ - None, - bool, - float, - int, - str, -] - -# Base64 data should only be valid ascii, we limit our encoding to ascii so that -# any erroneous data is caught as early on as possible. -BASE64_ENCODING = 'ascii' - - -# inherit from _PydanticJson so that pydantic will automatically -# transform the json string into python objects. -class Json(BaseJson): - data: 'Serializable' - - def __init__(self, data: 'Serializable') -> None: - self.data = data - super().__init__() - - @classmethod - def keys(cls, **data: 'Serializable') -> 'Json': - return cls(data) - - if TYPE_CHECKING: - # Fields that are of the `Json` type are automatically - # de-serialized from json to the corresponding python type - # when the model is created, e.g. - # - # User(json_obj='{"foo": null}') -> User(json_obj={'foo': None}) - # - # As we don't know what the type will actually be at runtime - # we add methods here for convenience so that naive access - # to the field is still allowed, e.g. - # - # user.json_obj['foo'] - # user.json_obj[1] - # user.json_obj[1:5] - # - # It should be noted that users will still have - # to validate / cast fields to the type they are expecting - # for any strict type binding or nested index calls to work, e.g. - # - # isinstance(user.json_obj, dict) - # cast(Dict[str, Any], user.json_obj) - # prisma.validate(ExpectedType, user.json_obj) # NOTE: not implemented yet - @overload # type: ignore - def __getitem__(self, i: slice) -> List['Serializable']: - ... - - @overload - def __getitem__(self, i: '_JsonKeys') -> 'Serializable': - ... - - @override - def __getitem__(self, i: Union['_JsonKeys', slice]) -> 'Serializable': # pyright: ignore[reportIncompatibleMethodOverride] - ... - - -class Base64: - __slots__ = ('_raw',) - - def __init__(self, raw: bytes) -> None: - self._raw = raw - - @classmethod - def encode(cls, value: bytes) -> 'Base64': - """Encode bytes into valid Base64""" - return cls(base64.b64encode(value)) - - @classmethod - def fromb64(cls, value: Union[str, bytes]) -> 'Base64': - """ - Create an instance of the `Base64` class from data that has already - been encoded into a valid base 64 structure. - """ - if isinstance(value, bytes): - return cls(value) - - return cls(value.encode(BASE64_ENCODING)) - - def decode(self) -> bytes: - """Decode from Base64 to the original bytes object""" - return base64.b64decode(self._raw) - - # NOTE: we explicitly use a different encoding here as we are decoding - # to the original data provided by the user, this data does not have - # the limitation of being ascii only that the raw Base64 data does - def decode_str(self, encoding: str = 'utf-8') -> str: - """Decode from Base64 to the original string - - This decodes using the `utf-8` encoding by default, - you can customise the encoding like so: - - ```py - value = b64.decode_str('ascii') - ``` - """ - return self.decode().decode(encoding) - - # Support OpenAPI schema generation - if PYDANTIC_V2: - @classmethod - def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: Any) -> Any: - json_schema = handler(core_schema) - json_schema = handler.resolve_ref_schema(json_schema) - json_schema['type'] = 'string' - json_schema['format'] = 'byte' - return json_schema - else: - @classmethod - def __modify_schema__(cls, field_schema: Dict[str, object]) -> None: - field_schema['type'] = 'string' - field_schema['format'] = 'byte' - - # Support converting objects into Base64 at the Pydantic level - if PYDANTIC_V2: - @classmethod - def __get_pydantic_core_schema__( - cls, - source_type: Any, - *args: Any, - **kwargs: Any, - ) -> CoreSchema: - return core_schema.no_info_before_validator_function( - cls._validate, - schema=core_schema.any_schema(), - serialization=core_schema.plain_serializer_function_ser_schema( - lambda instance: str(instance) - ) - ) - else: - @classmethod - def __get_validators__(cls) -> Iterator[object]: - yield cls._validate - - @classmethod - def _validate(cls, value: object) -> 'Base64': - if isinstance(value, Base64): - return value - - # TODO: validate that the structure of the input is valid too? - if isinstance(value, str): - return cls(bytes(value, BASE64_ENCODING)) - - if isinstance(value, bytes): - return cls(value) - - raise ValueError( - f'Could not convert type: {type(value)} to a Base64 object; Expected a string or bytes object' - ) - - @override - def __str__(self) -> str: - return self._raw.decode(BASE64_ENCODING) - - @override - def __repr__(self) -> str: - return f'{self.__class__.__name__}({self._raw})' # type: ignore[str-bytes-safe] - - @override - def __eq__(self, other: Any) -> bool: - if isinstance(other, Base64): - return self._raw == other._raw - - return False - - -from .types import Serializable -''' \ No newline at end of file diff --git a/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_sync[fields.py].raw b/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_sync[fields.py].raw deleted file mode 100644 index 4078ae710..000000000 --- a/tests/test_generation/exhaustive/__snapshots__/test_exhaustive/test_sync[fields.py].raw +++ /dev/null @@ -1,231 +0,0 @@ -''' -# -*- coding: utf-8 -*- -# code generated by Prisma. DO NOT EDIT. -# pyright: reportUnusedImport=false -# fmt: off - -# global imports for type checking -from builtins import bool as _bool -from builtins import int as _int -from builtins import float as _float -from builtins import str as _str -import sys -import decimal -import datetime -from typing import ( - TYPE_CHECKING, - Optional, - Iterable, - Iterator, - Sequence, - Callable, - ClassVar, - NoReturn, - TypeVar, - Generic, - Mapping, - Tuple, - Union, - List, - Dict, - Type, - Any, - Set, - overload, - cast, -) -from typing_extensions import TypedDict, Literal - - -LiteralString = str -# -- template fields.py.jinja -- -from typing_extensions import override -from ._compat import PYDANTIC_V2, CoreSchema, core_schema - -import base64 -from pydantic import Json as _PydanticJson - - -__all__ = ( - 'Json', - 'Base64', -) - - -if TYPE_CHECKING: - BaseJson = str -else: - BaseJson = _PydanticJson - -_JsonKeys = Union[ - None, - bool, - float, - int, - str, -] - -# Base64 data should only be valid ascii, we limit our encoding to ascii so that -# any erroneous data is caught as early on as possible. -BASE64_ENCODING = 'ascii' - - -# inherit from _PydanticJson so that pydantic will automatically -# transform the json string into python objects. -class Json(BaseJson): - data: 'Serializable' - - def __init__(self, data: 'Serializable') -> None: - self.data = data - super().__init__() - - @classmethod - def keys(cls, **data: 'Serializable') -> 'Json': - return cls(data) - - if TYPE_CHECKING: - # Fields that are of the `Json` type are automatically - # de-serialized from json to the corresponding python type - # when the model is created, e.g. - # - # User(json_obj='{"foo": null}') -> User(json_obj={'foo': None}) - # - # As we don't know what the type will actually be at runtime - # we add methods here for convenience so that naive access - # to the field is still allowed, e.g. - # - # user.json_obj['foo'] - # user.json_obj[1] - # user.json_obj[1:5] - # - # It should be noted that users will still have - # to validate / cast fields to the type they are expecting - # for any strict type binding or nested index calls to work, e.g. - # - # isinstance(user.json_obj, dict) - # cast(Dict[str, Any], user.json_obj) - # prisma.validate(ExpectedType, user.json_obj) # NOTE: not implemented yet - @overload # type: ignore - def __getitem__(self, i: slice) -> List['Serializable']: - ... - - @overload - def __getitem__(self, i: '_JsonKeys') -> 'Serializable': - ... - - @override - def __getitem__(self, i: Union['_JsonKeys', slice]) -> 'Serializable': # pyright: ignore[reportIncompatibleMethodOverride] - ... - - -class Base64: - __slots__ = ('_raw',) - - def __init__(self, raw: bytes) -> None: - self._raw = raw - - @classmethod - def encode(cls, value: bytes) -> 'Base64': - """Encode bytes into valid Base64""" - return cls(base64.b64encode(value)) - - @classmethod - def fromb64(cls, value: Union[str, bytes]) -> 'Base64': - """ - Create an instance of the `Base64` class from data that has already - been encoded into a valid base 64 structure. - """ - if isinstance(value, bytes): - return cls(value) - - return cls(value.encode(BASE64_ENCODING)) - - def decode(self) -> bytes: - """Decode from Base64 to the original bytes object""" - return base64.b64decode(self._raw) - - # NOTE: we explicitly use a different encoding here as we are decoding - # to the original data provided by the user, this data does not have - # the limitation of being ascii only that the raw Base64 data does - def decode_str(self, encoding: str = 'utf-8') -> str: - """Decode from Base64 to the original string - - This decodes using the `utf-8` encoding by default, - you can customise the encoding like so: - - ```py - value = b64.decode_str('ascii') - ``` - """ - return self.decode().decode(encoding) - - # Support OpenAPI schema generation - if PYDANTIC_V2: - @classmethod - def __get_pydantic_json_schema__(cls, core_schema: CoreSchema, handler: Any) -> Any: - json_schema = handler(core_schema) - json_schema = handler.resolve_ref_schema(json_schema) - json_schema['type'] = 'string' - json_schema['format'] = 'byte' - return json_schema - else: - @classmethod - def __modify_schema__(cls, field_schema: Dict[str, object]) -> None: - field_schema['type'] = 'string' - field_schema['format'] = 'byte' - - # Support converting objects into Base64 at the Pydantic level - if PYDANTIC_V2: - @classmethod - def __get_pydantic_core_schema__( - cls, - source_type: Any, - *args: Any, - **kwargs: Any, - ) -> CoreSchema: - return core_schema.no_info_before_validator_function( - cls._validate, - schema=core_schema.any_schema(), - serialization=core_schema.plain_serializer_function_ser_schema( - lambda instance: str(instance) - ) - ) - else: - @classmethod - def __get_validators__(cls) -> Iterator[object]: - yield cls._validate - - @classmethod - def _validate(cls, value: object) -> 'Base64': - if isinstance(value, Base64): - return value - - # TODO: validate that the structure of the input is valid too? - if isinstance(value, str): - return cls(bytes(value, BASE64_ENCODING)) - - if isinstance(value, bytes): - return cls(value) - - raise ValueError( - f'Could not convert type: {type(value)} to a Base64 object; Expected a string or bytes object' - ) - - @override - def __str__(self) -> str: - return self._raw.decode(BASE64_ENCODING) - - @override - def __repr__(self) -> str: - return f'{self.__class__.__name__}({self._raw})' # type: ignore[str-bytes-safe] - - @override - def __eq__(self, other: Any) -> bool: - if isinstance(other, Base64): - return self._raw == other._raw - - return False - - -from .types import Serializable -''' \ No newline at end of file