zhmiscellany 6.3.6__py3-none-any.whl → 6.3.7__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.
zhmiscellany/fileio.py CHANGED
@@ -231,77 +231,78 @@ def cache(function, *args, _cache_compressed=False, **kwargs):
231
231
 
232
232
  cache_folder = 'zhmiscellany_cache'
233
233
 
234
- def get_hash_orjson(data):
235
- def default_converter(obj):
236
- if callable(obj):
237
- try:
238
- return inspect.getsource(obj)
239
- except (OSError, TypeError):
240
- return str(obj) # Fallback for lambdas/partials
241
-
242
- # DICT-LIKE OBJECTS WITH NON-STRING KEYS (e.g., bidict, defaultdict, etc.)
243
- # Convert keys to strings to make them JSON-serializable
244
- if isinstance(obj, dict):
245
- try:
246
- # Check if any key is not a string
247
- if any(not isinstance(k, str) for k in obj.keys()):
248
- return {str(k): v for k, v in obj.items()}
249
- except (TypeError, AttributeError):
250
- pass
251
-
252
- # PANDAS DATAFRAMES: Convert to stable dictionary format
253
- if hasattr(obj, '__class__') and obj.__class__.__name__ == 'DataFrame':
254
- try:
255
- import pandas as pd
256
- if isinstance(obj, pd.DataFrame):
257
- # Convert to dict with records orientation for stability
258
- # Include dtypes to ensure type information is preserved
259
- return {
260
- 'data': obj.to_dict(orient='split'),
261
- 'dtypes': {col: str(dtype) for col, dtype in obj.dtypes.items()},
262
- 'index_name': obj.index.name,
263
- 'columns': list(obj.columns)
264
- }
265
- except ImportError:
266
- pass
234
+ def normalize_for_json(obj):
235
+ """Recursively normalize objects to be JSON-serializable."""
236
+ if callable(obj):
237
+ try:
238
+ return ('__callable__', inspect.getsource(obj))
239
+ except (OSError, TypeError):
240
+ return ('__callable__', str(obj))
241
+
242
+ # Handle dict-like objects (including bidict, defaultdict, etc.)
243
+ if isinstance(obj, dict):
244
+ # Convert non-string keys to strings
245
+ return {str(k): normalize_for_json(v) for k, v in obj.items()}
246
+
247
+ # Handle lists and tuples
248
+ if isinstance(obj, (list, tuple)):
249
+ return type(obj)(normalize_for_json(item) for item in obj)
250
+
251
+ # Handle sets
252
+ if isinstance(obj, set):
253
+ return sorted([normalize_for_json(item) for item in obj])
254
+
255
+ # Handle pandas DataFrames
256
+ if hasattr(obj, '__class__') and obj.__class__.__name__ == 'DataFrame':
257
+ try:
258
+ import pandas as pd
259
+ if isinstance(obj, pd.DataFrame):
260
+ return {
261
+ '__type__': 'DataFrame',
262
+ 'data': obj.to_dict(orient='split'),
263
+ 'dtypes': {col: str(dtype) for col, dtype in obj.dtypes.items()},
264
+ 'index_name': obj.index.name,
265
+ 'columns': list(obj.columns)
266
+ }
267
+ except ImportError:
268
+ pass
269
+
270
+ # Handle pandas Series
271
+ if hasattr(obj, '__class__') and obj.__class__.__name__ == 'Series':
272
+ try:
273
+ import pandas as pd
274
+ if isinstance(obj, pd.Series):
275
+ return {
276
+ '__type__': 'Series',
277
+ 'data': obj.to_dict(),
278
+ 'dtype': str(obj.dtype),
279
+ 'name': obj.name,
280
+ 'index': list(obj.index)
281
+ }
282
+ except ImportError:
283
+ pass
284
+
285
+ # Handle bytes
286
+ if isinstance(obj, bytes):
287
+ return ('__bytes__', obj.hex())
288
+
289
+ # Handle datetime
290
+ if isinstance(obj, datetime):
291
+ return ('__datetime__', obj.isoformat())
292
+
293
+ # Handle custom objects with __dict__
294
+ if hasattr(obj, '__dict__') and not isinstance(obj, type):
295
+ return {f'__{obj.__class__.__name__}__': normalize_for_json(obj.__dict__)}
296
+
297
+ # Return primitives as-is
298
+ return obj
267
299
 
