Skip to content

Commit

Permalink
configurable return behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
bckohan committed Nov 10, 2023
1 parent 224f0a4 commit e27df32
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 33 deletions.
6 changes: 6 additions & 0 deletions render_static/templatetags/render_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ def enums_to_js(
transpiler: Union[Type[Transpiler], str] = EnumClassWriter,
indent: str = '\t',
depth: int = 0,
unrecognized_behavior: str = 'THROW_EXCEPTION',
**kwargs
) -> str:
"""
Expand All @@ -263,14 +264,19 @@ def enums_to_js(
class to use for the transpilation.
:param indent: The indent string to use
:param depth: The depth of the initial indent
:param unrecognized_behavior: The behavior to use when an unrecognized enum
value is attempted to be coerced to the enum. Either THROW_EXCEPTION,
RETURN_NULL, or RETURN_INPUT.
:param kwargs: Any other parameters to pass to the configured transpiler.
See transpiler docs for details.
:return: SafeString of rendered transpiled code.
"""
from render_static.transpilers.enums_to_js import UnrecognizedBehavior
return transpile(
targets=enums,
transpiler=transpiler,
indent=indent,
depth=depth,
unrecognized_behavior=UnrecognizedBehavior[unrecognized_behavior],
**kwargs
)
16 changes: 7 additions & 9 deletions render_static/tests/js_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1808,29 +1808,27 @@ def setUp(self):
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'urls.js': '{% urls_to_js '
'raise_on_not_found=False '
'unrecognized_behavior="RETURN_NULL" '
'indent=None '
'include=include '
'%}',
'urls2.js': '{% urls_to_js '
'raise_on_not_found=True '
'indent="" '
'include=include '
'%}',
'urls3.js': 'var urls = {\n{% urls_to_js '
'transpiler="render_static.SimpleURLWriter" '
'raise_on_not_found=False '
'unrecognized_behavior="RETURN_NULL" '
'indent=None '
'include=include '
'%}}\n',
'urls4.js': 'var urls = {\n{% urls_to_js '
'transpiler="render_static.SimpleURLWriter" '
'raise_on_not_found=True '
'indent="" '
'include=include '
'%}};\n',
'urls3_export.mjs': '{% urls_to_js '
'raise_on_not_found=False '
'unrecognized_behavior="RETURN_NULL" '
'indent="\t" '
'include=include '
'export=True '
Expand Down Expand Up @@ -1937,8 +1935,8 @@ def test_class_parameters_es6(self):
self.compare('path_tst', {'arg1': 12, 'arg2': 'xo'}, js_generator=generator, url_path=up3_exprt)

# uncomment to not delete generated js
# def tearDown(self):
# pass
def tearDown(self):
pass


