Source code for magento.attributes

"""
Custom attributes utilities.
"""
from collections import OrderedDict
from typing import Callable, Optional, cast, Dict, Any, Union, Sequence, List, Tuple, Iterable, \
    OrderedDict as OrderedDictType, overload, TypeVar

T = TypeVar('T')


@overload
def get_custom_attribute(item: dict, attribute_code: str,
                         coerce_as: Callable[[str], T]) -> Union[None, T, List[T]]:
    ...


@overload
def get_custom_attribute(item: dict, attribute_code: str) -> Union[None, str, List[str]]:
    ...


[docs]def get_custom_attribute(item, attribute_code, coerce_as=None): """ Get a custom attribute from an item given its code. For example: >>> get_custom_attribute(..., "my_custom_attribute") "0" >>> get_custom_attribute(..., "my_custom_attribute", bool) False :param item: :param attribute_code: :param coerce_as: optional callable that is called on the attribute value if it's set. This is useful to circumvent Magento's limitation where all attribute values are strings. :return: attribute value or None. """ if coerce_as == bool: # "0" -> False / "1" -> True coerce_as = lambda s: bool(int(s)) for attribute in item.get("custom_attributes", []): if attribute["attribute_code"] == attribute_code: value: Union[str, List[str]] = attribute["value"] if coerce_as is None: return value if isinstance(value, list): return [coerce_as(s) for s in value] return coerce_as(value) return None
[docs]def get_boolean_custom_attribute(item: dict, attribute_code: str) -> Optional[bool]: """ Equivalent of ``get_custom_attribute(item, attribute_code, coerce_as=bool)`` with proper typing. """ return cast(Optional[bool], get_custom_attribute(item, attribute_code, coerce_as=bool))
[docs]def get_custom_attributes_dict(item: Dict[str, Any]) -> OrderedDictType[str, Union[Sequence[str], str]]: """ Get all custom attributes from an item as an ordered dict of code->value. """ d = OrderedDict() for attribute in item.get("custom_attributes", []): d[attribute["attribute_code"]] = attribute["value"] return d
[docs]def serialize_attribute_value(value: Union[str, int, float, bool, None], force_none=False): """ Serialize a value to be stored in a Magento attribute. """ if isinstance(value, bool): return "1" if value else "0" elif value is None: if force_none: return None return "" return str(value)
[docs]def set_custom_attribute(item: dict, attribute_code: str, attribute_value: Union[str, int, float, bool, None], *, force_none=False): """ Set a custom attribute in an item dict. For example: >>> set_custom_attribute({}, "my_custom_attribute", 42) >>> set_custom_attribute({}, "my_custom_attribute", False) :param item: item dict. It’s modified in-place. :param attribute_code: :param attribute_value: :param force_none: by default, the attribute value ``None`` is serialized as an empty string. Setting this parameter to ``True`` forces this attribute value to ``None`` instead. This can be used to delete attributes. :return: the modified item dict. """ return set_custom_attributes(item, [(attribute_code, attribute_value)], force_none=force_none)
[docs]def set_custom_attributes(item: dict, attributes: Iterable[Tuple[str, Union[str, int, float, bool, None]]], *, force_none=False): """ Set custom attributes in an item dict. Like ``set_custom_attribute`` but with an iterable of attributes. :param item: item dict. It’s modified in-place. :param attributes: iterable of label/value attribute tuples :param force_none: see ``set_custom_attribute`` for usage. :return: the modified item dict. """ item_custom_attributes: List[Dict[str, str]] = item.get("custom_attributes", []) attributes_index = {attribute["attribute_code"]: index for index, attribute in enumerate(item_custom_attributes)} for attribute_code, attribute_value in attributes: serialized_value = serialize_attribute_value(attribute_value, force_none=force_none) if attribute_code in attributes_index: index = attributes_index[attribute_code] item_custom_attributes[index]["value"] = serialized_value else: attributes_index[attribute_code] = len(item_custom_attributes) item_custom_attributes.append({ "attribute_code": attribute_code, "value": serialized_value, }) item["custom_attributes"] = item_custom_attributes return item