def test_pack_list(self): destinys_child = [ Artist("Beyoncé"), Artist("Kelly Rowland"), Artist("Michelle Williams"), ] ctx = JSContext() result = ctx.pack(destinys_child) self.assertEqual( result, [ { "_type": "music.Artist", "_args": ["Beyoncé"] }, { "_type": "music.Artist", "_args": ["Kelly Rowland"] }, { "_type": "music.Artist", "_args": ["Michelle Williams"] }, ], )
def test_recursive_arg_packing(self): dangerously_in_love = Album( "Dangerously in Love", [ Artist("Beyoncé"), ], ) ctx = JSContext() result = ctx.pack(dangerously_in_love) self.assertEqual( result, { "_type": "music.Album", "_args": [ "Dangerously in Love", [ { "_type": "music.Artist", "_args": ["Beyoncé"] }, ], ], }, ) self.assertIn("music_player.js", str(ctx.media))
def test_pack_object(self): beyonce = Artist("Beyoncé") ctx = JSContext() result = ctx.pack(beyonce) self.assertEqual(result, { "_type": "music.Artist", "_args": ["Beyoncé"] })
def test_list_references(self): destinys_child = [ Artist("Beyoncé"), Artist("Kelly Rowland"), Artist("Michelle Williams"), ] discography = [ Album("Destiny's Child", destinys_child), Album("Survivor", destinys_child), ] ctx = JSContext() result = ctx.pack(discography) self.assertEqual( result, [ { "_type": "music.Album", "_args": [ "Destiny's Child", { "_list": [ { "_type": "music.Artist", "_args": ["Beyoncé"] }, { "_type": "music.Artist", "_args": ["Kelly Rowland"] }, { "_type": "music.Artist", "_args": ["Michelle Williams"], }, ], "_id": 0, }, ], }, { "_type": "music.Album", "_args": [ "Survivor", { "_ref": 0 }, ], }, ], )
def sidebar_props(context): request = context["request"] search_areas = admin_search_areas.search_items_for_request(request) if search_areas: search_area = search_areas[0] else: search_area = None account_menu = [ sidebar.LinkMenuItem("account", _("Account"), reverse("wagtailadmin_account"), icon_name="user"), sidebar.LinkMenuItem("logout", _("Log out"), reverse("wagtailadmin_logout"), icon_name="logout"), ] modules = [ sidebar.WagtailBrandingModule(), sidebar.SearchModule(search_area) if search_area else None, sidebar.MainMenuModule(admin_menu.render_component(request), account_menu, request.user), ] modules = [module for module in modules if module is not None] return json_script( { "modules": JSContext().pack(modules), }, element_id="wagtail-sidebar-props", )
def test_adapt_with_classnames_and_icon(self): packed = JSContext().pack( LinkMenuItem( "link", "Link", "/link/", icon_name="link-icon", classnames="some classes", ) ) self.assertEqual( packed, { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [ { "classnames": "some classes", "icon_name": "link-icon", "label": "Link", "name": "link", "url": "/link/", } ], }, )
def test_adapt_with_optional_parameters(self): packed = JSContext().pack( LinkMenuItem( "link", "Link", "/link/", icon_name="link-icon", classnames="some classes", attrs={"data-is-custom": "true"}, )) self.assertEqual( packed, { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [{ "classnames": "some classes", "icon_name": "link-icon", "label": "Link", "name": "link", "url": "/link/", "attrs": { "data-is-custom": "true" }, }], }, )
def test_primitive_value_references(self): beyonce_name = "Beyoncé Giselle Knowles-Carter" beyonce = Artist(beyonce_name) discography = [ Album("Dangerously in Love", [beyonce]), Album(beyonce_name, [beyonce]), ] ctx = JSContext() result = ctx.pack(discography) self.assertEqual( result, [ { "_type": "music.Album", "_args": [ "Dangerously in Love", [ { "_type": "music.Artist", "_args": [{ "_val": "Beyoncé Giselle Knowles-Carter", "_id": 0 }], "_id": 1, }, ], ], }, { "_type": "music.Album", "_args": [ { "_ref": 0 }, [ { "_ref": 1 }, ], ], }, ], )
def test_object_references(self): beyonce = Artist("Beyoncé") jay_z = Artist("Jay-Z") discography = [ Album("Dangerously in Love", [beyonce]), Album("Everything Is Love", [beyonce, jay_z]), ] ctx = JSContext() result = ctx.pack(discography) self.assertEqual( result, [ { "_type": "music.Album", "_args": [ "Dangerously in Love", [ { "_type": "music.Artist", "_args": ["Beyoncé"], "_id": 0 }, ], ], }, { "_type": "music.Album", "_args": [ "Everything Is Love", [ { "_ref": 0 }, { "_type": "music.Artist", "_args": ["Jay-Z"] }, ], ], }, ], ) self.assertIn("music_player.js", str(ctx.media))
def test_adapt(self): packed = JSContext().pack( SearchModule(SearchArea("Search", "/search/"))) self.assertEqual(packed, { "_type": "wagtail.sidebar.SearchModule", "_args": ["/search/"] })
def test_pack_dict(self): glastonbury = { "pyramid_stage": Artist("Beyoncé"), "acoustic_stage": Artist("Ed Sheeran"), } ctx = JSContext() result = ctx.pack(glastonbury) self.assertEqual( result, { "pyramid_stage": { "_type": "music.Artist", "_args": ["Beyoncé"] }, "acoustic_stage": { "_type": "music.Artist", "_args": ["Ed Sheeran"] }, }, )
def test_dict_reserved_words(self): profile = { "_artist": Artist("Beyoncé"), "_type": "R&B", } ctx = JSContext() result = ctx.pack(profile) self.assertEqual( result, { "_dict": { "_artist": { "_type": "music.Artist", "_args": ["Beyoncé"] }, "_type": "R&B", } }, )
def test_avoid_primitive_value_references_for_short_strings(self): beyonce_name = "Beyoncé" beyonce = Artist(beyonce_name) discography = [ Album("Dangerously in Love", [beyonce]), Album(beyonce_name, [beyonce]), ] ctx = JSContext() result = ctx.pack(discography) self.assertEqual( result, [ { "_type": "music.Album", "_args": [ "Dangerously in Love", [ { "_type": "music.Artist", "_args": ["Beyoncé"], "_id": 1, }, ], ], }, { "_type": "music.Album", "_args": [ "Beyoncé", [ { "_ref": 1 }, ], ], }, ], )
def test_adapt(self): packed = JSContext().pack(LinkMenuItem("link", "Link", "/link/")) self.assertEqual( packed, { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [{ "classnames": "", "icon_name": "", "label": "Link", "name": "link", "url": "/link/", "attrs": None, }], }, )
def test_adapt(self): packed = JSContext().pack(PageExplorerMenuItem("pages", "Pages", "/pages/", 1)) self.assertEqual( packed, { "_type": "wagtail.sidebar.PageExplorerMenuItem", "_args": [ { "classnames": "", "icon_name": "", "label": "Pages", "name": "pages", "url": "/pages/", }, 1, ], }, )
def test_adapt(self): packed = JSContext().pack( SubMenuItem( "sub-menu", "Sub menu", [ LinkMenuItem("link", "Link", "/link/", icon_name="link-icon"), ], footer_text="Footer text", ) ) self.assertEqual( packed, { "_type": "wagtail.sidebar.SubMenuItem", "_args": [ { "name": "sub-menu", "label": "Sub menu", "icon_name": "", "classnames": "", "footer_text": "Footer text", }, [ { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [ { "name": "link", "label": "Link", "icon_name": "link-icon", "classnames": "", "url": "/link/", } ], } ], ], }, )
class BlockWidget(forms.Widget): """Wraps a block object as a widget so that it can be incorporated into a Django form""" def __init__(self, block_def, attrs=None): super().__init__(attrs=attrs) self.block_def = block_def self._js_context = None def _build_block_json(self): self._js_context = JSContext() self._block_json = json.dumps(self._js_context.pack(self.block_def)) @property def js_context(self): if self._js_context is None: self._build_block_json() return self._js_context @property def block_json(self): if self._js_context is None: self._build_block_json() return self._block_json def id_for_label(self, prefix): # Delegate the job of choosing a label ID to the top-level block. # (In practice, the top-level block will typically be a StreamBlock, which returns None.) return self.block_def.id_for_label(prefix) def render_with_errors(self, name, value, attrs=None, errors=None, renderer=None): value_json = json.dumps(self.block_def.get_form_state(value)) if errors: errors_json = json.dumps(self.js_context.pack(errors.as_data())) else: errors_json = "[]" return format_html( """ <div id="{id}" data-block="{block_json}" data-value="{value_json}" data-errors="{errors_json}"></div> <script> initBlockWidget('{id}'); </script> """, id=name, block_json=self.block_json, value_json=value_json, errors_json=errors_json, ) def render(self, name, value, attrs=None, renderer=None): return self.render_with_errors(name, value, attrs=attrs, errors=None, renderer=renderer) @cached_property def media(self): return self.js_context.media + forms.Media( js=[ # needed for initBlockWidget, although these will almost certainly be # pulled in by the block adapters too versioned_static("wagtailadmin/js/telepath/telepath.js"), versioned_static("wagtailadmin/js/telepath/blocks.js"), ], css={ "all": [ versioned_static( "wagtailadmin/css/panels/streamfield.css"), ] }, ) def value_from_datadict(self, data, files, name): return self.block_def.value_from_datadict(data, files, name) def value_omitted_from_data(self, data, files, name): return self.block_def.value_omitted_from_data(data, files, name)
def test_adapt(self): main_menu = [ LinkMenuItem("pages", "Pages", "/pages/"), ] account_menu = [ LinkMenuItem("account", "Account", reverse("wagtailadmin_account"), icon_name="user"), LinkMenuItem("logout", "Logout", reverse("wagtailadmin_logout"), icon_name="logout"), ] user = self.create_user(username="******") packed = JSContext().pack(MainMenuModule(main_menu, account_menu, user)) self.assertEqual( packed, { "_type": "wagtail.sidebar.MainMenuModule", "_args": [ [{ "_type": "wagtail.sidebar.LinkMenuItem", "_args": [{ "name": "pages", "label": "Pages", "icon_name": "", "classnames": "", "url": "/pages/", "attrs": None, }], }], [ { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [{ "name": "account", "label": "Account", "icon_name": "user", "classnames": "", "url": reverse("wagtailadmin_account"), "attrs": None, }], }, { "_type": "wagtail.sidebar.LinkMenuItem", "_args": [{ "name": "logout", "label": "Logout", "icon_name": "logout", "classnames": "", "url": reverse("wagtailadmin_logout"), "attrs": None, }], }, ], { "name": user.first_name or user.get_username(), "avatarUrl": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=100&d=mm", }, ], }, )
def _build_block_json(self): self._js_context = JSContext() self._block_json = json.dumps(self._js_context.pack(self.block_def))
def test_grouper_object_collisions(self): """ Certain functions such as itertools.groupby will cause new objects (namely, tuples and custom itertools._grouper iterables) to be created in the course of iterating over the object tree. If we're not careful, these will be released and the memory reallocated to new objects while we're still iterating, leading to ID collisions. """ # create 100 Ark objects all with distinct animals (no object references are re-used) arks = [ Ark([ { "type": "lion", "name": "Simba %i" % i }, { "type": "lion", "name": "Nala %i" % i }, { "type": "dog", "name": "Lady %i" % i }, { "type": "dog", "name": "Tramp %i" % i }, ]) for i in range(0, 100) ] ctx = JSContext() result = ctx.pack(arks) self.assertEqual(len(result), 100) for i, ark in enumerate(result): # each object should be represented in full, with no _id or _ref keys self.assertEqual( ark, { "_type": "boats.Ark", "_args": [[ [ "lion", [ { "type": "lion", "name": "Simba %i" % i }, { "type": "lion", "name": "Nala %i" % i }, ], ], [ "dog", [ { "type": "dog", "name": "Lady %i" % i }, { "type": "dog", "name": "Tramp %i" % i }, ], ], ]], }, )