DataExcept 0.1.0__tar.gz → 0.2.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 (35) hide show
  1. dataexcept-0.2.0/CHANGELOG.md +98 -0
  2. {dataexcept-0.1.0 → dataexcept-0.2.0}/CITATION.cff +2 -2
  3. {dataexcept-0.1.0 → dataexcept-0.2.0}/PKG-INFO +5 -5
  4. {dataexcept-0.1.0 → dataexcept-0.2.0}/README.md +2 -1
  5. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/__init__.py +18 -5
  6. dataexcept-0.2.0/dataexcept/_deprecation.py +38 -0
  7. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/datascience_exceptions/__init__.py +13 -2
  8. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/datascience_exceptions/operations.py +2 -2
  9. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/__init__.py +18 -4
  10. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/external.py +2 -2
  11. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/job_exceptions.py +18 -6
  12. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/logging_helpers.py +7 -0
  13. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/pipeline_exceptions.py +13 -2
  14. {dataexcept-0.1.0 → dataexcept-0.2.0}/pyproject.toml +40 -23
  15. dataexcept-0.1.0/CHANGELOG.md +0 -42
  16. {dataexcept-0.1.0 → dataexcept-0.2.0}/LICENSE +0 -0
  17. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/__main__.py +0 -0
  18. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/database_exceptions.py +0 -0
  19. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/dataengineering_exceptions.py +0 -0
  20. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/datascience_exceptions/base.py +0 -0
  21. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/datascience_exceptions/ingestion.py +0 -0
  22. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/datascience_exceptions/training.py +0 -0
  23. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/authentication.py +0 -0
  24. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/base.py +0 -0
  25. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/configuration.py +0 -0
  26. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/lifecycle.py +0 -0
  27. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/notification.py +0 -0
  28. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/parsing.py +0 -0
  29. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/scheduling.py +0 -0
  30. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/exceptions/validation.py +0 -0
  31. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/io_exceptions.py +0 -0
  32. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/network_exceptions.py +0 -0
  33. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/pandas_exceptions.py +0 -0
  34. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/py.typed +0 -0
  35. {dataexcept-0.1.0 → dataexcept-0.2.0}/dataexcept/security_exceptions.py +0 -0
