Repository: SebRut/pygrocy
Pull request #163 (2021-03-21 12:43:38)

add tojson helper method
relates to #158 



Patch:
diff --git a/pygrocy/base.py b/pygrocy/base.py
index fe714d8..96b852c 100644
--- a/pygrocy/base.py
+++ b/pygrocy/base.py
@@ -1,10 +1,20 @@
+import json
+
+
 def get_val(obj):
-    if hasattr(obj, 'as_dict'):
-        as_attr = getattr(obj, 'as_dict')
+    if hasattr(obj, "as_dict"):
+        as_attr = getattr(obj, "as_dict")
         return as_attr()
     return obj
 
 
 class DataModel(object):
+    def toJson(self):
+        return json.dumps(self.as_dict())
+
     def as_dict(self):
-        return {k: get_val(getattr(self, k)) for k, v in self.__class__.__dict__.items() if isinstance(v, property)}
+        return {
+            k: get_val(getattr(self, k))
+            for k, v in self.__class__.__dict__.items()
+            if isinstance(v, property)
+        }
diff --git a/pygrocy/data_models/product.py b/pygrocy/data_models/product.py
index 1fae201..bb98038 100644
--- a/pygrocy/data_models/product.py
+++ b/pygrocy/data_models/product.py
@@ -7,13 +7,22 @@ from pygrocy.grocy_api_client import (
     GrocyApiClient,
     LocationData,
     MissingProductResponse,
-    ProductBarcode,
+    ProductBarcodeData,
     ProductData,
     ProductDetailsResponse,
     ShoppingListItem,
 )
 
 
+class ProductBarcode(DataModel):
+    def __init__(self, data: ProductBarcodeData):
+        self._barcode = data.barcode
+
+    @property
+    def barcode(self) -> str:
+        return self._barcode
+
+
 class Product(DataModel):
     def __init__(self, data):
         self._init_empty()
@@ -55,7 +64,7 @@ class Product(DataModel):
     def _init_from_ProductDetailsResponse(self, response: ProductDetailsResponse):
         self._available_amount = response.stock_amount
         self._best_before_date = response.next_best_before_date
-        self._barcodes = response.barcodes
+        self._barcodes = [ProductBarcode(data) for data in response.barcodes]
 
         if response.product:
             self._init_from_ProductData(response.product)
diff --git a/pygrocy/grocy_api_client.py b/pygrocy/grocy_api_client.py
index e283ce9..6cfc93c 100644
--- a/pygrocy/grocy_api_client.py
+++ b/pygrocy/grocy_api_client.py
@@ -365,7 +365,7 @@ class CurrentVolatilStockResponse(object):
         return self._missing_products
 
 
-class ProductBarcode(object):
+class ProductBarcodeData(object):
     def __init__(self, parsed_json):
         self._barcode = parsed_json.get("barcode")
 
@@ -398,7 +398,7 @@ class ProductDetailsResponse(object):
     def _parse_barcodes(self, parsed_json):
         barcodes_raw = parsed_json.get("product_barcodes", "")
         if barcodes_raw is not None:
-            self._barcodes = [ProductBarcode(barcode) for barcode in barcodes_raw]
+            self._barcodes = [ProductBarcodeData(barcode) for barcode in barcodes_raw]
 
     def _parse_location(self, parsed_json):
         raw_location = parsed_json.get("location")
@@ -432,7 +432,7 @@ class ProductDetailsResponse(object):
         return self._last_price
 
     @property
-    def barcodes(self) -> List[ProductBarcode]:
+    def barcodes(self) -> List[ProductBarcodeData]:
         return self._barcodes
 
     @property


Test patch:
diff --git a/test/cassettes/test_product/TestProduct.test_product_get_details_valid.yaml b/test/cassettes/test_product/TestProduct.test_product_get_details_valid.yaml
index e80e8d8..87065e1 100644
--- a/test/cassettes/test_product/TestProduct.test_product_get_details_valid.yaml
+++ b/test/cassettes/test_product/TestProduct.test_product_get_details_valid.yaml
@@ -15,18 +15,19 @@ interactions:
   response:
     body:
       string: !!binary |
