1212
1313
1414from typing import Any , cast
15-
1615from collections import Counter
16+ from collections .abc import Collection , Mapping
1717
1818import httpx
1919from lxml import html
2020from lxml .etree import _Element
2121
2222from finance_enums import exchange_records_by_market_category
2323
24- from equities_classifier .enums import (
25- DataSourceID ,
26- SecurityIdentifierType ,
27- )
24+ from equities_classifier .enums import DataSourceID , SecurityIdentifierType
2825from equities_classifier .models import SecurityIdentifier
2926from equities_classifier .exceptions import ClientResponseError
3027from equities_classifier .logginghelper import logger_equities_classifier
3128
3229
33- class ClientHelper :
30+ # common error handler
31+
32+
33+ class ClientHelperErrorHandler :
3434 """Helper methods for client processing."""
3535
3636 @staticmethod
@@ -290,7 +290,7 @@ def get_primary_ticker(
290290 if list_ticker and len (list_ticker ) > 0 and list_mic_code and len (list_mic_code ) > 0 :
291291
292292 if len (list_ticker ) != len (list_mic_code ):
293- ClientHelper .inconsistent_provider_data (
293+ ClientHelperErrorHandler .inconsistent_provider_data (
294294 provider ,
295295 name ,
296296 "count of 'ticker_exchange' and 'mic_code' differ" ,
@@ -311,15 +311,15 @@ def get_primary_ticker(
311311 if len (counter_tickers ) > 0 :
312312 ticker_new = counter_tickers .most_common (1 )[0 ][0 ]
313313 if ticker_for_check and ticker_for_check != ticker_new :
314- ClientHelper .inconsistent_provider_data (
314+ ClientHelperErrorHandler .inconsistent_provider_data (
315315 DataSourceID .OPENFIGI ,
316316 name ,
317317 f"ticker '{ ticker_for_check } ' currently set does not match assumed primary ticker '{ ticker_new } '" ,
318318 error_object ,
319319 )
320320 if (len (counter_tickers .most_common ()) > 1 and
321321 counter_tickers .most_common (1 )[0 ][1 ] == counter_tickers .most_common (2 )[1 ][1 ]):
322- ClientHelper .primary_ticker_not_unique (
322+ ClientHelperErrorHandler .primary_ticker_not_unique (
323323 DataSourceID .OPENFIGI ,
324324 isin ,
325325 error_object ,
@@ -328,3 +328,43 @@ def get_primary_ticker(
328328 return ticker_new
329329
330330 return None
331+
332+
333+ # handling JSON maps
334+
335+
336+ def leaf_paths (
337+ data : Mapping [str , Any ],
338+ path : tuple [str , ...] = (),
339+ exclude_leaves : Collection [str ] = []
340+ ) -> list [tuple [str , ...]]:
341+ """Return all key paths from the root to every leaf."""
342+
343+ result : list [tuple [str , ...]] = []
344+
345+ for key , value in data .items ():
346+
347+ if key in exclude_leaves :
348+ continue
349+
350+ current = (* path , key )
351+ if isinstance (value , Mapping ):
352+ result .extend (leaf_paths (value , current , exclude_leaves ))
353+ elif value :
354+ result .append (current )
355+
356+ return result
357+
358+
359+ def get_nested_value (data : dict [str , Any ], path : tuple [str , ...], ) -> Any :
360+ """Return a nested value from a dictionary."""
361+
362+ value : Any = data
363+ for key in path :
364+ if not isinstance (value , dict ):
365+ return None
366+ value = value .get (key )
367+ if value is None :
368+ return None
369+
370+ return value
0 commit comments