poelis-sdk 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl

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.

Potentially problematic release.


This version of poelis-sdk might be problematic. Click here for more details.

poelis_sdk/browser.py CHANGED
@@ -140,39 +140,77 @@ class _Node:
140
140
  self._props_loaded_at = time.time()
141
141
  return self._props_cache
142
142
  # Try direct properties(itemId: ...) first; fallback to searchProperties
143
- q = (
143
+ # Attempt 1: query with parsedValue support
144
+ q_parsed = (
144
145
  "query($iid: ID!) {\n"
145
146
  " properties(itemId: $iid) {\n"
146
147
  " __typename\n"
147
- " ... on NumericProperty { integerPart exponent category }\n"
148
- " ... on TextProperty { value }\n"
148
+ " ... on NumericProperty { category value parsedValue }\n"
149
+ " ... on TextProperty { value parsedValue }\n"
149
150
  " ... on DateProperty { value }\n"
150
151
  " }\n"
151
152
  "}"
152
153
  )
153
154
  try:
154
- r = self._client._transport.graphql(q, {"iid": self._id})
155
+ r = self._client._transport.graphql(q_parsed, {"iid": self._id})
155
156
  r.raise_for_status()
156
157
  data = r.json()
157
158
  if "errors" in data:
158
- raise RuntimeError(data["errors"]) # trigger fallback
159
+ raise RuntimeError(data["errors"]) # try value-only shape
159
160
  self._props_cache = data.get("data", {}).get("properties", []) or []
160
161
  self._props_loaded_at = time.time()
161
162
  except Exception:
162
- q2 = (
163
- "query($iid: ID!, $limit: Int!, $offset: Int!) {\n"
164
- " searchProperties(q: \"*\", itemId: $iid, limit: $limit, offset: $offset) {\n"
165
- " hits { id workspaceId productId itemId propertyType name category value owner }\n"
163
+ # Attempt 2: value-only, legacy compatible
164
+ q_value_only = (
165
+ "query($iid: ID!) {\n"
166
+ " properties(itemId: $iid) {\n"
167
+ " __typename\n"
168
+ " ... on NumericProperty { category value }\n"
169
+ " ... on TextProperty { value }\n"
170
+ " ... on DateProperty { value }\n"
166
171
  " }\n"
167
172
  "}"
168
173
  )
169
- r2 = self._client._transport.graphql(q2, {"iid": self._id, "limit": 100, "offset": 0})
170
- r2.raise_for_status()
171
- data2 = r2.json()
172
- if "errors" in data2:
173
- raise RuntimeError(data2["errors"]) # propagate
174
- self._props_cache = data2.get("data", {}).get("searchProperties", {}).get("hits", []) or []
175
- self._props_loaded_at = time.time()
174
+ try:
175
+ r = self._client._transport.graphql(q_value_only, {"iid": self._id})
176
+ r.raise_for_status()
177
+ data = r.json()
178
+ if "errors" in data:
179
+ raise RuntimeError(data["errors"]) # trigger fallback to search
180
+ self._props_cache = data.get("data", {}).get("properties", []) or []
181
+ self._props_loaded_at = time.time()
182
+ except Exception:
183
+ # Fallback to searchProperties
184
+ q2_parsed = (
185
+ "query($iid: ID!, $limit: Int!, $offset: Int!) {\n"
186
+ " searchProperties(q: \"*\", itemId: $iid, limit: $limit, offset: $offset) {\n"
187
+ " hits { id workspaceId productId itemId propertyType name category value parsedValue owner }\n"
188
+ " }\n"
189
+ "}"
190
+ )
191
+ try:
192
+ r2 = self._client._transport.graphql(q2_parsed, {"iid": self._id, "limit": 100, "offset": 0})
193
+ r2.raise_for_status()
194
+ data2 = r2.json()
195
+ if "errors" in data2:
196
+ raise RuntimeError(data2["errors"]) # try minimal
197
+ self._props_cache = data2.get("data", {}).get("searchProperties", {}).get("hits", []) or []
198
+ self._props_loaded_at = time.time()
199
+ except Exception:
200
+ q2_min = (
201
+ "query($iid: ID!, $limit: Int!, $offset: Int!) {\n"
202
+ " searchProperties(q: \"*\", itemId: $iid, limit: $limit, offset: $offset) {\n"
203
+ " hits { id workspaceId productId itemId propertyType name category value owner }\n"
204
+ " }\n"
205
+ "}"
206
+ )
207
+ r3 = self._client._transport.graphql(q2_min, {"iid": self._id, "limit": 100, "offset": 0})
208
+ r3.raise_for_status()
209
+ data3 = r3.json()
210
+ if "errors" in data3:
211
+ raise RuntimeError(data3["errors"]) # propagate
212
+ self._props_cache = data3.get("data", {}).get("searchProperties", {}).get("hits", []) or []
213
+ self._props_loaded_at = time.time()
176
214
  return self._props_cache
177
215
 
178
216
  def _props_key_map(self) -> Dict[str, Dict[str, Any]]:
@@ -419,6 +457,10 @@ class _PropWrapper:
419
457
  @property
420
458
  def value(self) -> Any: # type: ignore[override]
421
459
  p = self._raw
460
+ # Use parsedValue if available (new backend feature)
461
+ if "parsedValue" in p:
462
+ return p["parsedValue"]
463
+ # Fallback to legacy parsing logic for backward compatibility
422
464
  # searchProperties shape
423
465
  if "numericValue" in p and p.get("numericValue") is not None:
424
466
  return p["numericValue"]
poelis_sdk/models.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Optional
3
+ from typing import Optional, Any, Union, List
4
4
 
5
5
  from pydantic import BaseModel, Field
6
6
 
@@ -25,3 +25,106 @@ class PaginatedProducts(BaseModel):
25
25
  offset: int
26
26
 
27
27
 
28
+ class PropertyValue(BaseModel):
29
+ """Base class for property values with typed access."""
30
+
31
+ raw_value: str = Field(alias="value")
32
+ parsed_value: Optional[Any] = Field(alias="parsedValue", default=None)
33
+
34
+ @property
35
+ def value(self) -> Any:
36
+ """Get the properly typed value, falling back to raw string if parsing failed."""
37
+ return self.parsed_value if self.parsed_value is not None else self.raw_value
38
+
39
+
40
+ class NumericProperty(BaseModel):
41
+ """Numeric property representation."""
42
+
43
+ id: str = Field(min_length=1)
44
+ item_id: str = Field(alias="itemId", min_length=1)
45
+ position: float
46
+ name: str = Field(min_length=1)
47
+ value: str
48
+ category: str
49
+ display_unit: Optional[str] = Field(alias="displayUnit", default=None)
50
+ owner: str = Field(min_length=1)
51
+ type: str = Field(min_length=1)
52
+ parsed_value: Optional[Union[int, float, List[Any], str]] = Field(alias="parsedValue", default=None)
53
+
54
+ @property
55
+ def typed_value(self) -> Union[int, float, List[Any], str]:
56
+ """Get the properly typed value, falling back to raw string if parsing failed."""
57
+ return self.parsed_value if self.parsed_value is not None else self.value
58
+
59
+
60
+ class TextProperty(BaseModel):
61
+ """Text property representation."""
62
+
63
+ id: str = Field(min_length=1)
64
+ item_id: str = Field(alias="itemId", min_length=1)
65
+ position: float
66
+ name: str = Field(min_length=1)
67
+ value: str
68
+ owner: str = Field(min_length=1)
69
+ type: str = Field(min_length=1)
70
+ parsed_value: Optional[Union[int, float, List[Any], str]] = Field(alias="parsedValue", default=None)
71
+
72
+ @property
73
+ def typed_value(self) -> Union[int, float, List[Any], str]:
74
+ """Get the properly typed value, falling back to raw string if parsing failed."""
75
+ return self.parsed_value if self.parsed_value is not None else self.value
76
+
77
+
78
+ class DateProperty(BaseModel):
79
+ """Date property representation."""
80
+
81
+ id: str = Field(min_length=1)
82
+ item_id: str = Field(alias="itemId", min_length=1)
83
+ position: float
84
+ name: str = Field(min_length=1)
85
+ value: str
86
+ owner: str = Field(min_length=1)
87
+ type: str = Field(min_length=1)
88
+ parsed_value: Optional[str] = Field(alias="parsedValue", default=None)
89
+
90
+ @property
91
+ def typed_value(self) -> str:
92
+ """Get the properly typed value, falling back to raw string if parsing failed."""
93
+ return self.parsed_value if self.parsed_value is not None else self.value
94
+
95
+
96
+ class PropertySearchResult(BaseModel):
97
+ """Property search result with unified fields across all property types."""
98
+
99
+ id: str = Field(min_length=1)
100
+ workspace_id: str = Field(alias="workspaceId", min_length=1)
101
+ product_id: str = Field(alias="productId", min_length=1)
102
+ item_id: str = Field(alias="itemId", min_length=1)
103
+ property_type: str = Field(alias="propertyType", min_length=1)
104
+ name: str = Field(min_length=1)
105
+ category: Optional[str] = None
106
+ display_unit: Optional[str] = Field(alias="displayUnit", default=None)
107
+ value: Any # Raw value from GraphQL
108
+ parsed_value: Optional[Union[int, float, List[Any], str]] = Field(alias="parsedValue", default=None)
109
+ owner: str = Field(min_length=1)
110
+ created_by: str = Field(alias="createdBy", min_length=1)
111
+ created_at: str = Field(alias="createdAt", min_length=1)
112
+ updated_at: str = Field(alias="updatedAt", min_length=1)
113
+
114
+ @property
115
+ def typed_value(self) -> Union[int, float, List[Any], str]:
116
+ """Get the properly typed value, falling back to raw string if parsing failed."""
117
+ return self.parsed_value if self.parsed_value is not None else self.value
118
+
119
+
120
+ class PropertySearchResponse(BaseModel):
121
+ """Response for property search queries."""
122
+
123
+ query: str
124
+ hits: List[PropertySearchResult]
125
+ total: int
126
+ limit: int
127
+ offset: int
128
+ processing_time_ms: int = Field(alias="processingTimeMs")
129
+
130
+
poelis_sdk/search.py CHANGED
@@ -54,7 +54,7 @@ class SearchClient:
54
54
  "query($q: String!, $ws: ID, $pid: ID, $iid: ID, $ptype: String, $cat: String, $limit: Int!, $offset: Int!, $sort: String) {\n"
55
55
  " searchProperties(q: $q, workspaceId: $ws, productId: $pid, itemId: $iid, propertyType: $ptype, category: $cat, limit: $limit, offset: $offset, sort: $sort) {\n"
56
56
  " query total limit offset processingTimeMs\n"
57
- " hits { id workspaceId productId itemId propertyType name category value owner }\n"
57
+ " hits { id workspaceId productId itemId propertyType name category value parsedValue owner }\n"
58
58
  " }\n"
59
59
  "}"
60
60
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: poelis-sdk
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Official Python SDK for Poelis
5
5
  Project-URL: Homepage, https://poelis.com
6
6
  Project-URL: Source, https://github.com/PoelisTechnologies/poelis-python-sdk
@@ -1,16 +1,16 @@
1
1
  poelis_sdk/__init__.py,sha256=vRKuvnMGtq2_6SYDPNpckSPYXTgMDD1vBAfZ1bXlHL0,924
2
2
  poelis_sdk/_transport.py,sha256=Na1neuS9JyLwHqhWkqwpQiGdbRtS0EJlWd587kQ88-s,7069
3
- poelis_sdk/browser.py,sha256=Ornhl821UtoGXttCF5yJnDluu2BXNOG5VJPP5Fc0vjI,22913
3
+ poelis_sdk/browser.py,sha256=drWI86XKhVCcwOO27HD3gSRyLoJG13Ak5RZE0HC95WA,25183
4
4
  poelis_sdk/client.py,sha256=10__5po-foX36ZCCduQmzdoh9NNS320kyaqztUNtPvo,3872
5
5
  poelis_sdk/exceptions.py,sha256=qX5kpAr8ozJUOW-CNhmspWVIE-bvUZT_PUnimYuBxNY,1101
6
6
  poelis_sdk/items.py,sha256=vomXn43gcUlX2iUro3mpb8Qicmmt4sWFB2vXXxIfLsM,2575
7
7
  poelis_sdk/logging.py,sha256=zmg8Us-7qjDl0n_NfOSvDolLopy7Dc_hQ-pcrC63dY8,2442
8
- poelis_sdk/models.py,sha256=tpL7f66dsCobapKp3_rt-w6oiyYvWtoehLvCfjTDLl4,538
8
+ poelis_sdk/models.py,sha256=PduXuivhpJDjR_MmYYrZ1ha5IFPT8AW0jdm_wOrN2zA,4478
9
9
  poelis_sdk/org_validation.py,sha256=c4fB6ySTvcovWxG4F1wU_OBlP-FyuIaAUzCwqgJKzBE,5607
10
10
  poelis_sdk/products.py,sha256=bwV2mOPvBriy83F3BxWww1oSsyLZFQvh4XOiIE9fI1s,3240
11
- poelis_sdk/search.py,sha256=KQbdnu2khQDewddSJHR7JWysH1f2M7swK6MR-ZwrLAE,4101
11
+ poelis_sdk/search.py,sha256=3DqFd7ilTpizjOYgWplR7MTslnY89Q8AmUfn865TnKc,4113
12
12
  poelis_sdk/workspaces.py,sha256=hpmRl-Hswr4YDvObQdyVpegIYjUWno7A_BiVBz-AQGc,2383
13
- poelis_sdk-0.3.2.dist-info/METADATA,sha256=W834FuqvtAm2s2M-og9gt4gTttkkkj3NRJSxY1xAJVE,2968
14
- poelis_sdk-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
- poelis_sdk-0.3.2.dist-info/licenses/LICENSE,sha256=EEmE_r8wk_pdXB8CWp1LG6sBOl7--hNSS2kV94cI6co,1075
16
- poelis_sdk-0.3.2.dist-info/RECORD,,
13
+ poelis_sdk-0.3.3.dist-info/METADATA,sha256=ipFrZcuCD5mRUbKJrpBnO7Ix6XozSYM4Nxh4tDIsXE8,2968
14
+ poelis_sdk-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
15
+ poelis_sdk-0.3.3.dist-info/licenses/LICENSE,sha256=EEmE_r8wk_pdXB8CWp1LG6sBOl7--hNSS2kV94cI6co,1075
16
+ poelis_sdk-0.3.3.dist-info/RECORD,,