artifex-api-python-sdk 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. artifex_api_python_sdk-0.1.1/PKG-INFO +6 -0
  2. artifex_api_python_sdk-0.1.1/README.md +84 -0
  3. artifex_api_python_sdk-0.1.1/pyproject.toml +8 -0
  4. artifex_api_python_sdk-0.1.1/setup.cfg +4 -0
  5. artifex_api_python_sdk-0.1.1/src/artifex/__init__.py +0 -0
  6. artifex_api_python_sdk-0.1.1/src/artifex/entity/__init__.py +0 -0
  7. artifex_api_python_sdk-0.1.1/src/artifex/entity/artwork/__init__.py +0 -0
  8. artifex_api_python_sdk-0.1.1/src/artifex/entity/artwork/artwork_geometry.py +14 -0
  9. artifex_api_python_sdk-0.1.1/src/artifex/entity/artwork/position.py +20 -0
  10. artifex_api_python_sdk-0.1.1/src/artifex/entity/artwork/position_geometry.py +20 -0
  11. artifex_api_python_sdk-0.1.1/src/artifex/entity/artwork/position_type.py +20 -0
  12. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/__init__.py +0 -0
  13. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/content_box.py +32 -0
  14. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/dimensions.py +101 -0
  15. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/geometric_box.py +105 -0
  16. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/geometry.py +44 -0
  17. artifex_api_python_sdk-0.1.1/src/artifex/entity/geometry/unit_format.py +6 -0
  18. artifex_api_python_sdk-0.1.1/src/artifex/entity/product/__init__.py +0 -0
  19. artifex_api_python_sdk-0.1.1/src/artifex/entity/product/product.py +20 -0
  20. artifex_api_python_sdk-0.1.1/src/artifex/entity/product/product_type.py +9 -0
  21. artifex_api_python_sdk-0.1.1/src/artifex_api_python_sdk.egg-info/PKG-INFO +6 -0
  22. artifex_api_python_sdk-0.1.1/src/artifex_api_python_sdk.egg-info/SOURCES.txt +23 -0
  23. artifex_api_python_sdk-0.1.1/src/artifex_api_python_sdk.egg-info/dependency_links.txt +1 -0
  24. artifex_api_python_sdk-0.1.1/src/artifex_api_python_sdk.egg-info/requires.txt +1 -0
  25. artifex_api_python_sdk-0.1.1/src/artifex_api_python_sdk.egg-info/top_level.txt +1 -0
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: artifex-api-python-sdk
3
+ Version: 0.1.1
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: pydantic>=2.0.0
@@ -0,0 +1,84 @@
1
+ # Artifex Python SDK
2
+
3
+ The official Python SDK for Artifex entities. This package provides high-performance, type-safe Pydantic V2 models for products, artwork, and geometry, making it easy to integrate with Artifex services.
4
+
5
+ ## Features
6
+
7
+ - **Pydantic V2 Models**: Built on the latest Pydantic for high performance and strict validation.
8
+ - **CamelCase Compatibility**: Seamlessly handles `camelCase` JSON from Java-based systems while providing Pythonic `snake_case` attribute access.
9
+ - **Unit Conversion**: Built-in logic for converting between Metric (mm), Imperial (inches), points, and DPI-based pixel calculations.
10
+ - **Type Safety**: Fully type-annotated for excellent IDE support and static analysis.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install artifex-api-python-sdk
16
+ ```
17
+
18
+ Or using `uv`:
19
+
20
+ ```bash
21
+ uv add artifex-api-python-sdk
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Parse Artifex JSON
27
+
28
+ The SDK is designed to parse standard Artifex API responses.
29
+
30
+ ```python
31
+ from artifex.entity.product.product import Product
32
+
33
+ # Example Artifex JSON (camelCase)
34
+ data = {
35
+ "productType": "FLYERS",
36
+ "artworkGeometry": {
37
+ "positions": [
38
+ {
39
+ "position": {"type": "FRONT", "pageOrSideNumber": 1},
40
+ "geometry": {"bleedTop": 3.0, "bleedRight": 3.0}
41
+ }
42
+ ]
43
+ }
44
+ }
45
+
46
+ # Deserialization
47
+ product = Product.model_validate(data)
48
+
49
+ # Access using Pythonic snake_case
50
+ print(product.product_type) # FLYERS
51
+ print(product.artwork_geometry.positions[0].position.page_or_side_number) # 1
52
+
53
+ # Serialization to snake_case JSON
54
+ print(product.model_dump_json(indent=2))
55
+
56
+ # Serialization back to Artifex-compatible camelCase JSON
57
+ print(product.model_dump_json(by_alias=True, indent=2))
58
+ ```
59
+
60
+ ### Unit Conversions
61
+
62
+ Handle dimensions and geometric boxes with built-in conversion utilities.
63
+
64
+ ```python
65
+ from artifex.entity.geometry.dimensions import Dimensions
66
+ from artifex.entity.geometry.unit_format import UnitFormat
67
+
68
+ # Create a metric dimension
69
+ dim = Dimensions(width=210.0, height=297.0, size_format=UnitFormat.METRIC)
70
+
71
+ # Convert to Imperial (inches)
72
+ imperial = dim.to_imperial()
73
+ print(f"{imperial.width}\" x {imperial.height}\"")
74
+
75
+ # Convert to points (for PDF generation)
76
+ points = dim.as_point()
77
+
78
+ # Get dimensions at specific DPI
79
+ pixels_300 = dim.as_300_dpi_pixel()
80
+ ```
81
+
82
+ ## License
83
+
84
+ This project is licensed under the terms of the MIT license.
@@ -0,0 +1,8 @@
1
+ [project]
2
+ name = "artifex-api-python-sdk"
3
+ version = "0.1.1"
4
+ description = "Add your description here"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "pydantic>=2.0.0",
8
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,14 @@
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .position_geometry import PositionGeometry
4
+
5
+ class ArtworkGeometry(BaseModel):
6
+ """A collection of artwork positions and their geometries"""
7
+
8
+ model_config = ConfigDict(populate_by_name=True)
9
+
10
+ positions: Optional[List[PositionGeometry]] = Field(
11
+ default=None,
12
+ description="List of position and geometry pairs",
13
+ alias="positions"
14
+ )
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .position_type import PositionType
4
+
5
+ class Position(BaseModel):
6
+ """Represents a specific position within an artwork item"""
7
+
8
+ model_config = ConfigDict(populate_by_name=True)
9
+
10
+ type: Optional[PositionType] = Field(
11
+ default=None,
12
+ description="The type of position",
13
+ alias="type"
14
+ )
15
+ page_or_side_number: Optional[int] = Field(
16
+ default=None,
17
+ description="The page or side number",
18
+ examples=[1],
19
+ alias="pageOrSideNumber"
20
+ )
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .position import Position
4
+ from ..geometry.geometry import Geometry
5
+
6
+ class PositionGeometry(BaseModel):
7
+ """Combines a Position and its Geometry"""
8
+
9
+ model_config = ConfigDict(populate_by_name=True)
10
+
11
+ position: Optional[Position] = Field(
12
+ default=None,
13
+ description="The position details",
14
+ alias="position"
15
+ )
16
+ geometry: Optional[Geometry] = Field(
17
+ default=None,
18
+ description="The geometry details for the position",
19
+ alias="geometry"
20
+ )
@@ -0,0 +1,20 @@
1
+ from enum import Enum
2
+
3
+ class PositionType(str, Enum):
4
+ """
5
+ Possible types of artwork positions.
6
+ NOTE: the order of values is important! New artwork (uploaded by customers) will be organised
7
+ into positions (by the Asset server) in the order specified below.
8
+ """
9
+ FRONT = "FRONT"
10
+ BACK = "BACK"
11
+ COVER_SPREAD_OUTER = "COVER_SPREAD_OUTER"
12
+ COVER_SPREAD_INNER = "COVER_SPREAD_INNER"
13
+ DUST_JACKET = "DUST_JACKET"
14
+ DUST_JACKET_INNER = "DUST_JACKET_INNER"
15
+ SPINE = "SPINE"
16
+ FRONT_COVER_OUTER = "FRONT_COVER_OUTER"
17
+ FRONT_COVER_INNER = "FRONT_COVER_INNER"
18
+ BODY = "BODY"
19
+ BACK_COVER_INNER = "BACK_COVER_INNER"
20
+ BACK_COVER_OUTER = "BACK_COVER_OUTER"
@@ -0,0 +1,32 @@
1
+ from pydantic import ConfigDict, Field
2
+ from .geometric_box import GeometricBox
3
+
4
+ class ContentBox(GeometricBox):
5
+ """Box defining a content area with quiet zones"""
6
+
7
+ model_config = ConfigDict(populate_by_name=True)
8
+
9
+ quiet_top: float = Field(
10
+ default=0.0,
11
+ description="Quiet zone at the top",
12
+ examples=[5.0],
13
+ alias="quietTop"
14
+ )
15
+ quiet_right: float = Field(
16
+ default=0.0,
17
+ description="Quiet zone on the right",
18
+ examples=[5.0],
19
+ alias="quietRight"
20
+ )
21
+ quiet_bottom: float = Field(
22
+ default=0.0,
23
+ description="Quiet zone at the bottom",
24
+ examples=[5.0],
25
+ alias="quietBottom"
26
+ )
27
+ quiet_left: float = Field(
28
+ default=0.0,
29
+ description="Quiet zone on the left",
30
+ examples=[5.0],
31
+ alias="quietLeft"
32
+ )
@@ -0,0 +1,101 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .unit_format import UnitFormat
4
+
5
+ class Dimensions(BaseModel):
6
+ """Dimensions of an object"""
7
+
8
+ model_config = ConfigDict(populate_by_name=True)
9
+
10
+ MM_IN_INCH: float = 25.4
11
+ MM_IN_POINT: float = 2.8346456693
12
+ MM_IN_140_DPI_PIXEL: float = 5.51181102
13
+ MM_IN_300_DPI_PIXEL: float = 11.811023622
14
+ INCH_IN_POINT: float = 72.0
15
+ INCH_IN_140_DPI_PIXEL: float = 140.0
16
+ INCH_IN_300_DPI_PIXEL: float = 300.0
17
+
18
+ width: Optional[float] = Field(
19
+ default=None,
20
+ description="Width of the object",
21
+ examples=[210.0],
22
+ alias="width"
23
+ )
24
+ height: Optional[float] = Field(
25
+ default=None,
26
+ description="Height of the object",
27
+ examples=[297.0],
28
+ alias="height"
29
+ )
30
+ size_format: Optional[UnitFormat] = Field(
31
+ default=None,
32
+ description="Unit format for the dimensions",
33
+ alias="sizeFormat"
34
+ )
35
+
36
+ def to_size_format(self, format_type: UnitFormat) -> 'Dimensions':
37
+ if format_type == UnitFormat.IMPERIAL:
38
+ return self.to_imperial()
39
+ return self.to_metric()
40
+
41
+ def as_point(self) -> 'Dimensions':
42
+ if self.size_format == UnitFormat.IMPERIAL:
43
+ return Dimensions(
44
+ width=self.width * self.INCH_IN_POINT,
45
+ height=self.height * self.INCH_IN_POINT,
46
+ size_format=self.size_format
47
+ )
48
+ return Dimensions(
49
+ width=self.width * self.MM_IN_POINT,
50
+ height=self.height * self.MM_IN_POINT,
51
+ size_format=self.size_format
52
+ )
53
+
54
+ def as_140dpi_pixel(self) -> 'Dimensions':
55
+ if self.size_format == UnitFormat.IMPERIAL:
56
+ return Dimensions(
57
+ width=self.width * self.INCH_IN_140_DPI_PIXEL,
58
+ height=self.height * self.INCH_IN_140_DPI_PIXEL,
59
+ size_format=self.size_format
60
+ )
61
+ return Dimensions(
62
+ width=self.width * self.MM_IN_140_DPI_PIXEL,
63
+ height=self.height * self.MM_IN_140_DPI_PIXEL,
64
+ size_format=self.size_format
65
+ )
66
+
67
+ def as_300dpi_pixel(self) -> 'Dimensions':
68
+ if self.size_format == UnitFormat.IMPERIAL:
69
+ return Dimensions(
70
+ width=self.width * self.INCH_IN_300_DPI_PIXEL,
71
+ height=self.height * self.INCH_IN_300_DPI_PIXEL,
72
+ size_format=self.size_format
73
+ )
74
+ return Dimensions(
75
+ width=self.width * self.MM_IN_300_DPI_PIXEL,
76
+ height=self.height * self.MM_IN_300_DPI_PIXEL,
77
+ size_format=self.size_format
78
+ )
79
+
80
+ def to_imperial(self) -> 'Dimensions':
81
+ if self.size_format == UnitFormat.IMPERIAL:
82
+ return self
83
+ return Dimensions(
84
+ width=self.width / self.MM_IN_INCH,
85
+ height=self.height / self.MM_IN_INCH,
86
+ size_format=UnitFormat.IMPERIAL
87
+ )
88
+
89
+ def to_metric(self) -> 'Dimensions':
90
+ if self.size_format == UnitFormat.METRIC:
91
+ return self
92
+ return Dimensions(
93
+ width=self.width * self.MM_IN_INCH,
94
+ height=self.height * self.MM_IN_INCH,
95
+ size_format=UnitFormat.METRIC
96
+ )
97
+
98
+ def __str__(self) -> str:
99
+ if self.size_format == UnitFormat.METRIC:
100
+ return f"{self.width:.0f}mm X {self.height:.0f}mm"
101
+ return f"{self.width:.2f}\" X {self.height:.2f}\""
@@ -0,0 +1,105 @@
1
+ from enum import Enum
2
+ from typing import List, Optional
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+ from .unit_format import UnitFormat
5
+
6
+ class Edge(str, Enum):
7
+ TOP = "TOP"
8
+ RIGHT = "RIGHT"
9
+ BOTTOM = "BOTTOM"
10
+ LEFT = "LEFT"
11
+
12
+ class BorderUnit(str, Enum):
13
+ LENGTH = "LENGTH"
14
+ PERCENTAGE = "PERCENTAGE"
15
+
16
+ class GeometricBox(BaseModel):
17
+ """Base class for geometric shapes"""
18
+
19
+ model_config = ConfigDict(populate_by_name=True)
20
+
21
+ x: float = Field(
22
+ default=0.0,
23
+ description="X coordinate of the box",
24
+ examples=[0.0],
25
+ alias="x"
26
+ )
27
+ y: float = Field(
28
+ default=0.0,
29
+ description="Y coordinate of the box",
30
+ examples=[0.0],
31
+ alias="y"
32
+ )
33
+ width: float = Field(
34
+ default=100.0,
35
+ description="Width of the box",
36
+ examples=[100.0],
37
+ alias="width"
38
+ )
39
+ height: float = Field(
40
+ default=100.0,
41
+ description="Height of the box",
42
+ examples=[100.0],
43
+ alias="height"
44
+ )
45
+
46
+ top_left_radius: float = Field(
47
+ default=0.0,
48
+ description="Radius for the top left corner",
49
+ examples=[0.0],
50
+ alias="topLeftRadius"
51
+ )
52
+ top_right_radius: float = Field(
53
+ default=0.0,
54
+ description="Radius for the top right corner",
55
+ examples=[0.0],
56
+ alias="topRightRadius"
57
+ )
58
+ bottom_right_radius: float = Field(
59
+ default=0.0,
60
+ description="Radius for the bottom right corner",
61
+ examples=[0.0],
62
+ alias="bottomRightRadius"
63
+ )
64
+ bottom_left_radius: float = Field(
65
+ default=0.0,
66
+ description="Radius for the bottom left corner",
67
+ examples=[0.0],
68
+ alias="bottomLeftRadius"
69
+ )
70
+
71
+ border_unit: Optional[BorderUnit] = Field(
72
+ default=None,
73
+ description="Unit used for the border radii",
74
+ alias="borderUnit"
75
+ )
76
+ inner_edges: Optional[List[Edge]] = Field(
77
+ default=None,
78
+ description="List of inner edges",
79
+ alias="innerEdges"
80
+ )
81
+ page_or_side_number: Optional[int] = Field(
82
+ default=None,
83
+ description="The page or side number this box belongs to",
84
+ examples=[1],
85
+ alias="pageOrSideNumber"
86
+ )
87
+
88
+ def as_point(self, from_format: UnitFormat) -> 'GeometricBox':
89
+ from .dimensions import Dimensions
90
+
91
+ multiplier = Dimensions.INCH_IN_POINT if from_format == UnitFormat.IMPERIAL else Dimensions.MM_IN_POINT
92
+
93
+ return GeometricBox(
94
+ x=self.x * multiplier,
95
+ y=self.y * multiplier,
96
+ width=self.width * multiplier,
97
+ height=self.height * multiplier,
98
+ top_left_radius=self.top_left_radius * multiplier,
99
+ top_right_radius=self.top_right_radius * multiplier,
100
+ bottom_right_radius=self.bottom_right_radius * multiplier,
101
+ bottom_left_radius=self.bottom_left_radius * multiplier,
102
+ border_unit=self.border_unit,
103
+ inner_edges=self.inner_edges,
104
+ page_or_side_number=self.page_or_side_number
105
+ )
@@ -0,0 +1,44 @@
1
+ from typing import List, Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .dimensions import Dimensions
4
+ from .geometric_box import GeometricBox
5
+
6
+ class Geometry(BaseModel):
7
+ """Geometry information for an artwork"""
8
+
9
+ model_config = ConfigDict(populate_by_name=True)
10
+
11
+ trim_dimensions: Optional[Dimensions] = Field(
12
+ default=None,
13
+ description="Trim dimensions of the artwork",
14
+ alias="trimDimensions"
15
+ )
16
+ bleed_top: float = Field(
17
+ default=3.0,
18
+ description="Top bleed distance",
19
+ examples=[3.0],
20
+ alias="bleedTop"
21
+ )
22
+ bleed_right: float = Field(
23
+ default=3.0,
24
+ description="Right bleed distance",
25
+ examples=[3.0],
26
+ alias="bleedRight"
27
+ )
28
+ bleed_bottom: float = Field(
29
+ default=3.0,
30
+ description="Bottom bleed distance",
31
+ examples=[3.0],
32
+ alias="bleedBottom"
33
+ )
34
+ bleed_left: float = Field(
35
+ default=3.0,
36
+ description="Left bleed distance",
37
+ examples=[3.0],
38
+ alias="bleedLeft"
39
+ )
40
+ geometric_boxes: Optional[List[GeometricBox]] = Field(
41
+ default=None,
42
+ description="List of geometric boxes within the artwork",
43
+ alias="geometricBoxes"
44
+ )
@@ -0,0 +1,6 @@
1
+ from enum import Enum
2
+
3
+ class UnitFormat(str, Enum):
4
+ """Unit format (Metric or Imperial)"""
5
+ METRIC = "METRIC"
6
+ IMPERIAL = "IMPERIAL"
@@ -0,0 +1,20 @@
1
+ from typing import Optional
2
+ from pydantic import BaseModel, ConfigDict, Field
3
+ from .product_type import ProductType
4
+ from ..artwork.artwork_geometry import ArtworkGeometry
5
+
6
+ class Product(BaseModel):
7
+ """Represents the schema for a product, including its type and artwork geometry"""
8
+
9
+ model_config = ConfigDict(populate_by_name=True)
10
+
11
+ product_type: Optional[ProductType] = Field(
12
+ default=None,
13
+ description="The type of the product",
14
+ alias="productType"
15
+ )
16
+ artwork_geometry: Optional[ArtworkGeometry] = Field(
17
+ default=None,
18
+ description="The artwork geometry for the product",
19
+ alias="artworkGeometry"
20
+ )
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+ class ProductType(str, Enum):
4
+ """Possible types of products"""
5
+ BOOKMARKS = "BOOKMARKS"
6
+ BUSINESS_CARDS = "BUSINESS_CARDS"
7
+ FLYERS = "FLYERS"
8
+ POSTCARDS = "POSTCARDS"
9
+ POSTERS = "POSTERS"
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: artifex-api-python-sdk
3
+ Version: 0.1.1
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: pydantic>=2.0.0
@@ -0,0 +1,23 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/artifex/__init__.py
4
+ src/artifex/entity/__init__.py
5
+ src/artifex/entity/artwork/__init__.py
6
+ src/artifex/entity/artwork/artwork_geometry.py
7
+ src/artifex/entity/artwork/position.py
8
+ src/artifex/entity/artwork/position_geometry.py
9
+ src/artifex/entity/artwork/position_type.py
10
+ src/artifex/entity/geometry/__init__.py
11
+ src/artifex/entity/geometry/content_box.py
12
+ src/artifex/entity/geometry/dimensions.py
13
+ src/artifex/entity/geometry/geometric_box.py
14
+ src/artifex/entity/geometry/geometry.py
15
+ src/artifex/entity/geometry/unit_format.py
16
+ src/artifex/entity/product/__init__.py
17
+ src/artifex/entity/product/product.py
18
+ src/artifex/entity/product/product_type.py
19
+ src/artifex_api_python_sdk.egg-info/PKG-INFO
20
+ src/artifex_api_python_sdk.egg-info/SOURCES.txt
21
+ src/artifex_api_python_sdk.egg-info/dependency_links.txt
22
+ src/artifex_api_python_sdk.egg-info/requires.txt
23
+ src/artifex_api_python_sdk.egg-info/top_level.txt