diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | python-marshy.spec | 928 | ||||
| -rw-r--r-- | sources | 1 |
3 files changed, 930 insertions, 0 deletions
@@ -0,0 +1 @@ +/marshy-4.0.3.tar.gz diff --git a/python-marshy.spec b/python-marshy.spec new file mode 100644 index 0000000..1f4147b --- /dev/null +++ b/python-marshy.spec @@ -0,0 +1,928 @@ +%global _empty_manifest_terminate_build 0 +Name: python-marshy +Version: 4.0.3 +Release: 1 +Summary: A convention over configuration approach to object marshalling. +License: MIT License +URL: https://github.com/tofarr/marshy +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/0a/ff/2a578cdd0811414709b46d16f3bd9d4cd98474a48d2393b2f4c9ac878249/marshy-4.0.3.tar.gz +BuildArch: noarch + +Requires: python3-typing-inspect +Requires: python3-black +Requires: python3-marshmallow-dataclass +Requires: python3-pytest +Requires: python3-pytest-cov +Requires: python3-pytest-xdist +Requires: python3-pylint + +%description +# Marshy - Better Marshalling for Python. + +This project is a general purpose externalizer for python objects. +(Like Marshmallow or Pedantic) The guiding philosophy is convention +over configuration, with the aim of still making customizations as +pain free as possible, based on python type hints. + +Out of the box, it supports primitives, dataclasses, and enums. + +## Installation + +`pip install marshy` + +## General Usage + +Given the following dataclass: +``` +from typing import List, Optional +import dataclasses + + +@dataclasses.dataclass +class Doohickey: + title: str + description: Optional[str] = None + tags: List[str] = dataclasses.field(default_factory=list) +``` + +Marshall data with: +``` +import marshy +result = marshy.dump(Doohickey('Thingy', tags=['a','b'])) +# result == dict(title='Thingy', description=None, tags=['a','b']) +``` + +Unmarshall data with: +``` +result = marshy.load(Doohickey, dict(title='Thingy')) +# result == Doohickey('Thingy', description=None, tags=[]) +``` + +## Custom properties + +Custom properties are also serialized by default. (If they +have a setter, it is used when loading): + +``` +@dataclass +class Factorial: + value: int + + @property + def factorial(self) -> int: + return reduce(lambda a, b: a*b, range(1, self.value+1)) + +factorial = Factorial(4) +dumped = dump(factorial) +# dumped == dict(value=4, factorial=24) +loaded = load(Factorial, dumped) +# loaded == factorial +``` + +## Under The Hood + +Internally, API defines 3 core concepts: + +* A [Marshaller](marshy/marshaller/marshaller_abc.py): Is + responsible for marshalling / unmarshalling a single type of + object. +* A [MarshallerFactory](marshy/factory/marshaller_factory_abc.py): has + a `create` method used to create marshallers for types, and has + a priority which controls the order in which they are run. + (higher first) +* A [MarshallerContext](marshy/marshaller_context.py): coordinates + the activities of Marshallers and Factories + +## Creating a Custom Marshaller Context + +If you need multiple independent sets of rules for +marshalling data, then you should create your own marshalling +contexts and store references to them. The default works well +otherwise: + +``` +# Dump a Doohickey using the default context (Same as marshy.dump...) +from marshy import get_default_context +dumped = get_default_context().dump(Doohickey('Thingy')) + +# Create a new blank marshaller context - this will fail +# because there are no preset types or factories. +from marshy.marshaller_context import MarshallerContext +my_marshaller_context = MarshallerContext() +dumped = my_marshaller_context.dump(Doohickey('Thingy')) + +# Create a new marshaller context which copies the default rules. +from marshy.default_context import new_default_context +my_default_context = new_default_context() +dumped = my_default_context.dump(Doohickey('Thingy')) +``` + +## Creating a Custom Marshaller + +To customize marshalling for a type, write a marshaller and then +register it with your context: +``` +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy.types import ExternalType + + +class MyDoohickeyMarshaller(MarshallerABC[Doohickey]): + + def __init__(self): + super().__init__(Doohickey) + + def load(self, item: ExternalType) -> Doohickey: + return Doohickey(item[0], item[1], item[2]) + + def dump(self, item: Doohickey) -> ExternalType: + return [item.title, item.description, item.tags] + +my_default_context.register_marshaller(MyDoohickeyMarshaller()) +dumped = my_default_context.dump(Doohickey('Thingy')) +# dumped == ['Thingy', None, []] + +loaded = my_default_context.load(Doohickey, dumped) +# dumped == Doohickey('Thingy') +``` + +## Creating a Custom Marshaller Factory + +Sometimes you need to create a marshaller for a while concept of +object rather than a single type - In this case you need a factory, +(this is how the default rules work!). Examples: +* [ListMarshallerFactory](marshy/factory/list_marshaller_factory.py) + looks for typed lists (e.g.,: List[str]) and creates marshallers + for them - you already saw the results in `Doohickey.tags` above. +* [OptionalMarshallerFactory](marshy/factory/optional_marshaller_factory.py) + looks for optional fields (e.g.,: Optional[str]) and creates + marshallers that mean each individual other marshaller does not + need to accommodate the case where a value is None - just mark + it optional! +* [DataClassMarshallerFactory](marshy/factory/dataclass_marshaller_factory.py) + provides a marshaller for dataclasses assuming they have a standard + constructor based on their fields. + +## Customizing dataclass attributes: + +Taking the doohickey example: + +``` +from marshy import dump, get_default_context +from marshy.marshaller import str_marshaller, bool_marshaller +from marshy.marshaller.obj_marshaller import ObjMarshaller +attr_marshallers = dict(title=str_marshaller, tags=bool_marshaller) +get_default_context().register_marshaller(ObjMarshaller(Doohickey, attr_marshallers, False)) +dumped = dump(Doohickey('Thingy')) +# dumped == dict(title='Thingy', tags=False) +``` + +## Customizing dataclass marshalling + +As an alternative to defining a custom marshaller / factory, it is possible to simply +define a __marshaller_factory__ class method. (Note: this becomes the default for all +contexts) Imagine a case where you have a dataclass representing a 2D point, which you +want to be marshalled in the format [x, y] (An array rather than the standard object): +``` +from dataclasses import dataclass +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy import load, dump + +@dataclass +class Point: + x: float + y: float + + @classmethod + def __marshaller_factory__(cls, marshaller_context): + return PointMarshaller() + +class PointMarshaller(MarshallerABC): + + def __init__(self): + super().__init__(Point) + + def load(self, item): + return Point(item[0], item[1]) + + def dump(self, item): + return [item.x, item.y] + +dumped = dump(Point(1.2, 3.4)) +loaded = load(Point, dumped) +``` + +## Circular References + +Due to the fact that types in the object graph can self reference, +we defer resolution of most marshaller until as late as possible. +[DeferredMarshaller](marshy/marshaller/deferred_marshaller.py) +is responsible for this, and means types can +[self reference](test/test_marshall_deferred.py). + +Circular references within objects will still cause an error. +(Unless you decide on an error handling protocol for this an +implement a custom Factory to deal with it!) + +## Customizing the default context + +The project uses the namespace convention `marshy_config_` to identity configuration packages. +(https://packaging.python.org/guides/creating-and-discovering-plugins/). Configuration packages should have an integer +priority attribute, and a `def configure(context: MarshallerContext)` function. e.g.: +[default_config](marshy_config_default/__init__.py) + +## Adding Polymorphic Implementations + +Taking the following polymorphic classes where `Pet` has implementations `Cat` and `Dog`: + +``` +from abc import ABC, abstractmethod +from dataclasses import dataclass + +@dataclass +class PetAbc(ABC): + name: str + + @abstractmethod + def vocalize(self) -> str: + """ What sound does this make? """ + + +class Cat(PetAbc): + + def vocalize(self): + return "Meow!" + + +class Dog(PetAbc): + + def vocalize(self) -> str: + return "Woof!" +``` + +In order to deserialize a Pet, marshy needs to be informed tha the implementations exist. This can be done at any point +in the configuration: + +``` +from marshy import load +from marshy.factory.impl_marshaller_factory import register_impl +register_impl(PetAbc, Cat) +register_impl(PetAbc, Dog) +pet = ['Cat', dict(name='Felix')] +loaded = load(PetAbc, pet) +``` + +[Tests for this are here] (test/test_impl_marshaller.py) + +## Performance Tests + +Basic Tests show performance is approximate with marshmallow: + +``` +python -m timeit -s " +from test.performance.marshy_performance import run +run(1000) +" +``` + +``` +python -m timeit -s " +from test.performance.marshmallow_performance import run +run(1000) +" +``` + + +## Release Proceedure + + + +The typical process here is: +* Create a PR with changes. Merge these to main (The `Quality` workflows make sure that your PR + meets the styling, linting, and code coverage standards). +* New releases created in github are automatically uploaded to pypi + + +%package -n python3-marshy +Summary: A convention over configuration approach to object marshalling. +Provides: python-marshy +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-marshy +# Marshy - Better Marshalling for Python. + +This project is a general purpose externalizer for python objects. +(Like Marshmallow or Pedantic) The guiding philosophy is convention +over configuration, with the aim of still making customizations as +pain free as possible, based on python type hints. + +Out of the box, it supports primitives, dataclasses, and enums. + +## Installation + +`pip install marshy` + +## General Usage + +Given the following dataclass: +``` +from typing import List, Optional +import dataclasses + + +@dataclasses.dataclass +class Doohickey: + title: str + description: Optional[str] = None + tags: List[str] = dataclasses.field(default_factory=list) +``` + +Marshall data with: +``` +import marshy +result = marshy.dump(Doohickey('Thingy', tags=['a','b'])) +# result == dict(title='Thingy', description=None, tags=['a','b']) +``` + +Unmarshall data with: +``` +result = marshy.load(Doohickey, dict(title='Thingy')) +# result == Doohickey('Thingy', description=None, tags=[]) +``` + +## Custom properties + +Custom properties are also serialized by default. (If they +have a setter, it is used when loading): + +``` +@dataclass +class Factorial: + value: int + + @property + def factorial(self) -> int: + return reduce(lambda a, b: a*b, range(1, self.value+1)) + +factorial = Factorial(4) +dumped = dump(factorial) +# dumped == dict(value=4, factorial=24) +loaded = load(Factorial, dumped) +# loaded == factorial +``` + +## Under The Hood + +Internally, API defines 3 core concepts: + +* A [Marshaller](marshy/marshaller/marshaller_abc.py): Is + responsible for marshalling / unmarshalling a single type of + object. +* A [MarshallerFactory](marshy/factory/marshaller_factory_abc.py): has + a `create` method used to create marshallers for types, and has + a priority which controls the order in which they are run. + (higher first) +* A [MarshallerContext](marshy/marshaller_context.py): coordinates + the activities of Marshallers and Factories + +## Creating a Custom Marshaller Context + +If you need multiple independent sets of rules for +marshalling data, then you should create your own marshalling +contexts and store references to them. The default works well +otherwise: + +``` +# Dump a Doohickey using the default context (Same as marshy.dump...) +from marshy import get_default_context +dumped = get_default_context().dump(Doohickey('Thingy')) + +# Create a new blank marshaller context - this will fail +# because there are no preset types or factories. +from marshy.marshaller_context import MarshallerContext +my_marshaller_context = MarshallerContext() +dumped = my_marshaller_context.dump(Doohickey('Thingy')) + +# Create a new marshaller context which copies the default rules. +from marshy.default_context import new_default_context +my_default_context = new_default_context() +dumped = my_default_context.dump(Doohickey('Thingy')) +``` + +## Creating a Custom Marshaller + +To customize marshalling for a type, write a marshaller and then +register it with your context: +``` +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy.types import ExternalType + + +class MyDoohickeyMarshaller(MarshallerABC[Doohickey]): + + def __init__(self): + super().__init__(Doohickey) + + def load(self, item: ExternalType) -> Doohickey: + return Doohickey(item[0], item[1], item[2]) + + def dump(self, item: Doohickey) -> ExternalType: + return [item.title, item.description, item.tags] + +my_default_context.register_marshaller(MyDoohickeyMarshaller()) +dumped = my_default_context.dump(Doohickey('Thingy')) +# dumped == ['Thingy', None, []] + +loaded = my_default_context.load(Doohickey, dumped) +# dumped == Doohickey('Thingy') +``` + +## Creating a Custom Marshaller Factory + +Sometimes you need to create a marshaller for a while concept of +object rather than a single type - In this case you need a factory, +(this is how the default rules work!). Examples: +* [ListMarshallerFactory](marshy/factory/list_marshaller_factory.py) + looks for typed lists (e.g.,: List[str]) and creates marshallers + for them - you already saw the results in `Doohickey.tags` above. +* [OptionalMarshallerFactory](marshy/factory/optional_marshaller_factory.py) + looks for optional fields (e.g.,: Optional[str]) and creates + marshallers that mean each individual other marshaller does not + need to accommodate the case where a value is None - just mark + it optional! +* [DataClassMarshallerFactory](marshy/factory/dataclass_marshaller_factory.py) + provides a marshaller for dataclasses assuming they have a standard + constructor based on their fields. + +## Customizing dataclass attributes: + +Taking the doohickey example: + +``` +from marshy import dump, get_default_context +from marshy.marshaller import str_marshaller, bool_marshaller +from marshy.marshaller.obj_marshaller import ObjMarshaller +attr_marshallers = dict(title=str_marshaller, tags=bool_marshaller) +get_default_context().register_marshaller(ObjMarshaller(Doohickey, attr_marshallers, False)) +dumped = dump(Doohickey('Thingy')) +# dumped == dict(title='Thingy', tags=False) +``` + +## Customizing dataclass marshalling + +As an alternative to defining a custom marshaller / factory, it is possible to simply +define a __marshaller_factory__ class method. (Note: this becomes the default for all +contexts) Imagine a case where you have a dataclass representing a 2D point, which you +want to be marshalled in the format [x, y] (An array rather than the standard object): +``` +from dataclasses import dataclass +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy import load, dump + +@dataclass +class Point: + x: float + y: float + + @classmethod + def __marshaller_factory__(cls, marshaller_context): + return PointMarshaller() + +class PointMarshaller(MarshallerABC): + + def __init__(self): + super().__init__(Point) + + def load(self, item): + return Point(item[0], item[1]) + + def dump(self, item): + return [item.x, item.y] + +dumped = dump(Point(1.2, 3.4)) +loaded = load(Point, dumped) +``` + +## Circular References + +Due to the fact that types in the object graph can self reference, +we defer resolution of most marshaller until as late as possible. +[DeferredMarshaller](marshy/marshaller/deferred_marshaller.py) +is responsible for this, and means types can +[self reference](test/test_marshall_deferred.py). + +Circular references within objects will still cause an error. +(Unless you decide on an error handling protocol for this an +implement a custom Factory to deal with it!) + +## Customizing the default context + +The project uses the namespace convention `marshy_config_` to identity configuration packages. +(https://packaging.python.org/guides/creating-and-discovering-plugins/). Configuration packages should have an integer +priority attribute, and a `def configure(context: MarshallerContext)` function. e.g.: +[default_config](marshy_config_default/__init__.py) + +## Adding Polymorphic Implementations + +Taking the following polymorphic classes where `Pet` has implementations `Cat` and `Dog`: + +``` +from abc import ABC, abstractmethod +from dataclasses import dataclass + +@dataclass +class PetAbc(ABC): + name: str + + @abstractmethod + def vocalize(self) -> str: + """ What sound does this make? """ + + +class Cat(PetAbc): + + def vocalize(self): + return "Meow!" + + +class Dog(PetAbc): + + def vocalize(self) -> str: + return "Woof!" +``` + +In order to deserialize a Pet, marshy needs to be informed tha the implementations exist. This can be done at any point +in the configuration: + +``` +from marshy import load +from marshy.factory.impl_marshaller_factory import register_impl +register_impl(PetAbc, Cat) +register_impl(PetAbc, Dog) +pet = ['Cat', dict(name='Felix')] +loaded = load(PetAbc, pet) +``` + +[Tests for this are here] (test/test_impl_marshaller.py) + +## Performance Tests + +Basic Tests show performance is approximate with marshmallow: + +``` +python -m timeit -s " +from test.performance.marshy_performance import run +run(1000) +" +``` + +``` +python -m timeit -s " +from test.performance.marshmallow_performance import run +run(1000) +" +``` + + +## Release Proceedure + + + +The typical process here is: +* Create a PR with changes. Merge these to main (The `Quality` workflows make sure that your PR + meets the styling, linting, and code coverage standards). +* New releases created in github are automatically uploaded to pypi + + +%package help +Summary: Development documents and examples for marshy +Provides: python3-marshy-doc +%description help +# Marshy - Better Marshalling for Python. + +This project is a general purpose externalizer for python objects. +(Like Marshmallow or Pedantic) The guiding philosophy is convention +over configuration, with the aim of still making customizations as +pain free as possible, based on python type hints. + +Out of the box, it supports primitives, dataclasses, and enums. + +## Installation + +`pip install marshy` + +## General Usage + +Given the following dataclass: +``` +from typing import List, Optional +import dataclasses + + +@dataclasses.dataclass +class Doohickey: + title: str + description: Optional[str] = None + tags: List[str] = dataclasses.field(default_factory=list) +``` + +Marshall data with: +``` +import marshy +result = marshy.dump(Doohickey('Thingy', tags=['a','b'])) +# result == dict(title='Thingy', description=None, tags=['a','b']) +``` + +Unmarshall data with: +``` +result = marshy.load(Doohickey, dict(title='Thingy')) +# result == Doohickey('Thingy', description=None, tags=[]) +``` + +## Custom properties + +Custom properties are also serialized by default. (If they +have a setter, it is used when loading): + +``` +@dataclass +class Factorial: + value: int + + @property + def factorial(self) -> int: + return reduce(lambda a, b: a*b, range(1, self.value+1)) + +factorial = Factorial(4) +dumped = dump(factorial) +# dumped == dict(value=4, factorial=24) +loaded = load(Factorial, dumped) +# loaded == factorial +``` + +## Under The Hood + +Internally, API defines 3 core concepts: + +* A [Marshaller](marshy/marshaller/marshaller_abc.py): Is + responsible for marshalling / unmarshalling a single type of + object. +* A [MarshallerFactory](marshy/factory/marshaller_factory_abc.py): has + a `create` method used to create marshallers for types, and has + a priority which controls the order in which they are run. + (higher first) +* A [MarshallerContext](marshy/marshaller_context.py): coordinates + the activities of Marshallers and Factories + +## Creating a Custom Marshaller Context + +If you need multiple independent sets of rules for +marshalling data, then you should create your own marshalling +contexts and store references to them. The default works well +otherwise: + +``` +# Dump a Doohickey using the default context (Same as marshy.dump...) +from marshy import get_default_context +dumped = get_default_context().dump(Doohickey('Thingy')) + +# Create a new blank marshaller context - this will fail +# because there are no preset types or factories. +from marshy.marshaller_context import MarshallerContext +my_marshaller_context = MarshallerContext() +dumped = my_marshaller_context.dump(Doohickey('Thingy')) + +# Create a new marshaller context which copies the default rules. +from marshy.default_context import new_default_context +my_default_context = new_default_context() +dumped = my_default_context.dump(Doohickey('Thingy')) +``` + +## Creating a Custom Marshaller + +To customize marshalling for a type, write a marshaller and then +register it with your context: +``` +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy.types import ExternalType + + +class MyDoohickeyMarshaller(MarshallerABC[Doohickey]): + + def __init__(self): + super().__init__(Doohickey) + + def load(self, item: ExternalType) -> Doohickey: + return Doohickey(item[0], item[1], item[2]) + + def dump(self, item: Doohickey) -> ExternalType: + return [item.title, item.description, item.tags] + +my_default_context.register_marshaller(MyDoohickeyMarshaller()) +dumped = my_default_context.dump(Doohickey('Thingy')) +# dumped == ['Thingy', None, []] + +loaded = my_default_context.load(Doohickey, dumped) +# dumped == Doohickey('Thingy') +``` + +## Creating a Custom Marshaller Factory + +Sometimes you need to create a marshaller for a while concept of +object rather than a single type - In this case you need a factory, +(this is how the default rules work!). Examples: +* [ListMarshallerFactory](marshy/factory/list_marshaller_factory.py) + looks for typed lists (e.g.,: List[str]) and creates marshallers + for them - you already saw the results in `Doohickey.tags` above. +* [OptionalMarshallerFactory](marshy/factory/optional_marshaller_factory.py) + looks for optional fields (e.g.,: Optional[str]) and creates + marshallers that mean each individual other marshaller does not + need to accommodate the case where a value is None - just mark + it optional! +* [DataClassMarshallerFactory](marshy/factory/dataclass_marshaller_factory.py) + provides a marshaller for dataclasses assuming they have a standard + constructor based on their fields. + +## Customizing dataclass attributes: + +Taking the doohickey example: + +``` +from marshy import dump, get_default_context +from marshy.marshaller import str_marshaller, bool_marshaller +from marshy.marshaller.obj_marshaller import ObjMarshaller +attr_marshallers = dict(title=str_marshaller, tags=bool_marshaller) +get_default_context().register_marshaller(ObjMarshaller(Doohickey, attr_marshallers, False)) +dumped = dump(Doohickey('Thingy')) +# dumped == dict(title='Thingy', tags=False) +``` + +## Customizing dataclass marshalling + +As an alternative to defining a custom marshaller / factory, it is possible to simply +define a __marshaller_factory__ class method. (Note: this becomes the default for all +contexts) Imagine a case where you have a dataclass representing a 2D point, which you +want to be marshalled in the format [x, y] (An array rather than the standard object): +``` +from dataclasses import dataclass +from marshy.marshaller.marshaller_abc import MarshallerABC +from marshy import load, dump + +@dataclass +class Point: + x: float + y: float + + @classmethod + def __marshaller_factory__(cls, marshaller_context): + return PointMarshaller() + +class PointMarshaller(MarshallerABC): + + def __init__(self): + super().__init__(Point) + + def load(self, item): + return Point(item[0], item[1]) + + def dump(self, item): + return [item.x, item.y] + +dumped = dump(Point(1.2, 3.4)) +loaded = load(Point, dumped) +``` + +## Circular References + +Due to the fact that types in the object graph can self reference, +we defer resolution of most marshaller until as late as possible. +[DeferredMarshaller](marshy/marshaller/deferred_marshaller.py) +is responsible for this, and means types can +[self reference](test/test_marshall_deferred.py). + +Circular references within objects will still cause an error. +(Unless you decide on an error handling protocol for this an +implement a custom Factory to deal with it!) + +## Customizing the default context + +The project uses the namespace convention `marshy_config_` to identity configuration packages. +(https://packaging.python.org/guides/creating-and-discovering-plugins/). Configuration packages should have an integer +priority attribute, and a `def configure(context: MarshallerContext)` function. e.g.: +[default_config](marshy_config_default/__init__.py) + +## Adding Polymorphic Implementations + +Taking the following polymorphic classes where `Pet` has implementations `Cat` and `Dog`: + +``` +from abc import ABC, abstractmethod +from dataclasses import dataclass + +@dataclass +class PetAbc(ABC): + name: str + + @abstractmethod + def vocalize(self) -> str: + """ What sound does this make? """ + + +class Cat(PetAbc): + + def vocalize(self): + return "Meow!" + + +class Dog(PetAbc): + + def vocalize(self) -> str: + return "Woof!" +``` + +In order to deserialize a Pet, marshy needs to be informed tha the implementations exist. This can be done at any point +in the configuration: + +``` +from marshy import load +from marshy.factory.impl_marshaller_factory import register_impl +register_impl(PetAbc, Cat) +register_impl(PetAbc, Dog) +pet = ['Cat', dict(name='Felix')] +loaded = load(PetAbc, pet) +``` + +[Tests for this are here] (test/test_impl_marshaller.py) + +## Performance Tests + +Basic Tests show performance is approximate with marshmallow: + +``` +python -m timeit -s " +from test.performance.marshy_performance import run +run(1000) +" +``` + +``` +python -m timeit -s " +from test.performance.marshmallow_performance import run +run(1000) +" +``` + + +## Release Proceedure + + + +The typical process here is: +* Create a PR with changes. Merge these to main (The `Quality` workflows make sure that your PR + meets the styling, linting, and code coverage standards). +* New releases created in github are automatically uploaded to pypi + + +%prep +%autosetup -n marshy-4.0.3 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-marshy -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Wed May 10 2023 Python_Bot <Python_Bot@openeuler.org> - 4.0.3-1 +- Package Spec generated @@ -0,0 +1 @@ +a442381f7649be2bc5b8a66f221580fc marshy-4.0.3.tar.gz |