@override_settings(
Expand Down Expand Up @@ -2860,7 +2858,7 @@ def test_resolve_symmetric_props(self):
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums summetric_properties=True raise_on_not_found=False %}\n'
'enum_app/test.js': '{% enums_to_js enums=enums summetric_properties=True unrecognized_behavior="RETURN_NULL" %}\n'
'console.log(JSON.stringify({not_found: AddressRoute.get("Aly")}));'
})
],
Expand Down Expand Up @@ -2892,7 +2890,7 @@ def test_no_raise_on_not_found(self):
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums summetric_properties=True raise_on_not_found=True %}\n'
'enum_app/test.js': '{% enums_to_js enums=enums summetric_properties=True unrecognized_behavior="THROW_EXCEPTION" %}\n'
'try { AddressRoute.get("Aly") } catch (e) {console.log(JSON.stringify({not_found: e instanceof TypeError ? "TypeError" : "Unknown"}));}'
})
],
Expand Down
70 changes: 46 additions & 24 deletions render_static/transpilers/enums_to_js.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import sys
from abc import abstractmethod
from enum import Enum, Flag, IntEnum, IntFlag
from enum import Enum, Flag, IntEnum, IntFlag, auto
from typing import (
Any,
Collection,
Expand All @@ -18,6 +18,7 @@

from django.db.models import IntegerChoices, TextChoices
from render_static.transpilers import Transpiler, TranspilerTarget
import warnings

try:
from django.utils.decorators import classproperty # pylint: disable=C0412
Expand All @@ -31,6 +32,13 @@
IGNORED_ENUMS.update({FlagBoundary, ReprEnum, StrEnum, EnumCheck})


class UnrecognizedBehavior(Enum):

THROW_EXCEPTION = auto()
RETURN_NULL = auto()
RETURN_INPUT = auto()


class EnumTranspiler(Transpiler):
"""
The base javascript transpiler for python PEP 435 Enums. Extend from this
Expand Down Expand Up @@ -83,9 +91,9 @@ class EnumClassWriter(EnumTranspiler): # pylint: disable=R0902
:param class_name: A pattern to use to generate class names. This should
be a string that will be formatted with the class name of each enum.
The default string '{}' will resolve to the python class name.
:param raise_on_not_found: If true, in the transpiled javascript throw a
TypeError if an Enum instance cannot be mapped to the given value.
If false, return null
:param unrecognized_behavior: If the given value cannot be mapped to an
enum instance, either throw an exception, return null, or return the
input value.
:param export: If true the classes will be exported - Default: False
:param include_properties: If true, any python properties present on the
enums will be included in the transpiled javascript enums.
Expand All @@ -106,7 +114,7 @@ class EnumClassWriter(EnumTranspiler): # pylint: disable=R0902
class_name_: str
class_name_map_: Dict[Type[Enum], str] = {}

raise_on_not_found_: bool = True
unrecognized_behavior_: bool = UnrecognizedBehavior.THROW_EXCEPTION

export_: bool = False

Expand Down Expand Up @@ -308,25 +316,37 @@ def str_prop(self, enum: Type[Enum]):
self.str_prop_ = candidate

def __init__( # pylint: disable=R0913
self,
class_name: str = class_name_pattern_,
raise_on_not_found: bool = raise_on_not_found_,
export: bool = export_,
include_properties: bool = include_properties_,
symmetric_properties: Union[
bool,
Collection[str]
] = symmetric_properties_kwarg_,
exclude_properties: Optional[Collection[str]] = None,
class_properties: Union[
bool,
Collection[str]
] = class_properties_kwarg_,
**kwargs
self,
class_name: str = class_name_pattern_,
unrecognized_behavior: UnrecognizedBehavior = unrecognized_behavior_,
export: bool = export_,
include_properties: bool = include_properties_,
symmetric_properties: Union[
bool,
Collection[str]
] = symmetric_properties_kwarg_,
exclude_properties: Optional[Collection[str]] = None,
class_properties: Union[
bool,
Collection[str]
] = class_properties_kwarg_,
**kwargs
) -> None:
super().__init__(**kwargs)
self.class_name_pattern_ = class_name
self.raise_on_not_found_ = raise_on_not_found
raise_on_not_found = kwargs.pop('raise_on_not_found', None)
self.unrecognized_behavior_ = unrecognized_behavior
if raise_on_not_found is not None:
warnings.warn(
'raise_on_not_found is deprecated, use unrecgonized_behavior instead.',
DeprecationWarning,
stacklevel=2
)
self.unrecognized_behavior_ = (
UnrecognizedBehavior.THROW_EXCEPTION
if raise_on_not_found else
UnrecognizedBehavior.RETURN_NULL
)
self.export_ = export
self.include_properties_ = include_properties
self.symmetric_properties_kwarg_ = symmetric_properties
Expand Down Expand Up @@ -476,11 +496,13 @@ def getter(self, enum: Type[Enum]) -> Generator[Optional[str], None, None]:
for prop in ['value'] + self.symmetric_properties:
yield from self.prop_getter(enum, prop)

if self.raise_on_not_found_:
if self.unrecognized_behavior_ == UnrecognizedBehavior.RETURN_INPUT:
yield 'return value;'
elif self.unrecognized_behavior_ == UnrecognizedBehavior.RETURN_NULL:
yield 'return null;'
else:
yield f'throw new TypeError(`No {self.class_name} ' \
f'enumeration maps to value ${{value}}`);'
else:
yield 'return null;'
self.outdent()
yield '}'

Expand Down

0 comments on commit e27df32

Please sign in to comment.