@@ -0,0 +1,98 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2026-08-24
11
+
12
+ ### Changed
13
+
14
+ - **`ConnectionError` is now `ServiceConnectionError`, and `TimeoutError` is
15
+ now `OperationTimeoutError`.** The old names shadowed Python builtins without
16
+ inheriting from them, so after `from dataexcept import ConnectionError` an
17
+ `except ConnectionError:` in that module silently stopped catching real
18
+ socket failures.
19
+ - **`datascience_exceptions.SerializationError` is now
20
+ `ModelSerializationError`**, and **`pipeline_exceptions.FeatureEngineeringError`
21
+ is now `FeaturePreprocessingError`.** Each of those names previously referred
22
+ to two different classes in different modules, so catching one silently
23
+ missed the other.
24
+ - Project metadata moved from Poetry's `[tool.poetry]` table to the standard
25
+ PEP 621 `[project]` table, clearing every `poetry check` deprecation. The
26
+ license is now an SPDX expression (PEP 639), so the built metadata carries
27
+ `License-Expression: MIT` and the redundant license classifier is gone.
28
+ Wheel and sdist contents are otherwise unchanged.
29
+ - `dataexcept.job_exceptions` now names its removal version, 1.0.0, in both the
30
+ warning and the module docstring.
31
+
32
+ ### Deprecated
33
+
34
+ - `ConnectionError`, `TimeoutError`, `datascience_exceptions.SerializationError`
35
+ and `pipeline_exceptions.FeatureEngineeringError`. All four still resolve, to
36
+ the **same class object** as their replacement, so existing `except` clauses
37
+ keep working; touching one emits a `DeprecationWarning` naming the
38
+ replacement and 1.0.0 as the removal. Importing the package does not warn.
39
+ Find remaining uses with `python -W error::DeprecationWarning -m pytest`.
40
+
41
+ ### Added
42
+
43
+ - A published [API stability policy](https://diogoribeiro7.github.io/DataExcept/stability/)
44
+ stating what is public, what each kind of change costs in version terms, the
45
+ deprecation process, and how to migrate off the 0.2.0 renames.
46
+ - Security scanning: CodeQL, and pip-audit against the runtime and
47
+ documentation dependency sets, on push, pull request and weekly — advisories
48
+ are published against code that has not changed. Pull requests also get a
49
+ dependency review failing at moderate severity.
50
+ - Complexity and security linting via ruff's mccabe (`C90`) and flake8-bandit
51
+ (`S`) rule sets, so neither needs a separate tool. Complexity is capped at 8;
52
+ the highest score in the package is 6.
53
+ - A regression guard that fails if any exported name ever shadows a builtin
54
+ again.
55
+ - `__all__` on `dataexcept.logging_helpers`, the one public module without one.
56
+
57
+ ### Fixed
58
+
59
+ - `dataexcept.__version__` and `tests/test_version.py` read the version out of
60
+ `pyproject.toml` when the package is not installed, and were still looking in
61
+ `[tool.poetry]`. They now read `[project]`.
62
+ - `examples/example_usage.py` raised `TimeoutError` with keyword arguments the
63
+ builtin does not accept — a live instance of the shadowing hazard.
64
+
65
+ ## [0.1.0] - 2026-08-24
66
+
67
+ First public release.
68
+
69
+ ### Added
70
+
71
+ - Hierarchical exception classes for data science, machine learning and data
72
+ engineering workflows. Catch a specific failure or a broad category, and get
73
+ a message that names the value that caused it rather than a bare
74
+ `ValueError`.
75
+ - Domain modules for validation, configuration, authentication, parsing,
76
+ serialization, scheduling, notification, lifecycle and external-service
77
+ errors, plus dedicated pandas, database, network, I/O, pipeline and security
78
+ exception groups.
79
+ - `dataexcept.logging_helpers` with `log_exception`, `log_and_raise` and
80
+ `log_then_raise`, for logging exceptions with structured context and
81
+ re-raising without losing the traceback.
82
+ - A `dataexcept` command-line entry point that lists the exported exception
83
+ classes and reports the installed version.
84
+ - A `py.typed` marker, backed by a mypy-clean codebase that CI enforces, so
85
+ downstream type checkers get annotations that are actually correct.
86
+ - Documentation at
87
+ [diogoribeiro7.github.io/DataExcept](https://diogoribeiro7.github.io/DataExcept/),
88
+ including an API reference generated from the docstrings.
89
+
90
+ ### Notes
91
+
92
+ - Supports Python 3.10 through 3.13.
93
+ - Published to PyPI via OIDC trusted publishing; no long-lived API token is
94
+ involved in a release.
95
+
96
+ [Unreleased]: https://github.com/DiogoRibeiro7/DataExcept/compare/v0.2.0...HEAD
97
+ [0.2.0]: https://github.com/DiogoRibeiro7/DataExcept/compare/v0.1.0...v0.2.0
98
+ [0.1.0]: https://github.com/DiogoRibeiro7/DataExcept/releases/tag/v0.1.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: "0.1.0"
4
+ version: "0.2.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: "2025-06-16"
14
+ date-released: "2026-08-24"
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: DataExcept
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A Python package providing structured, easily-extendable custom exception types.
5
- License: MIT
5
+ License-Expression: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: exceptions,errors,logging
8
8
  Author: Diogo Ribeiro
@@ -10,13 +10,12 @@ Author-email: dfr@esmad.ipp.pt
10
10
  Maintainer: Diogo Ribeiro
11
11
  Maintainer-email: diogo.debastos.ribeiro@gmail.com
12
12
  Requires-Python: >=3.10,<3.14
13
- Classifier: License :: OSI Approved :: MIT License
14
13
  Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
17
17
  Classifier: Programming Language :: Python :: 3.12
18
18
  Classifier: Programming Language :: Python :: 3.13
19
- Classifier: Programming Language :: Python :: 3 :: Only
20
19
  Requires-Dist: tomli ; python_version < "3.11"
21
20
  Project-URL: Changelog, https://github.com/DiogoRibeiro7/DataExcept/releases
22
21
  Project-URL: Documentation, https://diogoribeiro7.github.io/DataExcept/
@@ -43,7 +42,7 @@ Description-Content-Type: text/markdown
43
42
  ## 🎯 Key Features
44
43
 
45
44
  - **🏗️ Hierarchical Structure**: Catch specific errors or broad categories
46
- - **📊 Data Science Focused**: 40+ exceptions covering ML pipelines, feature engineering, model training
45
+ - **📊 Data Science Focused**: 96 exception classes covering ML pipelines, feature engineering, model training
47
46
  - **🔧 Production Ready**: Comprehensive logging helpers and error context
48
47
  - **📚 Academic Quality**: Proper documentation, type hints, and citation support
49
48
  - **🐍 Python 3.10+**: Modern Python with full type safety
@@ -360,6 +359,7 @@ through [SECURITY.md](SECURITY.md), not the public issue tracker.
360
359
 
361
360
  - **Full Documentation**: [diogoribeiro7.github.io/DataExcept](https://diogoribeiro7.github.io/DataExcept/)
362
361
  - **API Reference**: [API Docs](https://diogoribeiro7.github.io/DataExcept/api/)
362
+ - **API Stability**: [What is public and what may change](https://diogoribeiro7.github.io/DataExcept/stability/)
363
363
  - **Advanced Usage**: [Advanced Guide](https://diogoribeiro7.github.io/DataExcept/advanced_usage/)
364
364
  - **CLI Reference**: [CLI Guide](https://diogoribeiro7.github.io/DataExcept/cli/)
365
365
  - **Changelog**: [CHANGELOG.md](CHANGELOG.md)
@@ -16,7 +16,7 @@
16
16
  ## 🎯 Key Features
17
17
 
18
18
  - **🏗️ Hierarchical Structure**: Catch specific errors or broad categories
19
- - **📊 Data Science Focused**: 40+ exceptions covering ML pipelines, feature engineering, model training
19
+ - **📊 Data Science Focused**: 96 exception classes covering ML pipelines, feature engineering, model training
20
20
  - **🔧 Production Ready**: Comprehensive logging helpers and error context
21
21
  - **📚 Academic Quality**: Proper documentation, type hints, and citation support
22
22
  - **🐍 Python 3.10+**: Modern Python with full type safety
@@ -333,6 +333,7 @@ through [SECURITY.md](SECURITY.md), not the public issue tracker.
333
333
 
334
334
  - **Full Documentation**: [diogoribeiro7.github.io/DataExcept](https://diogoribeiro7.github.io/DataExcept/)
335
335
  - **API Reference**: [API Docs](https://diogoribeiro7.github.io/DataExcept/api/)
336
+ - **API Stability**: [What is public and what may change](https://diogoribeiro7.github.io/DataExcept/stability/)
336
337
  - **Advanced Usage**: [Advanced Guide](https://diogoribeiro7.github.io/DataExcept/advanced_usage/)
337
338
  - **CLI Reference**: [CLI Guide](https://diogoribeiro7.github.io/DataExcept/cli/)
338
339
  - **Changelog**: [CHANGELOG.md](CHANGELOG.md)
@@ -28,11 +28,11 @@ from . import (
28
28
  pipeline_exceptions,
29
29
  security_exceptions,
30
30
  )
31
+ from ._deprecation import resolve_deprecated
31
32
  from .exceptions import ( # noqa: F401
32
33
  AuthenticationError,
33
34
  AuthorizationError,
34
35
  ConfigurationError,
35
- ConnectionError,
36
36
  CronExpressionError,
37
37
  DependencyError,
38
38
  DeserializationError,
@@ -40,22 +40,27 @@ from .exceptions import ( # noqa: F401
40
40
  JobCancellationError,
41
41
  JobError,
42
42
  NotificationError,
43
+ OperationTimeoutError,
43
44
  ParsingError,
44
45
  ResourceNotFoundError,
45
46
  ScheduleConflictError,
46
47
  SerializationError,
47
- TimeoutError,
48
+ ServiceConnectionError,
48
49
  ValidationError,
49
50
  WebhookError,
50
51
  )
51
- from .logging_helpers import log_and_raise, log_exception, log_then_raise
52
+ from .logging_helpers import (
53
+ log_and_raise,
54
+ log_exception,
55
+ log_then_raise,
56
+ )
52
57
 
53
58
  try:
54
59
  __version__ = metadata.version("DataExcept")
55
60
  except metadata.PackageNotFoundError: # pragma: no cover - fallback during dev
56
61
  _root = Path(__file__).resolve().parents[1]
57
62
  with open(_root / "pyproject.toml", "rb") as _f:
58
- __version__ = tomllib.load(_f)["tool"]["poetry"]["version"]
63
+ __version__ = tomllib.load(_f)["project"]["version"]
59
64
 
60
65
  __all__ = list(_exceptions.__all__) + [
61
66
  "datascience_exceptions",
@@ -73,9 +78,17 @@ __all__ = list(_exceptions.__all__) + [
73
78
  ]
74
79
 
75
80
 
81
+ #: Renamed in 0.2.0 because they shadowed Python builtins without inheriting
82
+ #: from them. Each alias is the same class object as its replacement.
83
+ _DEPRECATED_ALIASES = {
84
+ "ConnectionError": ServiceConnectionError,
85
+ "TimeoutError": OperationTimeoutError,
86
+ }
87
+
88
+
76
89
  def __getattr__(name: str) -> Any:
77
90
  if name == "job_exceptions":
78
91
  module = import_module("dataexcept.job_exceptions")
79
92
  globals()[name] = module
80
93
  return module
81
- raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
94
+ return resolve_deprecated(__name__, _DEPRECATED_ALIASES, name)
@@ -0,0 +1,38 @@
1
+ """Internal support for names that have been renamed.
2
+
3
+ A rename keeps the old name working as an alias bound to the *same* class
4
+ object, so an existing ``except OldName:`` keeps catching exactly what it
5
+ caught before -- the alias is not a separate class.
6
+
7
+ Access goes through a PEP 562 module ``__getattr__`` rather than a plain
8
+ ``OldName = NewName`` assignment, because an assignment cannot warn. This is
9
+ private; see the stability policy for the user-facing contract.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import warnings
15
+ from typing import Any, Mapping
16
+
17
+ #: Version in which every currently deprecated alias is removed.
18
+ REMOVED_IN = "1.0.0"
19
+
20
+
21
+ def resolve_deprecated(module: str, aliases: Mapping[str, Any], name: str) -> Any:
22
+ """Return the target of the deprecated *name*, warning first.
23
+
24
+ Raises ``AttributeError`` for anything not in *aliases*, so normal
25
+ attribute lookup on the module keeps behaving normally.
26
+ """
27
+ try:
28
+ target = aliases[name]
29
+ except KeyError:
30
+ raise AttributeError(f"module {module!r} has no attribute {name!r}") from None
31
+ warnings.warn(
32
+ f"{module}.{name} is deprecated and will be removed in {REMOVED_IN}; "
33
+ f"use {target.__name__} instead",
34
+ DeprecationWarning,
35
+ # resolve_deprecated -> __getattr__ -> the caller we want to blame.
36
+ stacklevel=3,
37
+ )
38
+ return target
@@ -1,5 +1,8 @@
1
1
  """Custom exceptions for data science workflows."""
2
2
 
3
+ from typing import Any
4
+
5
+ from .._deprecation import resolve_deprecated
3
6
  from .base import DataScienceError
4
7
  from .ingestion import (
5
8
  DataAugmentationError,
@@ -18,8 +21,8 @@ from .operations import (
18
21
  DataDriftError,
19
22
  DataExportError,
20
23
  DeploymentError,
24
+ ModelSerializationError,
21
25
  ResourceLimitError,
22
- SerializationError,
23
26
  )
24
27
  from .training import (
25
28
  BiasDetectionError,
@@ -59,7 +62,7 @@ __all__ = [
59
62
  "HyperparameterError",
60
63
  "ModelEvaluationError",
61
64
  "PredictionError",
62
- "SerializationError",
65
+ "ModelSerializationError",
63
66
  "DeploymentError",
64
67
  "DataDriftError",
65
68
  "ResourceLimitError",
@@ -83,3 +86,11 @@ __all__ = [
83
86
  "FeatureScalingError",
84
87
  "ModelCompatibilityError",
85
88
  ]
89
+
90
+ #: Renamed in 0.2.0: this named the same thing as
91
+ #: ``dataexcept.exceptions.SerializationError`` while being a different class.
92
+ _DEPRECATED_ALIASES = {"SerializationError": ModelSerializationError}
93
+
94
+
95
+ def __getattr__(name: str) -> Any:
96
+ return resolve_deprecated(__name__, _DEPRECATED_ALIASES, name)
@@ -7,7 +7,7 @@ from typing import Any, Optional
7
7
  from .base import DataScienceError
8
8
 
9
9
 
10
- class SerializationError(DataScienceError):
10
+ class ModelSerializationError(DataScienceError):
11
11
  """
12
12
  Raised when saving or loading a model fails.
13
13
 
@@ -30,7 +30,7 @@ class SerializationError(DataScienceError):
30
30
  super().__init__(message)
31
31
 
32
32
  def __str__(self) -> str:
33
- return f"[SerializationError] {self.path}"
33
+ return f"[ModelSerializationError] {self.path}"
34
34
 
35
35
 
36
36
  class DeploymentError(DataScienceError):
@@ -1,12 +1,15 @@
1
1
  # __init__.py
2
+ from typing import Any
3
+
4
+ from .._deprecation import resolve_deprecated
2
5
  from .authentication import AuthenticationError, AuthorizationError
3
6
  from .base import JobError
4
7
  from .configuration import ConfigurationError
5
8
  from .external import (
6
- ConnectionError,
7
9
  DependencyError,
10
+ OperationTimeoutError,
8
11
  ResourceNotFoundError,
9
- TimeoutError,
12
+ ServiceConnectionError,
10
13
  )
11
14
  from .lifecycle import JobCancellationError
12
15
  from .notification import EmailError, NotificationError, WebhookError
@@ -18,8 +21,8 @@ __all__ = [
18
21
  "JobError",
19
22
  "ValidationError",
20
23
  "ConfigurationError",
21
- "ConnectionError",
22
- "TimeoutError",
24
+ "ServiceConnectionError",
25
+ "OperationTimeoutError",
23
26
  "ResourceNotFoundError",
24
27
  "DependencyError",
25
28
  "AuthenticationError",
@@ -34,3 +37,14 @@ __all__ = [
34
37
  "WebhookError",
35
38
  "JobCancellationError",
36
39
  ]
40
+
41
+ #: Renamed in 0.2.0 because they shadowed Python builtins without inheriting
42
+ #: from them. The alias is the same class object, so ``except`` keeps working.
43
+ _DEPRECATED_ALIASES = {
44
+ "ConnectionError": ServiceConnectionError,
45
+ "TimeoutError": OperationTimeoutError,
46
+ }
47
+
48
+
49
+ def __getattr__(name: str) -> Any:
50
+ return resolve_deprecated(__name__, _DEPRECATED_ALIASES, name)
@@ -1,7 +1,7 @@
1
1
  from .base import JobError
2
2
 
3
3
 
4
- class ConnectionError(JobError):
4
+ class ServiceConnectionError(JobError):
5
5
  """Raised when a connection to an external service fails."""
6
6
 
7
7
  def __init__(self, service_name: str, original_exception: Exception | None = None):
@@ -13,7 +13,7 @@ class ConnectionError(JobError):
13
13
  super().__init__(msg)
14
14
 
15
15
 
16
- class TimeoutError(JobError):
16
+ class OperationTimeoutError(JobError):
17
17
  """Raised when an operation exceeds its time limit."""
18
18
 
19
19
  def __init__(self, operation: str, timeout: float):
@@ -1,9 +1,15 @@
1
1
  """Backward compatible job-related exceptions.
2
2
 
3
+ .. deprecated:: 0.1.0
4
+ Use :mod:`dataexcept.exceptions` instead. This module is scheduled for
5
+ removal in 1.0.0; see the stability policy in the documentation.
6
+
3
7
  This module re-exports the core job exceptions defined in
4
- :mod:`dataexcept.exceptions`. Applications should import from that
5
- package directly going forward. Importing from :mod:`dataexcept.job_exceptions`
6
- will raise a :class:`DeprecationWarning`.
8
+ :mod:`dataexcept.exceptions`. Importing it emits a :class:`DeprecationWarning`.
9
+ Every name it exports is available from :mod:`dataexcept.exceptions` and from
10
+ the top-level :mod:`dataexcept` package, so the migration is a change of import
11
+ line only -- the classes are identical objects, not replacements, so existing
12
+ ``except`` clauses keep working during the transition.
7
13
  """
8
14
 
9
15
  from __future__ import annotations
@@ -14,7 +20,6 @@ from .exceptions import (
14
20
  AuthenticationError,
15
21
  AuthorizationError,
16
22
  ConfigurationError,
17
- ConnectionError,
18
23
  CronExpressionError,
19
24
  DependencyError,
20
25
  DeserializationError,
@@ -22,15 +27,21 @@ from .exceptions import (
22
27
  JobCancellationError,
23
28
  JobError,
24
29
  NotificationError,
30
+ OperationTimeoutError,
25
31
  ParsingError,
26
32
  ResourceNotFoundError,
27
33
  ScheduleConflictError,
28
34
  SerializationError,
29
- TimeoutError,
35
+ ServiceConnectionError,
30
36
  ValidationError,
31
37
  WebhookError,
32
38
  )
33
39
 
40
+ # This module is itself deprecated, so it binds the pre-0.2.0 names directly
41
+ # rather than going through the alias machinery and warning a second time.
42
+ ConnectionError = ServiceConnectionError
43
+ TimeoutError = OperationTimeoutError
44
+
34
45
  __all__ = [
35
46
  "JobError",
36
47
  "ValidationError",
@@ -53,7 +64,8 @@ __all__ = [
53
64
  ]
54
65
 
55
66
  warnings.warn(
56
- "dataexcept.job_exceptions is deprecated; use dataexcept.exceptions instead",
67
+ "dataexcept.job_exceptions is deprecated and will be removed in 1.0.0; "
68
+ "use dataexcept.exceptions instead",
57
69
  DeprecationWarning,
58
70
  stacklevel=2,
59
71
  )
@@ -9,6 +9,13 @@ from typing import Any, Iterator, Mapping, Optional
9
9
 
10
10
  Context = Mapping[str, Any]
11
11
 
12
+ __all__ = [
13
+ "Context",
14
+ "log_and_raise",
15
+ "log_exception",
16
+ "log_then_raise",
17
+ ]
18
+
12
19
 
13
20
  def _normalize_context_value(value: Any) -> Any:
14
21
  try:
@@ -4,6 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  from typing import Any, Optional
6
6
 
7
+ from ._deprecation import resolve_deprecated
8
+
7
9
 
8
10
  class PipelineError(Exception):
9
11
  """Base exception for pipeline errors."""
@@ -22,7 +24,7 @@ class PreprocessingError(PipelineError):
22
24
  super().__init__(message)
23
25
 
24
26
 
25
- class FeatureEngineeringError(PreprocessingError):
27
+ class FeaturePreprocessingError(PreprocessingError):
26
28
  """Raised when feature engineering fails."""
27
29
 
28
30
  def __init__(self, feature: str, reason: Optional[str] = None) -> None:
@@ -190,7 +192,7 @@ class DataFetchError(PipelineError):
190
192
  __all__ = [
191
193
  "PipelineError",
192
194
  "PreprocessingError",
193
- "FeatureEngineeringError",
195
+ "FeaturePreprocessingError",
194
196
  "StorageError",
195
197
  "PipelineNotificationError",
196
198
  "RetryLimitExceededError",
@@ -203,3 +205,12 @@ __all__ = [
203
205
  "TypeCheckError",
204
206
  "DataFetchError",
205
207
  ]
208
+
209
+ #: Renamed in 0.2.0: this named the same thing as
210
+ #: ``dataexcept.datascience_exceptions.FeatureEngineeringError`` while being a
211
+ #: different class, so catching one silently missed the other.
212
+ _DEPRECATED_ALIASES = {"FeatureEngineeringError": FeaturePreprocessingError}
213
+
214
+
215
+ def __getattr__(name: str) -> Any:
216
+ return resolve_deprecated(__name__, _DEPRECATED_ALIASES, name)
@@ -1,24 +1,15 @@
1
- [tool.poetry]
1
+ [project]
2
2
  name = "DataExcept"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "A Python package providing structured, easily-extendable custom exception types."
5
- authors = ["Diogo Ribeiro <dfr@esmad.ipp.pt>"]
6
- maintainers = ["Diogo Ribeiro <diogo.debastos.ribeiro@gmail.com>"]
7
- license = "MIT"
8
5
  readme = "README.md"
9
- homepage = "https://github.com/DiogoRibeiro7/DataExcept"
10
- repository = "https://github.com/DiogoRibeiro7/DataExcept"
11
- documentation = "https://diogoribeiro7.github.io/DataExcept/"
12
- packages = [{ include = "dataexcept" }]
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.10,<3.14"
9
+ authors = [{ name = "Diogo Ribeiro", email = "dfr@esmad.ipp.pt" }]
10
+ maintainers = [{ name = "Diogo Ribeiro", email = "diogo.debastos.ribeiro@gmail.com" }]
13
11
  keywords = ["exceptions", "errors", "logging"]
14
- include = [
15
- "CITATION.cff",
16
- "LICENSE",
17
- "CHANGELOG.md",
18
- ]
19
-
20
12
  classifiers = [
21
- "License :: OSI Approved :: MIT License",
22
13
  "Programming Language :: Python :: 3",
23
14
  "Programming Language :: Python :: 3 :: Only",
24
15
  "Programming Language :: Python :: 3.10",
@@ -26,17 +17,26 @@ classifiers = [
26
17
  "Programming Language :: Python :: 3.12",
27
18
  "Programming Language :: Python :: 3.13",
28
19
  ]
20
+ dependencies = [
21
+ "tomli ; python_version < '3.11'",
22
+ ]
29
23
 
30
- [tool.poetry.urls]
24
+ [project.urls]
25
+ Homepage = "https://github.com/DiogoRibeiro7/DataExcept"
26
+ Repository = "https://github.com/DiogoRibeiro7/DataExcept"
27
+ Documentation = "https://diogoribeiro7.github.io/DataExcept/"
31
28
  Changelog = "https://github.com/DiogoRibeiro7/DataExcept/releases"
32
29
  Issues = "https://github.com/DiogoRibeiro7/DataExcept/issues"
33
30
 
34
- [tool.poetry.scripts]
31
+ [project.scripts]
35
32
  dataexcept = "dataexcept.__main__:main"
36
33
 
37
- [tool.poetry.dependencies]
38
- python = ">=3.10,<3.14"
39
- tomli = { version = "*", python = "<3.11" }
34
+ [tool.poetry]
35
+ packages = [{ include = "dataexcept" }]
36
+ include = [
37
+ "CITATION.cff",
38
+ "CHANGELOG.md",
39
+ ]
40
40
 
41
41
  [tool.poetry.group.dev.dependencies]
42
42
  black = "*"
@@ -54,7 +54,7 @@ mkdocs-material = ">=9.5,<10"
54
54
  mkdocstrings = { extras = ["python"], version = ">=0.26" }
55
55
 
56
56
  [build-system]
57
- requires = ["poetry-core>=1.0.0"]
57
+ requires = ["poetry-core>=2.0.0"]
58
58
  build-backend = "poetry.core.masonry.api"
59
59
 
60
60
  [tool.flake8]
@@ -72,9 +72,26 @@ line-length = 88
72
72
  target-version = "py310"
73
73
 
74
74
  [tool.ruff.lint]
75
- select = ["E", "F"]
75
+ # S = flake8-bandit (security), C90 = mccabe (complexity). Both ship with ruff,
76
+ # so neither needs a separate tool in CI.
77
+ select = ["E", "F", "S", "C90"]
76
78
  ignore = []
77
79
 
80
+ [tool.ruff.lint.mccabe]
81
+ # The most complex function in the package currently scores 6. Eight leaves
82
+ # room to breathe while still catching a function that grows out of hand.
83
+ max-complexity = 8
84
+
85
+ [tool.ruff.lint.per-file-ignores]
86
+ # assert is how a test asserts, and "/tmp/data" there is a string literal used
87
+ # as fixture data rather than a path that is ever opened.
88
+ "tests/**" = ["S101", "S108", "S603"]
89
+ # The lambda example asserts to narrow Optionals for the type checker.
90
+ "examples/**" = ["S101"]
91
+ # bump_version.py deliberately shells out to poetry, by name, on a maintainer's
92
+ # own machine.
93
+ "scripts/**" = ["S603", "S607"]
94
+
78
95
  [tool.mypy]
79
96
  python_version = "3.10"
80
97
  files = ["dataexcept"]
@@ -1,42 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project are documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
9
-
10
- ## [0.1.0] - 2026-08-24
11
-
12
- First public release.
13
-
14
- ### Added
15
-
16
- - Hierarchical exception classes for data science, machine learning and data
17
- engineering workflows. Catch a specific failure or a broad category, and get
18
- a message that names the value that caused it rather than a bare
19
- `ValueError`.
20
- - Domain modules for validation, configuration, authentication, parsing,
21
- serialization, scheduling, notification, lifecycle and external-service
22
- errors, plus dedicated pandas, database, network, I/O, pipeline and security
23
- exception groups.
24
- - `dataexcept.logging_helpers` with `log_exception`, `log_and_raise` and
25
- `log_then_raise`, for logging exceptions with structured context and
26
- re-raising without losing the traceback.
27
- - A `dataexcept` command-line entry point that lists the exported exception
28
- classes and reports the installed version.
29
- - A `py.typed` marker, backed by a mypy-clean codebase that CI enforces, so
30
- downstream type checkers get annotations that are actually correct.
31
- - Documentation at
32
- [diogoribeiro7.github.io/DataExcept](https://diogoribeiro7.github.io/DataExcept/),
33
- including an API reference generated from the docstrings.
34
-
35
- ### Notes
36
-
37
- - Supports Python 3.10 through 3.13.
38
- - Published to PyPI via OIDC trusted publishing; no long-lived API token is
39
- involved in a release.
40
-
41
- [Unreleased]: https://github.com/DiogoRibeiro7/DataExcept/compare/v0.1.0...HEAD
42
- [0.1.0]: https://github.com/DiogoRibeiro7/DataExcept/releases/tag/v0.1.0
File without changes