From: 
Subject: Debian changes

The Debian packaging of pyecotrend-ista is maintained in git, using a workflow
similar to the one described in dgit-maint-merge(7).
The Debian delta is represented by this one combined patch; there isn't a
patch queue that can be represented as a quilt series.

A detailed breakdown of the changes is available from their canonical
representation -- git commits in the packaging repository.
For example, to see the changes made by the Debian maintainer in the first
upload of upstream version 1.2.3, you could use:

    % git clone https://git.dgit.debian.org/pyecotrend-ista
    % cd pyecotrend-ista
    % git log --oneline 1.2.3..debian/1.2.3-1 -- . ':!debian'

(If you have dgit, use `dgit clone pyecotrend-ista`, rather than plain `git clone`.)

We don't use debian/source/options single-debian-patch because it has bugs.
Therefore, NMUs etc. may nevertheless have made additional patches.

---

diff --git a/pyproject.toml b/pyproject.toml
index 88e1616..9339858 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [build-system]
 build-backend = "setuptools.build_meta"
-requires = ['setuptools>=77.0.3', "setuptools-scm", "requests", "dataclasses-json"]
+requires = ['setuptools>=77.0.3', "setuptools-scm", "requests"]
 
 [project]
 authors = [
@@ -22,8 +22,7 @@ classifiers = [
   "Topic :: Software Development :: Libraries :: Python Modules"
 ]
 dependencies = [
-  "requests>=2",
-  "dataclasses-json>=0.6"
+  "requests>=2"
 ]
 description = "Python EcoTrend-ista Api"
 dynamic = ["version", "readme"]
diff --git a/requirements.in b/requirements.in
index 508a4ab..d539cf2 100644
--- a/requirements.in
+++ b/requirements.in
@@ -1,6 +1,5 @@
 # Main dependencies
 requests>=2
-dataclasses-json>=0.6
 
 # Optional dependencies: doc
 babel==2.17.0
diff --git a/requirements.txt b/requirements.txt
index 0fa43e0..a1060ec 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -262,10 +262,6 @@ csscompressor==0.9.5 \
     # via
     #   -r requirements.in
     #   mkdocs-minify-plugin
-dataclasses-json==0.6.7 \
-    --hash=sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a \
-    --hash=sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0
-    # via -r requirements.in
 distlib==0.4.0 \
     --hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
     --hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
@@ -443,10 +439,6 @@ markupsafe==3.0.3 \
     #   mkdocs
     #   mkdocs-autorefs
     #   mkdocstrings
-marshmallow==3.26.1 \
-    --hash=sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c \
-    --hash=sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6
-    # via dataclasses-json
 mdx-gh-links==0.4 \
     --hash=sha256:41d5aac2ab201425aa0a19373c4095b79e5e015fdacfe83c398199fe55ca3686 \
     --hash=sha256:9057bca1fa5280bf1fcbf354381e46c9261cc32c2d5c0407801f8a910be5f099
@@ -840,10 +832,6 @@ typing-extensions==4.15.0 \
     --hash=sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466 \
     --hash=sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548
     # via typing-inspect
-typing-inspect==0.9.0 \
-    --hash=sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f \
-    --hash=sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78
-    # via dataclasses-json
 urllib3==2.6.1 \
     --hash=sha256:5379eb6e1aba4088bae84f8242960017ec8d8e3decf30480b3a1abdaa9671a3f \
     --hash=sha256:e67d06fe947c36a7ca39f4994b08d73922d40e6cca949907be05efa6fd75110b
diff --git a/src/pyecotrend_ista/helper_object_de.py b/src/pyecotrend_ista/helper_object_de.py
index 484fd3e..31b2d75 100644
--- a/src/pyecotrend_ista/helper_object_de.py
+++ b/src/pyecotrend_ista/helper_object_de.py
@@ -2,15 +2,83 @@
 
 from __future__ import annotations
 
-from dataclasses import dataclass
+from dataclasses import MISSING, asdict, dataclass, fields, is_dataclass
+import json
+from types import NoneType, UnionType
+from typing import Any, TypeVar, get_args, get_origin, get_type_hints
 
-from dataclasses_json import DataClassJsonMixin, dataclass_json
+T = TypeVar("T", bound="DataClassDictMixin")
+
+
+def _decode_value(value: Any, annotation: Any) -> Any:
+    """Decode a plain Python value into the target annotation."""
+    if annotation is Any:
+        return value
+
+    origin = get_origin(annotation)
+    args = get_args(annotation)
+
+    if origin in (list, tuple):
+        inner_type = args[0] if args else Any
+        return [_decode_value(item, inner_type) for item in value]
+
+    if origin is dict:
+        key_type, value_type = args if args else (Any, Any)
+        return {_decode_value(key, key_type): _decode_value(item, value_type) for key, item in value.items()}
+
+    if origin in (UnionType,):
+        non_none_args = [arg for arg in args if arg is not NoneType]
+        if value is None and len(non_none_args) != len(args):
+            return None
+        for arg in non_none_args:
+            try:
+                return _decode_value(value, arg)
+            except (TypeError, ValueError, AttributeError):
+                continue
+        return value
+
+    if is_dataclass(annotation):
+        return annotation.from_dict(value)
+
+    if annotation is NoneType or value is None:
+        return None
+
+    return value
+
+
+class DataClassDictMixin:
+    """Minimal dataclass dict/json conversion helpers."""
+
+    @classmethod
+    def from_dict(cls: type[T], value: dict[str, Any] | None) -> T:
+        """Build a dataclass instance from a nested dictionary."""
+        if value is None:
+            raise TypeError(f"Cannot build {cls.__name__} from None")
+
+        type_hints = get_type_hints(cls)
+        kwargs = {}
+        for field in fields(cls):
+            if field.name in value:
+                kwargs[field.name] = _decode_value(value[field.name], type_hints.get(field.name, field.type))
+            elif field.default is not MISSING or field.default_factory is not MISSING:
+                continue
+            else:
+                raise TypeError(f"Missing required field '{field.name}' for {cls.__name__}")
+        return cls(**kwargs)
+
+    @classmethod
+    def from_json(cls: type[T], value: str) -> T:
+        """Build a dataclass instance from a JSON document."""
+        return cls.from_dict(json.loads(value))
+
+    def to_dict(self) -> dict[str, Any]:
+        """Convert a dataclass instance into a nested dictionary."""
+        return asdict(self)
 
 
 # pylint: disable=invalid-name
-@dataclass_json
 @dataclass
-class AverageConsumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class AverageConsumption(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Represents average consumption data.
 
     Attributes
@@ -60,9 +128,8 @@ class AverageConsumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
         self.replace_point()
 
 
-@dataclass_json
 @dataclass
-class ComparedConsumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class ComparedConsumption(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """
     Represents compared consumption data.
 
@@ -101,9 +168,8 @@ class ComparedConsumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
         self.replace_point()
 
 
-@dataclass_json
 @dataclass
-class Consumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01,PR02
+class Consumption(DataClassDictMixin):  # numpydoc ignore=ES01,EX01,PR02
     """Data class representing consumption.
 
     Parameters
@@ -151,9 +217,8 @@ class Consumption(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01,PR02
         self.replace_point()
 
 
-@dataclass_json
 @dataclass
-class Cost(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class Cost(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing cost information.
 
     Attributes
@@ -177,9 +242,8 @@ class Cost(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     comparedCost: ComparedConsumption | None  # noqa: N815
 
 
-@dataclass_json
 @dataclass
-class Date(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class Date(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing a date with month and year.
 
     Attributes
@@ -194,9 +258,8 @@ class Date(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     year: int
 
 
-@dataclass_json
 @dataclass
-class LastValue(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class LastValue(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing last values.
 
     Attributes
@@ -229,9 +292,8 @@ class LastValue(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     h: str | None = None
 
 
-@dataclass_json
 @dataclass
-class LastCustomValue(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class LastCustomValue(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing last custom values.
 
     Attributes
@@ -264,9 +326,8 @@ class LastCustomValue(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     h: str | None = None
 
 
-@dataclass_json
 @dataclass
-class LastCosts(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class LastCosts(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing last costs.
 
     Attributes
@@ -293,9 +354,8 @@ class LastCosts(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     unit: str | None = None
 
 
-@dataclass_json
 @dataclass
-class CombinedData(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class CombinedData(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class representing combined data.
 
     Attributes
@@ -313,9 +373,8 @@ class CombinedData(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     costs: list[Cost]
 
 
-@dataclass_json
 @dataclass
-class TotalAdditionalValues(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class TotalAdditionalValues(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class for representing total additional values.
 
     Attributes
@@ -342,9 +401,8 @@ class TotalAdditionalValues(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     h: str | None = None
 
 
-@dataclass_json
 @dataclass
-class TotalAdditionalCustomValues(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class TotalAdditionalCustomValues(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class for representing total additional custom values.
 
     Attributes
@@ -371,9 +429,8 @@ class TotalAdditionalCustomValues(DataClassJsonMixin):  # numpydoc ignore=ES01,E
     h: str | None = None
 
 
-@dataclass_json
 @dataclass
-class SumByYear(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class SumByYear(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class for representing the sum of values grouped by year.
 
     Attributes
@@ -400,9 +457,8 @@ class SumByYear(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
     h: str | None = None
 
 
-@dataclass_json
 @dataclass
-class CustomRaw(DataClassJsonMixin):  # numpydoc ignore=ES01,EX01
+class CustomRaw(DataClassDictMixin):  # numpydoc ignore=ES01,EX01
     """Data class for representing custom raw data.
 
     Attributes
