diff --git a/CHANGELOG.md b/CHANGELOG.md index b48829f..83b8764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added new methods `video` and `video_thumbnail` that return a video and video thumbnail related to a given mode, video name and customization - [ripe-white/#996](https://github.com/ripe-tech/ripe-white/issues/996) * General order chat methods - [ripe-core/#4702](https://github.com/ripe-tech/ripe-core/issues/4702) * Order tag methods - [ripe-robin-revamp/#363](https://github.com/ripe-tech/ripe-robin-revamp/issues/363) +* Port `_query_to_spec`, `_unpack_query`, `_parse_extra_s`, `_tuples_to_parts`, `_parts_to_parts_m` from RIPE SDK JS ### Changed diff --git a/setup.py b/setup.py index 453d6dd..b306d5e 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ url="http://www.platforme.com", zip_safe=False, packages=["ripe"], + test_suite="ripe.test", package_dir={"": os.path.normpath("src")}, install_requires=["appier"], classifiers=[ diff --git a/src/ripe/base.py b/src/ripe/base.py index 13b4c96..1327f0f 100644 --- a/src/ripe/base.py +++ b/src/ripe/base.py @@ -54,6 +54,127 @@ class API( transport_rule.TransportRuleAPI, availability_rule.AvailabilityRuleAPI, ): + @classmethod + def _query_to_spec(cls, query): + options = cls._unpack_query(query) + brand = options.get("brand", None) + model = options.get("model", None) + variant = options.get("variant", None) + version = options.get("version", None) + description = options.get("description", None) + initials = options.get("initials", None) + engraving = options.get("engraving", None) + gender = options.get("gender", None) + size = options.get("size", None) + meta = options.get("meta", []) + tuples = options.get("p", []) + tuples = tuples if isinstance(tuples, list) else [tuples] + initials_extra = options.get("initials_extra", []) + initials_extra = ( + initials_extra if isinstance(initials_extra, list) else [initials_extra] + ) + initials_extra = cls._parse_extra_s(initials_extra) + parts = cls._tuples_to_parts(tuples) + parts_m = cls._parts_to_parts_m(parts) + spec = dict( + brand=brand, + model=model, + parts=parts_m, + initials=initials, + engraving=engraving, + initials_extra=initials_extra, + ) + if variant: + spec["variant"] = variant + if version: + spec["version"] = version + if description: + spec["description"] = description + if gender: + spec["gender"] = gender + if size: + spec["size"] = size + if meta: + spec["meta"] = cls._normalize_meta(meta) + return spec + + @classmethod + def _unpack_query(cls, query): + query = query.strip("?") + parts = appier.split_unescape(query, "&") + options = dict() + for part in parts: + key, value = part.split("=") + if not key in options: + options[key] = value + elif isinstance(options[key], list): + options[key].append(value) + else: + options[key] = [options[key], value] + return options + + @classmethod + def _parse_extra_s(cls, extra_s): + extra = dict() + for extra_i in extra_s: + name, initials, engraving = appier.split_unescape(extra_i, ":", 2) + extra[name] = dict(initials=initials, engraving=engraving or None) + return extra + + @classmethod + def _tuples_to_parts(cls, tuples): + parts = [] + for triplet in tuples: + name, material, color = appier.split_unescape(triplet, ":", 2) + part = dict(name=name, material=material, color=color) + parts.append(part) + return parts + + @classmethod + def _parts_to_parts_m(cls, parts): + parts_m = dict() + for part in parts: + name = part["name"] + material = part["material"] + color = part["color"] + parts_m[name] = dict(material=material, color=color) + return parts_m + + @classmethod + def _normalize_meta(cls, meta): + meta_d = {} + meta_l = ( + [ + appier.split_unescape(element, ":", 2) + if element.startswith("$") + else appier.split_unescape(element, ":", 1) + for element in meta + ] + if meta + else [] + ) + for parts in meta_l: + if len(parts) == 2: + parts = None, parts[0], parts[1] + type, key, value = parts + if key in meta_d: + old = meta_d[key] + is_sequence = isinstance(old, (list, tuple)) + if not is_sequence: + old = [old] + old.append(value) + value = old + if type == "$list" and not isinstance(value, list): + value = [value] + if type == "$int": + value = int(value) + if type == "$float": + value = float(value) + if type == "$bool": + value = value in ("1", "true", "True") + meta_d[key] = value + return meta_d + def __init__(self, *args, **kwargs): appier.API.__init__(self, *args, **kwargs) self.base_url = appier.conf("RIPE_BASE_URL", RIPE_BASE_URL) diff --git a/src/ripe/test/__init__.py b/src/ripe/test/__init__.py new file mode 100644 index 0000000..5bcfe9b --- /dev/null +++ b/src/ripe/test/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- diff --git a/src/ripe/test/base.py b/src/ripe/test/base.py new file mode 100644 index 0000000..cf9fe07 --- /dev/null +++ b/src/ripe/test/base.py @@ -0,0 +1,90 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import unittest + +import ripe + + +class APITest(unittest.TestCase): + def test__query_to_spec(self): + result = ripe.API._query_to_spec( + "brand=dummy&model=dummy&locale=en_us&format=webp&initials=AAA&engraving=grey&initials_extra=main:AAA:grey&p=side:leather_dmy:black&p=piping:leather_dmy:black&p=top0_bottom:leather_dmy:black&p=shadow:default:default" + ) + self.assertEqual( + result, + dict( + brand="dummy", + model="dummy", + parts=dict( + side=dict(material="leather_dmy", color="black"), + piping=dict(material="leather_dmy", color="black"), + top0_bottom=dict(material="leather_dmy", color="black"), + shadow=dict(material="default", color="default"), + ), + initials="AAA", + engraving="grey", + initials_extra=dict(main=dict(engraving="grey", initials="AAA")), + ), + ) + + def test__unpack_query(self): + result = ripe.API._unpack_query( + "brand=dummy&model=dummy&p=sole:rubber:red&p=laces:metal:black" + ) + self.assertEqual( + result, + dict( + brand="dummy", model="dummy", p=["sole:rubber:red", "laces:metal:black"] + ), + ) + + result = ripe.API._unpack_query( + "?brand=dummy&model=dummy&p=sole:rubber:red&p=laces:metal:black" + ) + self.assertEqual( + result, + dict( + brand="dummy", model="dummy", p=["sole:rubber:red", "laces:metal:black"] + ), + ) + + def test__parse_extra_s(self): + result = ripe.API._parse_extra_s(["name1:aaa:black", "name2:bbb:white"]) + self.assertEqual( + result, + dict( + name1=dict(initials="aaa", engraving="black"), + name2=dict(initials="bbb", engraving="white"), + ), + ) + + def test__tuples_to_parts(self): + result = ripe.API._tuples_to_parts( + ["sole:rubber:red", "laces:metal:black", "side:rubber:white"] + ) + self.assertEqual( + result, + [ + dict(name="sole", material="rubber", color="red"), + dict(name="laces", material="metal", color="black"), + dict(name="side", material="rubber", color="white"), + ], + ) + + def test__parts_to_parts_m(self): + result = ripe.API._parts_to_parts_m( + [ + dict(name="sole", material="rubber", color="red"), + dict(name="laces", material="metal", color="black"), + dict(name="side", material="rubber", color="white"), + ] + ) + self.assertEqual( + result, + dict( + sole=dict(material="rubber", color="red"), + laces=dict(material="metal", color="black"), + side=dict(material="rubber", color="white"), + ), + )