summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-10 06:01:50 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-10 06:01:50 +0000
commit781ceea4cd3a1f020fff28944615c07631d2be75 (patch)
treece1d5a09e06c6b36fe383caf5d334e074b459848
parentc2c8bbfe2cc1397d4add3865aec561ea30ba2e71 (diff)
automatic import of python-django-better-choices
-rw-r--r--.gitignore1
-rw-r--r--python-django-better-choices.spec675
-rw-r--r--sources1
3 files changed, 677 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e69de29..fd12b66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1 @@
+/django-better-choices-1.17.tar.gz
diff --git a/python-django-better-choices.spec b/python-django-better-choices.spec
new file mode 100644
index 0000000..c1ee479
--- /dev/null
+++ b/python-django-better-choices.spec
@@ -0,0 +1,675 @@
+%global _empty_manifest_terminate_build 0
+Name: python-django-better-choices
+Version: 1.17
+Release: 1
+Summary: Better choices library for Django web framework
+License: MIT
+URL: https://github.com/lokhman/django-better-choices
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/df/13/b9940aba2fe222159ea656dcb88a5ce5bc56c71faf4ba4959e27f8e119ef/django-better-choices-1.17.tar.gz
+BuildArch: noarch
+
+
+%description
+# Django Better Choices
+
+[![PyPI](https://img.shields.io/pypi/v/django-better-choices)](https://pypi.org/project/django-better-choices)
+![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-better-choices)
+[![Build Status](https://img.shields.io/github/workflow/status/lokhman/django-better-choices/CI/master)](https://github.com/lokhman/django-better-choices/actions?query=workflow%3ACI)
+[![codecov](https://codecov.io/gh/lokhman/django-better-choices/branch/master/graph/badge.svg)](https://codecov.io/gh/lokhman/django-better-choices)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
+
+Better [choices](https://docs.djangoproject.com/en/3.0/ref/models/fields/#choices) library for Django web framework.
+
+## Requirements
+This library was written for Python 3.7+ and will not work in any earlier versions.
+
+## Install
+
+ pip install django-better-choices
+
+## Usage
+To start defining better choices, you need first to import the `Choices` class.
+```python
+from django_better_choices import Choices
+```
+
+### Class definition
+The choices can be defined with overriding `Choices` class.
+```python
+class PageStatus(Choices):
+ CREATED = "Created"
+ PENDING = Choices.Value("Pending", help_text="This set status to pending")
+ ON_HOLD = Choices.Value("On Hold", value="custom_on_hold")
+
+ VALID = Choices.Subset("CREATED", "ON_HOLD")
+ INVISIBLE = Choices.Subset("PENDING", "ON_HOLD")
+
+ class InternalStatus(Choices):
+ REVIEW = _("On Review")
+
+ @classmethod
+ def get_help_text(cls):
+ return tuple(
+ value.help_text
+ for value in cls.values()
+ if hasattr(value, "help_text")
+ )
+```
+> Choices class key can be any *public* identifier (i.e. not starting with underscore `_`).
+> Overridden choices classes cannot be initialised to obtain a new instance, calling the instance will return a tuple of choice entries.
+
+### Inline definition
+Alternatively, the choices can be defined dynamically by creating a new `Choices` instance.
+```python
+PageStatus = Choices("PageStatus", SUCCESS="Success", FAIL="Error", VALID=Choices.Subset("SUCCESS"))
+```
+> The first `name` parameter of `Choices` constructor is optional and required only for better representation of the returned instance.
+
+### Value accessors
+You can access choices values using dot notation and with `getattr()`.
+```python
+value_created = PageStatus.CREATED
+value_review = PageStatus.InternalStatus.REVIEW
+value_on_hold = getattr(PageStatus, "ON_HOLD")
+```
+
+### Values and value parameters
+`Choices.Value` can hold any `typing.Hashable` value and once compiled equals to this value. In addition to `display` parameter, other optional parameters can be specified in `Choices.Value` constructor (see class definition example).
+```python
+print( PageStatus.CREATED ) # 'created'
+print( PageStatus.ON_HOLD ) # 'custom_on_hold'
+print( PageStatus.PENDING.display ) # 'Pending'
+print( PageStatus.PENDING.help_text ) # 'This set status to pending'
+
+PageStatus.ON_HOLD == "custom_on_hold" # True
+PageStatus.CREATED == PageStatus.CREATED # True
+
+
+class Rating(Choices):
+ VERY_POOR = Choices.Value("Very poor", value=1)
+ POOR = Choices.Value("Poor", value=2)
+ OKAY = Choices.Value("Okay", value=3, alt="Not great, not terrible")
+ GOOD = Choices.Value("Good", value=4)
+ VERY_GOOD = Choices.Value("Very good", value=5)
+
+print( Rating.VERY_GOOD ) # 5
+print( Rating.OKAY.alt ) # 'Not great, not terrible'
+print( {4: "Alright"}[Rating.GOOD] ) # 'Alright'
+```
+> Instance of `Choices.Value` class cannot be modified after initialisation. All native non-magic methods can be overridden in `Choices.Value` custom parameters.
+
+### Search in choices
+Search in choices is performed by value.
+```python
+"created" in PageStatus # True
+"custom_on_hold" in PageStatus # True
+"on_hold" in PageStatus # False
+value = PageStatus["custom_on_hold"] # ValueType('custom_on_hold')
+value = PageStatus.get("on_hold", 123.45) # 123.45
+key = PageStatus.get_key("created") # 'CREATED'
+```
+
+### Search in subsets
+Subsets are used to group several values together (see class definition example) and search by a specific value.
+```python
+"custom_on_hold" in PageStatus.VALID # True
+PageStatus.CREATED in PageStatus.VALID # True
+```
+> `Choices.Subset` is a subclass of `tuple`, which is compiled to inner choices class after its definition. All internal or custom choices class methods or properties will be available in a subset class (see "Custom methods" section).
+
+### Extract subset
+Subsets of choices can be dynamically extracted with `extract()` method.
+```python
+PageStatus.extract("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', CREATED, ON_HOLD)
+PageStatus.VALID.extract("ON_HOLD") # Choices('PageStatus.VALID.Subset', ON_HOLD)
+```
+
+### Exclude values
+The opposite action to `extract()` is `exclude()`. It is used to exclude values from choices class or a subset and return remaining values as a new subset.
+```python
+PageStatus.exclude("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', PENDING)
+PageStatus.VALID.exclude("ON_HOLD") # Choices('PageStatus.VALID.Subset', CREATED)
+```
+
+### Choices iteration
+Choices class implements `__iter__` magic method, hence choices are iterable that yield choice entries (i.e. `(value, display)`). Methods `items()`, `keys()` and `values()` can be used to return tuples of keys and values combinations.
+```python
+for value, display in PageStatus: # can also be used as callable, i.e. PageStatus()
+ print( value, display )
+
+for key, value in PageStatus.items():
+ print( key, value, value.display )
+
+for key in PageStatus.keys():
+ print( key )
+
+for value in PageStatus.values():
+ print( value, value.display, value.__choice_entry__ )
+```
+Additional `displays()` method is provided for choices and subsets to extract values display strings.
+```python
+for display in PageStatus.displays():
+ print( display )
+
+for display in PageStatus.SUBSET.displays():
+ print( display )
+```
+> Iteration methods `items()`, `keys()`, `values()`, `displays()`, as well as class constructor can accept keyword arguments to filter collections based on custom parameters, e.g. `PageStatus.values(help_text="Some", special=123)`.
+
+### Set operations
+Choices class and subsets support standard set operations: *union* (`|`), *intersection* (`&`), *difference* (`-`), and *symmetric difference* (`^`).
+```python
+PageStatus.VALID | PageStatus.INVISIBLE # Choices(CREATED, ON_HOLD, PENDING)
+PageStatus.VALID & PageStatus.INVISIBLE # Choices(ON_HOLD)
+PageStatus.VALID - PageStatus.INVISIBLE # Choices(CREATED)
+PageStatus.VALID ^ PageStatus.INVISIBLE # Choices(CREATED, PENDING)
+```
+
+### Custom methods
+All custom choices class methods or properties (non-values) will be available in all subsets.
+```python
+PageStatus.get_help_text()
+PageStatus.VALID.get_help_text()
+PageStatus.extract("PENDING", "ON_HOLD").get_help_text()
+PageStatus.VALID.extract("ON_HOLD").get_help_text()
+```
+
+### Inheritance
+Choices fully support class inheritance. All child choices classes have access to parent, grandparent, etc. values and custom methods.
+```python
+class NewPageStatus(PageStatus):
+ ARCHIVED = "Archived"
+ ON_HOLD = Choices.Value("On Hold", value="on-hold") # override parent value
+
+ INACTIVE = Choices.Subset("ON_HOLD", "ARCHIVED")
+
+print( NewPageStatus.CREATED ) # 'created'
+print( NewPageStatus.ARCHIVED ) # 'archived'
+print( NewPageStatus.ON_HOLD ) # 'on-hold'
+```
+
+### Django model fields
+Better choices are not different from the original Django choices in terms of usage in models.
+```python
+class Page(models.Model):
+ status = models.CharField(choices=PageStatus, default=PageStatus.CREATED)
+```
+> Better choices are fully supported by Django migrations and debug toolbar.
+
+### Saving choices on models
+Better choices are compatible with standard Django models manipulation.
+```python
+page = Page.objects.get(pk=1)
+page.status = PageStatus.PENDING
+page.save()
+```
+
+## Tests
+Run `python tests.py` for testing.
+
+## License
+Library is available under the MIT license. The included LICENSE file describes this in detail.
+
+
+
+
+%package -n python3-django-better-choices
+Summary: Better choices library for Django web framework
+Provides: python-django-better-choices
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-django-better-choices
+# Django Better Choices
+
+[![PyPI](https://img.shields.io/pypi/v/django-better-choices)](https://pypi.org/project/django-better-choices)
+![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-better-choices)
+[![Build Status](https://img.shields.io/github/workflow/status/lokhman/django-better-choices/CI/master)](https://github.com/lokhman/django-better-choices/actions?query=workflow%3ACI)
+[![codecov](https://codecov.io/gh/lokhman/django-better-choices/branch/master/graph/badge.svg)](https://codecov.io/gh/lokhman/django-better-choices)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
+
+Better [choices](https://docs.djangoproject.com/en/3.0/ref/models/fields/#choices) library for Django web framework.
+
+## Requirements
+This library was written for Python 3.7+ and will not work in any earlier versions.
+
+## Install
+
+ pip install django-better-choices
+
+## Usage
+To start defining better choices, you need first to import the `Choices` class.
+```python
+from django_better_choices import Choices
+```
+
+### Class definition
+The choices can be defined with overriding `Choices` class.
+```python
+class PageStatus(Choices):
+ CREATED = "Created"
+ PENDING = Choices.Value("Pending", help_text="This set status to pending")
+ ON_HOLD = Choices.Value("On Hold", value="custom_on_hold")
+
+ VALID = Choices.Subset("CREATED", "ON_HOLD")
+ INVISIBLE = Choices.Subset("PENDING", "ON_HOLD")
+
+ class InternalStatus(Choices):
+ REVIEW = _("On Review")
+
+ @classmethod
+ def get_help_text(cls):
+ return tuple(
+ value.help_text
+ for value in cls.values()
+ if hasattr(value, "help_text")
+ )
+```
+> Choices class key can be any *public* identifier (i.e. not starting with underscore `_`).
+> Overridden choices classes cannot be initialised to obtain a new instance, calling the instance will return a tuple of choice entries.
+
+### Inline definition
+Alternatively, the choices can be defined dynamically by creating a new `Choices` instance.
+```python
+PageStatus = Choices("PageStatus", SUCCESS="Success", FAIL="Error", VALID=Choices.Subset("SUCCESS"))
+```
+> The first `name` parameter of `Choices` constructor is optional and required only for better representation of the returned instance.
+
+### Value accessors
+You can access choices values using dot notation and with `getattr()`.
+```python
+value_created = PageStatus.CREATED
+value_review = PageStatus.InternalStatus.REVIEW
+value_on_hold = getattr(PageStatus, "ON_HOLD")
+```
+
+### Values and value parameters
+`Choices.Value` can hold any `typing.Hashable` value and once compiled equals to this value. In addition to `display` parameter, other optional parameters can be specified in `Choices.Value` constructor (see class definition example).
+```python
+print( PageStatus.CREATED ) # 'created'
+print( PageStatus.ON_HOLD ) # 'custom_on_hold'
+print( PageStatus.PENDING.display ) # 'Pending'
+print( PageStatus.PENDING.help_text ) # 'This set status to pending'
+
+PageStatus.ON_HOLD == "custom_on_hold" # True
+PageStatus.CREATED == PageStatus.CREATED # True
+
+
+class Rating(Choices):
+ VERY_POOR = Choices.Value("Very poor", value=1)
+ POOR = Choices.Value("Poor", value=2)
+ OKAY = Choices.Value("Okay", value=3, alt="Not great, not terrible")
+ GOOD = Choices.Value("Good", value=4)
+ VERY_GOOD = Choices.Value("Very good", value=5)
+
+print( Rating.VERY_GOOD ) # 5
+print( Rating.OKAY.alt ) # 'Not great, not terrible'
+print( {4: "Alright"}[Rating.GOOD] ) # 'Alright'
+```
+> Instance of `Choices.Value` class cannot be modified after initialisation. All native non-magic methods can be overridden in `Choices.Value` custom parameters.
+
+### Search in choices
+Search in choices is performed by value.
+```python
+"created" in PageStatus # True
+"custom_on_hold" in PageStatus # True
+"on_hold" in PageStatus # False
+value = PageStatus["custom_on_hold"] # ValueType('custom_on_hold')
+value = PageStatus.get("on_hold", 123.45) # 123.45
+key = PageStatus.get_key("created") # 'CREATED'
+```
+
+### Search in subsets
+Subsets are used to group several values together (see class definition example) and search by a specific value.
+```python
+"custom_on_hold" in PageStatus.VALID # True
+PageStatus.CREATED in PageStatus.VALID # True
+```
+> `Choices.Subset` is a subclass of `tuple`, which is compiled to inner choices class after its definition. All internal or custom choices class methods or properties will be available in a subset class (see "Custom methods" section).
+
+### Extract subset
+Subsets of choices can be dynamically extracted with `extract()` method.
+```python
+PageStatus.extract("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', CREATED, ON_HOLD)
+PageStatus.VALID.extract("ON_HOLD") # Choices('PageStatus.VALID.Subset', ON_HOLD)
+```
+
+### Exclude values
+The opposite action to `extract()` is `exclude()`. It is used to exclude values from choices class or a subset and return remaining values as a new subset.
+```python
+PageStatus.exclude("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', PENDING)
+PageStatus.VALID.exclude("ON_HOLD") # Choices('PageStatus.VALID.Subset', CREATED)
+```
+
+### Choices iteration
+Choices class implements `__iter__` magic method, hence choices are iterable that yield choice entries (i.e. `(value, display)`). Methods `items()`, `keys()` and `values()` can be used to return tuples of keys and values combinations.
+```python
+for value, display in PageStatus: # can also be used as callable, i.e. PageStatus()
+ print( value, display )
+
+for key, value in PageStatus.items():
+ print( key, value, value.display )
+
+for key in PageStatus.keys():
+ print( key )
+
+for value in PageStatus.values():
+ print( value, value.display, value.__choice_entry__ )
+```
+Additional `displays()` method is provided for choices and subsets to extract values display strings.
+```python
+for display in PageStatus.displays():
+ print( display )
+
+for display in PageStatus.SUBSET.displays():
+ print( display )
+```
+> Iteration methods `items()`, `keys()`, `values()`, `displays()`, as well as class constructor can accept keyword arguments to filter collections based on custom parameters, e.g. `PageStatus.values(help_text="Some", special=123)`.
+
+### Set operations
+Choices class and subsets support standard set operations: *union* (`|`), *intersection* (`&`), *difference* (`-`), and *symmetric difference* (`^`).
+```python
+PageStatus.VALID | PageStatus.INVISIBLE # Choices(CREATED, ON_HOLD, PENDING)
+PageStatus.VALID & PageStatus.INVISIBLE # Choices(ON_HOLD)
+PageStatus.VALID - PageStatus.INVISIBLE # Choices(CREATED)
+PageStatus.VALID ^ PageStatus.INVISIBLE # Choices(CREATED, PENDING)
+```
+
+### Custom methods
+All custom choices class methods or properties (non-values) will be available in all subsets.
+```python
+PageStatus.get_help_text()
+PageStatus.VALID.get_help_text()
+PageStatus.extract("PENDING", "ON_HOLD").get_help_text()
+PageStatus.VALID.extract("ON_HOLD").get_help_text()
+```
+
+### Inheritance
+Choices fully support class inheritance. All child choices classes have access to parent, grandparent, etc. values and custom methods.
+```python
+class NewPageStatus(PageStatus):
+ ARCHIVED = "Archived"
+ ON_HOLD = Choices.Value("On Hold", value="on-hold") # override parent value
+
+ INACTIVE = Choices.Subset("ON_HOLD", "ARCHIVED")
+
+print( NewPageStatus.CREATED ) # 'created'
+print( NewPageStatus.ARCHIVED ) # 'archived'
+print( NewPageStatus.ON_HOLD ) # 'on-hold'
+```
+
+### Django model fields
+Better choices are not different from the original Django choices in terms of usage in models.
+```python
+class Page(models.Model):
+ status = models.CharField(choices=PageStatus, default=PageStatus.CREATED)
+```
+> Better choices are fully supported by Django migrations and debug toolbar.
+
+### Saving choices on models
+Better choices are compatible with standard Django models manipulation.
+```python
+page = Page.objects.get(pk=1)
+page.status = PageStatus.PENDING
+page.save()
+```
+
+## Tests
+Run `python tests.py` for testing.
+
+## License
+Library is available under the MIT license. The included LICENSE file describes this in detail.
+
+
+
+
+%package help
+Summary: Development documents and examples for django-better-choices
+Provides: python3-django-better-choices-doc
+%description help
+# Django Better Choices
+
+[![PyPI](https://img.shields.io/pypi/v/django-better-choices)](https://pypi.org/project/django-better-choices)
+![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-better-choices)
+[![Build Status](https://img.shields.io/github/workflow/status/lokhman/django-better-choices/CI/master)](https://github.com/lokhman/django-better-choices/actions?query=workflow%3ACI)
+[![codecov](https://codecov.io/gh/lokhman/django-better-choices/branch/master/graph/badge.svg)](https://codecov.io/gh/lokhman/django-better-choices)
+[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
+
+Better [choices](https://docs.djangoproject.com/en/3.0/ref/models/fields/#choices) library for Django web framework.
+
+## Requirements
+This library was written for Python 3.7+ and will not work in any earlier versions.
+
+## Install
+
+ pip install django-better-choices
+
+## Usage
+To start defining better choices, you need first to import the `Choices` class.
+```python
+from django_better_choices import Choices
+```
+
+### Class definition
+The choices can be defined with overriding `Choices` class.
+```python
+class PageStatus(Choices):
+ CREATED = "Created"
+ PENDING = Choices.Value("Pending", help_text="This set status to pending")
+ ON_HOLD = Choices.Value("On Hold", value="custom_on_hold")
+
+ VALID = Choices.Subset("CREATED", "ON_HOLD")
+ INVISIBLE = Choices.Subset("PENDING", "ON_HOLD")
+
+ class InternalStatus(Choices):
+ REVIEW = _("On Review")
+
+ @classmethod
+ def get_help_text(cls):
+ return tuple(
+ value.help_text
+ for value in cls.values()
+ if hasattr(value, "help_text")
+ )
+```
+> Choices class key can be any *public* identifier (i.e. not starting with underscore `_`).
+> Overridden choices classes cannot be initialised to obtain a new instance, calling the instance will return a tuple of choice entries.
+
+### Inline definition
+Alternatively, the choices can be defined dynamically by creating a new `Choices` instance.
+```python
+PageStatus = Choices("PageStatus", SUCCESS="Success", FAIL="Error", VALID=Choices.Subset("SUCCESS"))
+```
+> The first `name` parameter of `Choices` constructor is optional and required only for better representation of the returned instance.
+
+### Value accessors
+You can access choices values using dot notation and with `getattr()`.
+```python
+value_created = PageStatus.CREATED
+value_review = PageStatus.InternalStatus.REVIEW
+value_on_hold = getattr(PageStatus, "ON_HOLD")
+```
+
+### Values and value parameters
+`Choices.Value` can hold any `typing.Hashable` value and once compiled equals to this value. In addition to `display` parameter, other optional parameters can be specified in `Choices.Value` constructor (see class definition example).
+```python
+print( PageStatus.CREATED ) # 'created'
+print( PageStatus.ON_HOLD ) # 'custom_on_hold'
+print( PageStatus.PENDING.display ) # 'Pending'
+print( PageStatus.PENDING.help_text ) # 'This set status to pending'
+
+PageStatus.ON_HOLD == "custom_on_hold" # True
+PageStatus.CREATED == PageStatus.CREATED # True
+
+
+class Rating(Choices):
+ VERY_POOR = Choices.Value("Very poor", value=1)
+ POOR = Choices.Value("Poor", value=2)
+ OKAY = Choices.Value("Okay", value=3, alt="Not great, not terrible")
+ GOOD = Choices.Value("Good", value=4)
+ VERY_GOOD = Choices.Value("Very good", value=5)
+
+print( Rating.VERY_GOOD ) # 5
+print( Rating.OKAY.alt ) # 'Not great, not terrible'
+print( {4: "Alright"}[Rating.GOOD] ) # 'Alright'
+```
+> Instance of `Choices.Value` class cannot be modified after initialisation. All native non-magic methods can be overridden in `Choices.Value` custom parameters.
+
+### Search in choices
+Search in choices is performed by value.
+```python
+"created" in PageStatus # True
+"custom_on_hold" in PageStatus # True
+"on_hold" in PageStatus # False
+value = PageStatus["custom_on_hold"] # ValueType('custom_on_hold')
+value = PageStatus.get("on_hold", 123.45) # 123.45
+key = PageStatus.get_key("created") # 'CREATED'
+```
+
+### Search in subsets
+Subsets are used to group several values together (see class definition example) and search by a specific value.
+```python
+"custom_on_hold" in PageStatus.VALID # True
+PageStatus.CREATED in PageStatus.VALID # True
+```
+> `Choices.Subset` is a subclass of `tuple`, which is compiled to inner choices class after its definition. All internal or custom choices class methods or properties will be available in a subset class (see "Custom methods" section).
+
+### Extract subset
+Subsets of choices can be dynamically extracted with `extract()` method.
+```python
+PageStatus.extract("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', CREATED, ON_HOLD)
+PageStatus.VALID.extract("ON_HOLD") # Choices('PageStatus.VALID.Subset', ON_HOLD)
+```
+
+### Exclude values
+The opposite action to `extract()` is `exclude()`. It is used to exclude values from choices class or a subset and return remaining values as a new subset.
+```python
+PageStatus.exclude("CREATED", "ON_HOLD") # Choices('PageStatus.Subset', PENDING)
+PageStatus.VALID.exclude("ON_HOLD") # Choices('PageStatus.VALID.Subset', CREATED)
+```
+
+### Choices iteration
+Choices class implements `__iter__` magic method, hence choices are iterable that yield choice entries (i.e. `(value, display)`). Methods `items()`, `keys()` and `values()` can be used to return tuples of keys and values combinations.
+```python
+for value, display in PageStatus: # can also be used as callable, i.e. PageStatus()
+ print( value, display )
+
+for key, value in PageStatus.items():
+ print( key, value, value.display )
+
+for key in PageStatus.keys():
+ print( key )
+
+for value in PageStatus.values():
+ print( value, value.display, value.__choice_entry__ )
+```
+Additional `displays()` method is provided for choices and subsets to extract values display strings.
+```python
+for display in PageStatus.displays():
+ print( display )
+
+for display in PageStatus.SUBSET.displays():
+ print( display )
+```
+> Iteration methods `items()`, `keys()`, `values()`, `displays()`, as well as class constructor can accept keyword arguments to filter collections based on custom parameters, e.g. `PageStatus.values(help_text="Some", special=123)`.
+
+### Set operations
+Choices class and subsets support standard set operations: *union* (`|`), *intersection* (`&`), *difference* (`-`), and *symmetric difference* (`^`).
+```python
+PageStatus.VALID | PageStatus.INVISIBLE # Choices(CREATED, ON_HOLD, PENDING)
+PageStatus.VALID & PageStatus.INVISIBLE # Choices(ON_HOLD)
+PageStatus.VALID - PageStatus.INVISIBLE # Choices(CREATED)
+PageStatus.VALID ^ PageStatus.INVISIBLE # Choices(CREATED, PENDING)
+```
+
+### Custom methods
+All custom choices class methods or properties (non-values) will be available in all subsets.
+```python
+PageStatus.get_help_text()
+PageStatus.VALID.get_help_text()
+PageStatus.extract("PENDING", "ON_HOLD").get_help_text()
+PageStatus.VALID.extract("ON_HOLD").get_help_text()
+```
+
+### Inheritance
+Choices fully support class inheritance. All child choices classes have access to parent, grandparent, etc. values and custom methods.
+```python
+class NewPageStatus(PageStatus):
+ ARCHIVED = "Archived"
+ ON_HOLD = Choices.Value("On Hold", value="on-hold") # override parent value
+
+ INACTIVE = Choices.Subset("ON_HOLD", "ARCHIVED")
+
+print( NewPageStatus.CREATED ) # 'created'
+print( NewPageStatus.ARCHIVED ) # 'archived'
+print( NewPageStatus.ON_HOLD ) # 'on-hold'
+```
+
+### Django model fields
+Better choices are not different from the original Django choices in terms of usage in models.
+```python
+class Page(models.Model):
+ status = models.CharField(choices=PageStatus, default=PageStatus.CREATED)
+```
+> Better choices are fully supported by Django migrations and debug toolbar.
+
+### Saving choices on models
+Better choices are compatible with standard Django models manipulation.
+```python
+page = Page.objects.get(pk=1)
+page.status = PageStatus.PENDING
+page.save()
+```
+
+## Tests
+Run `python tests.py` for testing.
+
+## License
+Library is available under the MIT license. The included LICENSE file describes this in detail.
+
+
+
+
+%prep
+%autosetup -n django-better-choices-1.17
+
+%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-django-better-choices -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Wed May 10 2023 Python_Bot <Python_Bot@openeuler.org> - 1.17-1
+- Package Spec generated
diff --git a/sources b/sources
new file mode 100644
index 0000000..3e2d4ec
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+fb30ae84efbe21df703544e94371cd91 django-better-choices-1.17.tar.gz