errortools 3.2.0__tar.gz → 3.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {errortools-3.2.0 → errortools-3.3.0}/AUTHORS.txt +2 -1
  2. {errortools-3.2.0/errortools.egg-info → errortools-3.3.0}/PKG-INFO +2 -1
  3. {errortools-3.2.0 → errortools-3.3.0}/_errortools/_speedup.c +11 -11
  4. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/cache.py +1 -2
  5. {errortools-3.2.0 → errortools-3.3.0}/_errortools/partial.py +4 -10
  6. errortools-3.3.0/_errortools/plugins.py +83 -0
  7. {errortools-3.2.0 → errortools-3.3.0}/_errortools/version.py +17 -17
  8. {errortools-3.2.0 → errortools-3.3.0}/docs/conf.py +60 -56
  9. {errortools-3.2.0 → errortools-3.3.0}/errortools/__init__.py +63 -1
  10. {errortools-3.2.0 → errortools-3.3.0/errortools.egg-info}/PKG-INFO +2 -1
  11. {errortools-3.2.0 → errortools-3.3.0}/errortools.egg-info/SOURCES.txt +4 -2
  12. {errortools-3.2.0 → errortools-3.3.0}/errortools.egg-info/top_level.txt +0 -5
  13. {errortools-3.2.0 → errortools-3.3.0}/pyproject.toml +4 -1
  14. {errortools-3.2.0 → errortools-3.3.0}/testing/__init__.py +4 -2
  15. errortools-3.3.0/testing/benchmark/__init__.py +4 -0
  16. {errortools-3.2.0 → errortools-3.3.0}/testing/test_groups.py +127 -130
  17. errortools-3.3.0/testing/test_plugins.py +105 -0
  18. errortools-3.3.0/testing/test_protocols.py +260 -0
  19. errortools-3.3.0/testing/test_version.py +71 -0
  20. errortools-3.2.0/_errortools/const.py +0 -12
  21. errortools-3.2.0/testing/benchmark/__init__.py +0 -1
  22. errortools-3.2.0/testing/test_const.py +0 -28
  23. {errortools-3.2.0 → errortools-3.3.0}/LICENSE.txt +0 -0
  24. {errortools-3.2.0 → errortools-3.3.0}/README.md +0 -0
  25. {errortools-3.2.0 → errortools-3.3.0}/_errortools/__init__.py +0 -0
  26. {errortools-3.2.0 → errortools-3.3.0}/_errortools/__main__.py +0 -0
  27. {errortools-3.2.0 → errortools-3.3.0}/_errortools/_cli.py +0 -0
  28. {errortools-3.2.0 → errortools-3.3.0}/_errortools/classes/__init__.py +0 -0
  29. {errortools-3.2.0 → errortools-3.3.0}/_errortools/classes/abc.py +0 -0
  30. {errortools-3.2.0 → errortools-3.3.0}/_errortools/classes/errorcodes.py +0 -0
  31. {errortools-3.2.0 → errortools-3.3.0}/_errortools/classes/group.py +0 -0
  32. {errortools-3.2.0 → errortools-3.3.0}/_errortools/classes/warn.py +0 -0
  33. {errortools-3.2.0 → errortools-3.3.0}/_errortools/cli.py +0 -0
  34. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/__init__.py +0 -0
  35. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/deprecated.py +0 -0
  36. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/handlers.py +0 -0
  37. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/retry.py +0 -0
  38. {errortools-3.2.0 → errortools-3.3.0}/_errortools/decorator/timeout.py +0 -0
  39. {errortools-3.2.0 → errortools-3.3.0}/_errortools/descriptor/__init__.py +0 -0
  40. {errortools-3.2.0 → errortools-3.3.0}/_errortools/descriptor/base.py +0 -0
  41. {errortools-3.2.0 → errortools-3.3.0}/_errortools/descriptor/errormsg.py +0 -0
  42. {errortools-3.2.0 → errortools-3.3.0}/_errortools/descriptor/nonblankmsg.py +0 -0
  43. {errortools-3.2.0 → errortools-3.3.0}/_errortools/errno.py +0 -0
  44. {errortools-3.2.0 → errortools-3.3.0}/_errortools/future.py +0 -0
  45. {errortools-3.2.0 → errortools-3.3.0}/_errortools/ignore.py +0 -0
  46. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/__init__.py +0 -0
  47. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/base.py +0 -0
  48. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/level.py +0 -0
  49. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/logger.py +0 -0
  50. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/record.py +0 -0
  51. {errortools-3.2.0 → errortools-3.3.0}/_errortools/logging/sink.py +0 -0
  52. {errortools-3.2.0 → errortools-3.3.0}/_errortools/metadata.py +0 -0
  53. {errortools-3.2.0 → errortools-3.3.0}/_errortools/py.typed +0 -0
  54. {errortools-3.2.0 → errortools-3.3.0}/_errortools/raises.py +0 -0
  55. {errortools-3.2.0 → errortools-3.3.0}/_errortools/typing.py +0 -0
  56. {errortools-3.2.0 → errortools-3.3.0}/_errortools/wrappers/__init__.py +0 -0
  57. {errortools-3.2.0 → errortools-3.3.0}/_errortools/wrappers/cache.py +0 -0
  58. {errortools-3.2.0 → errortools-3.3.0}/_errortools/wrappers/ignore.py +0 -0
  59. {errortools-3.2.0 → errortools-3.3.0}/errortools/__main__.py +0 -0
  60. {errortools-3.2.0 → errortools-3.3.0}/errortools/future.py +0 -0
  61. {errortools-3.2.0 → errortools-3.3.0}/errortools/logging.py +0 -0
  62. {errortools-3.2.0 → errortools-3.3.0}/errortools/partial.py +0 -0
  63. {errortools-3.2.0 → errortools-3.3.0}/errortools.egg-info/dependency_links.txt +0 -0
  64. {errortools-3.2.0 → errortools-3.3.0}/errortools.egg-info/entry_points.txt +0 -0
  65. {errortools-3.2.0 → errortools-3.3.0}/errortools.egg-info/requires.txt +0 -0
  66. {errortools-3.2.0 → errortools-3.3.0}/setup.cfg +0 -0
  67. {errortools-3.2.0 → errortools-3.3.0}/testing/__main__.py +0 -0
  68. {errortools-3.2.0 → errortools-3.3.0}/testing/benchmark/test_future_perf.py +0 -0
  69. {errortools-3.2.0 → errortools-3.3.0}/testing/conftest.py +0 -0
  70. {errortools-3.2.0 → errortools-3.3.0}/testing/run_tests.py +0 -0
  71. {errortools-3.2.0 → errortools-3.3.0}/testing/test_abc.py +0 -0
  72. {errortools-3.2.0 → errortools-3.3.0}/testing/test_decorator.py +0 -0
  73. {errortools-3.2.0 → errortools-3.3.0}/testing/test_descriptor.py +0 -0
  74. {errortools-3.2.0 → errortools-3.3.0}/testing/test_errno.py +0 -0
  75. {errortools-3.2.0 → errortools-3.3.0}/testing/test_errorcodes.py +0 -0
  76. {errortools-3.2.0 → errortools-3.3.0}/testing/test_future.py +0 -0
  77. {errortools-3.2.0 → errortools-3.3.0}/testing/test_ignore.py +0 -0
  78. {errortools-3.2.0 → errortools-3.3.0}/testing/test_logging.py +0 -0
  79. {errortools-3.2.0 → errortools-3.3.0}/testing/test_partials.py +0 -0
  80. {errortools-3.2.0 → errortools-3.3.0}/testing/test_raises.py +0 -0
  81. {errortools-3.2.0 → errortools-3.3.0}/testing/test_testing/__init__.py +0 -0
  82. {errortools-3.2.0 → errortools-3.3.0}/testing/test_testing/test_testing.py +0 -0
  83. {errortools-3.2.0 → errortools-3.3.0}/testing/test_typing.py +0 -0
  84. {errortools-3.2.0 → errortools-3.3.0}/testing/test_warnings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  # (Lines starting with # are comments)
