mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2026-05-04 12:01:41 +02:00
testing/py3-dataclasses-serialization: new aport
https://github.com/madman-bob/python-dataclasses-serialization Serialize/deserialize Python dataclasses
This commit is contained in:
parent
899917d331
commit
211584ea2d
61
testing/py3-dataclasses-serialization/APKBUILD
Normal file
61
testing/py3-dataclasses-serialization/APKBUILD
Normal file
@ -0,0 +1,61 @@
|
||||
# Maintainer: psykose <alice@ayaya.dev>
|
||||
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
|
||||
"
|
||||
@ -0,0 +1,4 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: UNKNOWN
|
||||
Version: 0.0.0
|
||||
|
||||
@ -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,,
|
||||
@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.41.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -0,0 +1 @@
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
<class 'Psittaciformes'>
|
||||
>>> Parrot.planet
|
||||
<class 'Earth'>
|
||||
```
|
||||
|
||||
## 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`.
|
||||
|
||||
<aside class="warning">
|
||||
<p>
|
||||
Due to the
|
||||
<a href="https://docs.python.org/3/reference/datamodel.html#object.__set__">Python data model</a>,
|
||||
using the setters/deleters on <em>classes</em> may not work as intended.
|
||||
</p>
|
||||
<p>
|
||||
Getters always work as intended, and using setters/deleters on <em>instances</em> work as intended.
|
||||
</p>
|
||||
</aside>
|
||||
|
||||
### `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`.
|
||||
|
||||
<aside class="warning">
|
||||
<p>
|
||||
Due to the
|
||||
<a href="https://docs.python.org/3/reference/datamodel.html#object.__set__">Python data model</a>,
|
||||
using the setters/deleters on <em>classes</em> may not work as intended.
|
||||
</p>
|
||||
<p>
|
||||
Getters always work as intended, and using setters/deleters on <em>instances</em> work as intended.
|
||||
</p>
|
||||
</aside>
|
||||
|
||||
### `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
|
||||
```
|
||||
@ -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,,
|
||||
@ -0,0 +1,5 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.41.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -0,0 +1 @@
|
||||
more_properties
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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]]
|
||||
@ -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__()
|
||||
15
testing/py3-dataclasses-serialization/root.patch
Normal file
15
testing/py3-dataclasses-serialization/root.patch
Normal file
@ -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"""
|
||||
Loading…
x
Reference in New Issue
Block a user