mixam-sdk


Namemixam-sdk JSON
Version 0.1.10 PyPI version JSON
download
home_pageNone
SummaryMixam Python SDK: ItemSpecification Core Models & Enums. KeyBuilder & KeyParser For Working With Universal Keys
upload_time2025-10-07 09:44:26
maintainerNone
docs_urlNone
authorMixam
requires_python<4.0,>=3.12
licenseNone
keywords mixam sdk printing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Mixam Python SDK

Mixam SDK is a lightweight Python library that helps you build, validate, serialize, and parse print Item Specifications used by Mixam. It provides:

- Core data models and enums to represent product specifications (components, substrates, bindings, sizes, etc.).
- A Universal Key system to serialize an ItemSpecification to a compact string and parse it back reliably.

## Installation

- Via pip:

```bash
pip install mixam-sdk
```

- Via Poetry:

```bash
poetry add mixam-sdk
```

Python 3.12+ is required (see `pyproject.toml`).

## Developers

- Run tests:

```bash
pytest -q
```

- Local install for development:

```bash
poetry install
poetry run pytest -q
```

See the Development section below for more details.

## Quick Start

Below are minimal examples showing how to work with Item Specifications and the Universal Key.

### Create an ItemSpecification and build a Universal Key

```python
from mixam_sdk.item_specification.models.item_specification import ItemSpecification
from mixam_sdk.item_specification.enums.product import Product
from mixam_sdk.item_specification.models.flat_component import FlatComponent
from mixam_sdk.item_specification.enums.component_type import ComponentType
from mixam_sdk.universal_key.models.key_builder import KeyBuilder

# Build a simple spec with one flat component
item = ItemSpecification()
item.copies = 250
item.product = Product.POSTERS

# Create a simple flat component
comp = FlatComponent()
comp.component_type = ComponentType.FLAT
# ... populate additional fields supported by FlatComponent as needed ...

item.components.append(comp)

# Build a Universal Key string
key = KeyBuilder().build(item)
print(key)
```

### Parse a Universal Key back into an ItemSpecification

```python
from mixam_sdk.universal_key.models.key_parser import KeyParser

parser = KeyParser()
# Provide a Universal Key string (from earlier build step or an external source)
some_key = "250~10-ft{...}"
parsed = parser.parse(some_key)

print(parsed.copies)
print(parsed.product)
print([c.component_type for c in parsed.components])
```

If the key does not match the expected format, `KeyParser.parse` raises a `ValueError` or `RuntimeError` indicating the issue.

## What is a Universal Key?

A Universal Key is a compact, validated string representation of an `ItemSpecification`.

- Format (high level):
  - `copies~productId-<component>{<memberTokens>}-<component>{...}`
- Example: `250~10-ft{...}-bd{...}`
- Keys are validated using a strict regex to ensure correctness before parsing.

The SDK provides:

- `KeyBuilder` to generate keys from `ItemSpecification` objects.
- `KeyParser` to parse keys back into `ItemSpecification` objects.

## Main Concepts

- Enums: Found under `mixam_sdk/item_specification/enums`, they define allowed values for products, sizes, colours, laminations, bindings, etc.
- Models: Under `mixam_sdk/item_specification/models`, they represent components such as flat, folded, cover, bound components, and more, as well as the root `ItemSpecification`.
- Interfaces/Support: Internal helpers for ordering components and mapping model fields to the Universal Key token format.

Explore the `tests/` folder for concrete usage patterns and expected behaviours:

- `tests/test_universal_key.py`
- `tests/test_item_specification_deserialization.py`

## Product Metadata and Validation

This SDK models Mixam Product Metadata and provides a validation service to check that a given `ItemSpecification` complies with that metadata.

Important scope notes:
- The validator service is the recommended way to validate a full ItemSpecification. Use `ProductItemSpecificationValidator` for end-to-end validation.
- For advanced implementations, you may validate only a specific component type using its corresponding component validator (component-based validation). See the section below for details.
- The SDK itself does not fetch product metadata; you must retrieve it from the Mixam Public API and pass it to the SDK.
- The SDK focuses on modelling the metadata objects and validating specifications against them.

Obtaining Product Metadata (Mixam Public API):
- Documentation: https://mixam.co.uk/documentation/api/public#openapi
- Endpoint to get product metadata for a specific product and sub-product (provide `productId`, `subProductId`, and `quoteType`, usually `QUOTE`):
  - Example: https://mixam.co.uk/api/public/products/metadata/1/0?quoteType=QUOTE

