22SDK Helper functions
33"""
44
5- # NOTE This is to prevent TypeError: '_ctypes.PyCPointerType' object is not subscriptable
6- # on _Pointer[c_char]) for FreeCResources
7- # ctypes._Pointer is generic for type checkers, but at runtime it's not generic, so annotations
8- # import is necessary - or string annotation ("_Pointer[c_char]") .
5+ # NOTE - This is to prevent TypeError: '_ctypes.PyCPointerType' object is not subscriptable on _Pointer[c_char]) for
6+ # NOTE - FreeCResources ctypes._Pointer is generic for type checkers, but at runtime it's not generic, so annotations
7+ # NOTE - import is necessary - or string annotation ("_Pointer[c_char]") .
98from __future__ import annotations
109
1110import platform
12- import sys
1311import threading
12+ from collections .abc import Callable
1413from contextlib import suppress
1514from ctypes import (
1615 CDLL ,
2827from ctypes .util import find_library
2928from functools import wraps
3029from types import TracebackType
31- from typing import Any , Callable , Dict , List , Optional , Type , TypeVar , Union
30+ from typing import Any , Dict , List , Optional , Type , TypeVar , Union
31+ from typing import cast as typing_cast
3232
3333from senzing import ENGINE_EXCEPTION_MAP , SzError , SzSdkError
3434
3535try :
36- import orjson
36+ import orjson # type: ignore[import-not-found, unused-ignore]
3737
3838 def _json_dumps (object_ : Any ) -> str :
39- return orjson .dumps (object_ ).decode ("utf-8" )
39+ return orjson .dumps (object_ ).decode ("utf-8" ) # type: ignore[no-any-return, unused-ignore]
4040
4141except ImportError :
4242 import json
4343
44+ # NOTE - separators= is used to be consistent with Sz engine and orjson output
4445 def _json_dumps (object_ : Any ) -> str :
45- return json .dumps (object_ , ensure_ascii = False )
46+ return json .dumps (object_ , ensure_ascii = False , separators = ( "," , ":" ) )
4647
4748
48- if sys .version_info < (3 , 11 ):
49- from typing_extensions import ParamSpec , Self
50- else :
51- from typing import ParamSpec , Self
52-
53- T = TypeVar ("T" )
54- P = ParamSpec ("P" )
49+ # NOTE - Using earlier Python version typing to support v3.9 still and not rely on typing_extensions.
50+ # NOTE - F can be changed to use ParamSpec when no longer need to support v3.9.
51+ # NOTE - SelfFreeCResources can be changed to use Self at v3.11.
52+ F = TypeVar ("F" , bound = Callable [..., Any ])
53+ SelfFreeCResources = TypeVar ("SelfFreeCResources" , bound = "FreeCResources" )
5554
5655START_DSRC_JSON = '{"DATA_SOURCES": ['
5756START_ENTITIES_JSON = '{"ENTITIES": ['
@@ -74,7 +73,7 @@ def __init__(self, handle: CDLL, resource: _Pointer[c_char]) -> None:
7473 self .handle = handle
7574 self .resource = resource
7675
77- def __enter__ (self ) -> Self :
76+ def __enter__ (self : SelfFreeCResources ) -> SelfFreeCResources :
7877 return self
7978
8079 def __exit__ (
@@ -91,7 +90,8 @@ def __exit__(
9190# -----------------------------------------------------------------------------
9291
9392
94- def catch_sdk_exceptions (func_to_decorate : Callable [P , T ]) -> Callable [P , T ]:
93+ # def catch_sdk_exceptions(func_to_decorate: Callable[P, T]) -> Callable[P, T]:
94+ def catch_sdk_exceptions (func_to_decorate : F ) -> F :
9595 """
9696 The Python SDK methods convert Python types to ctypes and utilize helper functions. If incorrect types/values are
9797 used standard library exceptions are raised not SzError exceptions as the Senzing library hasn't been called
@@ -103,9 +103,9 @@ def catch_sdk_exceptions(func_to_decorate: Callable[P, T]) -> Callable[P, T]:
103103 """
104104
105105 @wraps (func_to_decorate )
106- def wrapped_func (* args : P . args , ** kwargs : P . kwargs ) -> T :
106+ def wrapped_func (* args : Any , ** kwargs : Any ) -> F :
107107 try :
108- return func_to_decorate (* args , ** kwargs )
108+ return typing_cast ( F , func_to_decorate (* args , ** kwargs ) )
109109 except (ArgumentError , TypeError , ValueError ) as err :
110110 # Get wrapped function annotation, remove unwanted keys
111111 annotations_dict = func_to_decorate .__annotations__
@@ -132,7 +132,7 @@ def wrapped_func(*args: P.args, **kwargs: P.kwargs) -> T:
132132
133133 raise SzSdkError (err ) from err
134134
135- return wrapped_func
135+ return typing_cast ( F , wrapped_func )
136136
137137
138138# -----------------------------------------------------------------------------
@@ -160,7 +160,7 @@ def load_sz_library(lib: str = "", os: str = "") -> CDLL:
160160
161161 raise SzSdkError (f"{ system_name } is an unsupported operating system" )
162162 except OSError as err :
163- # TODO Wording & links for V4
163+ # TODO - Wording & links for V4
164164 print (
165165 f"ERROR: Unable to load the Senzing library: { err } \n "
166166 " Did you remember to setup your environment by sourcing the setupEnv file?\n "
0 commit comments