API

API reference

class jinjax.Catalog

The object that manages the components and their global settings.

Catalog(

    *,
    globals: 'dict[str, t.Any] | None' = None,
    filters: 'dict[str, t.Any] | None' = None,
    tests: 'dict[str, t.Any] | None' = None,
    extensions: 'list | None' = None,
    jinja_env: 'jinja2.Environment | None' = None,
    root_url: str = '/static/components/',
    file_ext: 'str | list[str] | tuple[str, ...]' = '.jinja',
    use_cache: bool = True,
    auto_reload: bool = True,
    fingerprint: bool = False
) -> None
ArgumentDescription
globals

Dictionary of Jinja globals to add to the Catalog's Jinja environment (or the one passed in jinja_env).

filters

Dictionary of Jinja filters to add to the Catalog's Jinja environment (or the one passed in jinja_env).

tests

Dictionary of Jinja tests to add to the Catalog's Jinja environment (or the one passed in jinja_env).

extensions

List of Jinja extensions to add to the Catalog's Jinja environment (or the one passed in jinja_env). The jinja2.ext.do extension is always added at the end of these.

jinja_env

Custom Jinja environment to use. This argument is useful to reuse an existing Jinja Environment from your web framework.

root_url

Add this prefix to every asset URL of the static middleware. By default, it is /static/components/, so, for example, the URL of the CSS file of a Card component is /static/components/Card.css.

You can also change this argument so the assets are requested from a Content Delivery Network (CDN) in production, for example, root_url="https://example.my-cdn.com/".

file_ext

The extensions the components files have. By default, ".jinja".

This argument can also be a list to allow more than one type of file to be a component.

use_cache

Cache the metadata of the component in memory.

auto_reload

Used with use_cache. If True, the last-modified date of the component file is checked every time to see if the cache is up-to-date.

Set to False in production.

fingerprint

If True, inserts a hash of the updated time into the URL of the asset files (after the name but before the extension).

This strategy encourages long-term caching while ensuring that new copies are only requested when the content changes, as any modification alters the fingerprint and thus the filename.

WARNING: Only works if the server knows how to filter the fingerprint to get the real name of the file.

attr collected_css attribute

List of CSS paths collected during a render.

attr collected_js attribute

List of JS paths collected during a render.

attr prefixes attribute

Mapping between folder prefixes and the Jinja loader that uses.

attr collected_css property

attr collected_js property

attr paths property

A helper property that returns a list of all the components folder paths.

method add_folder

Add a folder path from where to search for components, optionally under a prefix.

add_folder(root_path: 'str | Path', *, prefix: str = '') -> None
ArgumentDescription
root_path

Absolute path of the folder with component files.

prefix

Optional prefix that all the components in the folder will have. The default is empty.

The prefix acts like a namespace. For example, the name of a components/Card.jinja component is, by default, "Card", but under the prefix "common", it becomes "common.Card".

The rule for subfolders remains the same: a components/wrappers/Card.jinja name is, by default, "wrappers.Card", but under the prefix "common", it becomes "common.wrappers.Card".

If there is more than one component with the same name in multiple added folders under the same prefix, the one in the folder added first takes precedence.

method add_module

Reads an absolute path from module.components_path and an optional prefix from module.prefix, then calls Catalog.add_folder(path, prefix).

add_module(module: Any, *, prefix: str | None = None) -> None
ArgumentDescription
module

A Python module.

prefix

An optional prefix that replaces the one the module might include.

The prefix can also be passed as an argument instead of being read from the module.

This method exists to make it easy and consistent to have components installable as Python libraries.

method get_middleware

Wraps you application with Withenoise, a static file serving middleware.

get_middleware(
    application: Callable,
    allowed_ext: 't.Iterable[str] | None' = ('.css', '.js', '.mjs'),
    **kwargs
) -> 'ComponentsMiddleware'
ArgumentDescription
application

A WSGI application

allowed_ext

A list of file extensions the static middleware is allowed to read and return. By default, is just ".css", ".js", and ".mjs".

Tecnically not necessary if your components doesn't use static assets or if you serve them by other means. Requires the whitenoise python package to be installed.

method get_source

A helper method that returns the source file of a component.

get_source(cname: str, file_ext: 'tuple[str, ...] | str' = '') -> str

method irender

Renders the component and subcomponents inside of it without resetting the collected_css and collected_js lists.

irender(
    /,
    _Catalog__name: str, 
    *,
    caller: 't.Callable | None' = None,
    **kw
) -> str

This is the method you should call to render individual components that are later inserted into a parent template.

method render

Resets the collected_css and collected_js lists and renders the component and subcomponents inside of it.

render(
    /,
    _Catalog__name: str, 
    *,
    caller: 't.Callable | None' = None,
    **kw
) -> str

This is the method you should call to render a parent component from a view/controller in your app.

method render_assets

Uses the collected_css and collected_js lists to generate an HTML fragment with <link rel="stylesheet" href="{url}"> and <script type="module" src="{url}"></script> tags.

render_assets() -> str