2
2
  # Tips:
3
- # Contributors are not sorted by initials,
3
+ # Contributors are not sorted by initials,
4
4
  # but by contribution time.
5
5
  # Here are the real contributors
6
6
  aiwonderland
@@ -10,3 +10,4 @@ yangphysics
10
10
  # And here are bot contributors
11
11
  dependabot[bot]
12
12
  AbaAbaAba-bot-like[bot]
13
+ pre-commit-ci[bot]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: errortools
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: errortools - a toolset for working with Python exceptions and warnings and logging.
5
5
  Author-email: Evan Yang <quantbit@126.com>
6
6
  License: Copyright (c) 2026 authors see AUTHORS.txt
@@ -25,6 +25,7 @@ License: Copyright (c) 2026 authors see AUTHORS.txt
25
25
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
26
 
27
27
  Project-URL: Homepage, https://github.com/more-abc/errortools
28
+ Project-URL: Documentation, https://errortools.readthedocs.io/
28
29
  Classifier: License :: OSI Approved :: MIT License
29
30
  Classifier: Programming Language :: Python :: 3
30
31
  Classifier: Programming Language :: Python :: 3.8
@@ -2,23 +2,23 @@
2
2
  #include <Python.h>
3
3
 
4
4
  /* Fast exception type checking
5
- *
5
+ *
6
6
  * Optimized check for exception type hierarchy using PyObject_IsSubclass.
7
7
  * Returns False immediately if typ is None, otherwise checks if typ is a
8
8
  * subclass of excs.
9
- *
9
+ *
10
10
  * Args:
11
11
  * typ: The type object to check (or None)
12
12
  * excs: The exception class(es) to check against
13
- *
13
+ *
14
14
  * Returns:
15
15
  * True if typ is a subclass of excs, False otherwise
16
16
  * NULL on error with exception set
17
17
  */
