Skip to main content

Extract, resolve and replace [SIGILS] embedded in text.

Project description

A sigil is a token embedded in text, used as a magical placeholder for a future value. When resolved, the actual value will be extracted from an user-provided or global context.

This library contains tools to extract, replace and resolve such sigils.

Installing

Install and update using pip:

pip install -U sigils

Structure of Sigils

A typical sigil has one of the following forms:

[USERNAME]
[SETTINGS.BASE_DIR]
[MODEL='natural-key'.FIELD]
[MODEL.USR=[USERNAME].STATUS]

Each sigil is a list of nodes separated by a dot. Nodes can be standalone or parametrized. If parametrized, they can take one argument by using the equals sign. The argument can be a number, a single-quoted string, or another sigil.

[NODE1='ARG1'.NODE2=[ARG2].NODE3=10.ETC]

Sigils used as arguments can be nested to any depth.

Resolving Sigils

The resolve function will replace any sigils found in a string, given a context:

from sigils import resolve

text = "[USERNAME]: The BASE_DIR is [SETTINGS.BASE_DIR]."
context = {
    "USERNAME": "arthexis",
    "SETTINGS": {"BASE_DIR": "/home/arth/webapp"},
}
result = list(resolve(text, context))
assert result == "arthexis: The BASE_DIR is /home/arth/webapp"

Note that resolve returns a generator, so you will need to pass it to list or some other kind os sequence, or iterate it in a loop or comprehension.

All keys in the context mapping should be strings. Values can be anything, but usually it will be a string, another dict, a callable or an instance with public fields:

class Model:
    owner = "arthexis"
                                     # Valid tokens
context = {
    "USERNAME": "arthexis",          # [USERNAME]
    "SETTINGS": {"NAME": "webapp"},  # [SETTINGS.NAME]
    "MODEL": Model,                  # [MODEL.OWNER]
    "UPPER": lambda x: x.upper(),    # [UPPER='text']
    "RNG": lambda _: randint(),      # [RNG]
}

Instead of passing the context explicitly, a global default context can be set to be used by all calls to resolve, you can see an example in the Django integration below.

Django Integration

You can create a simple tag to resolve sigils in templates. Create <your_app>/templatetags/sigils.py with the following code:

import sigils
from django import templates

register = template.Library()

@register.simple_tag
def resolve(text, **context):
    return sigils.resolve(text, context)

In app.py add the following to register a model in the global context (rename MyModel to the name of your model class):

import sigils
from django.apps import AppConfig

class MyAppConfig(AppConfig):
    def ready():
        from .models import MyModel

        def my_model_lookup(parent, slug):
            if not parent:
                return MyModel.objects.filter(slug=slug)
            return parent.my_models.get(slug=slug)

        sigils.set_context("MyModel", my_model_lookup)

You can change the lambda to make your model searchable with a different argument or manager, here the primary key is used.

Then you can use something like this in your template:

{% load sigils %}
Some stuff: {% sigil '[MyModel=[obj.slug].some_field]' obj=foo %}

Dependencies

  • lark: Allows us to parse arbitrarily complex sigils fast.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sigils-0.0.4.tar.gz (7.0 kB view hashes)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page