Skip to content

Commit

Permalink
fixes #126
Browse files Browse the repository at this point in the history
  • Loading branch information
bckohan committed Nov 10, 2023
1 parent e27df32 commit ccc7b33
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 29 deletions.
2 changes: 1 addition & 1 deletion doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ sphinxcontrib-jsmath==1.0.1; python_version >= "3.5"
sphinxcontrib-qthelp==1.0.3; python_version >= "3.5"
sphinxcontrib-serializinghtml==1.1.5; python_version >= "3.5"
sphinx-js==3.2.2; python_version >= "3.5"
django-render-static==2.0.3
django-render-static==2.1.0
5 changes: 5 additions & 0 deletions doc/source/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Change Log
==========

v2.1.0
======
* Implemented `Add a pass through getter for enums_to_js transpilation. <https://github.com/bckohan/django-render-static/issues/126>`_


v2.0.3
======
* Fixed `Invalid URL generation for urls with default arguments. <https://github.com/bckohan/django-render-static/issues/124>`_
Expand Down
1 change: 1 addition & 0 deletions doc/source/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ transpilers.enums_to_js

.. automodule:: render_static.transpilers.enums_to_js

.. autoclass:: UnrecognizedBehavior
.. autoclass:: EnumTranspiler
.. autoclass:: EnumClassWriter

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "django-render-static"
version = "2.0.3"
version = "2.1.0"
description = "Use Django's template engine to render static files at deployment or package time. Includes transpilers for extending Django's url reversal and enums to JavaScript."
authors = ["Brian Kohan <[email protected]>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion render_static/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .transpilers.enums_to_js import EnumClassWriter
from .transpilers.urls_to_js import ClassURLWriter, SimpleURLWriter

VERSION = (2, 0, 3)
VERSION = (2, 1, 0)

__title__ = 'Django Render Static'
__version__ = '.'.join(str(i) for i in VERSION)
Expand Down
12 changes: 7 additions & 5 deletions render_static/templatetags/render_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
TranspilerTargets,
)
from render_static.transpilers.defines_to_js import DefaultDefineTranspiler
from render_static.transpilers.enums_to_js import EnumClassWriter
from render_static.transpilers.enums_to_js import (
EnumClassWriter,
UnrecognizedBehavior,
)
from render_static.transpilers.urls_to_js import ClassURLWriter

