From 211584ea2d42e4c581f103c6df84794409eea2eb Mon Sep 17 00:00:00 2001 From: psykose Date: Thu, 27 Jul 2023 13:54:14 +0000 Subject: [PATCH] testing/py3-dataclasses-serialization: new aport https://github.com/madman-bob/python-dataclasses-serialization Serialize/deserialize Python dataclasses --- .../py3-dataclasses-serialization/APKBUILD | 61 ++++ .../UNKNOWN-0.0.0.dist-info/METADATA | 4 + .../UNKNOWN-0.0.0.dist-info/RECORD | 4 + .../UNKNOWN-0.0.0.dist-info/WHEEL | 5 + .../UNKNOWN-0.0.0.dist-info/top_level.txt | 1 + .../more_properties-1.1.1.dist-info/LICENSE | 21 ++ .../more_properties-1.1.1.dist-info/METADATA | 285 ++++++++++++++++++ .../more_properties-1.1.1.dist-info/RECORD | 11 + .../more_properties-1.1.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../more_properties/__init__.py | 24 ++ .../more_properties/cached_property.py | 119 ++++++++ .../more_properties/class_property.py | 38 +++ .../more_properties/property.py | 63 ++++ .../more_properties/types.py | 22 ++ .../more_properties/util_properties.py | 52 ++++ .../py3-dataclasses-serialization/root.patch | 15 + 17 files changed, 731 insertions(+) create mode 100644 testing/py3-dataclasses-serialization/APKBUILD create mode 100644 testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/METADATA create mode 100644 testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/RECORD create mode 100644 testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/WHEEL create mode 100644 testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/top_level.txt create mode 100644 testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/LICENSE create mode 100644 testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/METADATA create mode 100644 testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/RECORD create mode 100644 testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/WHEEL create mode 100644 testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/top_level.txt create mode 100644 testing/py3-dataclasses-serialization/more_properties/__init__.py create mode 100644 testing/py3-dataclasses-serialization/more_properties/cached_property.py create mode 100644 testing/py3-dataclasses-serialization/more_properties/class_property.py create mode 100644 testing/py3-dataclasses-serialization/more_properties/property.py create mode 100644 testing/py3-dataclasses-serialization/more_properties/types.py create mode 100644 testing/py3-dataclasses-serialization/more_properties/util_properties.py create mode 100644 testing/py3-dataclasses-serialization/root.patch diff --git a/testing/py3-dataclasses-serialization/APKBUILD b/testing/py3-dataclasses-serialization/APKBUILD new file mode 100644 index 00000000000..d94a7bc15eb --- /dev/null +++ b/testing/py3-dataclasses-serialization/APKBUILD @@ -0,0 +1,61 @@ +# Maintainer: psykose +pkgname=py3-dataclasses-serialization +pkgver=1.3.1 +pkgrel=0 +pkgdesc="Serialize/deserialize Python dataclasses" +url="https://github.com/madman-bob/python-dataclasses-serialization" +arch="noarch" +license="MIT" +depends=" + py3-more-properties + py3-toolz + py3-toposort + py3-typing_inspect + " +makedepends=" + py3-gpep517 + py3-setuptools + py3-wheel + " +checkdepends=" + py3-pytest-forked + py3-pytest-xdist + " +subpackages="$pkgname-pyc" +source="$pkgname-$pkgver.tar.gz::https://github.com/madman-bob/python-dataclasses-serialization/archive/refs/tags/$pkgver.tar.gz + $pkgname-fix-deserialize.patch::https://github.com/madman-bob/python-dataclasses-serialization/commit/00fbd280034abeff277523a6579f14d10e8427a2.diff + root.patch + " +builddir="$srcdir/python-dataclasses-serialization-$pkgver/" + +prepare() { + default_prepare + + # fixup location + mv pypi_upload/setup.py . +} + +build() { + gpep517 build-wheel \ + --wheel-dir .dist \ + --output-fd 3 3>&1 >&2 +} + +check() { + python3 -m venv --clear --without-pip --system-site-packages .testenv + .testenv/bin/python3 -m installer .dist/*.whl + # https://github.com/madman-bob/python-dataclasses-serialization/issues/16 + .testenv/bin/python3 -m pytest -n auto --forked \ + -k 'not test_json_serialization_types' +} + +package() { + python3 -m installer -d "$pkgdir" \ + .dist/*.whl +} + +sha512sums=" +5dc3569675749c82aaf1d9a8e2507fa9a2ee2bb14d6cb082fde15a108e4651afbdb0b1d6c8ca60dca839206abfca2c10b0fc9efe4867e521c1522a7a68b8a7c1 py3-dataclasses-serialization-1.3.1.tar.gz +4febeff6f08f12267fdceb1243449099c16002c3731cdde80a841a3d63fcb27333ae871fd8d05f45ee8881eccc77b69e8bc6b737ccb49d3c55cb008b49e32762 py3-dataclasses-serialization-fix-deserialize.patch +78c1714b7373586fcf67adc5dd3ec39b42f9f4cd03cad705d568cbc45de10f506e04a76d112b5cc6ea9b3e0e110f32dd4b9163a3eddeecc1fc94237887b4ed45 root.patch +" diff --git a/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/METADATA b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/METADATA new file mode 100644 index 00000000000..3657e4a7a58 --- /dev/null +++ b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/METADATA @@ -0,0 +1,4 @@ +Metadata-Version: 2.1 +Name: UNKNOWN +Version: 0.0.0 + diff --git a/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/RECORD b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/RECORD new file mode 100644 index 00000000000..4510c310e8f --- /dev/null +++ b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/RECORD @@ -0,0 +1,4 @@ +UNKNOWN-0.0.0.dist-info/METADATA,sha256=-waPzueBeQZEhNDwrQ6SrCv-VlDxcEe0StZKrgA5-uA,52 +UNKNOWN-0.0.0.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92 +UNKNOWN-0.0.0.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +UNKNOWN-0.0.0.dist-info/RECORD,, diff --git a/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/WHEEL b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/WHEEL new file mode 100644 index 00000000000..d272f6ed555 --- /dev/null +++ b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/top_level.txt b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/top_level.txt new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/testing/py3-dataclasses-serialization/UNKNOWN-0.0.0.dist-info/top_level.txt @@ -0,0 +1 @@ + diff --git a/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/LICENSE b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/LICENSE new file mode 100644 index 00000000000..ab602974d20 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/METADATA b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/METADATA new file mode 100644 index 00000000000..dc1e69e698b --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/METADATA @@ -0,0 +1,285 @@ +Metadata-Version: 2.1 +Name: more-properties +Version: 1.1.1 +Summary: A collection of property variants +Home-page: https://github.com/madman-bob/python-more-properties +Author: Robert Wright +Author-email: madman.bob@hotmail.co.uk +License: MIT +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: dataclasses + +# `more_properties` + +A collection of `property` variants. + +## Basic Usage + +Variants behave mostly as the built-in `property`, except where noted. + +Given the following class, + +```python +from more_properties import property, class_property, static_property + + +class Parrot: + @property + def name(self): + return "Fred" + + @class_property + def order(cls): + return Psittaciformes + + @static_property + def planet(): + return Earth +``` + +the properties may be accessed like so: + +```pycon +>>> Parrot().name +'Fred' +>>> Parrot.order + +>>> Parrot.planet + +``` + +## Setters/Deleters + +Setters and deleters are defined in the same way as the built-in `property`. +Either with the decorator method + +```python +from more_properties import class_property + + +class Foo: + name = "Foo" + + @class_property + def identifier(cls): + """Object identifier""" + return cls.name.lower() + + @identifier.setter + def identifier(cls, value): + cls.name = value.title() + + @identifier.deleter + def identifier(cls): + cls.name = None +``` + +or the inline method + +```python +from more_properties import class_property + + +class Foo: + name = "Foo" + + @classmethod + def get_identifier(cls): + return cls.name.lower() + + @classmethod + def set_identifier(cls, value): + cls.name = value.title() + + @classmethod + def del_identifier(cls): + cls.name = None + + identifier = class_property( + get_identifier, + set_identifier, + del_identifier, + "Object identifier" + ) +``` + +## Reference + +### `property` + +A modified version of the built-in [`property`](https://docs.python.org/3/library/functions.html#property). + +Always behaves as a +[data descriptor](https://docs.python.org/3/howto/descriptor.html#descriptor-protocol), +regardless of which (if any) of getter, setter, and deleter are set. + +Behaviour when accessed on a class, is undefined. + +### `class_property` + +A `property` for classes. +Both `cls.x` and `instance.x` call the getter with the class. +Setting `instance.x` calls the setter with the class and value. +Deleting `instance.x` call the deleter with the class only. + +```python +from more_properties import class_property + + +class Foo: + @class_property + def identifier(cls): + """Class identifier""" + return cls.__name__.lower() + + +class Bar(Foo): + pass +``` + +```pycon +>>> Foo.identifier +'foo' +>>> Foo().identifier +'foo' +``` + +```pycon +>>> Bar.identifier +'bar' +>>> Bar().identifier +'bar' +``` + +`classproperty` provided as a synonym, for consistency with `classmethod`. + + + +### `static_property` + +A `property` independent of its accessor. +Both `cls.x` and `instance.x` call the getter with no parameters. +Setting `instance.x` calls the setter with the value only. +Deleting `instance.x` call the deleter with no parameters. + +```python +from more_properties import static_property + + +x = "bar" + +class Foo: + @static_property + def val(): + return x +``` + +```pycon +>>> Foo.val +'bar' +>>> Foo().val +'bar' +``` + +`staticproperty` provided as a synonym, for consistency with `staticmethod`. + + + +### `cached_property` +### `cached_class_property` +### `cached_static_property` + +Variants of `property`, `class_property`, and `static_property`, respectively. + +They are each used in the same way as the originals, +but cache the value of the getters. + +```python +from dataclasses import dataclass + +from more_properties import cached_property + + +@dataclass +class Foo: + x: int + + @cached_property + def y(self): + print("Doing work") + return self.x + 1 +``` + +```pycon +>>> bar = Foo(1) +>>> bar.y +Doing work +2 +>>> bar.y +2 +``` + +If the setters/deleters are defined, +then the cache is cleared before they are called. + +Further, the cache may be explicitly cleared through the `clear_cache` method, +exposed only during class creation. + +```python +@dataclass +class Foo: + x: int + + @cached_property + def y(self): + print("Doing work") + return self.x + 1 + + y_clear_cache = y.clear_cache +``` + +```pycon +>>> bar = Foo(1) +>>> bar.y +Doing work +2 +>>> bar.y +2 +>>> bar.y_clear_cache() +>>> bar.y +Doing work +2 +``` + +## Installation + +Install and update using the standard Python package manager [pip](https://pip.pypa.io/en/stable/): + +```bash +pip install more_properties +``` diff --git a/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/RECORD b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/RECORD new file mode 100644 index 00000000000..23a77a218ff --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/RECORD @@ -0,0 +1,11 @@ +more_properties/__init__.py,sha256=u1TijuEfL1JuqNhP5_XJkdQ941liKPYs52rC3ztWvr8,604 +more_properties/cached_property.py,sha256=k8QHAjCOgSsYkb1pId2agSG7Mm3qu82R4iS9YIewt9o,3376 +more_properties/class_property.py,sha256=pSUkG9zQ6X7y8UKeJPFkpOvHi2831kdj8kGEGnKzxfE,964 +more_properties/property.py,sha256=KtGr88bxxLKneHp-axVOi5BiyEp3dzV3FfCYJanKFSc,1744 +more_properties/types.py,sha256=4EDzgwr4X3iymUKIzqyEuyoNX160_RZDEfBZ5fD3vHU,656 +more_properties/util_properties.py,sha256=93050PQimdHN9OT1of0yPkC5OOPMHhlE40u-5Iaw6L8,1385 +more_properties-1.1.1.dist-info/LICENSE,sha256=g-TdIUKakft86mekdgMqlkFCXlNV3y4PWJpzi27J_Sw,1057 +more_properties-1.1.1.dist-info/METADATA,sha256=b1BMTg6DT5urMGhBmdzjUjd8fwC_rd5jkh1yPbIZX5o,5694 +more_properties-1.1.1.dist-info/WHEEL,sha256=AtBG6SXL3KF_v0NxLf0ehyVOh0cold-JbJYXNGorC6Q,92 +more_properties-1.1.1.dist-info/top_level.txt,sha256=YFJwQUwzeEb2V96cOjyK60NaqnYdMV0LPL-CGwUfGKc,16 +more_properties-1.1.1.dist-info/RECORD,, diff --git a/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/WHEEL b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/WHEEL new file mode 100644 index 00000000000..d272f6ed555 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/top_level.txt b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/top_level.txt new file mode 100644 index 00000000000..f6e0903b0aa --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties-1.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +more_properties diff --git a/testing/py3-dataclasses-serialization/more_properties/__init__.py b/testing/py3-dataclasses-serialization/more_properties/__init__.py new file mode 100644 index 00000000000..d424356d809 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/__init__.py @@ -0,0 +1,24 @@ +from more_properties.cached_property import ( + cached_class_property, + cached_property, + cached_static_property, +) +from more_properties.class_property import class_property, static_property +from more_properties.property import property + +__all__ = [ + "property", + "class_property", + "classproperty", + "static_property", + "staticproperty", + "cached_property", + "cached_class_property", + "cached_static_property", +] + +__version__ = "1.1.1" + +# Providing aliases for consistency with classmethod and staticmethod +classproperty = class_property +staticproperty = static_property diff --git a/testing/py3-dataclasses-serialization/more_properties/cached_property.py b/testing/py3-dataclasses-serialization/more_properties/cached_property.py new file mode 100644 index 00000000000..4a5a566da6c --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/cached_property.py @@ -0,0 +1,119 @@ +from dataclasses import dataclass +from typing import Optional, Type, TypeVar, Union + +from more_properties.class_property import ClassProperty, StaticProperty +from more_properties.types import Deleter +from more_properties.util_properties import NamedProperty + +__all__ = [ + "cached_property", + "cached_class_property", + "cached_static_property", +] + +OT = TypeVar("OT", contravariant=True) # Owner Type +VT = TypeVar("VT") # Value Type + + +class Uncached: + pass + + +Cache = Union[VT, Uncached] + + +@dataclass +class CachedProperty(NamedProperty[OT, VT]): + @property + def cache_name(self) -> str: + if self.name is None: + raise AttributeError(f"Property {self!r} not assigned to class") + + return f"__{self.name}_cache" + + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT: + cache_name = self.cache_name + + if cache_name not in instance.__dict__: + instance.__dict__[cache_name] = super().__get__(instance, owner) + + value: VT = instance.__dict__[cache_name] + + return value + + def __set__(self, instance: OT, value: VT) -> None: + # Mypy seems to unwrap the descriptor recursively, while Python only does it once + clear_cache: Deleter[OT] = self.clear_cache # type: ignore + + clear_cache.__get__(instance, type(instance))() + + super().__set__(instance, value) + + def __delete__(self, instance: OT) -> None: + # Mypy seems to unwrap the descriptor recursively, while Python only does it once + clear_cache: Deleter[OT] = self.clear_cache # type: ignore + + clear_cache.__get__(instance, type(instance))() + + super().__delete__(instance) + + @property + def clear_cache(self) -> Deleter[OT]: + def clear_cache(instance: OT) -> None: + cache_name = self.cache_name + + if cache_name in instance.__dict__: + delattr(instance, cache_name) + + # Mypy doesn't recognize functions as Getable + return clear_cache # type: ignore + + +@dataclass +class CachedClassProperty(CachedProperty[OT, VT], ClassProperty[OT, VT]): + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT: + cache_name = self.cache_name + + if cache_name in owner.__dict__: + value: VT = owner.__dict__[cache_name] + + return value + + value = super(CachedProperty, self).__get__(instance, owner) + + setattr(owner, cache_name, value) + + return value + + @property + def clear_cache(self) -> Deleter[OT]: + def clear_cache(owner: Type[OT]) -> None: + cache_name = self.cache_name + + if cache_name in owner.__dict__: + delattr(owner, cache_name) + + return classmethod(clear_cache) + + +@dataclass +class CachedStaticProperty(CachedProperty[OT, VT], StaticProperty[OT, VT]): + value: Cache[VT] = Uncached() + + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT: + if isinstance(self.value, Uncached): + self.value = super(CachedProperty, self).__get__(instance, owner) + + return self.value + + @property + def clear_cache(self) -> Deleter[OT]: + def clear_cache() -> None: + self.value = Uncached() + + return staticmethod(clear_cache) + + +cached_property = CachedProperty +cached_class_property = CachedClassProperty +cached_static_property = CachedStaticProperty diff --git a/testing/py3-dataclasses-serialization/more_properties/class_property.py b/testing/py3-dataclasses-serialization/more_properties/class_property.py new file mode 100644 index 00000000000..3b561f77465 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/class_property.py @@ -0,0 +1,38 @@ +from typing import TypeVar + +from more_properties.util_properties import WrappedProperty + +__all__ = [ + "ClassProperty", + "class_property", + "StaticProperty", + "static_property", +] + +OT = TypeVar("OT", contravariant=True) # Owner Type +VT = TypeVar("VT") # Value Type + + +class ClassProperty(WrappedProperty[OT, VT]): + wrapper = classmethod + + def __post_init__(self) -> None: + fget = self.__dict__["fget"] + + if isinstance(fget, self.wrapper): + fget.__doc__ = fget.__func__.__doc__ + + super().__post_init__() + + +class StaticProperty(ClassProperty[OT, VT]): + wrapper = staticmethod + + +# For some reason, Python 3.6 treats classmethod and staticmethod as abstract methods, +# disallowing instantiation of ClassProperty and StaticProperty +setattr(ClassProperty, "__abstractmethods__", frozenset()) +setattr(StaticProperty, "__abstractmethods__", frozenset()) + +class_property = ClassProperty +static_property = StaticProperty diff --git a/testing/py3-dataclasses-serialization/more_properties/property.py b/testing/py3-dataclasses-serialization/more_properties/property.py new file mode 100644 index 00000000000..29b18083e05 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/property.py @@ -0,0 +1,63 @@ +from dataclasses import dataclass, replace +from typing import Generic, Optional, Type, TypeVar + +from more_properties.types import Deleter, Getter, Setter + +__all__ = [ + "Property", + "property", +] + +OT = TypeVar("OT", contravariant=True) # Owner Type +VT = TypeVar("VT") # Value Type + + +@dataclass +class Property(Generic[OT, VT]): + fget: Optional[Getter[OT, VT]] = None + fset: Optional[Setter[OT, VT]] = None + fdel: Optional[Deleter[OT]] = None + doc: Optional[str] = None + + def __post_init__(self) -> None: + self.__doc__ = ( + self.doc + if self.doc is not None + else getattr(self.__dict__.get("fget"), "__doc__", None) + ) + + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT: + fget: Optional[Getter[OT, VT]] = self.__dict__["fget"] + + if fget is None: + raise AttributeError("unreadable attribute") + + return fget.__get__(instance, owner)() + + def __set__(self, instance: OT, value: VT) -> None: + fset = self.__dict__["fset"] + + if fset is None: + raise AttributeError("can't set attribute") + + fset.__get__(instance, type(instance))(value) + + def __delete__(self, instance: OT) -> None: + fdel = self.__dict__["fdel"] + + if fdel is None: + raise AttributeError("can't delete attribute") + + fdel.__get__(instance, type(instance))() + + def getter(self, func: Getter[OT, VT]) -> "Property[OT, VT]": + return replace(self, fget=func) + + def setter(self, func: Setter[OT, VT]) -> "Property[OT, VT]": + return replace(self, fset=func) + + def deleter(self, func: Deleter[OT]) -> "Property[OT, VT]": + return replace(self, fdel=func) + + +property = Property diff --git a/testing/py3-dataclasses-serialization/more_properties/types.py b/testing/py3-dataclasses-serialization/more_properties/types.py new file mode 100644 index 00000000000..1499d4077b8 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/types.py @@ -0,0 +1,22 @@ +from typing import Callable, Generic, Optional, Type, TypeVar + +__all__ = ["Getable", "Getter", "Setter", "Deleter"] + +OT = TypeVar("OT", contravariant=True) # Owner Type +VT_co = TypeVar("VT_co", covariant=True) # Covariant Value Type +VT_contra = TypeVar("VT_contra", contravariant=True) # Contravariant Value Type + +try: + from typing import Protocol +except ImportError: + Protocol = Generic + + +class Getable(Protocol[OT, VT_co]): + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT_co: + ... + + +Getter = Getable[OT, Callable[[], VT_co]] +Setter = Getable[OT, Callable[[VT_contra], None]] +Deleter = Getable[OT, Callable[[], None]] diff --git a/testing/py3-dataclasses-serialization/more_properties/util_properties.py b/testing/py3-dataclasses-serialization/more_properties/util_properties.py new file mode 100644 index 00000000000..744c2610606 --- /dev/null +++ b/testing/py3-dataclasses-serialization/more_properties/util_properties.py @@ -0,0 +1,52 @@ +from dataclasses import dataclass +from typing import Generic, Optional, Type, TypeVar + +from more_properties.property import Property +from more_properties.types import Getable + +__all__ = [ + "NamedProperty", + "WrappedProperty", +] + +OT = TypeVar("OT", contravariant=True) # Owner Type +VT = TypeVar("VT") # Value Type + + +@dataclass +class NamedProperty(Property[OT, VT]): + name: Optional[str] = None + + def __set_name__(self, owner: Type[OT], name: str) -> None: + self.name = name + + +@dataclass +class TrivialWrapper(Generic[OT, VT]): + getable: Getable[OT, VT] + + def __get__(self, instance: Optional[OT], owner: Type[OT]) -> VT: + getable: Getable[OT, VT] = self.__dict__["getable"] + return getable.__get__(instance, owner) + + +class WrappedProperty(Property[OT, VT]): + wrapper: type = TrivialWrapper + + def __post_init__(self) -> None: + fget = self.__dict__["fget"] + + if fget is not None and not isinstance(fget, self.wrapper): + setattr(self, "fget", self.wrapper(fget)) + + fset = self.__dict__["fset"] + + if fset is not None and not isinstance(fset, self.wrapper): + setattr(self, "fset", self.wrapper(fset)) + + fdel = self.__dict__["fdel"] + + if fdel is not None and not isinstance(fdel, self.wrapper): + setattr(self, "fdel", self.wrapper(fdel)) + + super().__post_init__() diff --git a/testing/py3-dataclasses-serialization/root.patch b/testing/py3-dataclasses-serialization/root.patch new file mode 100644 index 00000000000..19200dbd54e --- /dev/null +++ b/testing/py3-dataclasses-serialization/root.patch @@ -0,0 +1,15 @@ +diff --git a/pypi_upload/setup.py b/pypi_upload/setup.py +index cd56011..427bcc9 100644 +--- a/pypi_upload/setup.py ++++ b/pypi_upload/setup.py +@@ -6,8 +6,8 @@ from pathlib import Path + from setuptools import find_packages, setup + from setuptools.command.install import install + +-project_root = Path(__file__).parents[1] +- ++import pathlib ++project_root = pathlib.Path().resolve() + + class VerifyCommand(install): + """Custom command to verify module integrity"""