Skip to content

Commit

Permalink
fix: simpler, more robust output for objects
Browse files Browse the repository at this point in the history
  • Loading branch information
kdmccormick committed Jan 27, 2025
1 parent 0fe2773 commit 9008213
Showing 1 changed file with 10 additions and 31 deletions.
41 changes: 10 additions & 31 deletions openedx/core/djangoapps/util/management/commands/dump_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ class Command(BaseCommand):
rendered and how they differ between different settings files. The serialization format is NOT perfect: there are
certain situations where two different settings will output identical JSON. For example, this command does NOT:
disambiguate between strings and dotted paths to Python objects:
* some.module.some_function # <-- an actual function object, which will be printed as...
* "some.module.some_function" # <-- a string that is a dotted path to said function object
disambiguate between lists and tuples:
* (1, 2, 3) # <-- this tuple will be printed out as [1, 2, 3]
* [1, 2, 3]
Expand All @@ -39,6 +35,11 @@ class Command(BaseCommand):
disambiguate between internationalized and non-internationalized strings:
* _("hello") # <-- this will become just "hello"
* "hello"
Furthermore, objects which are not easily JSON-ifiable will stringified using their `repr(...)`, e.g.:
* "Path('my/path')" # a Path object
* "<lms.myapp.MyClass object at 0x704599fa2fd0>" # some random class instance
* "<_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>" # sys.stderr
"""

def handle(self, *args, **kwargs):
Expand Down Expand Up @@ -76,31 +77,9 @@ def _to_json_friendly_repr(value: object, debug_key: str) -> object:
if not isinstance(subkey, (str, int)):
raise ValueError(f"Unexpected dict key {subkey} of type {type(subkey)}")
return {subkey: _to_json_friendly_repr(subval, f"{debug_key}[{subkey!r}]") for subkey, subval in value.items()}
if isinstance(value, Path):
# Print path objects as the string `Path('path/to/something')`.
return repr(value)
if isinstance(value, timedelta):
# Print timedelta objects as the string `datetime.timedelta(days=1, ...)`
return repr(value)
if proxy_args := getattr(value, "_proxy____args", None):
# Print gettext_lazy as simply the wrapped string
if len(proxy_args) == 1:
if isinstance(proxy_args[0], str):
return proxy_args[0]
raise ValueError(f"Not sure how to dump {debug_key} with value {value!r} with proxy args {proxy_args!r}")
if value is sys.stderr:
# Print the stderr object as simply "sys.stderr"
return "sys.stderr"
try:
# For anything else, assume it's a function or a class, and try to print its dotted path.
module = value.__module__
qualname = value.__qualname__
except AttributeError:
# If that doesn't work, then give up--we don't know how to print this value.
raise ValueError( # pylint: disable=raise-missing-from
f"Not sure how to dump {debug_key} with value {value!r} of type {type(value)}"
)
if qualname == "<lambda>":
# Handle lambdas by printing the source lines
return inspect.getsource(value).strip()
return f"{module}.{qualname}"
if len(proxy_args) == 1 and isinstance(proxy_args[0], str):
# Print gettext_lazy as simply the wrapped string
return proxy_args[0]
# For all other objects, print the repr
return repr(value)

0 comments on commit 9008213

Please sign in to comment.