-        H4sIAAAAAAAEA81UTW/bMAz9K4PObWEnS7D5OmDn3YeBYGTaFipLqiwly4r+91GSHTdD9tHbLkHM
-        jyeS75HPwnnbRhlE8yxUKxpRV+JOGByJ/38aiCbi75Ym6ZULyhrRmKj13ZIHvbfRQU7dcyTKoI4p
-        t+YPbSWmnOLesGUarHPK9HDlKohPkePARS8H5FcbseWEYpyClY+rpeNXrL+EQrCwRNQPqf5RmWIB
-        HG003J1I5pY6jDrAgab001lP0OJ5+osbsAvkwTri7v8INEd2nugHd/lv0WHA0xrslAyR6+qUJig8
-        lPGQwQObArLzRKofAgxoWr2mvnKll/MkjA0gB5KP8zy6qBlZj2QCcP/gSSpHywQcg7Nj1kSmrTwu
-        UVuvcly9SbzIOEaNgeDXUYPtYIqHBWNBbiOXfnaLMp6i4pKkNVMcaSWpsDeoloBVkzkFeyR/VHSa
-        h+ntCaQnfrqFoEZmEkfHvk21qe6rD/f1/l21b95vm91evKwyPaCXlmUsmq/fWJjIAliUllS/ZFdJ
-        w9kbJ2JH6b4UcpHSjmOK6Yg6ppb29cNmtZbArJeEkRXzGgKw7z31qQX27jJPV/6kNG7vKqzQuSj4
-        KaIJKpwhGrV2clnixNC8w1+QN+fmBr9lkgUOnI4eNRedUCeGLYakpJFHm6bFM78uLnf2n1RWePdK
-        Zh3WD9t0k/DYs1pn26YQaTVrJS3CtTnn375hIkEt9NwOKWIy9D1AWoeWBcCjLNL7eF+kN1/My7wS
-        6szkZ6/a/jfX+G1cqgnyiSKf1cmUIS8Z9gTTQLoDrbrlMO5q1rqzSoNP2+7IS74QoqnuBKOsCl13
-        uBIvPwHQ5/ECVgYAAA==
+        H4sIAAAAAAAEA8WVTW/bMAyG/0qhc1PY+Sg2XwfsvPswEIpM20JlSZWlZF3R/z5Ksuxk6LLttEtR
+        kxRF8n3EvDLrTBuEZ80rky1rWF2xe6b5iPT/pwFxQvpucRJOWi+NZo0OSt2Xc9A7Eyyko48UyYWX
+        p3i2pg9lBI9nsntLlmkw1krdw5UrZ3wOFAc2ODFwurVhOzqQjZM34mm1dHSLcUsoeAMlon6I9Y9S
+        Zwvw0QRN3bFobrHjQXk44hT/dMYhtPxl+oMbeOfRgbFI3d9MNEd2DvEHdfl30X7g5zXYSuED1dVJ
+        hZB1yONBzY9k8pycZ5T94GHgulXr0QtXvDlNQhsPYkDxNM+jC4oyqxG1B+ofHAppsUzAUnJyzEwk
+        2fLlgivjZIqrt1EXEcaguEf4ddRgOpjCseQomdtApb/YQsZzkFSSMHoKI64iZfUG2SIQNUlTMCd0
+        J4nneZjOnEE4pKtb8HIkJfloybettvWm2m7q3V39sdnXze6Rva2YHrkThjBmzdcZ9D11cdloJn+O
+        o4TU5/5AMYlA+o5dLzTlQt+nmUXQFSfErJOCOs4jvF34blMf7qpDs9832w90nnSLs+JHwd6+lXTz
+        04jPtLRbxbLSZWFCcuS78uSWamMb2XTiKiQNDg/1as2BCfCYIyF+mQJ43zvs48zJe0hgXfnj0yA9
+        rsIyf+XJPQeuvfQvELSkwSyPfBYjdjEvnS+cnvq7K+f2BC+lj9rGdGBVcFxR0THrRNZsiOiPxEKc
+        FkFyXVzqbNmH/7eyS4zY7uEQNeOnvpBFpgSAUYT2wluxpsM3GC3avB+SSdL43UN8vC2pv3C321Rx
+        2Zclvgwrkj/L+NnJtv/Nb8e/CSknSAsVXUKT9OK0EniPMA2oOlCyK2v8UBPo1kgFLu4mi07QPmNN
+        dc8oy4rnunEq9vYTr/Y7BgQHAAA=
     headers:
       Access-Control-Allow-Headers:
       - '*'
@@ -41,59 +42,7 @@ interactions:
       Content-Type:
       - application/json
       Date:
-      - Fri, 12 Feb 2021 05:44:44 GMT
-      Server:
-      - nginx/1.18.0
-      Transfer-Encoding:
-      - chunked
-      X-Powered-By:
-      - PHP/7.4.14
-    status:
-      code: 200
-      message: OK
-- request:
-    body: null
-    headers:
-      Accept-Encoding:
-      - gzip, deflate
-      Connection:
-      - keep-alive
-      User-Agent:
-      - python-requests/2.25.1
-      accept:
-      - application/json
-    method: GET
-    uri: https://localhost/api/stock/products/10
-  response:
-    body:
-      string: !!binary |
-        H4sIAAAAAAAEA81UTW/bMAz9K4PObWEnS7D5OmDn3YeBYGTaFipLqiwly4r+91GSHTdD9tHbLkHM
-        jyeS75HPwnnbRhlE8yxUKxpRV+JOGByJ/38aiCbi75Ym6ZULyhrRmKj13ZIHvbfRQU7dcyTKoI4p
-        t+YPbSWmnOLesGUarHPK9HDlKohPkePARS8H5FcbseWEYpyClY+rpeNXrL+EQrCwRNQPqf5RmWIB
-        HG003J1I5pY6jDrAgab001lP0OJ5+osbsAvkwTri7v8INEd2nugHd/lv0WHA0xrslAyR6+qUJig8
-        lPGQwQObArLzRKofAgxoWr2mvnKll/MkjA0gB5KP8zy6qBlZj2QCcP/gSSpHywQcg7Nj1kSmrTwu
-        UVuvcly9SbzIOEaNgeDXUYPtYIqHBWNBbiOXfnaLMp6i4pKkNVMcaSWpsDeoloBVkzkFeyR/VHSa
-        h+ntCaQnfrqFoEZmEkfHvk21qe6rD/f1/l21b95vm91evKwyPaCXlmUsmq/fWJjIAliUllS/ZFdJ
-        w9kbJ2JH6b4UcpHSjmOK6Yg6ppb29cNmtZbArJeEkRXzGgKw7z31qQX27jJPV/6kNG7vKqzQuSj4
-        KaIJKpwhGrV2clnixNC8w1+QN+fmBr9lkgUOnI4eNRedUCeGLYakpJFHm6bFM78uLnf2n1RWePdK
-        Zh3WD9t0k/DYs1pn26YQaTVrJS3CtTnn375hIkEt9NwOKWIy9D1AWoeWBcCjLNL7eF+kN1/My7wS
-        6szkZ6/a/jfX+G1cqgnyiSKf1cmUIS8Z9gTTQLoDrbrlMO5q1rqzSoNP2+7IS74QoqnuBKOsCl13
-        uBIvPwHQ5/ECVgYAAA==
-    headers:
-      Access-Control-Allow-Headers:
-      - '*'
-      Access-Control-Allow-Methods:
-      - GET, POST, PUT, DELETE, OPTIONS
-      Access-Control-Allow-Origin:
-      - '*'
-      Connection:
-      - keep-alive
-      Content-Encoding:
-      - gzip
-      Content-Type:
-      - application/json
-      Date:
-      - Fri, 12 Feb 2021 05:44:44 GMT
+      - Mon, 15 Mar 2021 05:45:15 GMT
       Server:
       - nginx/1.18.0
       Transfer-Encoding:
diff --git a/test/test_misc.py b/test/test_misc.py
new file mode 100644
index 0000000..1e1ee8e
--- /dev/null
+++ b/test/test_misc.py
@@ -0,0 +1,15 @@
+from pygrocy.data_models.product import ProductBarcode
+from pygrocy.grocy_api_client import ProductBarcodeData
+
+
+class TestMisc:
+    def test_158_productbarcode_deserialization(self):
+        parsed_data = {"barcode": "123"}
+        data = ProductBarcodeData(parsed_data)
+
+        barcode = ProductBarcode(data)
+        result = barcode.toJson()
+
+        assert result is not None
+        assert "barcode" in result
+        assert "123" in result
diff --git a/test/test_product.py b/test/test_product.py
index a28a03c..44c52fc 100644
--- a/test/test_product.py
+++ b/test/test_product.py
@@ -1,6 +1,6 @@
 import pytest
 
-from pygrocy.data_models.product import Product
+from pygrocy.data_models.product import Product, ProductBarcode
 from pygrocy.errors.grocy_error import GrocyError
 
 
@@ -22,9 +22,13 @@ class TestProduct:
         assert isinstance(product, Product)
         assert product.name == "Cheese"
         assert product.available_amount == 5
-        assert len(product.barcodes) == 0
         assert product.product_group_id == 6
 
+        assert len(product.product_barcodes) == 1
+        barcode = product.product_barcodes[0]
+        assert isinstance(barcode, ProductBarcode)
+        assert barcode.barcode == "12345"
+
     @pytest.mark.vcr
     def test_product_no_barcodes(self, grocy):
         stock = grocy.stock()