What is Product Metadata?
- A structured definition of the options and constraints for a specific product (allowed components, sizes, substrates, laminations, page ranges, etc.).
- Represented by `mixam_sdk.metadata.product.models.product_metadata.ProductMetadata` (a Pydantic model).

Validation at a glance:
- You validate an `ItemSpecification` against a `ProductMetadata` using `ProductItemSpecificationValidator`.
- Validation returns a `ValidationResult` containing a list of violations (errors) and optionally warnings.
- Validation is not fail-fast; it accumulates all violations so you can report everything in one pass.
- Each violation includes a machine-readable `code`, a human `message`, a `path` to the offending field/component, and optional `allowed` or other context.

End-to-end example (fetch metadata, build spec in code, validate via service):

```python
import json
from urllib.request import urlopen

from mixam_sdk.item_specification.models.item_specification import ItemSpecification
from mixam_sdk.item_specification.models.flat_component import FlatComponent
from mixam_sdk.item_specification.enums.component_type import ComponentType
from mixam_sdk.metadata.product.models.product_metadata import ProductMetadata
from mixam_sdk.metadata.product.services.validator import ProductItemSpecificationValidator

# 1) Fetch Product Metadata from Mixam Public API (replace IDs as needed)
product_id = 1
sub_product_id = 0
quote_type = "QUOTE"
url = f"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}"
with urlopen(url, timeout=20) as resp:
    pm_json = resp.read().decode("utf-8")
pm = ProductMetadata.model_validate_json(pm_json)

# 2) Build an ItemSpecification in code (example: simple flat/poster-style component)
spec = ItemSpecification()
spec.copies = 100

comp = FlatComponent()
comp.component_type = ComponentType.FLAT
# Populate additional fields that your product requires (size, substrate, colours, etc.)
# e.g. comp.standard_size = ... ; comp.substrate = ... ; comp.colours = ...

spec.components.append(comp)

# 3) Validate via the service (the only supported entry point)
validator = ProductItemSpecificationValidator()
result = validator.validate(pm, spec)

# 4) Inspect result
if result.is_valid():
    print("Spec is valid for this product")
else:
    for err in result.errors:
        print(f"{err.path}: {err.code} - {err.message}")
        if err.allowed:
            print(f"  allowed: {err.allowed}")
```

Notes:
- Do not call `metadata.validate(spec)` directly; use `ProductItemSpecificationValidator`.
- Ensure the ItemSpecification fields you set correspond to options allowed by the fetched metadata.

Key classes:
- ProductMetadata: Pydantic model for the product's rules and options.
- ProductItemSpecificationValidator: Service that validates an `ItemSpecification` against `ProductMetadata`.
- ValidationResult and ValidationMessage: Returned by validation; contains `errors`, `warnings`, and helpers like `.is_valid()` and `.humanize()`.

See also:
- Component validators under `mixam_sdk/metadata/product/models/validators/` for component-specific rules (e.g., cover, bound, envelope).
- Tests that exercise validation: `tests/test_product_item_spec_validation.py`, product-specific tests like posters/booklets, etc.

### Example: Validate a 100 A5 Portrait Stapled Booklet (32 pages)

The following JSON spec (simplified) describes what we want to validate:

- 100 Booklets
- Size: A5 (148 mm x 210 mm) - Portrait
- Stapled, Full-colour printing, 32 pages, 130gsm Silk
- Cover: Full-colour printing (front and back), 250gsm Silk

And here is the equivalent ItemSpecification built in code and validated via the service:

