All docs
Tool·
decorator
Tool.template
declares a drag-drop import template that builds a pre-wired entity
Python
template(template_id, *, label, extensions, roles=(), params=None, preview="auto", priority=0, icon=None, sniff=None, suggests=())
Returns Callable — the decorated (ctx, files, name=None) -> Entity function, unchanged
Parameters#
| name | type | default | description |
|---|---|---|---|
template_id |
str |
— | the unique template id |
label |
str |
— | the human name shown in the import wizard (keyword-only, required) |
extensions |
tuple |
— | file extensions this template matches, e.g. (".csv",) (keyword-only, required) |
roles |
Any |
() |
[FileRole(...)] declaring the data slots the wizard maps columns into |
params |
type |
None |
a params class for wizard-collected options |
preview |
str |
"auto" |
preview mode for the wizard |
priority |
int |
0 |
tie-breaker when multiple templates match the same files |
icon |
str |
None |
a symbolic icon name |
sniff |
Callable |
None |
a content check to match files beyond extensions |
suggests |
tuple |
() |
follow-up templates suggested after this one |
Example#
Python
@tool.template("csv-holes", label="Drillholes CSV", extensions=(".csv",))
def build(ctx, files, name=None):
return drillholes.build(name=name, collar=str(files["collar"]))
Notes#
The build function is (ctx: Context, files, name=None) -> Entity. files["role"] returns the
Path for a role and files.main is the primary/single file, so it reads naturally. Typically it
calls an @tool.entity factory's .build(...). Dropped files are matched by extensions and, if
given, sniff; priority breaks ties.
See also#
Guides: Entity types · An import template
By LSD Team · Last updated Jul 17, 2026
Ask on Discord
View as Markdown