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.
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.