```python
from urllib.request import urlopen

from mixam_sdk.item_specification.models.item_specification import ItemSpecification
from mixam_sdk.item_specification.enums.product import Product
from mixam_sdk.item_specification.models.bound_component import BoundComponent
from mixam_sdk.item_specification.models.cover_component import CoverComponent
from mixam_sdk.item_specification.models.substrate import Substrate
from mixam_sdk.item_specification.models.binding import Binding
from mixam_sdk.item_specification.enums.orientation import Orientation
from mixam_sdk.item_specification.enums.colours import Colours
from mixam_sdk.item_specification.enums.standard_size import StandardSize
from mixam_sdk.item_specification.enums.lamination import Lamination
from mixam_sdk.item_specification.enums.ribbon_colour import RibbonColour
from mixam_sdk.item_specification.enums.binding_type import BindingType
from mixam_sdk.item_specification.enums.binding_edge import BindingEdge
from mixam_sdk.item_specification.enums.substrate_design import SubstrateDesign
from mixam_sdk.metadata.product.models.product_metadata import ProductMetadata
from mixam_sdk.metadata.product.services.validator import ProductItemSpecificationValidator

# 1) Fetch metadata for brochures (replace IDs for your locale/product if needed)
product_id = 1
sub_product_id = 0
quote_type = "QUOTE"
url = f"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}"
with urlopen(url, timeout=20) as resp:
    pm_json = resp.read().decode("utf-8")
pm = ProductMetadata.model_validate_json(pm_json)

# 2) Build the ItemSpecification matching the provided spec
spec = ItemSpecification()
spec.copies = 100
spec.product = Product.BROCHURES

# Primary content (text) block: BOUND component
inner = BoundComponent()
inner.format = 5  # A5
inner.orientation = Orientation.PORTRAIT
inner.colours = Colours.PROCESS
inner.substrate = Substrate(typeId=1, weightId=3, colourId=0, design=SubstrateDesign.NONE)
inner.pages = 32
inner.lamination = Lamination.NONE
inner.binding = Binding(type=BindingType.STAPLED, sewn=False, edge=BindingEdge.LEFT_RIGHT)
inner.ribbon_colour = RibbonColour.NONE

# Cover block: COVER component (front and back)
cover = CoverComponent()
cover.format = 5  # A5
cover.orientation = Orientation.PORTRAIT
cover.colours = Colours.PROCESS
cover.substrate = Substrate(typeId=1, weightId=7, colourId=0, design=SubstrateDesign.NONE)
cover.lamination = Lamination.NONE
cover.back_colours = Colours.PROCESS
cover.back_lamination = Lamination.NONE

spec.components = [inner, cover]

# 3) Validate via the service
validator = ProductItemSpecificationValidator()
result = validator.validate(pm, spec)

if result.is_valid():
    print("Spec is valid for this product")
else:
    for err in result.errors:
        print(f"{err.path}: {err.code} - {err.message}")
        if err.allowed:
            print(f"  allowed: {err.allowed}")
```

Notes:
- Substrate IDs (typeId/weightId/colourId) must match what the fetched Product Metadata allows for the chosen product and sub-product.

## Error Handling

- `KeyParser.parse(key)` validates input and raises a `ValueError` for invalid format and a `RuntimeError` for parsing failures.
- When building keys, ensure your components are populated with required fields; otherwise the builder may not emit expected tokens.

## Development

- Run tests:

```bash
pytest -q
```

- Local install for development:

```bash
poetry install
poetry run pytest -q
```

## Versioning

The package follows semantic versioning where possible. See `pyproject.toml` for the current version.

## License

Copyright (c) Mixam.

See the repository for license terms or contact developer@mixam.com.

## Examples (from tests)

Below are full examples taken directly from the test suite to illustrate the exact formats.

- Universal Key example (Booklet):

```
10~1-bd{4bt-5c-4f-200p-1st-3sw}-cr{5c-5c+-4f-4l-1st-7sw}
```

- Matching ItemSpecification JSON example (as used in tests):

```json
{
  "itemSpecification": {
    "copies": 10,
    "product": "BROCHURES",
    "components": [
      {
        "componentType": "BOUND",
        "format": 4,
        "standardSize": "NONE",
        "orientation": "PORTRAIT",
        "colours": "PROCESS",
        "substrate": {
          "typeId": 1,
          "weightId": 3,
          "colourId": 0
        },
        "pages": 200,
        "lamination": "NONE",
        "binding": {
          "type": "PUR"
        }
      },
      {
        "componentType": "COVER",
        "format": 4,
        "standardSize": "NONE",
        "orientation": "PORTRAIT",
        "colours": "PROCESS",
        "substrate": {
          "typeId": 1,
          "weightId": 7,
          "colourId": 0
        },
        "lamination": "GLOSS",
        "backColours": "PROCESS",
        "backLamination": "NONE"
      }
    ]
  }
}
```

## Links

- Source: https://github.com/mixam-platform/mixam-python-sdk
- Mixam: https://mixam.com


## Component-based validation (advanced)

### Validate just Cover components with the Cover validator (component-only)

While it is recommended to use the validator service to validate the entire Item Specification, the metadata validation system is component-based under the hood. You can shortcut the flow and validate only a specific component type using its corresponding component validator. This can be useful when composing a spec in a component-by-component manner (e.g., with an AI tool) and you only want to validate the component you just changed.

Below is a fully self-contained example that validates only COVER components using the CoverComponentValidator:

