{"id":20156135,"url":"https://github.com/openfun/xblock-utils2","last_synced_at":"2025-11-29T01:06:47.890Z","repository":{"id":30901359,"uuid":"34459138","full_name":"openfun/xblock-utils2","owner":"openfun","description":null,"archived":false,"fork":false,"pushed_at":"2018-03-21T15:12:27.000Z","size":77,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-03-03T01:44:43.252Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openfun.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-23T13:51:48.000Z","updated_at":"2018-03-21T15:12:24.000Z","dependencies_parsed_at":"2022-09-07T15:01:56.028Z","dependency_job_id":null,"html_url":"https://github.com/openfun/xblock-utils2","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/openfun/xblock-utils2","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fxblock-utils2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fxblock-utils2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fxblock-utils2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fxblock-utils2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openfun","download_url":"https://codeload.github.com/openfun/xblock-utils2/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fxblock-utils2/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27329505,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-28T02:00:06.623Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T23:37:43.835Z","updated_at":"2025-11-29T01:06:47.863Z","avatar_url":"https://github.com/openfun.png","language":"Python","readme":"xblock-utils: Various utilities for XBlocks\n===========================================\n\nThese are a collection of useful utility functions,\ntest base classes and documentation shared by many XBlocks.\n(Especially those of `edx-solutions`_.)\n\n.. _edx-solutions: https://github.com/edx-solutions\n\n.. image:: https://circleci.com/gh/openfun/xblock-utils2/tree/master.svg?style=svg\n    :target: https://circleci.com/gh/openfun/xblock-utils2/tree/master\n\n\nTo install this package with ``pip`` use FUN package index::\n\n    pip install --extra-index-url https://pypi.fury.io/openfun xblock-utils2\n\nTo test the utilities, run::\n\n    python run_tests.py\n\nTo get a coverage report, use::\n\n    python run_tests.py --with-coverage --cover-package=xblockutils --cover-html\n\n\nStudioEditableXBlockMixin\n-------------------------\n\n.. code:: python\n\n    from xblockutils.studio_editable import StudioEditableXBlockMixin\n\nThis mixin will automatically generate a working ``studio_view`` form\nthat allows content authors to edit the fields of your XBlock. To use,\nsimply add the class to your base class list, and add a new class field\ncalled ``editable_fields``, set to a tuple of the names of the fields\nyou want your user to be able to edit.\n\n.. code:: python\n\n    @XBlock.needs(\"i18n\")\n    class ExampleBlock(StudioEditableXBlockMixin, XBlock):\n        ...\n        mode = String(\n            display_name=\"Mode\",\n            help=\"Determines the behaviour of this component. Standard is recommended.\",\n            default='standard',\n            scope=Scope.content,\n            values=('standard', 'crazy')\n        )\n        editable_fields = ('mode', 'display_name')\n\nThat's all you need to do. The mixin will read the optional\n``display_name``, ``help``, ``default``, and ``values`` settings from\nthe fields you mention and build the editor form as well as an AJAX save\nhandler.\n\nIf you want to validate the data, you can override\n``validate_field_data(self, validation, data)`` and/or\n``clean_studio_edits(self, data)`` - see the source code for details.\n\nSupported field types:\n\n* Boolean:\n  ``field_name = Boolean(display_name=\"Field Name\")``\n* Float:\n  ``field_name = Float(display_name=\"Field Name\")``\n* Integer:\n  ``field_name = Integer(display_name=\"Field Name\")``\n* String:\n  ``field_name = String(display_name=\"Field Name\")``\n* String (multiline):\n  ``field_name = String(multiline_editor=True, resettable_editor=False)``\n* String (html):\n  ``field_name = String(multiline_editor='html', resettable_editor=False)``\n\nAny of the above will use a dropdown menu if they have a pre-defined\nlist of possible values.\n\n* List of unordered unique values (i.e. sets) drawn from a small set of\n  possible values:\n  ``field_name = List(list_style='set', list_values_provider=some_method)``\n\n  - The ``List`` declaration must include the property ``list_style='set'`` to\n    indicate that the ``List`` field is being used with set semantics.\n  - The ``List`` declaration must also define a ``list_values_provider`` method\n    which will be called with the block as its only parameter and which must\n    return a list of possible values.\n* Rudimentary support for Dict, ordered List, and any other JSONField-derived field types\n\n  - ``list_field = List(display_name=\"Ordered List\", default=[])``\n  - ``dict_field = Dict(display_name=\"Normal Dict\", default={})``\n\nSupported field options (all field types):\n\n* ``values`` can define a list of possible options, changing the UI element\n  to a select box. Values can be set to any of the formats `defined in the\n  XBlock source code \u003chttps://github.com/edx/XBlock/blob/master/xblock/fields.py\u003e`__:\n\n  - A finite set of elements: ``[1, 2, 3]``\n  - A finite set of elements where the display names differ from the values\n    ::\n        [\n            {\"display_name\": \"Always\", \"value\": \"always\"},\n            {\"display_name\": \"Past Due\", \"value\": \"past_due\"},\n        ]\n  - A range for floating point numbers with specific increments:\n    ``{\"min\": 0 , \"max\": 10, \"step\": .1}``\n  - A callable that returns one of the above. (Note: the callable does\n    *not* get passed the XBlock instance or runtime, so it cannot be a\n    normal member function)\n* ``values_provider`` can define a callable that accepts the XBlock\n  instance as an argument, and returns a list of possible values in one\n  of the formats listed above.\n* ``resettable_editor`` - defaults to ``True``. Set ``False`` to hide the\n  \"Reset\" button used to return a field to its default value by removing\n  the field's value from the XBlock instance.\n\nBasic screenshot: |Screenshot 1|\n\nStudioContainerXBlockMixin\n--------------------------\n\n.. code:: python\n\n    from xblockutils.studio_editable import StudioContainerXBlockMixin\n\nThis mixin helps to create XBlocks that allow content authors to add,\nremove, or reorder child blocks. By removing any existing\n``author_view`` and adding this mixin, you'll get editable,\nre-orderable, and deletable child support in Studio. To enable authors to\nadd arbitrary blocks as children, simply override ``author_edit_view``\nand set ``can_add=True`` when calling ``render_children`` - see the\nsource code. To restrict authors so they can add only specific types of\nchild blocks or a limited number of children requires custom HTML.\n\nAn example is the mentoring XBlock: |Screenshot 2|\n\nSeleniumXBlockTest\n------------------\n\n.. code:: python\n\n    from xblockutils.base_test import SeleniumXBlockTest\n\nThis is a base class that you can use for writing Selenium integration\ntests that are hosted in the XBlock SDK (Workbench).\n\nHere is an example:\n\n.. code:: python\n\n    class TestStudentView(SeleniumXBlockTest):\n        \"\"\"\n        Test the Student View of MyCoolXBlock\n        \"\"\"\n        def setUp(self):\n            super(TestStudentView, self).setUp()\n            self.set_scenario_xml('\u003cmycoolblock display_name=\"Test Demo Block\" field2=\"hello\" /\u003e')\n            self.element = self.go_to_view(\"student_view\")\n\n        def test_shows_field_2(self):\n            \"\"\"\n            The xblock should display the text value of field2.\n            \"\"\"\n            self.assertIn(\"hello\", self.element.text)\n\nStudioEditableBaseTest\n----------------------\n\n.. code:: python\n\n    from xblockutils.studio_editable_test import StudioEditableBaseTest\n\nThis is a subclass of ``SeleniumXBlockTest`` that adds a few helper\nmethods useful for testing the ``studio_view`` of any XBlock using\n``StudioEditableXBlockMixin``.\n\nchild\\_isinstance\n-----------------\n\n.. code:: python\n\n    from xblockutils.helpers import child_isinstance\n\nIf your XBlock needs to find children/descendants of a particular\nclass/mixin, you should use\n\n.. code:: python\n\n    child_isinstance(self, child_usage_id, SomeXBlockClassOrMixin)\n\nrather than calling\n\n.. code:: python\n\n    ``isinstance(self.runtime.get_block(child_usage_id), SomeXBlockClassOrMixin)``.\n\nOn runtimes such as those in edx-platform, ``child_isinstance`` is\norders of magnitude faster.\n\n.. |Screenshot 1| image:: https://cloud.githubusercontent.com/assets/945577/6341782/7d237966-bb83-11e4-9344-faa647056999.png\n.. |Screenshot 2| image:: https://cloud.githubusercontent.com/assets/945577/6341803/d0195ec4-bb83-11e4-82f6-8052c9f70690.png\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfun%2Fxblock-utils2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenfun%2Fxblock-utils2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfun%2Fxblock-utils2/lists"}