18
18
  static PyObject* fast_issubclass_check(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
19
19
  if (nargs != 2) {
20
- PyErr_Format(PyExc_TypeError,
21
- "fast_issubclass_check() takes exactly 2 arguments (%zd given)",
20
+ PyErr_Format(PyExc_TypeError,
21
+ "fast_issubclass_check() takes exactly 2 arguments (%zd given)",
22
22
  nargs);
23
23
  return NULL;
24
24
  }
@@ -33,7 +33,7 @@ static PyObject* fast_issubclass_check(PyObject* self, PyObject* const* args, Py
33
33
 
34
34
  /* Validate that excs is a class or tuple of classes */
35
35
  if (!PyType_Check(excs) && !PyTuple_Check(excs)) {
36
- PyErr_SetString(PyExc_TypeError,
36
+ PyErr_SetString(PyExc_TypeError,
37
37
  "second argument must be a class or tuple of classes");
38
38
  return NULL;
39
39
  }
@@ -52,21 +52,21 @@ static PyObject* fast_issubclass_check(PyObject* self, PyObject* const* args, Py
52
52
  }
53
53
 
54
54
  /* Fast exception collector append
55
- *
55
+ *
56
56
  * Optimized append operation for adding exceptions to a list.
57
- *
57
+ *
58
58
  * Args:
59
59
  * list: The list object to append to
60
60
  * exc: The exception object to append
61
- *
61
+ *
62
62
  * Returns:
63
63
  * None on success
64
64
  * NULL on error with exception set
65
65
  */
66
66
  static PyObject* fast_append_exception(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
67
67
  if (nargs != 2) {
68
- PyErr_Format(PyExc_TypeError,
69
- "fast_append_exception() takes exactly 2 arguments (%zd given)",
68
+ PyErr_Format(PyExc_TypeError,
69
+ "fast_append_exception() takes exactly 2 arguments (%zd given)",
70
70
  nargs);
71
71
  return NULL;
72
72
  }
@@ -9,7 +9,6 @@ from typing import (
9
9
  overload,
10
10
  )
11
11
 
12
- from ..const import DEFAULT_ERROR_CACHE_SIZE
13
12
  from ..wrappers.cache import ErrorCacheWrapper
14
13
 
15
14
  _T = TypeVar("_T", bound=Callable[..., Any])
@@ -28,7 +27,7 @@ def error_cache(maxsize: Optional[int] = 128) -> Callable[[_T], ErrorCacheWrappe
28
27
  # fmt: on
29
28
 
30
29
 
31
- def error_cache(func: Optional[_T] = None, maxsize: Optional[int] = DEFAULT_ERROR_CACHE_SIZE) -> Any: # type: ignore
30
+ def error_cache(func: Optional[_T] = None, maxsize: Optional[int] = 128) -> Any: # type: ignore
32
31
  """
33
32
  Decorator to cache exceptions raised by a function.
34
33
 
@@ -14,12 +14,6 @@ from .ignore import (
14
14
  retry,
15
15
  )
16
16
  from .decorator.cache import error_cache
17
- from .const import (
18
- LARGE_ERROR_CACHE_SIZE,
19
- SMALL_ERROR_CACHE_SIZE,
20
- DEFAULT_ERROR_CACHE_SIZE,
21
- UNLIMITED_ERROR_CACHE,
22
- )
23
17
 
24
18
  # ------------------------------------------------------------------
25
19
  # ignore: Common exception shortcuts
@@ -114,10 +108,10 @@ retry_5_delay_1s: Callable = partial(retry, times=5, delay=1)
114
108
  # error cache presets
115
109
  # ------------------------------------------------------------------
116
110
 
117
- unlimited_error_cache: Callable = partial(error_cache, maxsize=UNLIMITED_ERROR_CACHE)
118
- lru_error_cache: Callable = partial(error_cache, maxsize=DEFAULT_ERROR_CACHE_SIZE)
119
- small_error_cache: Callable = partial(error_cache, maxsize=SMALL_ERROR_CACHE_SIZE)
120
- large_error_cache: Callable = partial(error_cache, maxsize=LARGE_ERROR_CACHE_SIZE)
111
+ unlimited_error_cache: Callable = partial(error_cache, maxsize=1024)
112
+ lru_error_cache: Callable = partial(error_cache, maxsize=128)
113
+ small_error_cache: Callable = partial(error_cache, maxsize=64)
114
+ large_error_cache: Callable = partial(error_cache, maxsize=None)
121
115
 
122
116
 
123
117
  # ------------------------------------------------------------------
@@ -0,0 +1,83 @@
1
+ """Ultra-lightweight plugin system for errortools."""
2
+
3
+ from typing import Callable, Any
4
+
5
+ _REGISTRY: dict[str, Callable[..., Any]] = {}
6
+
7
+ __all__ = [
8
+ "register",
9
+ "get",
10
+ "list_all",
11
+ "run",
12
+ "remove",
13
+ "Registry",
14
+ ]
15
+
16
+
17
+ def register(name: str) -> Callable:
18
+ """
19
+ Register plugin (decorator)
20
+
21
+ .. versionadded:: 3.2
22
+ """
23
+
24
+ def decorator(func: Callable) -> Callable:
25
+ _REGISTRY[name] = func
26
+ return func
27
+
28
+ return decorator
29
+
30
+
31
+ def get(name: str, default: Any = None) -> Any:
32
+ """
33
+ Get registered plugin
34
+
35
+ .. versionadded:: 3.2
36
+ """
37
+ plugin = _REGISTRY.get(name)
38
+ if plugin is None:
39
+ if default is not None:
40
+ return default
41
+ raise ValueError(f"Plugin {name!r} is not registered")
42
+ return plugin
43
+
44
+
45
+ def remove(name: str) -> None:
46
+ """
47
+ Remove a plugin
48
+
49
+ .. versionadded:: 3.2
50
+ """
51
+ _REGISTRY.pop(name, None)
52
+
53
+
54
+ def list_all() -> list[str]:
55
+ """
56
+ List all plugin names
57
+
58
+ .. versionadded:: 3.2
59
+ """
60
+ return list(_REGISTRY.keys())
61
+
62
+
63
+ def run(name: str, *args, **kwargs) -> Any:
64
+ """Run plugin
65
+
66
+ .. versionadded:: 3.2"""
67
+ return get(name)(*args, **kwargs)
68
+
69
+
70
+ class Registry:
71
+ """.. versionadded:: 3.2"""
72
+
73
+ @staticmethod
74
+ def register(name: str, func: Callable) -> None:
75
+ _REGISTRY[name] = func
76
+
77
+ @staticmethod
78
+ def list_all() -> list[str]:
79
+ return list_all()
80
+
81
+ @staticmethod
82
+ def get(name: str) -> Any:
83
+ return get(name)
@@ -1,17 +1,17 @@
1
- def _get_version_tuple(version: str) -> tuple[int, int, int]:
2
- parts = [int(p) for p in version.split(".")]
3
-
4
- major = parts[0] if len(parts) >= 1 else 0
5
- minor = parts[1] if len(parts) >= 2 else 0
6
- patch = parts[2] if len(parts) >= 3 else 0
7
-
8
- return (major, minor, patch)
9
-
10
-
11
- __version__: str = "3.2.0"
12
- __version_tuple__: tuple[int, int, int] = _get_version_tuple(__version__)
13
- __commit_id__: str | None = None
14
-
15
- version = __version__
16
- version_tuple = __version_tuple__
17
- commit_id = __commit_id__
1
+ def _get_version_tuple(version: str) -> tuple[int, int, int]:
2
+ parts = [int(p) for p in version.split(".")]
3
+
4
+ major = parts[0] if len(parts) >= 1 else 0
5
+ minor = parts[1] if len(parts) >= 2 else 0
6
+ patch = parts[2] if len(parts) >= 3 else 0
7
+
8
+ return (major, minor, patch)
9
+
10
+
11
+ __version__: str = "3.3.0"
12
+ __version_tuple__: tuple[int, int, int] = _get_version_tuple(__version__)
13
+ __commit_id__: str | None = None
14
+
15
+ version = __version__
16
+ version_tuple = __version_tuple__
17
+ commit_id = __commit_id__
@@ -1,56 +1,60 @@
1
- # Configuration file for the Sphinx documentation builder.
2
- #
3
- # For the full list of built-in configuration values, see the documentation:
4
- # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
-
6
- # -- Project information -----------------------------------------------------
7
- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
-
9
-
10
- from _errortools.version import __version__, __version_tuple__
11
-
12
- project = "errortools"
13
- copyright = "(C) 2026 aiwonderland and more-abc team"
14
- author = "aiwonderland"
15
- release = __version__
16
- version = f"{__version_tuple__[0]}.{__version_tuple__[1]}"
17
-
18
-
19
- # -- General configuration ---------------------------------------------------
20
- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
21
-
22
-
23
- templates_path = ["_templates"]
24
- exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
25
-
26
-
27
- # -- Options for HTML output -------------------------------------------------
28
- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
29
-
30
- html_static_path = ["_static"]
31
-
32
- extensions = [
33
- "myst_parser",
34
- "sphinx_rtd_theme",
35
- "sphinx.ext.intersphinx",
36
- "sphinx.ext.viewcode",
37
- ]
38
-
39
- source_suffix = {
40
- # ".rst": "restructuredtext",
41
- ".md": "markdown",
42
- }
43
-
44
- html_theme = "sphinx_rtd_theme"
45
-
46
- myst_enable_extensions = [
47
- "colon_fence",
48
- "dollarmath",
49
- "tasklist",
50
- ]
51
-
52
- intersphinx_mapping = {
53
- "python": ("https://docs.python.org/3", None),
54
- }
55
-
56
- autodoc_member_order = "bysource"
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ # -- Project information -----------------------------------------------------
7
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
8
+
9
+ from _errortools.version import __version__, __version_tuple__
10
+ import os
11
+ import sys
12
+
13
+ sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)) + "/..")
14
+
15
+
16
+ project = "errortools"
17
+ copyright = "(C) 2026 aiwonderland and more-abc team"
18
+ author = "aiwonderland"
19
+ release = __version__
20
+ version = f"{__version_tuple__[0]}.{__version_tuple__[1]}"
21
+
22
+
23
+ # -- General configuration ---------------------------------------------------
24
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
25
+
26
+
27
+ templates_path = ["_templates"]
28
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
29
+
30
+
31
+ # -- Options for HTML output -------------------------------------------------
32
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
33
+
34
+ html_static_path = ["_static"]
35
+
36
+ extensions = [
37
+ "myst_parser",
38
+ "sphinx_rtd_theme",
39
+ "sphinx.ext.intersphinx",
40
+ "sphinx.ext.viewcode",
41
+ ]
42
+
43
+ source_suffix = {
44
+ # ".rst": "restructuredtext",
45
+ ".md": "markdown",
46
+ }
47
+
48
+ html_theme = "sphinx_rtd_theme"
49
+
50
+ myst_enable_extensions = [
51
+ "colon_fence",
52
+ "dollarmath",
53
+ "tasklist",
54
+ ]
55
+
56
+ intersphinx_mapping = {
57
+ "python": ("https://docs.python.org/3", None),
58
+ }
59
+
60
+ autodoc_member_order = "bysource"
@@ -2,6 +2,8 @@
2
2
  errortools - a toolset for working with Python exceptions and warnings and logging.
3
3
  """
4
4
 
5
+ from typing import Any
6
+
5
7
  from _errortools.raises import raises, assert_raises, raises_all, reraise
6
8
  from _errortools.ignore import (
7
9
  ignore,
@@ -45,6 +47,22 @@ from _errortools.classes.abc import (
45
47
  Raiseable,
46
48
  Error,
47
49
  )
50
+ from _errortools.classes.protocol import (
51
+ ExceptionLike,
52
+ ExceptionGroupLike,
53
+ BaseExceptionGroupLike,
54
+ BlockingIOErrorLike,
55
+ NameErrorLike,
56
+ StopIterationLike,
57
+ SyntaxErrorLike,
58
+ SystemExitLike,
59
+ ImportErrorLike,
60
+ UnicodeDecodeErrorLike,
61
+ UnicodeEncodeErrorLike,
62
+ UnicodeTranslateErrorLike,
63
+ AttributeErrorLike,
64
+ GroupErrorsLike,
65
+ )
48
66
  from _errortools.typing import (
49
67
  AnyErrorCode,
50
68
  BaseErrorCodesType,
@@ -55,6 +73,7 @@ from _errortools.typing import (
55
73
  TracebackType,
56
74
  FrameType,
57
75
  )
76
+ from _errortools.plugins import run, register, list_all, get, remove, Registry
58
77
  from _errortools.descriptor.errormsg import ErrorMsg
59
78
  from _errortools.descriptor.nonblankmsg import NonBlankErrorMsg
60
79
  from _errortools.version import (
@@ -88,6 +107,10 @@ _DEPRECATED_NAMES: dict[str, tuple[str, str]] = {
88
107
  }
89
108
 
90
109
 
110
+ class ErrortoolsDeprecationWarning(DeprecationWarning):
111
+ """Base class for warnings about deprecated features in errortools module."""
112
+
113
+
91
114
  def __getattr__(name: str):
92
115
  import importlib
93
116
  import warnings
@@ -96,7 +119,7 @@ def __getattr__(name: str):
96
119
  attr_name, reason = _DEPRECATED_NAMES[name]
97
120
  warnings.warn(
98
121
  f"errortools.{attr_name} is deprecated. {reason}",
99
- DeprecationWarning,
122
+ ErrortoolsDeprecationWarning,
100
123
  stacklevel=2,
101
124
  )
102
125
  return globals()[f"_{name}"] if f"_{name}" in globals() else globals().get(name)
@@ -104,6 +127,11 @@ def __getattr__(name: str):
104
127
  if name in ("future", "logging", "partial"):
105
128
  return importlib.import_module(f"_errortools.{name}")
106
129
 
130
+ try:
131
+ return get(name)
132
+ except ValueError:
133
+ pass
134
+
107
135
  raise AttributeError(f"module 'errortools' has no attribute {name!r}")
108
136
 
109
137
 
@@ -111,6 +139,16 @@ def __dir__() -> list[str]:
111
139
  return __all__
112
140
 
113
141
 
142
+ class PluginNamespace:
143
+ def __getattr__(self, name: str) -> Any:
144
+ plugin = get(name)
145
+ if plugin is None:
146
+ raise AttributeError(f"Plugin {name!r} not found")
147
+ return plugin
148
+
149
+
150
+ plugins = PluginNamespace()
151
+
114
152
  __all__ = [
115
153
  # functions
116
154
  "raises",
@@ -158,6 +196,21 @@ __all__ = [
158
196
  "PureBaseException",
159
197
  "ContextException",
160
198
  "Error",
199
+ "ExceptionLike",
200
+ "ExceptionGroupLike",
201
+ "BaseExceptionGroupLike",
202
+ "BlockingIOErrorLike",
203
+ "NameErrorLike",
204
+ "StopIterationLike",
205
+ "SystemExitLike",
206
+ "ImportErrorLike",
207
+ "SyntaxErrorLike",
208
+ "UnicodeDecodeErrorLike",
209
+ "UnicodeEncodeErrorLike",
210
+ "UnicodeTranslateErrorLike",
211
+ "AttributeErrorLike",
212
+ "GroupErrorsLike",
213
+ "ErrortoolsDeprecationWarning",
161
214
  # for type hints
162
215
  "PureBaseExceptionType",
163
216
  "ContextExceptionType",
@@ -169,6 +222,13 @@ __all__ = [
169
222
  "RuntimeError_",
170
223
  "ExceptionType",
171
224
  "WarningType",
225
+ # plugins
226
+ "register",
227
+ "get",
228
+ "list_all",
229
+ "run",
230
+ "remove",
231
+ "Registry",
172
232
  # metadata
173
233
  "__version__",
174
234
  "__version_tuple__",
@@ -192,3 +252,5 @@ __all__ = [
192
252
  "logging",
193
253
  "partial",
194
254
  ]
255
+
256
+ __all__.append("plugins")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: errortools
3
- Version: 3.2.0
3
+ Version: 3.3.0
4
4
  Summary: errortools - a toolset for working with Python exceptions and warnings and logging.
5
5
  Author-email: Evan Yang <quantbit@126.com>
6
6
  License: Copyright (c) 2026 authors see AUTHORS.txt
@@ -25,6 +25,7 @@ License: Copyright (c) 2026 authors see AUTHORS.txt
25
25
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
26
 
27
27
  Project-URL: Homepage, https://github.com/more-abc/errortools
28
+ Project-URL: Documentation, https://errortools.readthedocs.io/
28
29
  Classifier: License :: OSI Approved :: MIT License
29
30
  Classifier: Programming Language :: Python :: 3
30
31
  Classifier: Programming Language :: Python :: 3.8
@@ -7,12 +7,12 @@ _errortools/__main__.py
7
7
  _errortools/_cli.py
8
8
  _errortools/_speedup.c
9
9
  _errortools/cli.py
10
- _errortools/const.py
11
10
  _errortools/errno.py
12
11
  _errortools/future.py
13
12
  _errortools/ignore.py
14
13
  _errortools/metadata.py
15
14
  _errortools/partial.py
15
+ _errortools/plugins.py
16
16
  _errortools/py.typed
17
17
  _errortools/raises.py
18
18
  _errortools/typing.py
@@ -58,7 +58,6 @@ testing/__main__.py
58
58
  testing/conftest.py
59
59
  testing/run_tests.py
60
60
  testing/test_abc.py
61
- testing/test_const.py
62
61
  testing/test_decorator.py
63
62
  testing/test_descriptor.py
64
63
  testing/test_errno.py
@@ -68,8 +67,11 @@ testing/test_groups.py
68
67
  testing/test_ignore.py
69
68
  testing/test_logging.py
70
69
  testing/test_partials.py
70
+ testing/test_plugins.py
71
+ testing/test_protocols.py
71
72
  testing/test_raises.py
72
73
  testing/test_typing.py
74
+ testing/test_version.py
73
75
  testing/test_warnings.py
74
76
  testing/benchmark/__init__.py
75
77
  testing/benchmark/test_future_perf.py
@@ -1,8 +1,3 @@
1
1
  _errortools
2
- build
3
- dist
4
- docs
5
- emeps
6
2
  errortools
7
- htmlcov
8
3
  testing
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "errortools"
8
- version = "3.2.0"
8
+ version = "3.3.0"
9
9
  authors = [
10
10
  { name = "Evan Yang", email = "quantbit@126.com" }
11
11
  ]
@@ -38,6 +38,7 @@ classifiers = [
38
38
 
39
39
  [project.urls]
40
40
  Homepage = "https://github.com/more-abc/errortools"
41
+ Documentation = "https://errortools.readthedocs.io/"
41
42
 
42
43
 
43
44
  [project.scripts]
@@ -50,6 +51,8 @@ _errortools = ["py.typed"]
50
51
 
51
52
  [tool.setuptools.packages.find]
52
53
  where = ["."]
54
+ include = ["errortools", "_errortools", "testing"]
55
+ exclude = ["htmlcov", ".*", "docs"]
53
56
 
54
57
 
55
58
  [[tool.setuptools.ext-modules]]
@@ -2,14 +2,16 @@
2
2
 
3
3
  import warnings
4
4
 
5
+ from _errortools.version import _get_version_tuple
6
+
5
7
  __all__ = [
6
8
  "__version__",
7
9
  "__version_tuple__",
8
10
  "HAS_PYTEST",
9
11
  "NO_ONE_CHANGE_VERSION",
10
12
  ]
11
- __version__ = "1.2.0"
12
- __version_tuple__ = (1, 2, 0)
13
+ __version__ = "1.2.5"
14
+ __version_tuple__ = _get_version_tuple(__version__)
13
15
 
14
16
  try:
15
17
  import pytest
@@ -0,0 +1,4 @@
1
+ from _errortools.version import _get_version_tuple
2
+
3
+ __version__ = "0.1.0"
4
+ __version_tuple__ = _get_version_tuple(__version__)