```python
from urllib.request import urlopen

from mixam_sdk.item_specification.models.item_specification import ItemSpecification
from mixam_sdk.item_specification.models.cover_component import CoverComponent
from mixam_sdk.item_specification.models.substrate import Substrate
from mixam_sdk.item_specification.enums.component_type import ComponentType
from mixam_sdk.item_specification.enums.colours import Colours
from mixam_sdk.item_specification.enums.orientation import Orientation
from mixam_sdk.item_specification.enums.standard_size import StandardSize
from mixam_sdk.item_specification.enums.substrate_design import SubstrateDesign
from mixam_sdk.item_specification.enums.product import Product
from mixam_sdk.metadata.product.models.product_metadata import ProductMetadata
from mixam_sdk.metadata.product.models.validators.cover import CoverComponentValidator
from mixam_sdk.metadata.product.services.validation_result import ValidationResult

# 1) Fetch Product Metadata for a brochures-like product (adjust IDs for your target product)
product_id = 1
sub_product_id = 0
quote_type = "QUOTE"
url = f"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}"
with urlopen(url, timeout=20) as resp:
    pm_json = resp.read().decode("utf-8")
pm = ProductMetadata.model_validate_json(pm_json)

# 2) Build an ItemSpecification with a COVER component (minimal example)
spec = ItemSpecification()
spec.copies = 100
spec.product = Product.BROCHURES

cover = CoverComponent()
cover.format = 5
cover.orientation = Orientation.PORTRAIT
cover.colours = Colours.PROCESS
cover.substrate = Substrate(typeId=1, weightId=7, colourId=0, design=SubstrateDesign.NONE)
# Optionally set back side settings if printing both sides
cover.back_colours = Colours.PROCESS

spec.components.append(cover)

# 3) Validate only the COVER components using the specific component validator
cover_validator = CoverComponentValidator()
partial_result = ValidationResult()

for idx, comp in enumerate(spec.components):
    if comp.component_type == ComponentType.COVER:
        base_path = f"components[{idx}]"
        cover_validator.validate(pm, spec, comp, partial_result, base_path)

# 4) Inspect results from validating only the cover components
if partial_result.is_valid():
    print("All cover components are valid")
else:
    for err in partial_result.errors:
        print(f"{err.path}: {err.code} - {err.message}")
        if err.allowed:
            print(f"  allowed: {err.allowed}")
```

