diff --git a/.github/workflows/python_ci.yml b/.github/workflows/python_ci.yml index 469f90a..89c96c4 100644 --- a/.github/workflows/python_ci.yml +++ b/.github/workflows/python_ci.yml @@ -27,13 +27,13 @@ jobs: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - - {python-version: "3.7", testenvs: "py37,build", experimental: False} - - {python-version: "3.8", testenvs: "py38,build", experimental: False} - - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} - - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: True} + - {python-version: "3.6", testenvs: "py36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.7", testenvs: "py37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.8", testenvs: "py38-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.9", testenvs: "py39-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.10", testenvs: "py310-dev-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} + - {python-version: "pypy-3.6", testenvs: "pypy36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "pypy-3.7", testenvs: "pypy37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} steps: - name: Checkout 🛎️ diff --git a/.github/workflows/python_ci_linux.yml b/.github/workflows/python_ci_linux.yml index 4b38cfd..e84a316 100644 --- a/.github/workflows/python_ci_linux.yml +++ b/.github/workflows/python_ci_linux.yml @@ -28,13 +28,13 @@ jobs: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - - {python-version: "3.7", testenvs: "py37,build", experimental: False} - - {python-version: "3.8", testenvs: "py38,build", experimental: False} - - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} - - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: True} + - {python-version: "3.6", testenvs: "py36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.7", testenvs: "py37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.8", testenvs: "py38-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.9", testenvs: "py39-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.10", testenvs: "py310-dev-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} + - {python-version: "pypy-3.6", testenvs: "pypy36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "pypy-3.7", testenvs: "pypy37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} steps: - name: Checkout 🛎️ diff --git a/.github/workflows/python_ci_macos.yml b/.github/workflows/python_ci_macos.yml index 54945b1..f3f1082 100644 --- a/.github/workflows/python_ci_macos.yml +++ b/.github/workflows/python_ci_macos.yml @@ -27,13 +27,13 @@ jobs: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - - {python-version: "3.7", testenvs: "py37,build", experimental: False} - - {python-version: "3.8", testenvs: "py38,build", experimental: False} - - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} - - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: True} + - {python-version: "3.6", testenvs: "py36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.7", testenvs: "py37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.8", testenvs: "py38-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.9", testenvs: "py39-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "3.10", testenvs: "py310-dev-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} + - {python-version: "pypy-3.6", testenvs: "pypy36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: False} + - {python-version: "pypy-3.7", testenvs: "pypy37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3},build", experimental: True} steps: - name: Checkout 🛎️ diff --git a/__pkginfo__.py b/__pkginfo__.py index 30243c2..6e7dfb2 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -14,6 +14,6 @@ __all__ = ["extras_require"] extras_require = { - "sphinx": ["sphinx<3.5.0,>=3.0.3", "sphinx-toolbox>=1.2.0"], - "all": ["sphinx<3.5.0,>=3.0.3", "sphinx-toolbox>=1.2.0"] + "sphinx": ["sphinx<4.4,>=3.2.0", "sphinx-toolbox>=1.2.0"], + "all": ["sphinx<4.4,>=3.2.0", "sphinx-toolbox>=1.2.0"] } diff --git a/enum_tools/autoenum.py b/enum_tools/autoenum.py index 0c86532..788f1ed 100644 --- a/enum_tools/autoenum.py +++ b/enum_tools/autoenum.py @@ -54,7 +54,7 @@ # stdlib from contextlib import suppress from enum import Enum -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional, Tuple, get_type_hints # 3rd party from docutils.nodes import Element # nodep @@ -62,9 +62,18 @@ from sphinx.domains import ObjType # nodep from sphinx.domains.python import PyClasslike, PyXRefRole # nodep from sphinx.environment import BuildEnvironment # nodep -from sphinx.ext.autodoc import ALL, INSTANCEATTR, AttributeDocumenter, ClassDocumenter, Documenter # nodep +from sphinx.ext.autodoc import ( # nodep + ALL, + INSTANCEATTR, + SUPPRESS, + AttributeDocumenter, + ClassDocumenter, + ClassLevelDocumenter, + Documenter + ) from sphinx.locale import _ # nodep -from sphinx.util.inspect import object_description # nodep +from sphinx.util.inspect import memory_address_re, safe_getattr # nodep +from sphinx.util.typing import stringify as stringify_typehint # nodep from sphinx_toolbox.more_autodoc.typehints import format_annotation # nodep from sphinx_toolbox.utils import begin_generate # nodep @@ -321,7 +330,6 @@ def import_object(self, raiseerror: bool = False) -> bool: .. latex:clearpage:: """ - self._datadescriptor = False return Documenter.import_object(self, raiseerror=raiseerror) def generate( @@ -366,12 +374,40 @@ def add_directive_header(self, sig: str) -> None: :param sig: """ - super().add_directive_header(sig) + ClassLevelDocumenter.add_directive_header(self, sig) + sourcename = self.get_sourcename() + if not self.options.annotation: + # obtain type annotation for this attribute + try: + annotations = get_type_hints(self.parent) + except NameError: + # Failed to evaluate ForwardRef (maybe TYPE_CHECKING) + annotations = safe_getattr(self.parent, "__annotations__", {}) + except (TypeError, KeyError, AttributeError): + # KeyError = a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) + # AttributeError is raised on 3.5.2 (fixed by 3.5.3) + annotations = {} + + if self.objpath[-1] in annotations: + objrepr = stringify_typehint(annotations.get(self.objpath[-1])) + self.add_line(" :type: " + objrepr, sourcename) + else: + key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) + if self.analyzer and key in self.analyzer.annotations: + self.add_line(" :type: " + self.analyzer.annotations[key], sourcename) + + elif self.options.annotation is SUPPRESS: + pass + else: + self.add_line(" :annotation: %s" % self.options.annotation, sourcename) if not self.options.annotation: - with suppress(ValueError): + with suppress(Exception): if self.object is not INSTANCEATTR: - objrepr = object_description(self.object) + + # Workaround for https://github.com/sphinx-doc/sphinx/issues/9272 + # which broke Enum displays in 4.1.0 + objrepr = memory_address_re.sub('', repr(self.object)).replace('\n', ' ') self.add_line(f' :value: {objrepr}', self.get_sourcename()) diff --git a/pyproject.toml b/pyproject.toml index 381a506..857add6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,8 @@ Homepage = "https://github.com/domdfcoding/enum_tools" Documentation = "https://enum_tools.readthedocs.io/en/latest" [project.optional-dependencies] -sphinx = [ "sphinx<3.5.0,>=3.0.3", "sphinx-toolbox>=1.2.0",] -all = [ "sphinx<3.5.0,>=3.0.3", "sphinx-toolbox>=1.2.0",] +sphinx = [ "sphinx<4.4,>=3.2.0", "sphinx-toolbox>=1.2.0",] +all = [ "sphinx<4.4,>=3.2.0", "sphinx-toolbox>=1.2.0",] [tool.whey] base-classifiers = [ diff --git a/repo_helper.yml b/repo_helper.yml index af3c459..f329d28 100644 --- a/repo_helper.yml +++ b/repo_helper.yml @@ -12,7 +12,7 @@ short_desc: "Tools to expand Python's enum module." use_whey: true tox_testenv_extras: all standalone_contrib_guide: true -min_coverage: 85 +min_coverage: 88 docs_fail_on_warning: true conda_channels: @@ -51,7 +51,7 @@ keywords: extras_require: sphinx: - - sphinx<3.5.0,>=3.0.3 + - sphinx<4.4,>=3.2.0 - sphinx-toolbox>=1.2.0 extra_sphinx_extensions: @@ -76,3 +76,15 @@ sphinx_conf_epilogue: - enum_tools.autoenum.Type = Type preserve_custom_theme: true + + +third_party_version_matrix: + sphinx: + - 3.2 + - 3.3 + - 3.4 + - 3.5 + - 4.0 + - 4.1 + - 4.2 + - 4.3 diff --git a/tests/requirements.txt b/tests/requirements.txt index 4931db3..42c2134 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -13,4 +13,4 @@ pytest-regressions>=2.0.1 pytest-rerunfailures>=9.0 pytest-timeout>=1.4.2 sphinx>=3.2.1 -sphinx-toolbox[testing]>=0.3.0 +sphinx-toolbox[testing]>=2.15.2 diff --git a/tests/test_autoenum.py b/tests/test_autoenum.py index 708fa7f..66b5d53 100644 --- a/tests/test_autoenum.py +++ b/tests/test_autoenum.py @@ -9,7 +9,8 @@ # 3rd party import pytest -from bs4 import BeautifulSoup # type: ignore +import sphinx +from bs4 import BeautifulSoup, NavigableString # type: ignore from pytest_regressions.file_regression import FileRegressionFixture # type: ignore from sphinx_toolbox.testing import HTMLRegressionFixture @@ -53,6 +54,33 @@ def test(app): # pytestmark = pytest.mark.sphinx('html', testroot='root') +return_arrow = " → " + + +def preprocess_soup(soup: BeautifulSoup): + + if sphinx.version_info >= (3, 5): # pragma: no cover + for em in soup.select("em.property"): + child = ''.join(c.string for c in em.contents) + for c in em.children: + c.extract() + em.contents = [] + em.insert(0, child) + + for dl in soup.select("dl.py.method dt"): # .sig.sig-object.py + if return_arrow in dl.contents: + arrow_idx = dl.contents.index(return_arrow) + dl.contents[arrow_idx] = NavigableString( + dl.contents[arrow_idx] + dl.contents[arrow_idx + 1].contents[0] + ) + dl.contents[arrow_idx + 1].extract() + + for dt in soup.select("span.pre"): + dt.replace_with_children() + + for dt in soup.select("span.sig-return"): + dt.replace_with(NavigableString(dt.get_text())) + @pytest.mark.parametrize( "page", [ @@ -64,6 +92,8 @@ def test_index(page: BeautifulSoup, html_regression: HTMLRegressionFixture): title = page.find("h1").contents[0].strip() assert "autoenum Demo" == title + preprocess_soup(page) + html_regression.check(page, jinja2=True) # Now test the directive @@ -81,10 +111,8 @@ def test_index(page: BeautifulSoup, html_regression: HTMLRegressionFixture): assert class_.find("dt")["id"] == "enum_tools.demo.NoMethods" assert class_.find("dd").findAll('p')[0].contents[0] == "An enumeration of people without any methods." - assert str(class_.find("dd").findAll('p')[1].contents[0]) == ( - '' - 'int' - ) + tag = 'int' + assert str(class_.find("dd").findAll('p')[1].contents[0]) == tag assert class_.find("dd").findAll('p')[2].contents[0] == "Valid values are as follows:" attr_count = 0 @@ -147,6 +175,8 @@ def test_flag(page: BeautifulSoup, html_regression: HTMLRegressionFixture): title = page.find("h1").contents[0].strip() assert "autoenum Demo - Flag" == title + preprocess_soup(page) + html_regression.check(page, jinja2=True) # Now test the directive @@ -164,10 +194,8 @@ def test_flag(page: BeautifulSoup, html_regression: HTMLRegressionFixture): assert class_.find("dd").findAll('p')[0].contents[0] == "An enumeration of status codes." - assert str(class_.find("dd").findAll('p')[1].contents[0]) == ( - '' - 'int' - ) + tag = 'int' + assert str(class_.find("dd").findAll('p')[1].contents[0]) == tag assert class_.find("dd").findAll('p')[2].contents[0] == "Valid values are as follows:" attr_count = 0 @@ -232,6 +260,8 @@ def test_no_member_doc(page: BeautifulSoup, html_regression: HTMLRegressionFixtu title = page.find("h1").contents[0].strip() assert "autoenum Demo - Members without docstrings" == title + preprocess_soup(page) + html_regression.check(page, jinja2=True) # Now test the directive @@ -247,10 +277,8 @@ def test_no_member_doc(page: BeautifulSoup, html_regression: HTMLRegressionFixtu 0] == "An enumeration of people without any member docstrings." if class_count == 0: - assert str(class_.find("dd").findAll('p')[1].contents[0]) == ( - '' - 'int' - ) + tag = 'int' + assert str(class_.find("dd").findAll('p')[1].contents[0]) == tag assert class_.find("dd").findAll('p')[2].contents[0] == "Valid values are as follows:" else: assert class_.find("dd").findAll('p')[1].contents[0] == "Valid values are as follows:" diff --git a/tests/test_autoenum_/test_flag_flag_html_.html b/tests/test_autoenum_/test_flag_flag_html_.html index a31e080..5229570 100644 --- a/tests/test_autoenum_/test_flag_flag_html_.html +++ b/tests/test_autoenum_/test_flag_flag_html_.html @@ -1,4 +1,5 @@ -{% set NEW_ENUM_REPR = python_version >= (3, 11) -%} +{% set sig_prename_tag=("span" if sphinx_version >= (4, 0) else 'code') -%} +{% set sig_object_class=(' class="sig sig-object py"' if sphinx_version >= (4, 0) else '') -%} @@ -30,16 +31,16 @@

-
+ flag - + <{{ sig_prename_tag }} class="sig-prename descclassname"> enum_tools.demo. - - + + <{{ sig_prename_tag }} class="sig-name descname"> StatusFlags - + ( @@ -66,9 +67,7 @@

- - int - + int

@@ -77,10 +76,10 @@

Valid values are as follows:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Running - + = {% if NEW_ENUM_REPR %}StatusFlags.Running{% else %}<StatusFlags.Running: 1>{% endif %} @@ -95,10 +94,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Stopped - + = {% if NEW_ENUM_REPR %}StatusFlags.Stopped{% else %}<StatusFlags.Stopped: 2>{% endif %} @@ -113,10 +112,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Error - + = {% if NEW_ENUM_REPR %}StatusFlags.Error{% else %}<StatusFlags.Error: 4>{% endif %} @@ -133,17 +132,15 @@

The - - Flag - + Flag and its members also have the following methods:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> has_errored - + ( @@ -166,16 +163,16 @@

-
+ flag - + <{{ sig_prename_tag }} class="sig-prename descclassname"> enum_tools.demo. - - + + <{{ sig_prename_tag }} class="sig-name descname"> StatusFlags - + ( @@ -202,9 +199,7 @@

- - int - + int

@@ -213,10 +208,10 @@

Valid values are as follows:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Running - + = {% if NEW_ENUM_REPR %}StatusFlags.Running{% else %}<StatusFlags.Running: 1>{% endif %} @@ -231,10 +226,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Stopped - + = {% if NEW_ENUM_REPR %}StatusFlags.Stopped{% else %}<StatusFlags.Stopped: 2>{% endif %} @@ -249,10 +244,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Error - + = {% if NEW_ENUM_REPR %}StatusFlags.Error{% else %}<StatusFlags.Error: 4>{% endif %} @@ -269,17 +264,15 @@

The - - Flag - + Flag and its members also have the following methods:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> has_errored - + ( diff --git a/tests/test_autoenum_/test_index_index_html_.html b/tests/test_autoenum_/test_index_index_html_.html index a51329f..031f1a4 100644 --- a/tests/test_autoenum_/test_index_index_html_.html +++ b/tests/test_autoenum_/test_index_index_html_.html @@ -1,4 +1,5 @@ -{% set NEW_ENUM_REPR = python_version >= (3, 11) -%} +{% set sig_prename_tag=("span" if sphinx_version >= (4, 0) else 'code') -%} +{% set sig_object_class=(' class="sig sig-object py"' if sphinx_version >= (4, 0) else '') -%} @@ -32,16 +33,16 @@

-
+ enum - + <{{ sig_prename_tag }} class="sig-prename descclassname"> enum_tools.demo. - - + + <{{ sig_prename_tag }} class="sig-name descname"> People - + ( @@ -68,9 +69,7 @@

- - int - + int

@@ -79,10 +78,10 @@

Valid values are as follows:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Bob - + = {% if NEW_ENUM_REPR %}People.Bob{% else %}<People.Bob: 1>{% endif %} @@ -97,10 +96,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Alice - + = {% if NEW_ENUM_REPR %}People.Alice{% else %}<People.Alice: 2>{% endif %} @@ -115,10 +114,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Carol - + = {% if NEW_ENUM_REPR %}People.Carol{% else %}<People.Carol: 3>{% endif %} @@ -135,20 +134,18 @@

The - - Enum - + Enum and its members also have the following methods:

-
+ classmethod - + <{{ sig_prename_tag }} class="sig-name descname"> iter_values - + ( @@ -166,13 +163,13 @@

-
+ classmethod - + <{{ sig_prename_tag }} class="sig-name descname"> as_list - + ( @@ -193,16 +190,16 @@

-
+ enum - + <{{ sig_prename_tag }} class="sig-prename descclassname"> enum_tools.demo. - - + + <{{ sig_prename_tag }} class="sig-name descname"> NoMethods - + ( @@ -229,9 +226,7 @@

- - int - + int

@@ -240,10 +235,10 @@

Valid values are as follows:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Bob - + = {% if NEW_ENUM_REPR %}NoMethods.Bob{% else %}<NoMethods.Bob: 1>{% endif %} @@ -258,10 +253,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Alice - + = {% if NEW_ENUM_REPR %}NoMethods.Alice{% else %}<NoMethods.Alice: 2>{% endif %} @@ -276,10 +271,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Carol - + = {% if NEW_ENUM_REPR %}NoMethods.Carol{% else %}<NoMethods.Carol: 3>{% endif %} @@ -298,27 +293,21 @@

- - enum_tools.demo.People - + enum_tools.demo.People

- - People - + People

- - People - + People

diff --git a/tests/test_autoenum_/test_no_member_doc_no_member_doc_html_.html b/tests/test_autoenum_/test_no_member_doc_no_member_doc_html_.html index 852da2d..eb653ff 100644 --- a/tests/test_autoenum_/test_no_member_doc_no_member_doc_html_.html +++ b/tests/test_autoenum_/test_no_member_doc_no_member_doc_html_.html @@ -1,4 +1,5 @@ -{% set NEW_ENUM_REPR = python_version >= (3, 11) -%} +{% set sig_prename_tag=("span" if sphinx_version >= (4, 0) else 'code') -%} +{% set sig_object_class=(' class="sig sig-object py"' if sphinx_version >= (4, 0) else '') -%} @@ -30,16 +31,16 @@

-
+ enum - + <{{ sig_prename_tag }} class="sig-prename descclassname"> enum_tools.demo. - - + + <{{ sig_prename_tag }} class="sig-name descname"> NoMemberDoc - + ( @@ -66,9 +67,7 @@

- - int - + int

@@ -77,10 +76,10 @@

Valid values are as follows:

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Bob - + = {% if NEW_ENUM_REPR %}NoMemberDoc.Bob{% else %}<NoMemberDoc.Bob: 1>{% endif %} @@ -92,10 +91,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Alice - + = {% if NEW_ENUM_REPR %}NoMemberDoc.Alice{% else %}<NoMemberDoc.Alice: 2>{% endif %} @@ -107,10 +106,10 @@

-
- + + <{{ sig_prename_tag }} class="sig-name descname"> Carol - + = {% if NEW_ENUM_REPR %}NoMemberDoc.Carol{% else %}<NoMemberDoc.Carol: 3>{% endif %} @@ -126,9 +125,7 @@

- - enum_tools.demo.NoMemberDoc.Alice - + enum_tools.demo.NoMemberDoc.Alice

diff --git a/tests/test_enums.py b/tests/test_enums.py index a874903..54d97a8 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -5,13 +5,14 @@ # stdlib import sys +from enum import Enum # 3rd party import pytest # this package from enum_tools import IntEnum, StrEnum -from enum_tools.custom_enums import IterableFlag, IterableIntFlag +from enum_tools.custom_enums import AutoNumberEnum, IterableFlag, IterableIntFlag, MemberDirEnum, OrderedEnum NEW_ENUM_REPR = sys.version_info >= (3, 11) @@ -87,7 +88,7 @@ class Color(IterableFlag): def test_strenum(): # From https://github.com/python/cpython/pull/22337 - # PDF License + # PSF License class GoodStrEnum(StrEnum): one = '1' @@ -125,3 +126,42 @@ class FourthFailedStrEnum(StrEnum): class FifthFailedStrEnum(StrEnum): one = '1' two = b'2', "ascii", 9 + + +def test_member_dir_enum(): + + class MyEnum(int, MemberDirEnum): + apple = 1 + orange = 2 + + assert dir(MyEnum) == ["__class__", "__doc__", "__members__", "__module__", "apple", "orange"] + + +def test_auto_number_enum(): + + class MyEnum(AutoNumberEnum): + apple = 1 + orange = 1 + + assert MyEnum.apple._value_ == 1 + assert MyEnum.orange._value_ == 2 + + +def test_ordered_enum(): + + class MyEnum(OrderedEnum): + apple = 1 + orange = 2 + strawberry = 0 + + assert MyEnum.apple < MyEnum.orange + assert MyEnum.apple <= MyEnum.orange + assert MyEnum.apple > MyEnum.strawberry + assert MyEnum.apple >= MyEnum.strawberry + + class MyEnum2(Enum): + apple = 1 + orange = 2 + + with pytest.raises(TypeError, match="'<' not supported between instances of 'MyEnum2' and 'MyEnum2'"): + MyEnum2.apple < MyEnum2.orange # type: ignore[operator] diff --git a/tox.ini b/tox.ini index c6a4e8c..4e92080 100644 --- a/tox.ini +++ b/tox.ini @@ -16,7 +16,16 @@ # * pytest [tox] -envlist = py36, py37, py38, py39, py310-dev, pypy36, pypy37, mypy, build +envlist = + py36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py38-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py39-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py310-dev-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + pypy36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + pypy37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + mypy + build skip_missing_interpreters = True isolated_build = True requires = @@ -25,15 +34,31 @@ requires = tox-pip-version>=0.0.7 [envlists] -test = py36, py37, py38, py39, py310-dev, pypy36, pypy37 +test = + py36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py38-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py39-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + py310-dev-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + pypy36-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} + pypy37-sphinx{3.2,3.3,3.4,3.5,4.0,4.1,4.2,4.3} qa = mypy, lint -cov = py36, coverage +cov = py36-sphinx3.2, coverage [testenv] setenv = PYTHONDEVMODE=1 PIP_DISABLE_PIP_VERSION_CHECK=1 -deps = -r{toxinidir}/tests/requirements.txt +deps = + -r{toxinidir}/tests/requirements.txt + sphinx3.2: sphinx~=3.2.0 + sphinx3.3: sphinx~=3.3.0 + sphinx3.4: sphinx~=3.4.0 + sphinx3.5: sphinx~=3.5.0 + sphinx4.0: sphinx~=4.0.0 + sphinx4.1: sphinx~=4.1.0 + sphinx4.2: sphinx~=4.2.0 + sphinx4.3: sphinx~=4.3.0 extras = all commands = python --version @@ -158,7 +183,7 @@ unused-arguments-ignore-variadic-names = True plugins = coverage_pyver_pragma [coverage:report] -fail_under = 85 +fail_under = 88 exclude_lines = raise AssertionError raise NotImplementedError