From c0cfc6ee6e924cf4641083e099bf1c0e17f42f1e Mon Sep 17 00:00:00 2001 From: Viggo de Vries Date: Tue, 2 Jan 2024 14:43:06 +0100 Subject: [PATCH] Use fake request for images, make the children mapping work --- Makefile | 7 ++-- .../management/commands/test_queries.py | 4 +-- oscar_odin/mappings/catalogue.py | 16 ++++++++- oscar_odin/resources/catalogue.py | 4 +++ poetry.lock | 33 +++++++++++++++---- pyproject.toml | 3 ++ tests/mappings/test_catalogue.py | 10 ++++++ tests/reverse/test_reallifecase.py | 10 ++++++ 8 files changed, 72 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 9428b2d..f7b46ff 100644 --- a/Makefile +++ b/Makefile @@ -25,18 +25,15 @@ lint: fail-if-no-virtualenv pylint oscar_odin/ test: fail-if-no-virtualenv - python3 manage.py makemigrations --check --dry-run + pip install .[test] @python3 manage.py test tests/ black: @black oscar_odin/ @black tests/ -test: - python3 manage.py test tests/ - ill: rm db.sqlite3 cp klaas.sqlite3 db.sqlite3 python3 manage.py migrate - python3 manage.py test_illshit + python3 manage.py test_queries diff --git a/oscar_odin/management/commands/test_queries.py b/oscar_odin/management/commands/test_queries.py index 7e1647a..4b9c435 100644 --- a/oscar_odin/management/commands/test_queries.py +++ b/oscar_odin/management/commands/test_queries.py @@ -118,7 +118,7 @@ def create_product(i): attributes=attributes, ) - products = list(map(create_product, range(0, 5000))) + products = list(map(create_product, range(0, 1000))) with querycounter("COMMANDO"): products_to_db( @@ -128,4 +128,4 @@ def create_product(i): + ALL_PRODUCTIMAGE_FIELDS, ) - print("AANTAL PRODUCTEN AANGEMAAKT:", Product.objects.count()) + print("Amount of products created:", Product.objects.count()) diff --git a/oscar_odin/mappings/catalogue.py b/oscar_odin/mappings/catalogue.py index af7a419..82155f0 100644 --- a/oscar_odin/mappings/catalogue.py +++ b/oscar_odin/mappings/catalogue.py @@ -216,6 +216,19 @@ def attributes(self) -> Dict[str, Any]: for item in self.source.get_attribute_values() } + @odin.assign_field + def children(self) -> Tuple[Optional[List[resources.catalogue.Product]]]: + """Children of parent products.""" + + if self.context.get("include_children", False) and self.source.is_parent: + # Return a tuple as an optional list causes problems. + return ( + map_queryset( + ProductToResource, self.source.children, context=self.context + ), + ) + return (None,) + @odin.assign_field(to_field=("price", "currency", "availability")) def map_stock_price(self) -> Tuple[Decimal, str, int]: """Resolve stock price using strategy and decompose into price/currency/availability.""" @@ -237,6 +250,8 @@ class ProductToModel(ModelMapping): from_obj = resources.catalogue.Product to_obj = ProductModel + mappings = (odin.define(from_field="children", skip_if_none=True),) + @odin.map_list_field def images(self, values) -> List[ProductImageModel]: """Map related image. We save these later in bulk""" @@ -383,7 +398,6 @@ def products_to_model( def products_to_db( products, - rollback=True, fields_to_update=ALL_CATALOGUE_FIELDS, identifier_mapping=MODEL_IDENTIFIERS_MAPPING, product_mapper=ProductToModel, diff --git a/oscar_odin/resources/catalogue.py b/oscar_odin/resources/catalogue.py index 1be67e2..a3531d2 100644 --- a/oscar_odin/resources/catalogue.py +++ b/oscar_odin/resources/catalogue.py @@ -123,3 +123,7 @@ class Product(OscarCatalogue): date_created: datetime date_updated: datetime + + children: Optional[List["Product"]] = odin.ListOf.delayed( + lambda: Product, null=True + ) diff --git a/poetry.lock b/poetry.lock index ba48a8c..96eee61 100644 --- a/poetry.lock +++ b/poetry.lock @@ -171,7 +171,7 @@ redis = ["redis (>=2.10.5)"] name = "certifi" version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." -optional = true +optional = false python-versions = ">=3.6" files = [ {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, @@ -257,7 +257,7 @@ files = [ name = "charset-normalizer" version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -optional = true +optional = false python-versions = ">=3.7.0" files = [ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, @@ -846,7 +846,7 @@ license = ["ukkonen"] name = "idna" version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" -optional = true +optional = false python-versions = ">=3.5" files = [ {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, @@ -1479,7 +1479,7 @@ files = [ name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -optional = true +optional = false python-versions = ">=3.6" files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, @@ -1640,7 +1640,7 @@ full = ["numpy"] name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -optional = true +optional = false python-versions = ">=3.7" files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, @@ -1671,6 +1671,25 @@ files = [ [package.dependencies] requests = ">=2.0.1,<3.0.0" +[[package]] +name = "responses" +version = "0.24.1" +description = "A utility library for mocking out the `requests` Python library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "responses-0.24.1-py3-none-any.whl", hash = "sha256:a2b43f4c08bfb9c9bd242568328c65a34b318741d3fab884ac843c5ceeb543f9"}, + {file = "responses-0.24.1.tar.gz", hash = "sha256:b127c6ca3f8df0eb9cc82fd93109a3007a86acb24871834c47b77765152ecf8c"}, +] + +[package.dependencies] +pyyaml = "*" +requests = ">=2.30.0,<3.0" +urllib3 = ">=1.25.10,<3.0" + +[package.extras] +tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli", "tomli-w", "types-PyYAML", "types-requests"] + [[package]] name = "ruff" version = "0.1.8" @@ -1825,7 +1844,7 @@ files = [ name = "urllib3" version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." -optional = true +optional = false python-versions = ">=3.8" files = [ {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, @@ -1963,4 +1982,4 @@ test = ["black", "coverage", "poetry", "pylint", "pylint-django"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "5a84c6a91069445359c16f074909edb368a09d65dd448ec30abd2c4a94e5d8ca" +content-hash = "9062cc68d4eecc0889190778402d2960256218d73c4968bf063912273380ea47" diff --git a/pyproject.toml b/pyproject.toml index bc50b1d..01fadc0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,6 +41,9 @@ pre-commit = {version = "*", optional = true} test = ["coverage", "pylint", "black", "pylint-django", "poetry"] dev = ["ruff", "isort", "pre-commit"] +[tool.poetry.group.test.dependencies] +responses = "^0.24.1" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" diff --git a/tests/mappings/test_catalogue.py b/tests/mappings/test_catalogue.py index ca6734c..8c183a4 100644 --- a/tests/mappings/test_catalogue.py +++ b/tests/mappings/test_catalogue.py @@ -31,3 +31,13 @@ def test_product_to_resource__where_is_a_parent_product_do_not_include_children( actual = catalogue.product_to_resource(product) self.assertEqual(product.title, actual.title) + self.assertIsNone(actual.children) + + def test_mapping__where_is_a_parent_product_include_children(self): + product = Product.objects.get(id=8) + + actual = catalogue.product_to_resource(product, include_children=True) + + self.assertEqual(product.title, actual.title) + self.assertIsNotNone(actual.children) + self.assertEqual(3, len(actual.children)) diff --git a/tests/reverse/test_reallifecase.py b/tests/reverse/test_reallifecase.py index 276ceae..7752871 100644 --- a/tests/reverse/test_reallifecase.py +++ b/tests/reverse/test_reallifecase.py @@ -2,6 +2,7 @@ import PIL import odin import requests +import responses from urllib.parse import urlparse @@ -139,7 +140,16 @@ def is_discountable(self): class RealLifeTest(TestCase): + @responses.activate def test_mapping(self): + responses.add( + responses.GET, + "https://picsum.photos/200/300", + body="Dit is nep content van een image", + status=200, + content_type="image/jpeg", + ) + for partner_id in ["1049", "1052", "1053", "1049"]: Partner.objects.get_or_create( code=partner_id, defaults={"name": partner_id}