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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.