sfq 0.0.37__py3-none-any.whl → 0.0.38__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.
sfq/__init__.py
CHANGED
@@ -43,7 +43,7 @@ __all__ = [
|
|
43
43
|
"__version__",
|
44
44
|
]
|
45
45
|
|
46
|
-
__version__ = "0.0.
|
46
|
+
__version__ = "0.0.38"
|
47
47
|
"""
|
48
48
|
### `__version__`
|
49
49
|
|
@@ -67,7 +67,7 @@ class SFAuth:
|
|
67
67
|
access_token: Optional[str] = None,
|
68
68
|
token_expiration_time: Optional[float] = None,
|
69
69
|
token_lifetime: int = 15 * 60,
|
70
|
-
user_agent: str = "sfq/0.0.
|
70
|
+
user_agent: str = "sfq/0.0.38",
|
71
71
|
sforce_client: str = "_auto",
|
72
72
|
proxy: str = "_auto",
|
73
73
|
) -> None:
|
@@ -132,7 +132,7 @@ class SFAuth:
|
|
132
132
|
self._debug_cleanup = DebugCleanup(sf_auth=self)
|
133
133
|
|
134
134
|
# Store version information
|
135
|
-
self.__version__ = "0.0.
|
135
|
+
self.__version__ = "0.0.38"
|
136
136
|
"""
|
137
137
|
### `__version__`
|
138
138
|
|
@@ -565,6 +565,7 @@ class SFAuth:
|
|
565
565
|
def records_to_html_table(
|
566
566
|
self,
|
567
567
|
items: List[Dict[str, Any]],
|
568
|
+
headers: Dict[str, str] = None,
|
568
569
|
styled: bool = False,
|
569
570
|
) -> str:
|
570
571
|
"""
|
@@ -576,4 +577,4 @@ class SFAuth:
|
|
576
577
|
"""
|
577
578
|
if "records" in items:
|
578
579
|
items = items["records"]
|
579
|
-
return records_to_html_table(items, styled=styled)
|
580
|
+
return records_to_html_table(items, headers=headers, styled=styled)
|
sfq/http_client.py
CHANGED
sfq/utils.py
CHANGED
@@ -197,9 +197,7 @@ def extract_org_and_user_ids(token_id_url: str) -> Tuple[str, str]:
|
|
197
197
|
raise ValueError(f"Invalid token ID URL format: {token_id_url}")
|
198
198
|
|
199
199
|
|
200
|
-
def dicts_to_html_table(
|
201
|
-
items: List[Dict[str, Any]], styled: bool = False
|
202
|
-
) -> str:
|
200
|
+
def dicts_to_html_table(items: List[Dict[str, Any]], styled: bool = False) -> str:
|
203
201
|
"""
|
204
202
|
Convert a list of dictionaries to a compact HTML table.
|
205
203
|
|
@@ -309,13 +307,70 @@ def dicts_to_html_table(
|
|
309
307
|
|
310
308
|
return "".join(html)
|
311
309
|
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
for
|
310
|
+
|
311
|
+
def flatten_dict(d, parent_key="", sep="."):
|
312
|
+
"""Recursively flatten a dictionary with dot notation."""
|
313
|
+
items = {}
|
314
|
+
for k, v in d.items():
|
315
|
+
new_key = f"{parent_key}{sep}{k}" if parent_key else k
|
316
|
+
if isinstance(v, dict):
|
317
|
+
items.update(flatten_dict(v, new_key, sep=sep))
|
318
|
+
else:
|
319
|
+
items[new_key] = v
|
320
|
+
return items
|
321
|
+
|
322
|
+
|
323
|
+
def remove_attributes(obj):
|
324
|
+
"""Recursively remove 'attributes' key from dicts/lists."""
|
325
|
+
if isinstance(obj, dict):
|
326
|
+
return {k: remove_attributes(v) for k, v in obj.items() if k != "attributes"}
|
327
|
+
elif isinstance(obj, list):
|
328
|
+
return [remove_attributes(item) for item in obj]
|
329
|
+
else:
|
330
|
+
return obj
|
331
|
+
|
332
|
+
|
333
|
+
def records_to_html_table(
|
334
|
+
records: List[Dict[str, Any]], headers: Dict[str, str] = None, styled: bool = False
|
335
|
+
) -> str:
|
336
|
+
if not isinstance(records, list):
|
337
|
+
raise ValueError("records must be a list of dictionaries")
|
338
|
+
|
339
|
+
cleaned = remove_attributes(records)
|
340
|
+
|
341
|
+
flat_rows = []
|
342
|
+
for record in cleaned:
|
317
343
|
if not isinstance(record, dict):
|
318
344
|
raise ValueError(f"Record is not a dictionary: {record!r}")
|
319
|
-
|
320
|
-
|
321
|
-
|
345
|
+
flat_rows.append(flatten_dict(record))
|
346
|
+
|
347
|
+
# Preserve column order across all rows
|
348
|
+
seen = set()
|
349
|
+
ordered_columns = []
|
350
|
+
for row in flat_rows:
|
351
|
+
for key in row.keys():
|
352
|
+
if key not in seen:
|
353
|
+
ordered_columns.append(key)
|
354
|
+
seen.add(key)
|
355
|
+
|
356
|
+
# headers optionally remaps flattened field names to user-friendly display names
|
357
|
+
if headers is None:
|
358
|
+
headers = {}
|
359
|
+
for col in ordered_columns:
|
360
|
+
headers[col] = col
|
361
|
+
else:
|
362
|
+
for col in ordered_columns:
|
363
|
+
headers[col] = headers.get(col, col)
|
364
|
+
|
365
|
+
# Normalize rows so all have the same keys, using remapped column names
|
366
|
+
normalized_data = []
|
367
|
+
for row in flat_rows:
|
368
|
+
normalized_row = {
|
369
|
+
headers.get(col, col): (
|
370
|
+
"" if row.get(col, None) is None else row.get(col, "")
|
371
|
+
)
|
372
|
+
for col in ordered_columns
|
373
|
+
}
|
374
|
+
normalized_data.append(normalized_row)
|
375
|
+
|
376
|
+
return dicts_to_html_table(normalized_data, styled=styled)
|
@@ -1,14 +1,14 @@
|
|
1
|
-
sfq/__init__.py,sha256=
|
1
|
+
sfq/__init__.py,sha256=phetYqYrR6LapFwR8FrwPa9lxRAh4oYWlBLq6JFCgzQ,20522
|
2
2
|
sfq/_cometd.py,sha256=QqdSGsms9uFm7vgmxgau7m2UuLHztK1yjN-BNjeo8xM,10381
|
3
3
|
sfq/auth.py,sha256=bD7kEI5UpUAh0xpE2GzB7EatfLE0q-rqG7tOpqn_cQY,13985
|
4
4
|
sfq/crud.py,sha256=fj4wPMt0DcrMKbMWQ9AUMsUNUWicsY93LP_3Q7lhmDU,20300
|
5
5
|
sfq/debug_cleanup.py,sha256=e2_Hpigy3F7XsATOUXo8DZNmuEIL9SDD0tBlZIZeQLc,2638
|
6
6
|
sfq/exceptions.py,sha256=HZctvGj1SGguca0oG6fqSmf3KDbq4v68FfQfqB-crpo,906
|
7
|
-
sfq/http_client.py,sha256=
|
7
|
+
sfq/http_client.py,sha256=k5BAASlx7j9zJedu_XkksrOcTMbYAapHIe45Kq2LhEY,11636
|
8
8
|
sfq/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
sfq/query.py,sha256=AoagL8PMKUcpbPPTcHJPKhmUdDDPa0La4JLC0TUN_Yc,14586
|
10
10
|
sfq/soap.py,sha256=FM4msP9ErrgLFaNOQy_kYVde8QFkT4yQu9TfMiZG0VA,7006
|
11
|
-
sfq/utils.py,sha256=
|
12
|
-
sfq-0.0.
|
13
|
-
sfq-0.0.
|
14
|
-
sfq-0.0.
|
11
|
+
sfq/utils.py,sha256=d1vhpTa5innn5w23dnb_9el_giOXRCuRIaP6XUnaLfc,12387
|
12
|
+
sfq-0.0.38.dist-info/METADATA,sha256=MSuTzdQws45q-pBGDJ-vA_3CDvhTt1B1-juRHx3sjEc,6899
|
13
|
+
sfq-0.0.38.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
14
|
+
sfq-0.0.38.dist-info/RECORD,,
|
File without changes
|