flufl_enum-6.1.0/conftest.py0000644000000000000000000000254113615410400012773 0ustar00import os import pytest from contextlib import ExitStack from sybil import Sybil from doctest import ELLIPSIS, REPORT_NDIFF, NORMALIZE_WHITESPACE from sybil.parsers.doctest import DocTestParser from sybil.parsers.codeblock import PythonCodeBlockParser DOCTEST_FLAGS = ELLIPSIS | NORMALIZE_WHITESPACE | REPORT_NDIFF class DoctestNamespace: def __init__(self): self._resources = ExitStack() def setup(self, namespace): # The docs include an example of how enums can be pickled and # unpickled. For this, our test module must be importable. Hack # sys.path so that the `fruit.py` module (containing an enum for the # pickle tests) can be imported. There's probably a more robust way to # do this, but it works and is simple so fix it only if necessary. test_dir = os.path.join(os.getcwd(), 'test') assert os.path.isfile(os.path.join(test_dir, 'fruit.py')) self._resources.enter_context( pytest.MonkeyPatch.context()).syspath_prepend(test_dir) def teardown(self, namespace): self._resources.close() namespace = DoctestNamespace() pytest_collect_file = Sybil( parsers=[ DocTestParser(optionflags=DOCTEST_FLAGS), PythonCodeBlockParser(), ], pattern='*.rst', setup=namespace.setup, teardown=namespace.teardown, ).pytest() flufl_enum-6.1.0/docs/NEWS.rst0000644000000000000000000001545013615410400013035 0ustar00===================== flufl.enum change log ===================== 6.1 (2024-03-30) ================ * Add support for Python 3.12. (GL#6) * Switch to ``hatch``, replacing ``pdm`` and ``tox``. (GL#7) * Switch to ``ruff`` from ``blue`` and ``isort``. (GL#8) 6.0.2 (2023-07-16) ================== * Update dependencies. * Minor documentation updates. 6.0.1 (2023-06-26) ================== * Update dependencies. * This release also utilizes a newer ``pdm-backend`` which fixes the project metadata. 6.0 (2023-06-05) ================ * Drop Python 3.7 support. (GL#4) * Switch from ``flake8`` and ``isort`` to ``ruff`` for code quality. (GL#5) * More GitLab CI integration improvements. * Bump dependencies. 5.0.1 (2022-09-03) ================== * Update ``pyproject.toml`` to latest pdm. * Update dependencies eagerly. * Improvements to the GitLab CI integration. 5.0 (2022-08-25) ================ Backward incompatibilities: * Removed all Python 2 support, and Python 2-isms. * Removed all remaining previously deprecated functionality. * Dropped support for Python < 3.7; add support for Python up to 3.11. * Switched to the Apache License Version 2.0. * Changed the way ``Enum[]`` and ``Enum()`` syntax are used to access enum items, to be more aligned with Python 3's standard ``enum`` library. Now you use ``Enum[]`` to look up an enum value by attribute name, and you use ``Enum()`` to look up an enum value by value. The one difference remaining is that with ``flufl.enum`` you can use ``Enum[]`` to look up an enum value by providing an enum value (standard library ``enum`` does not support this mode). Code and Documentation: * Added ``@public`` where appropriate. * Fixed some typos in the README. * Added an API reference document. * Updated dependencies. Housekeeping: * Source tree reorganization. * The ``master`` branch is renamed to ``main``. * Updated copyright years. * 100% coverage; mypy clean; i-blue-it * Use ``pdm`` as the package manager, and switch to ``pyproject.toml``. * Switched to the ``pytest`` runner. 4.1.1 (2017-01-24) ================== * Support Python 3.6. (Closes #1) 4.1 (2015-10-09) ================ * Fix the regexp that matches identifiers in the functional API. (LP: #1167052) * Deprecate using getitem syntax for accessing enum values by attribute name. Use ``getattr(Enum, name)`` instead. (LP: #1167091) * Duplicate enum values error now provides information on the attribute names that produced the conflict. Given by Eli Bendersky. * The documentation now makes it clear that iteration sort order is not guaranteed for ``Enum`` but *is* guaranteed for ``IntEnum``. * Comparison operators now return ``NotImplemented`` which cause their use to raise ``TypeError`` instead of ``NotImplementedError``. This is for consistency with Python 3. In Python 2, we raise the ``TypeError`` explicitly. * ``repr(Enum)`` now sorts in attribute name order, as does iteration over ``Enum``. Iteration over ``IntEnum`` is sorted by the enumeration item values (which must be integers). * ``Enum.__getattr__()`` and special treatment for ``__members__`` is removed. A ``__dir__()`` is provided to limit ``dir(Enum)`` to just the enumeration item names. * As per BDFL request, document the ``__value_factory__`` API. * Add support for Python 3.5 and drop support for Python 2.6. 4.0.1 (2014-06-11) ================== * Include MANIFEST.in and tox.ini in the sdist tarball, otherwise the Debian package won't built correctly. * Drop use of distribute. * Narrow tox supported environments. * Bump copyright years. 4.0 (2013-04-05) ================ * Fix documentation bugs. (LP: #1026403, LP: #1132830) * Deprecate ``EnumValue.__int__()``; use ``IntEnumValue`` (via ``IntEnum``) instead. * Add ``IntEnum`` class which returns int-subclass enum values. (LP: #1132976) - Add ``__index__()`` method to support slicing. (LP: #1132972) - Add non-deprecated ``__int__()`` method. * Deprecate ``make()``; use ``Enum()`` instead. - Call ``IntEnum()`` to create integer valued enums. (LP: #1162375) - Accept a space-separate string of enum values which are auto-split. - Accept a dictionary of enumeration name/value pairs. * Add ``.value`` attribute to enum values. (LP: #1132859) * For ``__getitem__()`` and ``__call__()``, fall back to using the ``.value`` attribute if the argument has one. (LP: #1124596) * Previously deprecated APIs ``EnumValue.enumclass``, ``EnumValue.enumname``, and ``enum.make_enum()`` are removed. (LP: #1132951) * Small change to the ``repr`` of enum values; they now say "value=" instead of "int=". * Multiple enum values now raise a `ValueError` instead of a `TypeError`. 3.3.2 (2012-04-19) ================== * Add classifiers to setup.py and make the long description more compatible with the Cheeseshop. * Other changes to make the Cheeseshop page look nicer. (LP: #680136) * setup_helper.py version 2.1. 3.3.1 (2012-01-19) ================== * Fix Python 3 compatibility with Sphinx's conf.py ($python setup.py install). 3.3 (2012-01-19) ================ * Remove the dependency on 2to3 for Python 3 support; support Python 3 directly with a single code base. * flufl.enum.make_enum() is deprecated in favor of flufl.enum.make() which provides a better API. (LP: #839529) * Updated to distribute 0.6.19. * Moved all documentation to .rst suffix. * Make test_deprecations() compatible with Python 3 and Python 2. * Removed markup for pylint. * Improve documentation to illustrate that enum values with similar names and integer representations still do not hash equally. (Found by Jeroen Vermeulen). 3.2 (2011-08-19) ================ * make_enum() accepts an optional `iterable` argument to provide the values for the enums. * The .enumclass and .enumname attributes are deprecated. Use .enum and .name instead, respectively. * Improve the documentation regarding ordered comparisons and equality tests. (LP: #794853) * make_enum() now enforces the use of valid Python identifiers. (LP: #803570) 3.1 (2011-03-01) ================ * New convenience function `make_enum()`. (Contributed by Michael Foord) * Fix `from flufl.enum import *`. * Enums created with the class syntax can be pickled and unpickled. (Suggestion and basic implementation idea by Phillip Eby). 3.0.1 (2010-06-07) ================== * Fixed typo which caused the package to break. 3.0 (2010-04-24) ================ * Package renamed to flufl.enum. 2.0.2 (2010-01-29) ================== * Fixed some test failures when running under 2to3. 2.0.1 (2010-01-08) ================== * Fix the manifest and clarify license. 2.0 (2010-01-07) ================ * Use Sphinx to build the documentation. * Updates to better package Debian/Ubuntu. * Use distribute_setup instead of ez_setup. * Rename pep-xxxx.txt; this won't be submitted as a PEP. * Remove dependencies on nose and setuptools_bzr * Support Python 3 via 2to3. flufl_enum-6.1.0/docs/__init__.py0000644000000000000000000000000013615410400013621 0ustar00flufl_enum-6.1.0/docs/apiref.rst0000644000000000000000000000033513615410400013523 0ustar00============= API Reference ============= API reference for ``flufl.enum``: .. autoclass:: flufl.enum.Enum :members: .. autoclass:: flufl.enum.IntEnum :members: .. autoclass:: flufl.enum.EnumValue :members: flufl_enum-6.1.0/docs/conf.py0000644000000000000000000001604513615410400013027 0ustar00# -*- coding: utf-8 -*- # # flufl.enum documentation build configuration file, created by # sphinx-quickstart on Thu Jan 7 18:41:30 2010. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os from datetime import date import importlib.metadata # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.append(os.path.abspath('../src')) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', ] intersphinx_mapping = { 'python': ('https://docs.python.org/3/', None), } #autodoc_typehints = 'both' autoclass_content = 'both' # We don't want to document the EnumValue.__init__() arguments because user # code will never call it directly. def skip_init(app, what, name, obj, skip, options): if getattr(obj, '__qualname__', None) == 'EnumValue.__init__': return True return skip def setup(app): app.connect('autodoc-skip-member', skip_init) autodoc_default_options = { 'exclude-members': '__weekref__', 'private-members': False, 'special-members': '__init__', 'undoc-members': False, 'typehints': 'both', } # Add any paths that contain templates here, relative to this directory. templates_path = ['../../_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'flufl.enum' author = 'Barry Warsaw' copyright = f'2004-{date.today().year}, {author}' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = importlib.metadata.version(project) # The full version, including alpha/beta/rc tags. release = version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build', 'build', 'flufl.enum.egg-info', 'distribute-0.6.10'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'furo' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". #html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'fluflenumdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('README.rst', 'fluflenum.tex', 'flufl.enum Documentation', author, 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True flufl_enum-6.1.0/docs/index.rst0000644000000000000000000000462313615410400013370 0ustar00========================================= flufl.enum - A Python enumeration package ========================================= This package is called ``flufl.enum``, a Python enumeration package. The goals of ``flufl.enum`` are to produce simple, specific, concise semantics in an easy to read and write syntax. ``flufl.enum`` has just enough of the features needed to make enumerations useful, but without a lot of extra baggage to weigh them down. This work grew out of the `Mailman 3.0 `_ project. This package was previously called ``munepy``. Since enums were added to Python in 3.4, why use this package instead of the Python standard library `enum `_ package? ``flufl.enum`` is intentionally simpler, and thus potentially faster and easier to maintain. Requirements ============ ``flufl.enum`` requires Python 3.8 or newer. Documentation ============= A `simple guide`_ to using the library is available within this package, along with a detailed `API reference`_. Project details =============== * Project home: https://gitlab.com/warsaw/flufl.enum * Report bugs at: https://gitlab.com/warsaw/flufl.enum/issues * Code hosting: https://gitlab.com/warsaw/flufl.enum.git * Documentation: http://fluflenum.readthedocs.org/ You can install it with ``pip``:: % pip install flufl.enum You can grab the latest development copy of the code using git. The repository is hosted on GitLab. If you have git installed, you can grab your own branch of the code like this:: $ git clone https://gitlab.com/warsaw/flufl.enum.git You may contact the author via barry@python.org. Copyright ========= Copyright (C) 2004-2024 Barry A. Warsaw Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Table of Contents ================= * :ref:`genindex` .. toctree:: :glob: using apiref NEWS .. _`simple guide`: using.html .. _`API reference`: apiref.html flufl_enum-6.1.0/docs/using.rst0000644000000000000000000003443013615410400013405 0ustar00============================ Using the flufl.enum library ============================ Author: `Barry Warsaw`_ The ``flufl.enum`` package provides an enumeration data type for Python. This package was the inspiration for `PEP 435`_. ``flufl.enum`` provides similar, but simpler functionality. An enumeration is a set of symbolic names bound to unique, constant values, called *enumeration items*. Within an enumeration, the items can be compared by identity, and the enumeration itself can be iterated over. The underlying values can be retrieved from the enumeration items. An integer based variant is provided which allows items to be used as slices, to interoperate with C-based APIs, and for logical operations. Motivation ========== [Lifted from `PEP 354`_ - the original rejected enumeration PEP] The properties of an enumeration are useful for defining an immutable, related set of constant values that have a defined sequence but no inherent semantic meaning. Classic examples are days of the week (Sunday through Saturday) and school assessment grades ('A' through 'D', and 'F'). Other examples include error status values and states within a defined process. It is possible to simply define a sequence of values of some other basic type, such as ``int`` or ``str``, to represent discrete arbitrary values. However, an enumeration ensures that such values are distinct from any others, and that operations without meaning ("Wednesday times two") are not defined for these values. Creating an Enumeration ======================= Class syntax ------------ Enumerations can be created using the class syntax, which makes them easy to read and write. Every enumeration item must have a unique value and the only restriction on their names is that they must be valid Python identifiers. To define an enumeration, derive from the ``Enum`` class and add attributes with assignment to their values. Values may not be duplicated. :: >>> from flufl.enum import Enum >>> class Colors(Enum): ... red = 1 ... green = 2 ... blue = 3 Enumeration items have nice, human readable string representations. >>> print(Colors.red) Colors.red The ``reprs`` have additional detail. >>> print(repr(Colors.red)) Accessing items --------------- You can look up an enumeration item by attribute name using "getitem" syntax. >>> print(Colors['red']) Colors.red Using the same syntax, you can look up the item by passing in the item. >>> print(Colors[Colors.red]) Colors.red You can also look up an enumeration item by value using "call" syntax. >>> print(Colors(1)) Colors.red Integer enumerations -------------------- A special subclass of ``Enum`` can be used when the enumeration items need to act like integers. In fact, the items in this ``IntEnum`` class *are* integers and can be used any place an integer needs to be used, including when interfacing with C APIs. :: >>> from flufl.enum import IntEnum >>> class Animals(IntEnum): ... ant = 1 ... bee = 2 ... cat = 3 These enumeration items can be converted to integers. >>> int(Animals.bee) 2 These enumeration items can also be used as slice indexes. >>> list(range(10)[Animals.ant:Animals.cat]) [1, 2] Convenience API --------------- For convenience, you can create an enumeration by calling the ``Enum`` class. The first argument is the name of the new enumeration, and the second is provides the enumeration items. There are several ways to specify the items -- see the section `Functional API`_ for details -- but the easiest way is to provide a string of space separated attribute names. The values for these items are auto-assigned integers starting from 1. >>> Rush = Enum('Rush', 'Geddy Alex Neil') The ``str`` and ``repr`` provide details. >>> print(Rush.Geddy) Rush.Geddy >>> print(repr(Rush.Geddy)) See the section on the `Functional API`_ for more options and information. Values ------ Enumeration items can have any value you choose, but typically they will be integer or string values, and it is recommended that all the values be of the same type, although this is not enforced. :: >>> class Rush(Enum): ... Geddy = 'bass' ... Alex = 'guitar' ... Neil = 'drums' >>> print(repr(Rush.Alex)) Inspecting Enumerations ======================= ``dir()`` returns the enumeration item names. >>> for member in sorted(dir(Colors)): ... print(member) blue green red The ``str()`` and ``repr()`` of the enumeration class also provides useful information. The items are always sorted by attribute name. >>> print(Colors) >>> print(repr(Colors)) You can get the enumeration class object from an enumeration item. >>> print(Colors.red.enum.__name__) Colors Enumerations also have a property that contains just their item name. >>> print(Colors.red.name) red >>> print(Colors.green.name) green >>> print(Colors.blue.name) blue The underlying item value can also be retrieved via the ``.value`` attribute. >>> print(Rush.Geddy.value) bass Integer enumerations can also be explicitly convert to their integer value using the ``int()`` built-in. >>> int(Animals.ant) 1 >>> int(Animals.bee) 2 >>> int(Animals.cat) 3 Comparison ========== Enumeration items are compared by identity. >>> Colors.red is Colors.red True >>> Colors.blue is Colors.blue True >>> Colors.red is not Colors.blue True >>> Colors.blue is Colors.red False The standard ``Enum`` class does not allow comparisons against the integer equivalent values, and if you define an enumeration with similar item names and integer values, they will not be identical. >>> class OtherColors(Enum): ... red = 1 ... blue = 2 ... yellow = 3 >>> Colors.red is OtherColors.red False >>> Colors.blue is not OtherColors.blue True These enumeration items are not equal, nor do they hash equally. >>> Colors.red == OtherColors.red False >>> len(set((Colors.red, OtherColors.red))) 2 Ordered comparisons between enumeration items are *not* supported. The base enumeration values are not integers! >>> Colors.red < Colors.blue Traceback (most recent call last): ... TypeError: ... >>> Colors.red <= Colors.blue Traceback (most recent call last): ... TypeError: ... >>> Colors.blue > Colors.green Traceback (most recent call last): ... TypeError: ... >>> Colors.blue >= Colors.green Traceback (most recent call last): ... TypeError: ... >>> Colors.red < 3 Traceback (most recent call last): ... TypeError: ... While discouraged for readability, equality comparisons are allowed. >>> Colors.blue == Colors.blue True >>> Colors.green != Colors.blue True However, comparisons against non-enumeration items will always compare not equal. >>> Colors.green == 2 False >>> Colors.blue == 3 False >>> Colors.green != 3 True >>> Colors.green == 'green' False Integer enumerations -------------------- With the ``IntEnum`` class though, enumeration items *are* integers, so all the ordered comparisons work as expected. >>> Animals.ant < Animals.bee True >>> Animals.cat > Animals.ant True Comparisons against other numbers also work as expected. >>> Animals.ant <= 1.0 True >>> Animals.bee == 2 True You can even compare integer enumeration items against other unrelated integer enumeration items, since the comparisons use the standard integer operators. :: >>> class Toppings(IntEnum): ... anchovies = 1 ... black_olives = 2 ... cheese = 4 ... dried_tomatoes = 8 ... eggplant = 16 >>> Toppings.black_olives == Animals.bee True Conversions =========== You can convert back to the enumeration item by using the ``Enum`` class's ``getitem`` syntax, passing in the value for the item you want. >>> Colors[2] >>> Rush['bass'] >>> Colors[1] is Colors.red True If instead you have the enumeration name (i.e. the attribute name), just use Python's normal ``getattr()`` function. >>> getattr(Colors, 'red') >>> getattr(Rush, Rush.Alex.name) >>> getattr(Colors, 'blue') is Colors.blue True Iteration ========= The ``Enum`` class supports iteration. Items are returned in order, sorted by their attribute name. >>> from operator import attrgetter >>> by_value = attrgetter('value') >>> [v.name for v in sorted(Colors, key=by_value)] ['red', 'green', 'blue'] >>> [v.value for v in sorted(Colors, key=by_value)] [1, 2, 3] >>> [v.name for v in sorted(Rush, key=by_value)] ['Geddy', 'Neil', 'Alex'] >>> for v in sorted(Rush, key=by_value): ... print(v.value) bass drums guitar Iteration over ``IntEnum`` is sorted in the order of the enumeration item values. :: >>> class Toppings(IntEnum): ... anchovies = 4 ... black_olives = 8 ... cheese = 2 ... dried_tomatoes = 16 ... eggplant = 1 >>> for value in Toppings: ... print(value.name, '=', value.value) eggplant = 1 cheese = 2 anchovies = 4 black_olives = 8 dried_tomatoes = 16 Enumeration items can be used in dictionaries and sets. >>> from operator import attrgetter >>> getvalue = attrgetter('value') >>> apples = {} >>> apples[Colors.red] = 'red delicious' >>> apples[Colors.green] = 'granny smith' >>> for color in sorted(apples, key=getvalue): ... print(color.name, '->', apples[color]) red -> red delicious green -> granny smith Extending an enumeration through subclassing ============================================ You can extend previously defined enumerations by subclassing. Just as before, items cannot be duplicated in either the base class or subclass. >>> class MoreColors(Colors): ... pink = 4 ... cyan = 5 When extended in this way, the base enumeration's items are identical to the same named items in the derived class. >>> Colors.red is MoreColors.red True >>> Colors.blue is MoreColors.blue True Pickling ======== Enumerations created with the class syntax can also be pickled and unpickled, as long as the module containing the enum is importable. :: >>> from fruit import Fruit >>> from pickle import dumps, loads >>> Fruit.tomato is loads(dumps(Fruit.tomato)) True Functional API ============== As described above, you can create enumerations functionally by calling ``Enum`` or ``IntEnum``. The first argument is always the name of the new enumeration. The second argument describes the enumeration item names and values. The easiest way to create new enumerations is to provide a single string with space-separated attribute names. In this case, the values are auto-assigned integers starting from 1. >>> Enum('Animals', 'ant bee cat dog') The second argument can also be a sequence of strings. In this case too, the values are auto-assigned integers starting from 1. >>> Enum('People', ('anne', 'bart', 'cate', 'dave')) The items can also be specified by using a sequence of 2-tuples, where the first item is the enumeration item name and the second is the value to use. If 2-tuples are given, all items must be 2-tuples. >>> def enumiter(): ... start = 1 ... while True: ... yield start ... start <<= 1 >>> Enum('Flags', zip(list('abcdefg'), enumiter())) You can also provide the enumeration items as a dictionary mapping names to values. Remember that the ``repr`` is sorted by attribute name. >>> bassists = dict(Geddy='Rush', Chris='Yes', Flea='RHCP', Jack='Cream') >>> Enum('Bassists', bassists) If you want to create an ``IntEnum`` where the values are integer subclasses, call that class instead. This has the same signature as calling ``Enum`` but the items of the returned enumeration are int subclasses. >>> Numbers = IntEnum('Numbers', 'one two three four') >>> Numbers.three == 3 True Customization protocol ====================== You can define your own enumeration value types by using the ``__value_factory__`` protocol. This is how the ``IntEnum`` type is defined. As an example, let's say you want to define a new type of enumeration where the values were subclasses of ``str``. First, define your enumeration value subclass. >>> from flufl.enum import EnumValue >>> class StrEnumValue(str, EnumValue): ... def __new__(cls, enum, value, attr): ... return super().__new__(cls, value) And then define your enumeration class. You must set the class attribute ``__value_factory__`` to the class of the values you want to create. >>> class StrEnum(Enum): ... __value_factory__ = StrEnumValue Now, when you define your enumerations, the values will be ``str`` subclasses. :: >>> class Noises(StrEnum): ... dog = 'bark' ... cat = 'meow' ... cow = 'moo' >>> isinstance(Noises.cow, str) True Acknowledgments =============== The ``flufl.enum`` implementation is based on an example by Jeremy Hylton. It has been modified and extended by Barry Warsaw for use in the `GNU Mailman`_ project. Ben Finney is the author of the earlier enumeration PEP 354. Eli Bendersky is the co-author of PEP 435. Numerous people on the `python-ideas`_ and `python-dev`_ mailing lists have provided valuable feedback. .. _`PEP 435`: http://www.python.org/dev/peps/pep-0435/ .. _`PEP 354`: http://www.python.org/dev/peps/pep-0354/ .. _`GNU Mailman`: http://www.list.org .. _`python-ideas`: http://mail.python.org/mailman/listinfo/python-ideas .. _`python-dev`: http://mail.python.org/mailman/listinfo/python-dev .. _`Barry Warsaw`: http://barry.warsaw.us flufl_enum-6.1.0/src/flufl/enum/__init__.py0000644000000000000000000000033713615410400015551 0ustar00from public import public as _public from ._enum import Enum, EnumValue, IntEnum __version__ = '6.1.0' _public( Enum=Enum, EnumValue=EnumValue, IntEnum=IntEnum, __version__=__version__, ) del _public flufl_enum-6.1.0/src/flufl/enum/_enum.py0000644000000000000000000002153013615410400015113 0ustar00"""Python enumerations.""" import re from operator import itemgetter from typing import Any, Dict, Iterable, Tuple, Union, cast from public import public COMMASPACE = ', ' SPACE = ' ' IDENTIFIER_RE = r'^[a-zA-Z_][a-zA-Z0-9_]*$' LookupValue = Union['EnumValue', str] class EnumMetaclass(type): """Meta class for Enums.""" def __init__( cls, name: str, bases: Tuple[type, ...], namespace: Dict[str, Any] ): """Create an Enum class. :param cls: The class being defined. :param name: The name of the class. :param bases: The class's base classes. :param namespace: The class attributes. """ super().__init__(name, bases, namespace) # values -> EnumValues cls._byvalue = {} # Figure out if this class has a custom factory for building enum # values. The default is EnumValue, but the class (or one of its # bases) can declare a custom one with a special attribute. factory = namespace.get('__value_factory__') # Figure out the set of enum values on the base classes, to ensure # that we don't get any duplicate values. At the same time, check the # base classes for the special attribute. for basecls in cls.__mro__: if hasattr(basecls, '_byvalue'): cls._byvalue.update(basecls._byvalue) if hasattr(basecls, '__value_factory__'): basecls_factory = basecls.__value_factory__ if factory is not None and basecls_factory != factory: raise TypeError( f'Conflicting enum factory in base class: {basecls_factory}' # noqa: E501 ) factory = basecls_factory # Set the factory default if necessary. if factory is None: factory = EnumValue # For each class attribute, create an enum value and store that back # on the class instead of the original value. Skip Python reserved # names. Also add a mapping from the original value to the enum value # instance so we can return the same object on conversion. for attr in namespace: if not (attr.startswith('__') and attr.endswith('__')): value = namespace[attr] enumval = factory(cls, value, attr) if value in cls._byvalue: other = cls._byvalue[value] # Without this, sort order is undefined and causes # unpredictable results for the test suite. first = attr if attr < other else other second = other if attr < other else attr raise ValueError( f"Conflicting enum value '{value}' " f"for names: '{first}' and '{second}'" ) # Store as an attribute on the class, and save the attr name. setattr(cls, attr, enumval) cls._byvalue[value] = attr def __dir__(cls) -> Iterable[str]: return list(cls._byvalue.values()) def __repr__(cls) -> str: # We want predictable reprs. Because base Enum items can have any # value, the only reliable way to sort the keys for the repr is based # on the attribute name, which must be Python identifiers. value = COMMASPACE.join( f'{value}: {key}' for key, value in sorted(cls._byvalue.items(), key=itemgetter(1)) ) return f'<{cls.__name__} {{{value}}}>' def __iter__(cls) -> Iterable['EnumValue']: for value in sorted(cls._byvalue.values()): yield getattr(cls, value) def __getitem__(cls, item: LookupValue) -> 'EnumValue': try: return getattr(cls, item) # type: ignore except (AttributeError, TypeError): if hasattr(item, 'value'): attr = cls._byvalue.get(item.value) if attr is None: raise KeyError(item) from None return cast('EnumValue', getattr(cls, attr)) else: missing = object() value = cls._byvalue.get(item, missing) if value is not missing: return cast('EnumValue', getattr(cls, value)) raise KeyError(item) from None def __call__(cls, *args): # type: ignore if len(args) == 1: return cls.__getitem__(args[0]) # Two argument allows for extending enums. name, source = args return _make(cls, name, source) @public class EnumValue: """Class representing an enumeration value. EnumValue(Color, 'red', 12) prints as 'Color.red' and can be converted to the integer 12. """ def __init__(self, enum: EnumMetaclass, value: Any, name: str): self._enum = enum self._value = value self._name = name def __repr__(self) -> str: return f'' # noqa: E501 def __str__(self) -> str: return f'{self._enum.__name__}.{self._name}' def __reduce__(self): # type: ignore return getattr, (self._enum, self._name) @property def enum(self) -> EnumMetaclass: """The underlying enum.""" return self._enum @property def name(self) -> str: """The enum's name.""" return self._name @property def value(self) -> Any: """The enum's value.""" return self._value # Support only comparison by identity and equality. Ordered comparisons # are not supported. def __eq__(self, other: Any) -> bool: return self is other def __ne__(self, other: Any) -> bool: return self is not other def __lt__(self, other: Any) -> Any: return NotImplemented def __gt__(self, other: Any) -> Any: return NotImplemented def __le__(self, other: Any) -> Any: return NotImplemented def __ge__(self, other: Any) -> Any: return NotImplemented __hash__ = object.__hash__ @public class Enum(metaclass=EnumMetaclass): """The public API Enum class.""" class IntEnumValue(int, EnumValue): """An EnumValue that is also an integer.""" def __new__( cls, enum: EnumMetaclass, value: Any, attr: str ) -> 'IntEnumValue': # `attr` is going to be the attribute name as created through the # factory call in EnumMetaclass.__init__(), however we need to throw # that away when calling int's __new__(). return super().__new__(cls, value) __repr__ = EnumValue.__repr__ __str__ = EnumValue.__str__ # The non-deprecated version of this method. def __int__(self) -> int: return cast(int, self._value) __hash__ = int.__hash__ # For slices and index(). __index__ = __int__ class IntEnumMetaclass(EnumMetaclass): # Define an iteration over the integer values instead of the attribute # names. def __iter__(cls) -> Iterable['IntEnumValue']: for key in sorted(cls._byvalue): yield getattr(cls, cls._byvalue[key]) @public class IntEnum(metaclass=IntEnumMetaclass): """A specialized enumeration with values that are also integers.""" __value_factory__ = IntEnumValue def _swap(sequence: Iterable[Any]) -> Iterable[Any]: for key, value in sequence: yield value, key def _make(enum_class: EnumMetaclass, name: str, source: Any) -> EnumMetaclass: # The common implementation for Enum() and IntEnum(). namespace = {} illegals = [] have_strings: Union[None, bool] = None # Auto-splitting of strings. if isinstance(source, str): source = source.split() # Look for dict-like arguments. Specifically, it must have a callable # .items() attribute. Because of the way enumerate() works, here we have # to swap the key/values. try: source = _swap(source.items()) except (TypeError, AttributeError): source = enumerate(source, start=1) for i, item in source: if isinstance(item, str): if have_strings is None: have_strings = True elif not have_strings: raise ValueError('heterogeneous source') namespace[item] = i if re.match(IDENTIFIER_RE, item) is None: illegals.append(item) else: if have_strings is None: have_strings = False elif have_strings: raise ValueError('heterogeneous source') item_name, item_value = item namespace[item_name] = item_value if re.match(IDENTIFIER_RE, item_name) is None: illegals.append(item_name) if len(illegals) > 0: raise ValueError(f'non-identifiers: {SPACE.join(illegals)}') return EnumMetaclass(str(name), (enum_class,), namespace) flufl_enum-6.1.0/test/__init__.py0000644000000000000000000000000013615410400013650 0ustar00flufl_enum-6.1.0/test/fruit.py0000644000000000000000000000013413615410400013252 0ustar00from flufl.enum import Enum class Fruit(Enum): kiwi = 1 banana = 2 tomato = 3 flufl_enum-6.1.0/test/test_enum.py0000644000000000000000000002355013615410400014133 0ustar00import pytest from flufl.enum import Enum, IntEnum, EnumValue from flufl.enum._enum import IntEnumValue from itertools import combinations from operator import attrgetter, index SPACE = ' ' class Colors(Enum): red = 1 green = 2 blue = 3 class OtherColors(Enum): red = 1 blue = 2 yellow = 3 class MoreColors(Colors): pink = 4 cyan = 5 ALL_COLORS = ['red', 'green', 'blue'] class Rush(Enum): geddy = 'bass' alex = 'guitar' neil = 'drums' class Animals(IntEnum): ant = 1 bee = 2 cat = 3 def test_basic_reprs(): assert str(Colors.red) == 'Colors.red' assert str(Colors.green) == 'Colors.green' assert str(Colors.blue) == 'Colors.blue' assert str(Colors['red']) == 'Colors.red' assert repr(Colors.red) == '' def test_string_value(): assert repr(Rush.alex) == '' def test_factory_single_string(): Color = Enum('Color', SPACE.join(ALL_COLORS)) for c in ALL_COLORS: assert str(Color[c]) == 'Color.' + c def test_enum_dir(): # dir() returns the list of enumeration item names. assert sorted(dir(Colors)) == sorted(ALL_COLORS) def test_enumclass_getitem(): assert Colors[2] is Colors.green assert Colors['red'] is Colors.red assert Colors[Colors.red] is Colors.red def test_iteration(): # Iteration over basic Enums is by attribute name. A = Enum('A', 'a b c') assert list(v.name for v in A) == ['a', 'b', 'c'] B = Enum('B', 'c b a') assert list(v.name for v in B) == ['a', 'b', 'c'] # If iteration sorted over values, this would give a TypeError. C = Enum('C', dict(a='7', b=7)) assert list(v.name for v in C) == ['a', 'b'] def test_hashing(): getvalue = attrgetter('value') apples = {} apples[Colors.red] = 'red delicious' apples[Colors.green] = 'granny smith' assert [(c.name, apples[c]) for c in sorted(apples, key=getvalue)] == [ ('red', 'red delicious'), ('green', 'granny smith'), ] def test_value_enum_attributes(): for i, c in enumerate(ALL_COLORS, 1): # enum attribute assert Colors[c].enum is Colors # name attribute assert Colors[c].name == c # value attribute assert Colors[c].value == i def test_enum_class_name(): assert Colors.__name__ == 'Colors' def test_comparisons(): r, g, b = Colors.red, Colors.green, Colors.blue for c in r, g, b: assert c is c assert c == c for first, second in combinations([r, g, b], 2): assert first is not second assert first != second with pytest.raises(TypeError): Colors.red < Colors.blue with pytest.raises(TypeError): Colors.red <= Colors.blue with pytest.raises(TypeError): Colors.red > Colors.green with pytest.raises(TypeError): Colors.green >= Colors.blue def test_comparison_with_int(): with pytest.raises(TypeError): Colors.red < 3 with pytest.raises(TypeError): Colors.red <= 3 with pytest.raises(TypeError): Colors.blue > 2 with pytest.raises(TypeError): Colors.green >= 1 assert Colors.green != 2 assert Colors.blue != 3 assert Colors.green != 3 def test_comparison_with_other_enum(): assert OtherColors.red is not Colors.red assert OtherColors.red != Colors.red assert hash(OtherColors.red) != hash(Colors.red) def test_subclass(): assert Colors.red is MoreColors.red assert Colors.blue is MoreColors.blue def test_pickle(): from .fruit import Fruit from pickle import dumps, loads assert Fruit.tomato is loads(dumps(Fruit.tomato)) def test_functional_api_single_string(): animals = Enum('Animals', 'ant bee cat dog') assert repr(animals) == '' def test_functional_api_sequence(): people = Enum('People', ('anne', 'bart', 'cate', 'dave')) assert repr(people) == '' def test_functional_api_2_tuples(): def enumiter(): start = 1 while True: yield start start <<= 1 flags = Enum('Flags', zip(list('abcdefg'), enumiter())) assert ( repr(flags) == '' ) def test_functional_api_dict(): # Note: repr is sorted by attribute name bassists = dict(geddy='rush', chris='yes', flea='rhcp', jack='cream') assert ( repr(Enum('Bassists', bassists)) == '' ) def test_invalid_getitem_arguments(): # Trying to get an invalid value raises an exception. with pytest.raises(KeyError) as exc_info: Colors['magenta'] assert exc_info.value.args == ('magenta',) def test_no_duplicates(): with pytest.raises(ValueError) as exc_info: class Bad(Enum): cartman = 1 stan = 2 kyle = 3 kenny = 3 # Oops! butters = 4 assert ( str(exc_info.value) == "Conflicting enum value '3' for names: 'kenny' and 'kyle'" ) def test_no_duplicates_in_subclass(): with pytest.raises(ValueError) as exc_info: class BadMoreColors(Colors): yellow = 4 magenta = 2 # Oops! assert ( str(exc_info.value) == "Conflicting enum value '2' for names: 'green' and 'magenta'" ) def test_no_duplicates_in_dict(): with pytest.raises(ValueError) as exc_info: Enum('Things', dict(a='yes', b='no', c='maybe', d='yes')) assert ( exc_info.value.args[0] == "Conflicting enum value 'yes' for names: 'a' and 'd'" ) def test_functional_api_not_all_2_tuples(): # If 2-tuples are used, all items must be 2-tuples. with pytest.raises(ValueError): Enum( 'Animals', ( ('ant', 1), ('bee', 2), 'cat', ('dog', 4), ), ) with pytest.raises(ValueError): Enum( 'Animals', ( ('ant', 1), ('bee', 2), ('cat',), ('dog', 4), ), ) with pytest.raises(ValueError): Enum( 'Animals', ( ('ant', 1), ('bee', 2), ('cat', 3, 'oops'), ('dog', 4), ), ) def test_functional_api_identifiers(): # Ensure that the functional API enforces identifiers. with pytest.raises(ValueError) as exc_info: Enum('Foo', ('1', '2', '3')) assert exc_info.value.args[0] == 'non-identifiers: 1 2 3' with pytest.raises(ValueError) as exc_info: Enum('Foo', (('ant', 1), ('bee', 2), ('3', 'cat'))) assert exc_info.value.args[0] == 'non-identifiers: 3' def test_functional_api_identifiers_lp1167052(): # LP: #1167052 with pytest.raises(ValueError): Enum('X', 'a-1') def test_functional_api_identifiers_numbers(): # There was a typo in IDENTIFIER_RE where the range 0-0 was used. MyEnum = Enum('X', 'a9') assert MyEnum.a9.name == 'a9' def test_explicit_getattr(): Fruit = Enum('Fruit', 'apple banana tangerine orange') assert getattr(Fruit, 'banana') is Fruit.banana assert getattr(Fruit, Fruit.banana.name) is Fruit.banana def test_issue_17576(): # http://bugs.python.org/issue17576 # # The problem is that despite the documentation, operator.index() is # *not* equivalent to calling obj.__index__() when the object in # question is an int subclass. # Test that while the actual type returned by operator.index() and # obj.__index__() are not the same (because the former returns the # subclass instance, but the latter returns the .value attribute) they # are equal. assert index(Animals.bee) == Animals.bee.__index__() def test_basic_intenum(): animal_list = [Animals.ant, Animals.bee, Animals.cat] assert animal_list == [1, 2, 3] assert [int(a) for a in animal_list] == [1, 2, 3] assert list(range(10)[Animals.ant : Animals.cat]) == [1, 2] def test_int_enums_type(): # IntEnum() enum values are ints. Toppings = IntEnum( 'Toppings', dict(olives=1, onions=2, mushrooms=4, cheese=8, garlic=16).items(), ) assert Toppings.garlic == 16 assert isinstance(Toppings.mushrooms, int) def test_intenum_comparisons(): assert Animals.ant < Animals.bee assert Animals.cat > Animals.ant assert Animals.ant <= 1.0 assert Animals.bee == 2 class Toppings(IntEnum): anchovies = 1 black_olives = 2 assert Animals.bee == Toppings.black_olives def test_intenum_iteration(): # Iteration over IntEnums is by value. A = IntEnum('A', 'a b c') assert list(v.name for v in A) == ['a', 'b', 'c'] B = IntEnum('B', 'c b a') # Iteration over this enum is different than if it were an Enum. assert list(v.name for v in B) == ['c', 'b', 'a'] def test_conflicting_factories(): # An enum extension cannot have a different value factory. class First(Enum): __value_factory__ = EnumValue red = 1 green = 2 blue = 3 with pytest.raises(TypeError): class Second(First): __value_factory__ = IntEnumValue red = 1 green = 2 blue = 3 def test_weird_getitem(): # If we try to get an enum item with an argument that pretends to be an # item, but really isn't, we'll get a KeyError. class Balls(Enum): foot = 1 base = 2 golf = 3 class NotAnEnumItem: value = 99 with pytest.raises(KeyError): Balls[NotAnEnumItem()] def test_make_with_inconsistent_values(): # Passing a dictionary into the functional API requires that all values be # of the same type. with pytest.raises(ValueError): Enum('Animal', ('ant', 7)) flufl_enum-6.1.0/.gitignore0000644000000000000000000000014213615410400012557 0ustar00build flufl.*.egg-info dist *.pyc .tox /.coverage /.pdm.toml /coverage.xml /.pdm-python /pdm.toml flufl_enum-6.1.0/LICENSE0000644000000000000000000000105613615410400011601 0ustar00Copyright 2004-2024 Barry Warsaw Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. flufl_enum-6.1.0/README.rst0000644000000000000000000000221513615410400012261 0ustar00========== flufl.enum ========== A Python enumeration package. The ``flufl.enum`` library is a Python enumeration package. Its goal is to provide simple, specific, concise semantics in an easy to read and write syntax. ``flufl.enum`` has just enough of the features needed to make enumerations useful, but without a lot of extra baggage to weigh them down. This work grew out of the Mailman 3.0 project. Since enums were added to Python in 3.4, why use this package instead of the Python standard library `enum `_ package? ``flufl.enum`` is intentionally simpler, and thus potentially faster and easier to maintain. Author ====== ``flufl.enum`` is Copyright (C) 2004-2024 Barry Warsaw Licensed under the terms of the Apache License Version 2.0. See the LICENSE file for details. Project details =============== * Project home: https://gitlab.com/warsaw/flufl.enum * Report bugs at: https://gitlab.com/warsaw/flufl.enum/issues * Code hosting: https://gitlab.com/warsaw/flufl.enum.git * Documentation: http://fluflenum.readthedocs.org/ * PyPI: https://pypi.python.org/pypi/flufl.enum flufl_enum-6.1.0/pyproject.toml0000644000000000000000000001104213615410400013504 0ustar00[project] name = 'flufl.enum' authors = [ {name = 'Barry Warsaw', email = 'barry@python.org'}, ] description = 'A Python enumeration package' readme = 'README.rst' requires-python = '>=3.8' license = {text = 'Apache-2.0'} keywords = [ 'enum', ] classifiers = [ 'Development Status :: 5 - Production/Stable', 'Development Status :: 6 - Mature', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Operating System :: POSIX', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules', ] dependencies = [ 'atpublic', ] dynamic = ['version'] [project.urls] 'Home Page' = 'https://fluflenum.readthedocs.io' 'Documentation' = 'https://fluflenum.readthedocs.io' 'Source Code' = 'https://gitlab.com/warsaw/flufl.enum.git' 'Bug Tracker' = 'https://gitlab.com/warsaw/flufl.enum/issues' [tool.hatch.version] path = 'src/flufl/enum/__init__.py' [tool.hatch.build.targets.wheel] packages = [ 'src/flufl', ] [tool.hatch.build.targets.sdist] include = [ 'src/flufl/', 'docs/', 'test/', 'conftest.py', ] excludes = [ '**/.mypy_cache', ] [tool.hatch.envs.default.scripts] all = [ 'hatch run test:test', 'hatch run qa:qa', 'hatch run docs:docs', ] [[tool.hatch.envs.test.matrix]] python = ['3.8', '3.9', '3.10', '3.11', '3.12'] [tool.hatch.envs.test] dependencies = [ 'coverage[toml]', 'diff-cover', 'pytest', 'pytest-cov', 'sybil', ] [tool.hatch.envs.test.scripts] test = [ 'pytest {args}', # The following is only useful in a git branch of main. '- diff-cover coverage.xml', ] [tool.hatch.envs.qa] dependencies = [ 'ruff', 'mypy', ] [tool.hatch.envs.qa.env-vars] MODULE_NAME = '{env:MODULE_NAME:flufl.enum}' MODULE_PATH = '{env:MODULE_PATH:src/flufl/enum}' [tool.hatch.envs.qa.scripts] qa = [ 'ruff check {env:MODULE_PATH}', 'mypy -p {env:MODULE_NAME}', ] fix = [ 'ruff check --fix {env:MODULE_PATH}', ] preview = [ 'ruff check --fix --diff {env:MODULE_PATH}', ] [tool.hatch.envs.docs] dependencies = [ 'sphinx', 'furo', ] [tool.hatch.envs.docs.scripts] docs = [ 'sphinx-build docs build/html', ] [tool.pytest.ini_options] addopts = '--cov=flufl --cov-report=term --cov-report=xml -p no:doctest' testpaths = 'test docs' [tool.coverage.paths] source = ['flufl/enum'] [tool.coverage.report] fail_under = 100 show_missing = true [tool.coverage.run] branch = true parallel = true [tool.ruff] line-length = 79 src = ['src'] [tool.ruff.lint] select = [ 'B', # flake8-bugbear 'D', # pydocstyle 'E', # pycodestyle 'F', # pyflakes 'I', # isort 'RUF100', # check for valid noqa directives 'UP', # pyupgrade 'W', # pycodestyle ] ignore = [ 'D100', # Missing docstring in public module 'D104', # Missing docstring in public package 'D105', # Missing docstring in magic method ] [tool.ruff.lint.pydocstyle] convention = 'pep257' [tool.ruff.lint.isort] case-sensitive = true known-first-party = ['flufl.enum'] length-sort-straight = true lines-after-imports = 2 lines-between-types = 1 order-by-type = true section-order = ['standard-library', 'third-party', 'local-folder', 'first-party'] [tool.mypy] mypy_path = 'src' # Disallow dynamic typing disallow_any_generics = true disallow_subclassing_any = true # Untyped definitions and calls disallow_untyped_calls = false disallow_untyped_defs = true disallow_incomplete_defs = true check_untyped_defs = true disallow_untyped_decorators = false # None and Optional handling no_implicit_optional = true # Configuring warnings warn_redundant_casts = true warn_unused_ignores = true warn_no_return = true warn_return_any = true warn_unreachable = true # Miscellaneous strictness flags implicit_reexport = false strict_equality = true # Configuring error messages show_error_context = true show_column_numbers = true show_error_codes = true pretty = true show_absolute_path = true # Miscellaneous warn_unused_configs = true verbosity = 0 [[tool.mypy.overrides]] module = [ 'pytest', 'sybil.*', ] ignore_missing_imports = true [build-system] requires = ['hatchling'] build-backend = 'hatchling.build' flufl_enum-6.1.0/PKG-INFO0000644000000000000000000000433313615410400011672 0ustar00Metadata-Version: 2.3 Name: flufl.enum Version: 6.1.0 Summary: A Python enumeration package Project-URL: Home Page, https://fluflenum.readthedocs.io Project-URL: Documentation, https://fluflenum.readthedocs.io Project-URL: Source Code, https://gitlab.com/warsaw/flufl.enum.git Project-URL: Bug Tracker, https://gitlab.com/warsaw/flufl.enum/issues Author-email: Barry Warsaw License: Apache-2.0 License-File: LICENSE Keywords: enum Classifier: Development Status :: 5 - Production/Stable Classifier: Development Status :: 6 - Mature Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Operating System :: POSIX Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Topic :: Software Development :: Libraries Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.8 Requires-Dist: atpublic Description-Content-Type: text/x-rst ========== flufl.enum ========== A Python enumeration package. The ``flufl.enum`` library is a Python enumeration package. Its goal is to provide simple, specific, concise semantics in an easy to read and write syntax. ``flufl.enum`` has just enough of the features needed to make enumerations useful, but without a lot of extra baggage to weigh them down. This work grew out of the Mailman 3.0 project. Since enums were added to Python in 3.4, why use this package instead of the Python standard library `enum `_ package? ``flufl.enum`` is intentionally simpler, and thus potentially faster and easier to maintain. Author ====== ``flufl.enum`` is Copyright (C) 2004-2024 Barry Warsaw Licensed under the terms of the Apache License Version 2.0. See the LICENSE file for details. Project details =============== * Project home: https://gitlab.com/warsaw/flufl.enum * Report bugs at: https://gitlab.com/warsaw/flufl.enum/issues * Code hosting: https://gitlab.com/warsaw/flufl.enum.git * Documentation: http://fluflenum.readthedocs.org/ * PyPI: https://pypi.python.org/pypi/flufl.enum