The URLs are prepended by root_url unless they begin with "http://" or "https://".


class jinjax.LazyString

Behave like regular strings, but the actual casting of the initial value is deferred until the value is actually required.

LazyString(seq)

Bases: UserString

class jinjax.HTMLAttrs

Contains all the HTML attributes/properties (a property is an attribute without a value) passed to a component but that weren't in the declared attributes list.

HTMLAttrs(attrs: 'dict[str, t.Any| LazyString]') -> None

For HTML classes you can use the name "classes" (instead of "class") if you need to.

NOTE: The string values passed to this class, are not cast to str until the string representation is actually needed, for example when attrs.render() is invoked.

attr as_dict property

An ordered dict of all the attributes and properties, both sorted by name before join.

Example:

attrs = HTMLAttrs({
"class": "lorem ipsum",
"data_test": True,
"hidden": True,
"aria_label": "hello",
"id": "world",
})
attrs.as_dict
{
    "aria_label": "hello",
    "class": "ipsum lorem",
    "id": "world",
    "data_test": True,
    "hidden": True
} 

attr classes property

All the HTML classes alphabetically sorted and separated by a space.

Example:

attrs = HTMLAttrs({"class": "italic bold bg-blue wide abcde"})
attrs.set(class="bold text-white")
print(attrs.classes)
abcde bg-blue bold italic text-white wide 

method add_class

Adds one or more classes to the list of classes, if not already present.

add_class(*values: str) -> None

Example:

attrs = HTMLAttrs({"class": "a b c"})
attrs.add_class("c", "d")
attrs.as_dict
{"class": "a b c d"} 

method get

Returns the value of the attribute or property, or the default value if it doesn't exists.

get(name: str, default: Any = None) -> Any

Example:

attrs = HTMLAttrs({"lorem": "ipsum", "hidden": True})

attrs.get("lorem", defaut="bar")
'ipsum'

attrs.get("foo")
None

attrs.get("foo", defaut="bar")
'bar'

attrs.get("hidden")
True 

method remove_class

Removes one or more classes from the list of classes.

remove_class(*names: str) -> None

Example:

attrs = HTMLAttrs({"class": "a b c"})
attrs.remove_class("c", "d")
attrs.as_dict
{"class": "a b"} 

method render

Renders the attributes and properties as a string.

render(**kw) -> str

Any arguments you use with this function are merged with the existing attibutes/properties by the same rules as the HTMLAttrs.set() function:

  • Pass a name and a value to set an attribute (e.g. type="text")
  • Use True as a value to set a property (e.g. disabled)
  • Use False to remove an attribute or property
  • If the attribute is "class", the new classes are appended to the old ones (if not repeated) instead of replacing them.
  • The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.

To provide consistent output, the attributes and properties are sorted by name and rendered like this: <sorted attributes> + <sorted properties>.

Example:

attrs = HTMLAttrs({"class": "ipsum", "data_good": True, "width": 42})

attrs.render()
'class="ipsum" width="42" data-good'

attrs.render(class="abc", data_good=False, tabindex=0)
'class="abc ipsum" width="42" tabindex="0"' 

method set

Sets an attribute or property

set(**kw) -> None
  • Pass a name and a value to set an attribute (e.g. type="text")
  • Use True as a value to set a property (e.g. disabled)
  • Use False to remove an attribute or property
  • If the attribute is "class", the new classes are appended to the old ones (if not repeated) instead of replacing them.
  • The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.
  •  

Example:

attrs = HTMLAttrs({"secret": "qwertyuiop"})
attrs.set(secret=False)
attrs.as_dict
{}

attrs.set(unknown=False, lorem="ipsum", count=42, data_good=True)
attrs.as_dict
{"count":42, "lorem":"ipsum", "data_good": True}

attrs = HTMLAttrs({"class": "b c a"})
attrs.set(class="c b f d e")
attrs.as_dict
{"class": "a b c d e f"} 

method setdefault

Adds an attribute, but only if it's not already present.

setdefault(**kw) -> None

The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.

Example:

attrs = HTMLAttrs({"lorem": "ipsum"})
attrs.setdefault(tabindex=0, lorem="meh")
attrs.as_dict
# "tabindex" changed but "lorem" didn't
{"lorem": "ipsum", tabindex: 0} 


Exceptions

class jinjax.ComponentNotFound

Raised when JinjaX can't find a component by name in none of the added folders, probably because of a typo.

ComponentNotFound(name: str) -> None

Bases: Exception

class jinjax.MissingRequiredArgument

Raised when a component is used/invoked without passing one or more of its required arguments (those without a default value).

MissingRequiredArgument(component: str, arg: str) -> None

Bases: Exception

class jinjax.DuplicateDefDeclaration

Raised when a component has more then one {#def ... #} declarations.

DuplicateDefDeclaration(component: str) -> None

Bases: Exception

class jinjax.InvalidArgument

Raised when the arguments passed to the component cannot be parsed by JinjaX because of an invalid syntax.

InvalidArgument(/, *args, **kwargs)

Bases: Exception