Notes and caveats:
- Prefer ProductItemSpecificationValidator for full validation because it also enforces top-level requirements (e.g., component counts, cross-component constraints) and runs primary-component rules.
- Component-only validation runs the base checks plus cover-specific rules implemented in CoverComponentValidator. It does not validate other component types present in the spec.
- The same pattern works for other component validators, e.g., DustJacketComponentValidator for dust jackets.


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mixam-sdk",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.12",
    "maintainer_email": null,
    "keywords": "mixam, sdk, printing",
    "author": "Mixam",
    "author_email": "developer@mixam.com",
    "download_url": "https://files.pythonhosted.org/packages/25/26/81ecd0766c2914bf5fe07134b76e5eb8f67e9a689ded119ce42c7ed8ca07/mixam_sdk-0.1.10.tar.gz",
    "platform": null,
    "description": "# Mixam Python SDK\n\nMixam SDK is a lightweight Python library that helps you build, validate, serialize, and parse print Item Specifications used by Mixam. It provides:\n\n- Core data models and enums to represent product specifications (components, substrates, bindings, sizes, etc.).\n- A Universal Key system to serialize an ItemSpecification to a compact string and parse it back reliably.\n\n## Installation\n\n- Via pip:\n\n```bash\npip install mixam-sdk\n```\n\n- Via Poetry:\n\n```bash\npoetry add mixam-sdk\n```\n\nPython 3.12+ is required (see `pyproject.toml`).\n\n## Developers\n\n- Run tests:\n\n```bash\npytest -q\n```\n\n- Local install for development:\n\n```bash\npoetry install\npoetry run pytest -q\n```\n\nSee the Development section below for more details.\n\n## Quick Start\n\nBelow are minimal examples showing how to work with Item Specifications and the Universal Key.\n\n### Create an ItemSpecification and build a Universal Key\n\n```python\nfrom mixam_sdk.item_specification.models.item_specification import ItemSpecification\nfrom mixam_sdk.item_specification.enums.product import Product\nfrom mixam_sdk.item_specification.models.flat_component import FlatComponent\nfrom mixam_sdk.item_specification.enums.component_type import ComponentType\nfrom mixam_sdk.universal_key.models.key_builder import KeyBuilder\n\n# Build a simple spec with one flat component\nitem = ItemSpecification()\nitem.copies = 250\nitem.product = Product.POSTERS\n\n# Create a simple flat component\ncomp = FlatComponent()\ncomp.component_type = ComponentType.FLAT\n# ... populate additional fields supported by FlatComponent as needed ...\n\nitem.components.append(comp)\n\n# Build a Universal Key string\nkey = KeyBuilder().build(item)\nprint(key)\n```\n\n### Parse a Universal Key back into an ItemSpecification\n\n```python\nfrom mixam_sdk.universal_key.models.key_parser import KeyParser\n\nparser = KeyParser()\n# Provide a Universal Key string (from earlier build step or an external source)\nsome_key = \"250~10-ft{...}\"\nparsed = parser.parse(some_key)\n\nprint(parsed.copies)\nprint(parsed.product)\nprint([c.component_type for c in parsed.components])\n```\n\nIf the key does not match the expected format, `KeyParser.parse` raises a `ValueError` or `RuntimeError` indicating the issue.\n\n## What is a Universal Key?\n\nA Universal Key is a compact, validated string representation of an `ItemSpecification`.\n\n- Format (high level):\n  - `copies~productId-<component>{<memberTokens>}-<component>{...}`\n- Example: `250~10-ft{...}-bd{...}`\n- Keys are validated using a strict regex to ensure correctness before parsing.\n\nThe SDK provides:\n\n- `KeyBuilder` to generate keys from `ItemSpecification` objects.\n- `KeyParser` to parse keys back into `ItemSpecification` objects.\n\n## Main Concepts\n\n- Enums: Found under `mixam_sdk/item_specification/enums`, they define allowed values for products, sizes, colours, laminations, bindings, etc.\n- Models: Under `mixam_sdk/item_specification/models`, they represent components such as flat, folded, cover, bound components, and more, as well as the root `ItemSpecification`.\n- Interfaces/Support: Internal helpers for ordering components and mapping model fields to the Universal Key token format.\n\nExplore the `tests/` folder for concrete usage patterns and expected behaviours:\n\n- `tests/test_universal_key.py`\n- `tests/test_item_specification_deserialization.py`\n\n## Product Metadata and Validation\n\nThis SDK models Mixam Product Metadata and provides a validation service to check that a given `ItemSpecification` complies with that metadata.\n\nImportant scope notes:\n- The validator service is the recommended way to validate a full ItemSpecification. Use `ProductItemSpecificationValidator` for end-to-end validation.\n- For advanced implementations, you may validate only a specific component type using its corresponding component validator (component-based validation). See the section below for details.\n- The SDK itself does not fetch product metadata; you must retrieve it from the Mixam Public API and pass it to the SDK.\n- The SDK focuses on modelling the metadata objects and validating specifications against them.\n\nObtaining Product Metadata (Mixam Public API):\n- Documentation: https://mixam.co.uk/documentation/api/public#openapi\n- Endpoint to get product metadata for a specific product and sub-product (provide `productId`, `subProductId`, and `quoteType`, usually `QUOTE`):\n  - Example: https://mixam.co.uk/api/public/products/metadata/1/0?quoteType=QUOTE\n\nWhat is Product Metadata?\n- A structured definition of the options and constraints for a specific product (allowed components, sizes, substrates, laminations, page ranges, etc.).\n- Represented by `mixam_sdk.metadata.product.models.product_metadata.ProductMetadata` (a Pydantic model).\n\nValidation at a glance:\n- You validate an `ItemSpecification` against a `ProductMetadata` using `ProductItemSpecificationValidator`.\n- Validation returns a `ValidationResult` containing a list of violations (errors) and optionally warnings.\n- Validation is not fail-fast; it accumulates all violations so you can report everything in one pass.\n- Each violation includes a machine-readable `code`, a human `message`, a `path` to the offending field/component, and optional `allowed` or other context.\n\nEnd-to-end example (fetch metadata, build spec in code, validate via service):\n\n```python\nimport json\nfrom urllib.request import urlopen\n\nfrom mixam_sdk.item_specification.models.item_specification import ItemSpecification\nfrom mixam_sdk.item_specification.models.flat_component import FlatComponent\nfrom mixam_sdk.item_specification.enums.component_type import ComponentType\nfrom mixam_sdk.metadata.product.models.product_metadata import ProductMetadata\nfrom mixam_sdk.metadata.product.services.validator import ProductItemSpecificationValidator\n\n# 1) Fetch Product Metadata from Mixam Public API (replace IDs as needed)\nproduct_id = 1\nsub_product_id = 0\nquote_type = \"QUOTE\"\nurl = f\"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}\"\nwith urlopen(url, timeout=20) as resp:\n    pm_json = resp.read().decode(\"utf-8\")\npm = ProductMetadata.model_validate_json(pm_json)\n\n# 2) Build an ItemSpecification in code (example: simple flat/poster-style component)\nspec = ItemSpecification()\nspec.copies = 100\n\ncomp = FlatComponent()\ncomp.component_type = ComponentType.FLAT\n# Populate additional fields that your product requires (size, substrate, colours, etc.)\n# e.g. comp.standard_size = ... ; comp.substrate = ... ; comp.colours = ...\n\nspec.components.append(comp)\n\n# 3) Validate via the service (the only supported entry point)\nvalidator = ProductItemSpecificationValidator()\nresult = validator.validate(pm, spec)\n\n# 4) Inspect result\nif result.is_valid():\n    print(\"Spec is valid for this product\")\nelse:\n    for err in result.errors:\n        print(f\"{err.path}: {err.code} - {err.message}\")\n        if err.allowed:\n            print(f\"  allowed: {err.allowed}\")\n```\n\nNotes:\n- Do not call `metadata.validate(spec)` directly; use `ProductItemSpecificationValidator`.\n- Ensure the ItemSpecification fields you set correspond to options allowed by the fetched metadata.\n\nKey classes:\n- ProductMetadata: Pydantic model for the product's rules and options.\n- ProductItemSpecificationValidator: Service that validates an `ItemSpecification` against `ProductMetadata`.\n- ValidationResult and ValidationMessage: Returned by validation; contains `errors`, `warnings`, and helpers like `.is_valid()` and `.humanize()`.\n\nSee also:\n- Component validators under `mixam_sdk/metadata/product/models/validators/` for component-specific rules (e.g., cover, bound, envelope).\n- Tests that exercise validation: `tests/test_product_item_spec_validation.py`, product-specific tests like posters/booklets, etc.\n\n### Example: Validate a 100 A5 Portrait Stapled Booklet (32 pages)\n\nThe following JSON spec (simplified) describes what we want to validate:\n\n- 100 Booklets\n- Size: A5 (148 mm x 210 mm) - Portrait\n- Stapled, Full-colour printing, 32 pages, 130gsm Silk\n- Cover: Full-colour printing (front and back), 250gsm Silk\n\nAnd here is the equivalent ItemSpecification built in code and validated via the service:\n\n```python\nfrom urllib.request import urlopen\n\nfrom mixam_sdk.item_specification.models.item_specification import ItemSpecification\nfrom mixam_sdk.item_specification.enums.product import Product\nfrom mixam_sdk.item_specification.models.bound_component import BoundComponent\nfrom mixam_sdk.item_specification.models.cover_component import CoverComponent\nfrom mixam_sdk.item_specification.models.substrate import Substrate\nfrom mixam_sdk.item_specification.models.binding import Binding\nfrom mixam_sdk.item_specification.enums.orientation import Orientation\nfrom mixam_sdk.item_specification.enums.colours import Colours\nfrom mixam_sdk.item_specification.enums.standard_size import StandardSize\nfrom mixam_sdk.item_specification.enums.lamination import Lamination\nfrom mixam_sdk.item_specification.enums.ribbon_colour import RibbonColour\nfrom mixam_sdk.item_specification.enums.binding_type import BindingType\nfrom mixam_sdk.item_specification.enums.binding_edge import BindingEdge\nfrom mixam_sdk.item_specification.enums.substrate_design import SubstrateDesign\nfrom mixam_sdk.metadata.product.models.product_metadata import ProductMetadata\nfrom mixam_sdk.metadata.product.services.validator import ProductItemSpecificationValidator\n\n# 1) Fetch metadata for brochures (replace IDs for your locale/product if needed)\nproduct_id = 1\nsub_product_id = 0\nquote_type = \"QUOTE\"\nurl = f\"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}\"\nwith urlopen(url, timeout=20) as resp:\n    pm_json = resp.read().decode(\"utf-8\")\npm = ProductMetadata.model_validate_json(pm_json)\n\n# 2) Build the ItemSpecification matching the provided spec\nspec = ItemSpecification()\nspec.copies = 100\nspec.product = Product.BROCHURES\n\n# Primary content (text) block: BOUND component\ninner = BoundComponent()\ninner.format = 5  # A5\ninner.orientation = Orientation.PORTRAIT\ninner.colours = Colours.PROCESS\ninner.substrate = Substrate(typeId=1, weightId=3, colourId=0, design=SubstrateDesign.NONE)\ninner.pages = 32\ninner.lamination = Lamination.NONE\ninner.binding = Binding(type=BindingType.STAPLED, sewn=False, edge=BindingEdge.LEFT_RIGHT)\ninner.ribbon_colour = RibbonColour.NONE\n\n# Cover block: COVER component (front and back)\ncover = CoverComponent()\ncover.format = 5  # A5\ncover.orientation = Orientation.PORTRAIT\ncover.colours = Colours.PROCESS\ncover.substrate = Substrate(typeId=1, weightId=7, colourId=0, design=SubstrateDesign.NONE)\ncover.lamination = Lamination.NONE\ncover.back_colours = Colours.PROCESS\ncover.back_lamination = Lamination.NONE\n\nspec.components = [inner, cover]\n\n# 3) Validate via the service\nvalidator = ProductItemSpecificationValidator()\nresult = validator.validate(pm, spec)\n\nif result.is_valid():\n    print(\"Spec is valid for this product\")\nelse:\n    for err in result.errors:\n        print(f\"{err.path}: {err.code} - {err.message}\")\n        if err.allowed:\n            print(f\"  allowed: {err.allowed}\")\n```\n\nNotes:\n- Substrate IDs (typeId/weightId/colourId) must match what the fetched Product Metadata allows for the chosen product and sub-product.\n\n## Error Handling\n\n- `KeyParser.parse(key)` validates input and raises a `ValueError` for invalid format and a `RuntimeError` for parsing failures.\n- When building keys, ensure your components are populated with required fields; otherwise the builder may not emit expected tokens.\n\n## Development\n\n- Run tests:\n\n```bash\npytest -q\n```\n\n- Local install for development:\n\n```bash\npoetry install\npoetry run pytest -q\n```\n\n## Versioning\n\nThe package follows semantic versioning where possible. See `pyproject.toml` for the current version.\n\n## License\n\nCopyright (c) Mixam.\n\nSee the repository for license terms or contact developer@mixam.com.\n\n## Examples (from tests)\n\nBelow are full examples taken directly from the test suite to illustrate the exact formats.\n\n- Universal Key example (Booklet):\n\n```\n10~1-bd{4bt-5c-4f-200p-1st-3sw}-cr{5c-5c+-4f-4l-1st-7sw}\n```\n\n- Matching ItemSpecification JSON example (as used in tests):\n\n```json\n{\n  \"itemSpecification\": {\n    \"copies\": 10,\n    \"product\": \"BROCHURES\",\n    \"components\": [\n      {\n        \"componentType\": \"BOUND\",\n        \"format\": 4,\n        \"standardSize\": \"NONE\",\n        \"orientation\": \"PORTRAIT\",\n        \"colours\": \"PROCESS\",\n        \"substrate\": {\n          \"typeId\": 1,\n          \"weightId\": 3,\n          \"colourId\": 0\n        },\n        \"pages\": 200,\n        \"lamination\": \"NONE\",\n        \"binding\": {\n          \"type\": \"PUR\"\n        }\n      },\n      {\n        \"componentType\": \"COVER\",\n        \"format\": 4,\n        \"standardSize\": \"NONE\",\n        \"orientation\": \"PORTRAIT\",\n        \"colours\": \"PROCESS\",\n        \"substrate\": {\n          \"typeId\": 1,\n          \"weightId\": 7,\n          \"colourId\": 0\n        },\n        \"lamination\": \"GLOSS\",\n        \"backColours\": \"PROCESS\",\n        \"backLamination\": \"NONE\"\n      }\n    ]\n  }\n}\n```\n\n## Links\n\n- Source: https://github.com/mixam-platform/mixam-python-sdk\n- Mixam: https://mixam.com\n\n\n## Component-based validation (advanced)\n\n### Validate just Cover components with the Cover validator (component-only)\n\nWhile it is recommended to use the validator service to validate the entire Item Specification, the metadata validation system is component-based under the hood. You can shortcut the flow and validate only a specific component type using its corresponding component validator. This can be useful when composing a spec in a component-by-component manner (e.g., with an AI tool) and you only want to validate the component you just changed.\n\nBelow is a fully self-contained example that validates only COVER components using the CoverComponentValidator:\n\n```python\nfrom urllib.request import urlopen\n\nfrom mixam_sdk.item_specification.models.item_specification import ItemSpecification\nfrom mixam_sdk.item_specification.models.cover_component import CoverComponent\nfrom mixam_sdk.item_specification.models.substrate import Substrate\nfrom mixam_sdk.item_specification.enums.component_type import ComponentType\nfrom mixam_sdk.item_specification.enums.colours import Colours\nfrom mixam_sdk.item_specification.enums.orientation import Orientation\nfrom mixam_sdk.item_specification.enums.standard_size import StandardSize\nfrom mixam_sdk.item_specification.enums.substrate_design import SubstrateDesign\nfrom mixam_sdk.item_specification.enums.product import Product\nfrom mixam_sdk.metadata.product.models.product_metadata import ProductMetadata\nfrom mixam_sdk.metadata.product.models.validators.cover import CoverComponentValidator\nfrom mixam_sdk.metadata.product.services.validation_result import ValidationResult\n\n# 1) Fetch Product Metadata for a brochures-like product (adjust IDs for your target product)\nproduct_id = 1\nsub_product_id = 0\nquote_type = \"QUOTE\"\nurl = f\"https://mixam.co.uk/api/public/products/metadata/{product_id}/{sub_product_id}?quoteType={quote_type}\"\nwith urlopen(url, timeout=20) as resp:\n    pm_json = resp.read().decode(\"utf-8\")\npm = ProductMetadata.model_validate_json(pm_json)\n\n# 2) Build an ItemSpecification with a COVER component (minimal example)\nspec = ItemSpecification()\nspec.copies = 100\nspec.product = Product.BROCHURES\n\ncover = CoverComponent()\ncover.format = 5\ncover.orientation = Orientation.PORTRAIT\ncover.colours = Colours.PROCESS\ncover.substrate = Substrate(typeId=1, weightId=7, colourId=0, design=SubstrateDesign.NONE)\n# Optionally set back side settings if printing both sides\ncover.back_colours = Colours.PROCESS\n\nspec.components.append(cover)\n\n# 3) Validate only the COVER components using the specific component validator\ncover_validator = CoverComponentValidator()\npartial_result = ValidationResult()\n\nfor idx, comp in enumerate(spec.components):\n    if comp.component_type == ComponentType.COVER:\n        base_path = f\"components[{idx}]\"\n        cover_validator.validate(pm, spec, comp, partial_result, base_path)\n\n# 4) Inspect results from validating only the cover components\nif partial_result.is_valid():\n    print(\"All cover components are valid\")\nelse:\n    for err in partial_result.errors:\n        print(f\"{err.path}: {err.code} - {err.message}\")\n        if err.allowed:\n            print(f\"  allowed: {err.allowed}\")\n```\n\nNotes and caveats:\n- Prefer ProductItemSpecificationValidator for full validation because it also enforces top-level requirements (e.g., component counts, cross-component constraints) and runs primary-component rules.\n- Component-only validation runs the base checks plus cover-specific rules implemented in CoverComponentValidator. It does not validate other component types present in the spec.\n- The same pattern works for other component validators, e.g., DustJacketComponentValidator for dust jackets.\n\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Mixam Python SDK: ItemSpecification Core Models & Enums. KeyBuilder & KeyParser For Working With Universal Keys",
    "version": "0.1.10",
    "project_urls": {
        "Homepage": "https://github.com/mixam-platform",
        "Repository": "https://github.com/mixam-platform/mixam-python-sdk"
    },
    "split_keywords": [
        "mixam",
        " sdk",
        " printing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "8cfc4b5949631d3a149a29940f19d59ee93de7d7cf31e3bc0738200dbdc8f716",
                "md5": "1a4cd77fa82265ccb2bbaa1becb4f7ca",
                "sha256": "2838a918de999d7c4b2fdfea9276aa22f11ee099825aef945b1633c300d2a840"
            },
            "downloads": -1,
            "filename": "mixam_sdk-0.1.10-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1a4cd77fa82265ccb2bbaa1becb4f7ca",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.12",
            "size": 106493,
            "upload_time": "2025-10-07T09:44:25",
            "upload_time_iso_8601": "2025-10-07T09:44:25.452436Z",
            "url": "https://files.pythonhosted.org/packages/8c/fc/4b5949631d3a149a29940f19d59ee93de7d7cf31e3bc0738200dbdc8f716/mixam_sdk-0.1.10-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "252681ecd0766c2914bf5fe07134b76e5eb8f67e9a689ded119ce42c7ed8ca07",
                "md5": "125db11ba2e20401443aa33c0a43b565",
                "sha256": "36eb18bbdcaea3523c60b5c4ca5df62a5018f0d0a0006d1576a8ac61419e8b85"
            },
            "downloads": -1,
            "filename": "mixam_sdk-0.1.10.tar.gz",
            "has_sig": false,
            "md5_digest": "125db11ba2e20401443aa33c0a43b565",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.12",
            "size": 54926,
            "upload_time": "2025-10-07T09:44:26",
            "upload_time_iso_8601": "2025-10-07T09:44:26.529383Z",
            "url": "https://files.pythonhosted.org/packages/25/26/81ecd0766c2914bf5fe07134b76e5eb8f67e9a689ded119ce42c7ed8ca07/mixam_sdk-0.1.10.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-07 09:44:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mixam-platform",
    "github_project": "mixam-python-sdk",
    "github_not_found": true,
    "lcname": "mixam-sdk"
}
        
Elapsed time: 0.52495s