DataExcept 1.2.0__tar.gz → 1.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 (37) hide show
  1. {dataexcept-1.2.0 → dataexcept-1.3.0}/CHANGELOG.md +25 -1
  2. {dataexcept-1.2.0 → dataexcept-1.3.0}/CITATION.cff +2 -2
  3. {dataexcept-1.2.0 → dataexcept-1.3.0}/PKG-INFO +6 -16
  4. {dataexcept-1.2.0 → dataexcept-1.3.0}/README.md +5 -15
  5. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/serialization.py +33 -5
  6. {dataexcept-1.2.0 → dataexcept-1.3.0}/pyproject.toml +1 -1
  7. {dataexcept-1.2.0 → dataexcept-1.3.0}/LICENSE +0 -0
  8. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/__init__.py +0 -0
  9. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/__main__.py +0 -0
  10. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/_validation.py +0 -0
  11. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/base.py +0 -0
  12. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/database_exceptions.py +0 -0
  13. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/dataengineering_exceptions.py +0 -0
  14. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/datascience_exceptions/__init__.py +0 -0
  15. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/datascience_exceptions/base.py +0 -0
  16. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/datascience_exceptions/ingestion.py +0 -0
  17. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/datascience_exceptions/operations.py +0 -0
  18. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/datascience_exceptions/training.py +0 -0
  19. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/__init__.py +0 -0
  20. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/authentication.py +0 -0
  21. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/base.py +0 -0
  22. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/configuration.py +0 -0
  23. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/external.py +0 -0
  24. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/lifecycle.py +0 -0
  25. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/notification.py +0 -0
  26. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/parsing.py +0 -0
  27. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/scheduling.py +0 -0
  28. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/exceptions/validation.py +0 -0
  29. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/io_exceptions.py +0 -0
  30. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/logging_helpers.py +0 -0
  31. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/network_exceptions.py +0 -0
  32. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/pandas_exceptions.py +0 -0
  33. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/pipeline_exceptions.py +0 -0
  34. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/py.typed +0 -0
  35. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/redaction.py +0 -0
  36. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/security_exceptions.py +0 -0
  37. {dataexcept-1.2.0 → dataexcept-1.3.0}/dataexcept/wrapping.py +0 -0
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.0] - 2026-09-03
11
+
12
+ ### Added
13
+
14
+ - **Structured `ExceptionGroup` support** on Python 3.11+:
15
+ `exception_to_dict` and `exception_to_json` now preserve group members under
16
+ an `exceptions` field, including nested groups, instead of flattening
17
+ concurrent failures into one rendered message.
18
+ - Group members use the same public-attribute, redaction, cycle and shared
19
+ `max_depth` guarantees as ordinary causes and contexts. Python 3.10 remains
20
+ supported without an `exceptiongroup` backport or additional runtime
21
+ dependency.
22
+
23
+ ### Changed
24
+
25
+ - Hostile or malformed exception-group member metadata now degrades to the
26
+ ordinary exception record rather than allowing serialization itself to fail.
27
+ - The README now uses a PyPI-backed version badge and avoids hard-coded version
28
+ and citation values that can drift between releases. The documented exception
29
+ count is contract-tested against the package.
30
+ - The roadmap now records a future language-neutral envelope schema and optional
31
+ Pino interoperability track without claiming Node.js/Pino support today.
32
+
10
33
  ## [1.2.0] - 2026-09-02
11
34
 
12
35
  ### Added
@@ -547,7 +570,8 @@ First public release.
547
570
  - Published to PyPI via OIDC trusted publishing; no long-lived API token is
548
571
  involved in a release.
549
572
 
550
- [Unreleased]: https://github.com/DiogoRibeiro7/DataExcept/compare/v1.2.0...HEAD
573
+ [Unreleased]: https://github.com/DiogoRibeiro7/DataExcept/compare/v1.3.0...HEAD
574
+ [1.3.0]: https://github.com/DiogoRibeiro7/DataExcept/compare/v1.2.0...v1.3.0
551
575
  [1.2.0]: https://github.com/DiogoRibeiro7/DataExcept/compare/v1.1.0...v1.2.0
552
576
  [1.1.0]: https://github.com/DiogoRibeiro7/DataExcept/compare/v1.0.0...v1.1.0
553
577
  [1.0.0]: https://github.com/DiogoRibeiro7/DataExcept/compare/v0.4.3...v1.0.0
@@ -1,7 +1,7 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use this software, please cite it using the following metadata."
3
3
  title: "DataExcept"
