from typing import Sequence def _clean(part: str) -> str: # Keep ASCII letters and digits only, then uppercase. Filtering first # matters: "ß".upper() is "SS", which would make the SKU depend on how each # language's Unicode tables treat one letter. return "".join(c for c in part if ("A" <= c <= "Z") or ("a" <= c <= "z") or ("0" <= c <= "9")).upper() def generate_sku(prefix: str, attributes: Sequence[str], segment_length: int) -> str: """A deterministic SKU: the cleaned prefix and attributes, joined by hyphens. Each attribute is cut to ``segment_length`` characters (0 keeps it whole). """ if isinstance(segment_length, bool) or not isinstance(segment_length, int) or segment_length < 0: raise ValueError("segmentLength must be 0 or more, received %r" % (segment_length,)) if len(attributes) == 0: raise ValueError("a SKU needs at least one attribute") parts = [] if prefix != "": cleaned = _clean(prefix) if cleaned == "": raise ValueError('prefix ("%s") has no letters or digits' % prefix) parts.append(cleaned) for index, attribute in enumerate(attributes): cleaned = _clean(attribute) if cleaned == "": raise ValueError('attribute %d ("%s") has no letters or digits' % (index + 1, attribute)) parts.append(cleaned if segment_length == 0 else cleaned[:segment_length]) return "-".join(parts)