register = template.Library()
Expand Down Expand Up @@ -252,7 +255,7 @@ def enums_to_js(
transpiler: Union[Type[Transpiler], str] = EnumClassWriter,
indent: str = '\t',
depth: int = 0,
unrecognized_behavior: str = 'THROW_EXCEPTION',
on_unrecognized: str = 'THROW_EXCEPTION',
**kwargs
) -> str:
"""
Expand All @@ -264,19 +267,18 @@ 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
:param on_unrecognized: 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],
on_unrecognized=UnrecognizedBehavior[on_unrecognized],
**kwargs
)
120 changes: 110 additions & 10 deletions render_static/tests/js_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,6 @@ def test_modules_to_js(self):
self.assertFalse(jf.readline().startswith(' '))

def test_empty_module_to_js(self):
# import ipdb
# ipdb.set_trace()
call_command('renderstatic', 'empty_defines.js')
self.assertEqual(
self.diff_modules(
Expand Down Expand Up @@ -1808,27 +1806,29 @@ def setUp(self):
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'urls.js': '{% urls_to_js '
'unrecognized_behavior="RETURN_NULL" '
'raise_on_not_found=False '
'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" '
'unrecognized_behavior="RETURN_NULL" '
'raise_on_not_found=False '
'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 '
'unrecognized_behavior="RETURN_NULL" '
'raise_on_not_found=False '
'indent="\t" '
'include=include '
'export=True '
Expand Down Expand Up @@ -2858,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 unrecognized_behavior="RETURN_NULL" %}\n'
'enum_app/test.js': '{% enums_to_js enums=enums symmetric_properties=True on_unrecognized="RETURN_NULL" %}\n'
'console.log(JSON.stringify({not_found: AddressRoute.get("Aly")}));'
})
],
Expand Down Expand Up @@ -2890,7 +2890,107 @@ 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 unrecognized_behavior="THROW_EXCEPTION" %}\n'
'enum_app/test.js': '{% enums_to_js enums=enums symmetric_properties=True raise_on_not_found=False %}\n'
'console.log(JSON.stringify({not_found: AddressRoute.get("Aly")}));'
})
],
'builtins': [
'render_static.templatetags.render_static'
]
},
}],
'templates': [
('enum_app/test.js', {
'context': {
'enums': [
EnumTester.AddressRoute
]
}
}),
]
}
)
def test_raise_on_not_found_false_deprecated(self):
with self.assertWarns(DeprecationWarning):
call_command('renderstatic', 'enum_app/test.js')
js_dict = self.get_js_structure(GLOBAL_STATIC_DIR / 'enum_app/test.js')
self.assertDictEqual(js_dict, {'not_found': None})

@override_settings(
STATIC_TEMPLATES={
'ENGINES': [{
'BACKEND': 'render_static.backends.StaticDjangoTemplates',
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums symmetric_properties=True raise_on_not_found=True %}\n'
'console.log(JSON.stringify({not_found: AddressRoute.get("Aly")}));'
})
],
'builtins': [
'render_static.templatetags.render_static'
]
},
}],
'templates': [
('enum_app/test.js', {
'context': {
'enums': [
EnumTester.AddressRoute
]
}
}),
]
}
)
def test_raise_on_not_found_true_deprecated(self):
with self.assertWarns(DeprecationWarning):
call_command('renderstatic', 'enum_app/test.js')
self.assertIn(
'TypeError: No AddressRoute enumeration maps to value Aly',
run_js_file(GLOBAL_STATIC_DIR / 'enum_app/test.js')
)

@override_settings(
STATIC_TEMPLATES={
'ENGINES': [{
'BACKEND': 'render_static.backends.StaticDjangoTemplates',
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums on_unrecognized="RETURN_INPUT" %}\n'
'console.log(JSON.stringify({not_found: AddressRoute.get("Aly")}));'
})
],
'builtins': [
'render_static.templatetags.render_static'
]
},
}],
'templates': [
('enum_app/test.js', {
'context': {
'enums': [
EnumTester.AddressRoute
]
}
}),
]
}
)
def test_return_input_on_unrecognized(self):
call_command('renderstatic', 'enum_app/test.js')
js_dict = self.get_js_structure(GLOBAL_STATIC_DIR / 'enum_app/test.js')
self.assertDictEqual(js_dict, {'not_found': 'Aly'})

@override_settings(
STATIC_TEMPLATES={
'ENGINES': [{
'BACKEND': 'render_static.backends.StaticDjangoTemplates',
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums symmetric_properties=True on_unrecognized="THROW_EXCEPTION" %}\n'
'try { AddressRoute.get("Aly") } catch (e) {console.log(JSON.stringify({not_found: e instanceof TypeError ? "TypeError" : "Unknown"}));}'
})
],
Expand Down Expand Up @@ -2922,7 +3022,7 @@ def test_raise_on_not_found(self):
'OPTIONS': {
'loaders': [
('render_static.loaders.StaticLocMemLoader', {
'enum_app/test.js': '{% enums_to_js enums=enums summetric_properties=True transpiler="render_static.EnumClassWriter" %}\n'
'enum_app/test.js': '{% enums_to_js enums=enums symmetric_properties=True transpiler="render_static.EnumClassWriter" %}\n'
'try { AddressRoute.get("Aly") } catch (e) {console.log(JSON.stringify({not_found: e instanceof TypeError ? "TypeError" : "Unknown"}));}'
})
],
Expand Down Expand Up @@ -3043,8 +3143,8 @@ def test_chained_enum_values(self):
self.assertIn('static VALUE1 = new DependentEnum(1, "VALUE1", IndependentEnum.VALUE1, "DependentEnum.VALUE1");', contents)
self.assertIn('static VALUE2 = new DependentEnum(2, "VALUE2", IndependentEnum.VALUE0, "DependentEnum.VALUE2");', contents)

#def tearDown(self):
# pass
def tearDown(self):
pass


@override_settings(
Expand Down
36 changes: 25 additions & 11 deletions render_static/transpilers/enums_to_js.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Transpiler tools for PEP 435 style python enumeration classes.
"""
import sys
import warnings
from abc import abstractmethod
from enum import Enum, Flag, IntEnum, IntFlag, auto
from typing import (
Expand All @@ -18,7 +19,6 @@

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 @@ -33,6 +33,13 @@


class UnrecognizedBehavior(Enum):
"""
Enumeration of behaviors when a value cannot be mapped to an enum instance:
* THROW_EXCEPTION - throw a TypeError
* RETURN_NULL - return null
* RETURN_INPUT - return the input value
"""

THROW_EXCEPTION = auto()
RETURN_NULL = auto()
Expand Down Expand Up @@ -91,9 +98,10 @@ 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 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 on_unrecognized: If the given value cannot be mapped to an
enum instance, either "THROW_EXCEPTION", "RETURN_NULL", or
"RETURN_INPUT". See
:py:class:`render_static.transpilers.enums_to_js.UnrecognizedBehavior`.
: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 @@ -114,7 +122,8 @@ class EnumClassWriter(EnumTranspiler): # pylint: disable=R0902
class_name_: str
class_name_map_: Dict[Type[Enum], str] = {}

unrecognized_behavior_: bool = UnrecognizedBehavior.THROW_EXCEPTION
on_unrecognized_: UnrecognizedBehavior = \
UnrecognizedBehavior.THROW_EXCEPTION

export_: bool = False

Expand Down Expand Up @@ -318,7 +327,7 @@ def str_prop(self, enum: Type[Enum]):
def __init__( # pylint: disable=R0913
self,
class_name: str = class_name_pattern_,
unrecognized_behavior: UnrecognizedBehavior = unrecognized_behavior_,
on_unrecognized: UnrecognizedBehavior = on_unrecognized_,
export: bool = export_,
include_properties: bool = include_properties_,
symmetric_properties: Union[
Expand All @@ -335,14 +344,19 @@ def __init__( # pylint: disable=R0913
super().__init__(**kwargs)
self.class_name_pattern_ = class_name
raise_on_not_found = kwargs.pop('raise_on_not_found', None)
self.unrecognized_behavior_ = unrecognized_behavior
self.on_unrecognized_ = (
on_unrecognized
if isinstance(on_unrecognized, UnrecognizedBehavior) else
UnrecognizedBehavior[on_unrecognized]
)
if raise_on_not_found is not None:
warnings.warn(
'raise_on_not_found is deprecated, use unrecgonized_behavior instead.',
'raise_on_not_found is deprecated, use on_unrecognized '
'instead.',
DeprecationWarning,
stacklevel=2
)
self.unrecognized_behavior_ = (
self.on_unrecognized_ = (
UnrecognizedBehavior.THROW_EXCEPTION
if raise_on_not_found else
UnrecognizedBehavior.RETURN_NULL
Expand Down Expand Up @@ -496,9 +510,9 @@ 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.unrecognized_behavior_ == UnrecognizedBehavior.RETURN_INPUT:
if self.on_unrecognized_ is UnrecognizedBehavior.RETURN_INPUT:
yield 'return value;'
elif self.unrecognized_behavior_ == UnrecognizedBehavior.RETURN_NULL:
elif self.on_unrecognized_ is UnrecognizedBehavior.RETURN_NULL:
yield 'return null;'
else:
yield f'throw new TypeError(`No {self.class_name} ' \
Expand Down

0 comments on commit ccc7b33

Please sign in to comment.