4
- version: "1.2.0"
4
+ version: "1.3.0"
5
5
  authors:
6
6
  - family-names: "Ribeiro"
7
7
  given-names: "Diogo"
@@ -11,4 +11,4 @@ authors:
11
11
  type: software
12
12
  url: "https://github.com/DiogoRibeiro7/DataExcept"
13
13
  repository-code: "https://github.com/DiogoRibeiro7/DataExcept"
14
- date-released: "2026-09-02"
14
+ date-released: "2026-09-03"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DataExcept
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: A Python package providing structured, easily-extendable custom exception types.
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
27
27
 
28
28
  # DataExcept
29
29
 
30
- [![CI](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml/badge.svg)](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml) [![PyPI version](https://badge.fury.io/py/DataExcept.svg)](https://badge.fury.io/py/DataExcept) [![Python Support](https://img.shields.io/pypi/pyversions/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Coverage](https://diogoribeiro7.github.io/DataExcept/coverage.svg)](https://diogoribeiro7.github.io/DataExcept/htmlcov/) [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://diogoribeiro7.github.io/DataExcept/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
30
+ [![CI](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml/badge.svg)](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml) [![PyPI version](https://img.shields.io/pypi/v/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Python Support](https://img.shields.io/pypi/pyversions/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Coverage](https://diogoribeiro7.github.io/DataExcept/coverage.svg)](https://diogoribeiro7.github.io/DataExcept/htmlcov/) [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://diogoribeiro7.github.io/DataExcept/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
31
31
 
32
32
  **DataExcept** is a production-ready Python library that provides **structured, hierarchical exception classes** specifically designed for **data science**, **machine learning**, and **data engineering** workflows. Stop debugging generic `ValueError`s and `RuntimeError`s -- get meaningful, actionable error messages that help you understand exactly what went wrong in your data pipeline.
33
33
 
@@ -223,9 +223,9 @@ BatchProcessingError
223
223
  BiasDetectionError
224
224
  ...
225
225
 
226
- # Check version
226
+ # Check the installed version
227
227
  $ dataexcept --version
228
- dataexcept 1.0.0
228
+ dataexcept <installed version>
229
229
  ```
230
230
 
231
231
  ## 🎯 Use Cases
@@ -369,18 +369,8 @@ through [SECURITY.md](SECURITY.md), not the public issue tracker.
369
369
 
370
370
  ## 🎓 Citation
371
371
 
372
- If you use DataExcept in your research, please cite it:
373
-
374
- ```bibtex
375
- @software{ribeiro_dataexcept_2026,
376
- author = {Ribeiro, Diogo},
377
- title = {DataExcept: Structured Exception Handling for Data Science},
378
- url = {https://github.com/DiogoRibeiro7/DataExcept},
379
- version = {1.0.0},
380
- year = {2026},
381
- publisher = {GitHub}
382
- }
383
- ```
372
+ If you use DataExcept in your research, please cite the exact release you used.
373
+ The canonical release metadata is maintained in [CITATION.cff](CITATION.cff).
384
374
 
385
375
  ## 📄 License
386
376
 
@@ -1,6 +1,6 @@
1
1
  # DataExcept
2
2
 
3
- [![CI](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml/badge.svg)](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml) [![PyPI version](https://badge.fury.io/py/DataExcept.svg)](https://badge.fury.io/py/DataExcept) [![Python Support](https://img.shields.io/pypi/pyversions/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Coverage](https://diogoribeiro7.github.io/DataExcept/coverage.svg)](https://diogoribeiro7.github.io/DataExcept/htmlcov/) [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://diogoribeiro7.github.io/DataExcept/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
3
+ [![CI](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml/badge.svg)](https://github.com/DiogoRibeiro7/DataExcept/actions/workflows/ci.yml) [![PyPI version](https://img.shields.io/pypi/v/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Python Support](https://img.shields.io/pypi/pyversions/DataExcept.svg)](https://pypi.org/project/DataExcept/) [![Coverage](https://diogoribeiro7.github.io/DataExcept/coverage.svg)](https://diogoribeiro7.github.io/DataExcept/htmlcov/) [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://diogoribeiro7.github.io/DataExcept/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
4
4
 
5
5
  **DataExcept** is a production-ready Python library that provides **structured, hierarchical exception classes** specifically designed for **data science**, **machine learning**, and **data engineering** workflows. Stop debugging generic `ValueError`s and `RuntimeError`s -- get meaningful, actionable error messages that help you understand exactly what went wrong in your data pipeline.
6
6
 
@@ -196,9 +196,9 @@ BatchProcessingError
196
196
  BiasDetectionError
197
197
  ...
198
198
 
199
- # Check version
199
+ # Check the installed version
200
200
  $ dataexcept --version
201
- dataexcept 1.0.0
201
+ dataexcept <installed version>
202
202
  ```
203
203
 
204
204
  ## 🎯 Use Cases
@@ -342,18 +342,8 @@ through [SECURITY.md](SECURITY.md), not the public issue tracker.
342
342
 
343
343
  ## 🎓 Citation
344
344
 
345
- If you use DataExcept in your research, please cite it:
346
-
347
- ```bibtex
348
- @software{ribeiro_dataexcept_2026,
349
- author = {Ribeiro, Diogo},
350
- title = {DataExcept: Structured Exception Handling for Data Science},
351
- url = {https://github.com/DiogoRibeiro7/DataExcept},
352
- version = {1.0.0},
353
- year = {2026},
354
- publisher = {GitHub}
355
- }
356
- ```
345
+ If you use DataExcept in your research, please cite the exact release you used.
346
+ The canonical release metadata is maintained in [CITATION.cff](CITATION.cff).
357
347
 
358
348
  ## 📄 License
359
349
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import builtins
5
6
  import json
6
7
  import math
7
8
  from collections.abc import Mapping, Sequence, Set
@@ -13,6 +14,7 @@ __all__ = ["exception_to_dict", "exception_to_json"]
13
14
 
14
15
  _MAX_VALUE_DEPTH = 8
15
16
  _NOT_SCALAR = object()
17
+ _EXCEPTION_GROUP_TYPE = getattr(builtins, "BaseExceptionGroup", None)
16
18
 
17
19
 
18
20
  def _redact_export_text(text: str) -> str:
@@ -112,12 +114,24 @@ def _attributes(exc: BaseException) -> dict[str, Any]:
112
114
  result[name] = _json_safe(value)
113
115
  return result
114
116
  except Exception:
115
- # This code runs at an error-transport boundary. A hostile __dict__,
116
- # custom mapping, iterator or key must not replace the original failure
117
- # with a serialization failure.
118
117
  return {}
119
118
 
120
119
 
120
+ def _group_members(exc: BaseException) -> Sequence[BaseException] | None:
121
+ """Return exception-group members without importing a 3.11-only symbol."""
122
+ if _EXCEPTION_GROUP_TYPE is None or not isinstance(exc, _EXCEPTION_GROUP_TYPE):
123
+ return None
124
+ try:
125
+ members: object = getattr(exc, "exceptions", None)
126
+ if not isinstance(members, tuple):
127
+ return None
128
+ if not all(isinstance(member, BaseException) for member in members):
129
+ return None
130
+ return members
131
+ except Exception:
132
+ return None
133
+
134
+
121
135
  def _exception_record(
122
136
  exc: BaseException,
123
137
  *,
@@ -149,6 +163,19 @@ def _exception_record(
149
163
  if attributes:
150
164
  record["attributes"] = attributes
151
165
 
166
+ members = _group_members(exc)
167
+ if members is not None:
168
+ record["exceptions"] = [
169
+ _exception_record(
170
+ member,
171
+ include_attributes=include_attributes,
172
+ max_depth=max_depth,
173
+ depth=depth + 1,
174
+ seen=seen,
175
+ )
176
+ for member in members
177
+ ]
178
+
152
179
  if exc.__cause__ is not None:
153
180
  record["cause"] = _exception_record(
154
181
  exc.__cause__,
@@ -179,8 +206,9 @@ def exception_to_dict(
179
206
  """Return a strict JSON-safe structured representation of *exc*.
180
207
 
181
208
  The representation contains the exception type, module and rendered
182
- message, optionally public instance attributes, and bounded cause/context
183
- chains. Traceback frames and private attributes are deliberately excluded.
209
+ message, optionally public instance attributes, bounded cause/context
210
+ chains, and on Python 3.11+ the member tree of exception groups. Traceback
211
+ frames and private attributes are deliberately excluded.
184
212
  """
185
213
  if not isinstance(exc, BaseException):
186
214
  raise TypeError("exc must be an exception instance")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "DataExcept"
3
- version = "1.2.0"
3
+ version = "1.3.0"
4
4
  description = "A Python package providing structured, easily-extendable custom exception types."
5
5
  readme = "README.md"
6
6
  license = "MIT"
File without changes