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 +58 -16
- poelis_sdk/models.py +104 -1
- poelis_sdk/search.py +1 -1
- {poelis_sdk-0.3.2.dist-info → poelis_sdk-0.3.3.dist-info}/METADATA +1 -1
- {poelis_sdk-0.3.2.dist-info → poelis_sdk-0.3.3.dist-info}/RECORD +7 -7
- {poelis_sdk-0.3.2.dist-info → poelis_sdk-0.3.3.dist-info}/WHEEL +0 -0
- {poelis_sdk-0.3.2.dist-info → poelis_sdk-0.3.3.dist-info}/licenses/LICENSE +0 -0
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
|
-
|
|
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 {
|
|
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(
|
|
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"]) #
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
"
|
|
165
|
-
"
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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,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=
|
|
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=
|
|
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=
|
|
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.
|
|
14
|
-
poelis_sdk-0.3.
|
|
15
|
-
poelis_sdk-0.3.
|
|
16
|
-
poelis_sdk-0.3.
|
|
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,,
|
|
File without changes
|
|
File without changes
|