Skip to content

Commit

Permalink
ExifTool - remove automatic ujson support, but support setting a cust…
Browse files Browse the repository at this point in the history
…om json.loads() - documentation not complete yet for method, and naming is not final

ExifToolHelper - updated some documentation.
  • Loading branch information
sylikc committed Oct 21, 2023
1 parent 7c59336 commit 7dd0553
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
50 changes: 36 additions & 14 deletions exiftool/exiftool.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,14 @@
from pathlib import Path # requires Python 3.4+
import random
import locale
import warnings
import json # NOTE: to use other json libraries (simplejson/ujson/orjson/...), see ``set_json_loads()``

# for the pdeathsig
import signal
import ctypes


# ---------- UltraJSON overloaded import ----------

try:
# Optional UltraJSON library - ultra-fast JSON encoder/decoder, drop-in replacement
import ujson as json
JSONDecodeError = ValueError # ujson doesn't throw json.JSONDecodeError, but ValueError when string is malformed
except ImportError:
import json # type: ignore # comment related to https://github.com/python/mypy/issues/1153
from json import JSONDecodeError
import warnings



# ---------- Typing Imports ----------
# for static analysis / type checking - Python 3.5+
Expand Down Expand Up @@ -281,6 +271,8 @@ def __init__(self,
self._common_args: Optional[List[str]] = None
self._logger = None
self._encoding: Optional[str] = None
self._json_loads: Callable = json.loads # variable points to the actual callable method
self._json_loads_kwargs: dict = {} # default optional params to pass into json.loads() call



Expand Down Expand Up @@ -685,6 +677,9 @@ def _set_logger(self, new_logger) -> None:
If this is set, then status messages will log out to the given class.
.. note::
This can be set and unset (set to ``None``) at any time, regardless of whether the subprocess is running (:py:attr:`running` == True) or not.
:setter: Specify an object to log to. The class is not checked, but validation is done to ensure the object has callable methods ``info``, ``warning``, ``error``, ``critical``, ``exception``.
:raises AttributeError: If object does not contain one or more of the required methods.
Expand All @@ -693,6 +688,30 @@ def _set_logger(self, new_logger) -> None:
:type: Object
"""

#########################################################################################
##################################### SETTER METHODS ####################################
#########################################################################################


# ----------------------------------------------------------------------------------------------------------------------
def set_json_loads(self, json_loads, **kwargs) -> None:
"""
set a new user-defined json.loads() call
call this setter the same way you would call the loads(), with any optional params
.. note::
This can be set at any time, regardless of whether the subprocess is running (:py:attr:`running` == True) or not.
"""
if not callable(json_loads):
# not a callable method
raise TypeError

self._json_loads = json_loads
self._json_loads_kwargs = kwargs



Expand Down Expand Up @@ -1150,8 +1169,11 @@ def execute_json(self, *params: Union[str, bytes]) -> List:


try:
parsed = json.loads(result)
except JSONDecodeError as e:
parsed = self._json_loads(result, **self._json_loads_kwargs)
except ValueError as e:
# most known JSON libraries return ValueError or a subclass.
# built-in json.JSONDecodeError is a subclass of ValueError -- https://docs.python.org/3/library/json.html#json.JSONDecodeError

# if `-w` flag is specified in common_args or params, stdout will not be JSON parseable
#
# which will return something like:
Expand Down
6 changes: 3 additions & 3 deletions exiftool/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _is_iterable(in_param: Any, ignore_str_bytes: bool = False) -> bool:
if you need to consider a code path for strings first, check that before checking if a parameter is iterable via this function
or specify ignore_str_bytes=True
or specify ``ignore_str_bytes=True``
:param in_param: Something to check if iterable or not
:param ignore_str_bytes: str/bytes are iterable. But usually we don't want to check that. set ``ignore_str_bytes`` to ``True`` to ignore strings on check
Expand Down Expand Up @@ -316,7 +316,7 @@ def get_tags(self, files: Union[Any, List[Any]], tags: Optional[Union[str, List]
which may cause unexpected behavior if you're using one and comparing the result to the other.
Read `ExifTool Common Mistakes - Over-use of Wildcards in File Names`_ for some related info.
:type files: str or list
:type files: Any or List(Any) - see Note
:param tags: Tag(s) to read. If tags is None, or [], method will returns all tags
Expand Down Expand Up @@ -411,7 +411,7 @@ def set_tags(self, files: Union[Any, List[Any]], tags: Dict, params: Optional[Un
which may cause unexpected behavior if you're using one and comparing the result to the other.
Read `ExifTool Common Mistakes - Over-use of Wildcards in File Names`_ for some related info.
:type files: str or list
:type files: Any or List(Any) - see Note
:param tags: Tag(s) to write.
Expand Down

0 comments on commit 7dd0553

Please sign in to comment.