268
- # PANDAS SERIES: Similar handling
269
- if hasattr(obj, '__class__') and obj.__class__.__name__ == 'Series':
270
- try:
271
- import pandas as pd
272
- if isinstance(obj, pd.Series):
273
- return {
274
- 'data': obj.to_dict(),
275
- 'dtype': str(obj.dtype),
276
- 'name': obj.name,
277
- 'index': list(obj.index)
278
- }
279
- except ImportError:
280
- pass
281
-
282
- # SETS: Must be sorted to ensure determinism!
283
- # JSON doesn't support sets, so we turn them into sorted lists.
284
- if isinstance(obj, set):
285
- return sorted(list(obj))
286
-
287
- # BYTES: Decode to string (if utf-8) or hex
288
- if isinstance(obj, bytes):
289
- return obj.hex()
290
-
291
- # DATETIMES: Convert to ISO format string
292
- if isinstance(obj, datetime):
293
- return obj.isoformat()
294
-
295
- # CUSTOM OBJECTS: Try to return their __dict__ or string rep
296
- if hasattr(obj, '__dict__'):
297
- return obj.__dict__
298
-
299
- # Fallback: String representation (risky if str() format changes)
300
- return str(obj)
300
+ def get_hash_orjson(data):
301
+ # Pre-process the data to handle non-string keys and other issues
302
+ normalized_data = normalize_for_json(data)
301
303
 
302
304
  json_bytes = orjson.dumps(
303
- data,
304
- default=default_converter,
305
+ normalized_data,
305
306
  option=orjson.OPT_SORT_KEYS
306
307
  )
307
308
  return hashlib.md5(json_bytes).hexdigest()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zhmiscellany
3
- Version: 6.3.6
3
+ Version: 6.3.7
4
4
  Summary: A collection of useful/interesting python libraries made by zh.
5
5
  Home-page: https://discord.gg/ThBBAuueVJ
6
6
  Author: zh
@@ -8,7 +8,7 @@ zhmiscellany/_resource_files_lookup.py,sha256=hsgPW0dngokgqWrAVAv5rUo-eobzJPjvWH
8
8
  zhmiscellany/cpp.py,sha256=XEUEoIKCDCdY5VgwNWE5oXrGjtsmGdz_MnaVwQmi2dk,179
9
9
  zhmiscellany/dict.py,sha256=dNu3G9qiJeLgE7JY3QD31GJU7EfLsYPqxf8AOhBsYag,81
10
10
  zhmiscellany/discord.py,sha256=yKoigWI3tONfYSoMEynGGEWW1VsXSRdkg8vPbIKwBNI,20312
11
- zhmiscellany/fileio.py,sha256=7eMIrLBX69KLdxNbFur8hG16iZkg570LzOGizU2h2s4,22676
11
+ zhmiscellany/fileio.py,sha256=Muiktj_fzCBNBzVMktJzKBkT1_Ssx3EbKkaBGkm6NPA,22372
12
12
  zhmiscellany/gui.py,sha256=OVwuZ_kWHJlgKPeYR7fAAyomNmU-OnxOgXZelVNPm1w,10409
13
13
  zhmiscellany/image.py,sha256=6Hz5sfym_o7FHokGUKeXRsjl89VY_ZMSLnvuSam1icI,8265
14
14
  zhmiscellany/list.py,sha256=BnbYG-lpHmi0C4v8jLfaeXqQdc3opmNgkvY6yz4pasg,1475
@@ -21,7 +21,7 @@ zhmiscellany/pipes.py,sha256=RlHxsW_M_R6UJUIDgYVS_zfqUwO8kXG8j-0YG5qByjo,4637
21
21
  zhmiscellany/processing.py,sha256=ZhNAJ5OfCUHuaXj0z6XZ94ZGSK86-EdCyqW-9ILayLg,11524
22
22
  zhmiscellany/rust.py,sha256=cHkSpdtq7QQW3yzBEAYL9lZxLW0h4wal2tsxIOnyTrA,494
23
23
  zhmiscellany/string.py,sha256=A4ilBWSYlrJ0AJ0axvepSSjYCYwYk5X-vRrHNphi_ow,4809
24
- zhmiscellany-6.3.6.dist-info/METADATA,sha256=HjIrPNfZ5x7q3srMfDGlcC8_Jkl5WWLPLdO-wkRS798,43872
25
- zhmiscellany-6.3.6.dist-info/WHEEL,sha256=hPN0AlP2dZM_3ZJZWP4WooepkmU9wzjGgCLCeFjkHLA,92
26
- zhmiscellany-6.3.6.dist-info/top_level.txt,sha256=ioDtsrevCI52rTxZntMPljRIBsZs73tD0hI00HektiE,13
27
- zhmiscellany-6.3.6.dist-info/RECORD,,
24
+ zhmiscellany-6.3.7.dist-info/METADATA,sha256=wtzaVO-OHJfk0qnhUfzRKlZj9ZihD0BEL4zoP0ILFGY,43872
25
+ zhmiscellany-6.3.7.dist-info/WHEEL,sha256=hPN0AlP2dZM_3ZJZWP4WooepkmU9wzjGgCLCeFjkHLA,92
26
+ zhmiscellany-6.3.7.dist-info/top_level.txt,sha256=ioDtsrevCI52rTxZntMPljRIBsZs73tD0hI00HektiE,13
27
+ zhmiscellany-6.3.7.dist-info/RECORD,,