6. Using Expressions in L7|ESP¶
6.1. L7|ESP Expression Language¶
As a platform, L7|ESP provides building blocks for creating complete laboratory Workflows. The Workflow, Protocol, Pipeline, and Task builders sufficiently capture a wide range of lab procedures. However, there are cases where another level of "programming" may be desired, either to more tightly couple disparate aspects of a Workflow, or to provide dynamic content, driven by choices the user makes while running a Workflow or Pipeline.
The L7|ESP Expression Language is an embedded programming language that offers deep access to L7|ESP. The Expression language has a few main uses within L7|ESP:
Expressions can be used to perform simple computations in Worksheets.
Expressions can be used to generate default values and selection lists for Worksheets.
Expressions can be used to pull values from one Protocol's Worksheet and populate cells in another Worksheet.
Expressions allow parameterization of Tasks in the Pipeline Engine.
Expressions define patterns for filenames for automatically registering files.
Expressions are used in workflow routing (workflow chain transitions) for calculating whether a sample should "move" to the next workflow(s) in the chain.
Using the Expression Language is simple: when the language is supported, just include an Expression delimited by double curly-brackets:
{{ 1 + 1 }}
This expression will put the result of 1 + 1
in place of the expression.
The Expression Language is based on the Python programming language, though it is limited to single-line statements. Most valid Python "one-liners" can be used as L7|ESP Expressions. The only exceptions are expressions with syntax errors or expressions that fail the Expression Language's security check.
Note
The Expression Language uses a combined white-list/black-list strategy to manage expression security. In general, any built-in command that would allow access to the underlying interpreter is forbidden, including import statements. To allow common function calls, L7|ESP includes a white-list of API functions that are accessible from the Expression language. White-listed functions include common Python functions and custom functions for interacting with L7|ESP.
Under the hood, L7|ESP parses each Expression, and inspects its syntax tree to ensure that no restricted operations are attempted.
Expressions can return scalar values or lists:
# Will return a scalar value: 2
{{ 1 + 1 }}
# Will return the list: [0, 1, 2, 3, ..., 9]
{{ list(range(10)) }}
Lists are especially useful for generating drop-down lists for columns in Protocol Worksheets. For example, the following Expression will generate a list of well labels for a 96-well plate:
{{ ['%s%d' % (row, col) for row in 'ABCDEFGH' for col in range(1, 13)] }}
API calls and global variables within Expressions provide additional access to L7|ESP. Some API calls and variables are always available to Expressions, while others are context-specific. For example, the param()
API call provides access to Parameter Groups, and their values and can be used in any L7|ESP Expression:
{{ param('Group Name', 'Key') }}
The param
API call significantly extends the ability to create dynamic, portable content for L7|ESP.
Within specific contexts, variables provide more access to related content. For instance, the following expression prints the active protocol name in the LIMS context:
{{ protocol_name }}
For details on using Expressions in specific contexts, see the following sections:
Expressions can be used to define patterns for registering files in Tasks.
Expression dependencies use Expressions and Expression Labels to pass values between Tasks.
Expressions are used to set up data links in Workflows.
Expressions can be used as Default Values and Grouping Values when creating Protocols.
6.2. Expression API¶
To provide access to information and also support complex operations (such as "one liners"), L7|ESP supports an expanding collection of API calls that are available from the Expression Language.
Note
In addition to these API calls, the L7 team can assist users in developing their own Expression Language API calls. Contact an L7 representative for details.
6.2.1. BioBuilds API¶
BioBuilds is the L7-supported packaging of over 100 bioinformatics tools in a safe, mutually compatible manner, with all applications linked against the same external dependencies (BLAS, ATLAS, libc, etc.). If a user has BioBuilds in their system with the appropriate BioBuilds Param Group setup, they can use the BioBuilds API function to reference the bioinformatics tools.
The BioBuilds Param Group is a key-value store with a minimum of two entries, as JSON:
{
"current": "biobuilds-1.0",
"biobuilds-1.0": "/data/ESP/biobuilds-1.0"
}
Where the value given by "current" references another key in the Param Group
and the value for all other keys is the installation path to the version of
BioBuilds indicated by the key. Note that the key naming other than "current" is
arbitrary but typically follows biobuilds-<version>
.
- bb(tool: str, version: str = None) str ¶
Return the path to a BioBuilds tool
- Parameters:
tool -- The BioBuilds tool
version -- The BioBuilds version. If unspecified, the "current" BioBuilds version will be used.
- Returns:
String path to the application
Examples:
{{ bb('bwa') }} -> '/data/ESP/biobuilds-1.1/bin/bwa' {{ bb('bwa', 'biobuilds-1.0') }} -> '/data/ESP/biobuilds-1.0/bin/bwa'
6.2.2. Config API¶
The Config API provides access to L7 configuration items.
- config(configuration_name: str, path: Optional[str] = None) Any ¶
Get a Configuration, as stored in the Config app.
- Parameters:
configuration_name -- the name of the Configuration to return
path -- an optional configuration path to return. If
None
, the full object is returned.
- Returns:
The configuration object (JSON) or value from path or
None
if the configuration or path are invalid.
Examples:
{{ config('Spectramax Assays') }} -> {..} # Full Spectramax Assays configuration returned. {{ config('Spectramax Assays', 'Picogreen.standards.Standard Set 1')[0]['conc'] }} -> 100.000 {{ config('Spectramax Assays', 'Picogreen.standards.Standard Set 1.0.conc) }} -> 100.000 {{ config('No Such Config') }} -> None {{ config('Bad Config', 'Bad Key') }} -> None {{ config('Good Config', 'Bad Key') }} -> None
- ds(datasource_name: str) Any ¶
Return a user-supplied data source
- Parameters:
datasource_name -- The name of the data source to access.
- Returns:
The loaded data source given by
datasource_name
, usually a Python list or dictionary.
Examples
Given an
illumina_adapters
entry in thelab7.conf
data sources configuration point referencing a file with contents:next: ['AGTTC', 'CTAGT'] tru: ['GTGAG', 'TGACA']
The expression:
{{ds('illumina_adapters')['next'][0]}}
returns: 'AGTTC'
6.2.3. File API¶
The File API provides basic file name and path manipulation utilities.
- file_path(uuid: str, ignore_deleted: bool = True) str ¶
Get the full path to a File from a UUID.
- Parameters:
uuid -- UUID for an ESP File
ignore_deleted -- If
True
, archived Files will be considered missing.
- Returns:
str - the full path to the File
Examples:
{{ file_path('577d0a13-2e20-45ac-89b9-c88f0c136ca5') }} -> /path/to/file.txt
- basename(path: str) str ¶
Wrapper for
os.path.basename
- Parameters:
path -- A path to a file
- Returns:
The final component of path
Examples:
{{ basename('/data/experiments/e1/reads.fastq') }} -> 'reads.fastq'
- dirname(path: str) str ¶
Wrapper for
os.path.dirname
- Parameters:
path -- A path to a file
- Returns:
The directory component of path
Examples:
{{ dirname('/data/experiments/e1/reads.fastq') }} -> '/data/experiments/e1'
- file_ext(file_path: str) str ¶
Get the extension for a file path.
- Parameters:
file_path -- The path to a file
- Returns:
The extension of the file, including the
.
Examples:
{{ file_ext('reads.fastq') }} -> '.fastq'
- remove_ext(file_path: str, ext: str = None) str ¶
Remove the extension from a filename.
- Parameters:
file_path -- The path to a file
ext -- an optional extension to remove (leading
.
optional)
- Returns:
file_path
with the extension removed
Examples:
{{ remove_ext('reads.fastq') }} -> 'reads' {{ remove_ext('reads.fastq', 'fastq') }} -> 'reads' {{ remove_ext('reads.fastq', '.fastq)' }} -> 'reads' {{ remove_ext('reads.fastq.gz') }} -> 'reads.fastq' {{ remove_ext('reads.fastq.gz', 'fastq') }} -> 'reads.fastq.gz'
Note
If
ext
isNone
(default), then any existing extension will be removed; if not, extension will be removed only if it matchesext
.
- replace_ext(file_path: str, new_ext: str, old_ext: str = None) str ¶
Replace extension of file specified by
file_path
withnew_ext
.- Parameters:
file_path -- The path to modify
new_ext -- The new extension to use (leading
.
optional)old_ext -- Optional - the old extension to replace (leading
.
optional)
- Returns:
file_path
with the extension replacednew_ext
Examples:
{{ replace_ext('reads.fastq', 'sam') }} -> 'reads.sam' {{ replace_ext('reads.fastq', '.sam') }} -> 'reads.sam' {{ replace_ext('reads.fastq', 'sam', 'fastq') }} -> 'reads.sam' {{ replace_ext('reads.fastq.gz', 'sam') }} -> 'reads.fastq.sam' {{ replace_ext('reads.fastq.gz', 'sam', 'fastq') }} -> 'reads.fastq.gz' {{ replace_ext('reads.fastq.gz', 'sam', 'fastq.gz') }} -> 'reads.sam'
Note
If
old_ext
isNone
(default), then any existing extension (defined as the substring after the last.
infile_path
) will be replaced; if not, replacement will only occur if the current extension matchesold_ext
.
6.2.4. Illumina API¶
The Illumina API simplifies working with Illumina instruments and Workflows. Currently, nearly all of the values returned by these functions are driven by configuration files, and are therefore very flexible and dynamic. Use of these functions requires the appropriate configuration to be set up first.
Illumina Kit Adapters¶
Illumina Kit Adapters are stored in a JSON or YAML file with one top-level entry per kit. API calls defined below provide access via the expression language to kit names, adapter names, and sequence lists.
The file is defined in the configuration and must reference a valid Data Source, e.g.:
illumina:
adapter_datasource: illumina_adapters
datasources:
illumina_adapters:
url: file://$LAB7DATA/reference/illumina/indexes/illumina-adapter-sequences.json
type: application/json
Each kit entry contains entries for each class of adapters supported by the kit. In general, the format for each kit is:
{
"Illumina Kit Name": {
"Individual Adapter": "adapter_sequence",
"Adapter Class 1": [
["adapter_name", "adapter_sequence"]
],
"Adapter Class 2": {
"Adapter Subclass 2.1": [
["adapter_name", "adapter_sequence"]
],
"Adapter Subclass 2.2": [
["adapter_name", "adapter_sequence"]
]
}
},
"Unsupported Kit": "unsupported"
}
Most amplicon and DNA kits have the same basic structure:
"TruSight Amplicon Panels": {
"Index 1 (i7) Adapters": [
["A701", "ATCACGAC"]
],
"Index 2 (i5) Adapter": {
"MiSeq, HiSeq 2000/2500": [
["A501", "TGAACCTT"]
],
"MiniSeq, NextSeq, HiSeq 3000/4000": [
["A501", " AAGGTTCA"]
]
}
}
Names are taken directly from the Illumina Adapter Sequences reference and other Vendor reference material to maintain consistency and simplify debugging. Hence, the plural for i7 and singular for i5 and the use of instrument names for selecting i5 forward/reverse complement variants.
RNA kits are more complicated and have many additional adapters. When present, the tend to use a mix of "Adapter Class 1" and "Individual Sequence" entries.
If a kit is present in the Illumina Adapter Sequences reference document but is not encoded fully in the JSON file, it has a single attribute, "unsupported".
Instruments¶
The "instruments" data source is a YAML or JSON file that consists of a key-value dictionary of known lab instruments, Illumina and otherwise. The key is the name of the instrument as known by the lab. The value is dictionary of configuration values. The exact values depend on the instrument class. Implementations are free to add any additional keys that would be of benefit to their implementation. ESP built-in Illumina support requires at least:
kit_version
- Sequencing kit version (fornovaseq
).vendor
- should beillumina
type
- should be one ofnovaseq
,miseq
,iseq
,hiseq
, ornextseq
(case-insensitive)serial
- instrument serial numberrunsheet_path
- Path for generated run sheets. May contain variables such as:{worksheet_name}
- LIMS worksheet name{today}
- today's date as a string{start_timestamp}
- timestamp of instrument start{assay_name}
- Usually the kit name(s) used for library prep{assay_number}
- The resolved run number{assay_serial}
- The resolved run name
output_path
- Path where instrument output files are (eventually) written.
Optional keys that some built-in functionality recognizes:
read_1_cycles
- default parameter for read 1 cyclesread_2_cycles
- default parameter for read 2 cyclesindex_cycles
- default parameter for read 2 cycles
Examples:
My NovaSeq:
kit_version: '1.5'
vendor: illumina
type: novaseq
serial: 5678
read_1_cycles: 150
read_2_cycles: 150
index_cycles: 8
path: /path/to/instrument_folder/{{runname}}/SampleSheet.csv
output_path: /path/to/instrument_folder
See also the espclient.instrument_support.illumina2
module of the ESP Python client.
Functions¶
- configured_ilmn_instruments(types: Optional[Union[str, list[str]]] = None) list[str] ¶
Get a list of configured Illumina instruments
- Parameters:
types -- Optional argument declaring type(s) of instrument to return, e.g. 'NextSeq'
- Returns:
A list of configured Illumina instrument names.
Examples:
{{ configured_ilmn_instruments() }} --> ['MS000001', 'NextSeq 10231'] {{ configured_ilmn_instruments('MiSeq') }} --> ['MS000001'] {{ configured_ilmn_instruments('NextSeq') }} --> ['NextSeq 10231']
Note
The list of instruments searched is defined in the "instruments" data source.
- ilmn_adapter_names(kit, inst=None, position='i7') list[str] ¶
Fetch adapter names.
General accessor for adapter names regardless of kit type. See also:
ilmn_i5_names
,ilmn_i5_names
, andilmn_primer_names
, andilmn_adapters
.- Parameters:
kit -- Name of the kit
inst -- Instrument type. Used for determining i5 index orientation.
position -- Optional adapter position (i.e. i5 or i7)
- Returns:
List of adapter names
Examples:
# equivalent to ilmn_primer_names('TruSeq Diverse 27F 16s') {{ ilmn_adapter_names('TruSeq Diverse 27F 16s') }} --> ['1', ...] # equivalent to ilmn_i7_names('TruSeq DNA-RNA') {{ ilmn_adapter_names('TruSeq DNA-RNA') }} --> ['A001', ...] # equivalent to ilmn_i5_names('TruSeq DNA-RNA') {{ ilmn_adapter_names('TruSeq DNA-RNA', position='i5') }} --> ['D501', ...] # [] {{ ilmn_adapter_names('TruSeq Diverse 27F 16s', position="i5") }} --> []
- ilmn_adapter_seq(kit: str, names: Union[str, list[str]], inst: str = None, position: str = 'i7') Optional[str] ¶
Like
ilmn_i[57]_seq
but accesses all adapter types.- Parameters:
kit -- Name of a configured Illumina kit
names -- Name or list of names of an adapter within kit
inst -- Name of instrument type
position -- Optional adapter position (i.e. i5 or i7)
- Returns:
The index sequence, or None if the adapter cannot be found
Examples:
# equivalent to ilmn_i7_seq('TruSeq DNA-RNA', 'A001') {{ ilmn_adapter_seq('TruSeq DNA-RNA', 'A001') }} --> 'ATCACG' # equivalent to ilmn_primer_seq('TruSeq Diverse 27F 16s', '1) {{ ilmn_adapter_seq('TruSeq Diverse 27F 16s', '1') }} --> 'TTGAC' # Equivalent to ilmn_i5_seq('TruSeq DNA-RNA', 'D501') {{ ilmn_adapter_seq('TruSeq DNA-RNA', 'D501', position='i5') }} --> 'TATAGCCT'
- ilmn_adapter_seqs(kit: str, inst: str = None, position: str = 'i7') list[str] ¶
Fetch adapter sequences.
General accessor for adapter sequences regardless of kit type. See also:
ilmn_i5_seqs
,ilmn_i5_seqs
, andilmn_primer_seqs
, andilmn_adapters
.- Parameters:
kit -- Name of the kit
inst -- Instrument type. Used for determining i5 index orientation.
position -- Optional adapter position (i.e. i5 or i7)
- Returns:
List of adapter sequences
Examples:
# equivalent to ilmn_primer_seqs('TruSeq Diverse 27F 16s') {{ ilmn_adapter_names('TruSeq Diverse 27F 16s') }} --> ['TTTGAC', ...] # equivalent to ilmn_i7_seqs('TruSeq DNA-RNA') {{ ilmn_adapter_seqs('TruSeq DNA-RNA') }} --> ['ATCACG', ...] # equivalent to ilmn_i5_seqs('TruSeq DNA-RNA') {{ ilmn_adapter_seqs('TruSeq DNA-RNA', position='i5') }} --> ['TATAGCCT', ...] # [] {{ ilmn_adapter_seqs('TruSeq Diverse 27F 16s', position="i5") }} --> []
- ilmn_adapters(kit: str, inst: str = None, position: str = 'i7', context: str = None) list[tuple[str, str]] ¶
Return adapters based on the kit type.
Primer kits can accept "i7" and this will return the primers for "i7" and empty lists for "i5". This allows primer lists to be used in protocols that support dual indexes.
- Parameters:
kit -- Name of the kit
inst -- Instrument type. Used for determining i5 index orientation.
position -- Optional adapter position (i.e. i5 or i7)
context -- Used for when the adapter type is "dual indexes" to determine whether to return sequences or names.
- Returns:
List of adapters, as for
ilmn_i7_adapters
Examples:
# equivalent to ilmn_primers('TruSeq Diverse 27F 16s') {{ ilmn_adapters('TruSeq Diverse 27F 16s') }} --> [['1', 'TTGAC'], ...] # equivalent to ilmn_i7_adapters('TruSeq DNA-RNA') {{ ilmn_adapters('TruSeq DNA-RNA') }} --> [['A001', 'ATCACG'], ...] # equivalent to ilmn_i5_adapters('TruSeq DNA-RNA') {{ ilmn_adapters('TruSeq DNA-RNA', position='i5') }} --> [['D501', 'TATAGCCT'], ...] # returns [] since there are no i5 adapters for TruSeq Diverse 27F 16s. {{ ilmn_adapters('TruSeq Diverse 27F 16s', position="i5") }} --> []
- ilmn_i5_adapters(kit: str, inst: str = None) list[tuple[str, str]] ¶
Fetch a list of i5 adapters for a given kit
- Parameters:
kit -- The name of the kit to get the adapters for
inst -- The Illumina instrument class (defaults to MiSeq-orientation I5) The value of "inst" can be one of these keys, or any of
"MiSeq"
,"HiSeq 2000"
,"HiSeq 2500"
,"MiniSeq"
,"NextSeq"
, or"HiSeq 4000"
. The value dictates the orientation of the returned sequences, based on the standard dual-indexed sequencing workflow for the instrument.
- Returns: The i5 adapters for a given kit as a list of
two-element lists. Each two-element list contains the adapter name and the adapter index sequence in that order. Note that the data source entry corresponding to kit must be of type "index adapters" to be included in this list. Also, if inst is none, NextSeq-style i5 index orientation is assumed.
- Raises:
ValueError -- If the kit type does not support i5 adapters
Examples:
{{ ilmn_i5_adapters('TruSeq DNA-RNA') }} --> [['D501', 'TATAGCCT'], ...]
- ilmn_i5_names(kit: str, inst: str = None) list[str] ¶
Fetch i5 adapter names for a given kit
- Parameters:
kit -- Name of the Illumina kit
inst -- The Illumina instrument class, or None. (defaults to NextSeq-orientation I5) The value of "inst" can be one of these keys, or any of
"MiSeq"
,"HiSeq 2000"
,"HiSeq 2500"
,"MiniSeq"
,"NextSeq"
, or"HiSeq 4000"
. The value dictates the orientation of the returned sequences, based on the standard dual-indexed sequencing workflow for the instrument.
- Returns:
A list of i5 adapter names for a kit.
Examples:
{{ ilmn_i5_names('TruSeq DNA-RNA') }} --> ['D501', 'D502', ...]
- ilmn_i5_seq(kit: str, names: Union[str, list[str]], inst: str = None) str ¶
Fetch the i5 sequence for a given kit and adapter, accounting for instrument.
- Parameters:
kit -- Name of the Illumina kit
names -- Name of the i5 adapter within the kit
inst -- Name of an Illumina instrument (defaults to NextSeq-orientation I5) The value of "inst" can be one of these keys, or any of
"MiSeq"
,"HiSeq 2000"
,"HiSeq 2500"
,"MiniSeq"
,"NextSeq"
, or"HiSeq 4000"
. The value dictates the orientation of the returned sequences, based on the standard dual-indexed sequencing workflow for the instrument.
- Returns:
The i5 adapter sequence
Examples:
{{ ilmn_i7_seq('TruSeq DNA-RNA', 'A001') }} --> 'ATCACG'
- ilmn_i5_seqs(kit: str, inst: str = None) list[str] ¶
Fetch a list of i5 adapter sequences for a kit
- Parameters:
kit -- Name of the Illumina kit
inst -- The Illumina instrument class, or None. (defaults to NextSeq-orientation I5) The value of "inst" can be one of these keys, or any of
"MiSeq"
,"HiSeq 2000"
,"HiSeq 2500"
,"MiniSeq"
,"NextSeq"
, or"HiSeq 4000"
. The value dictates the orientation of the returned sequences, based on the standard dual-indexed sequencing workflow for the instrument.
- Returns:
A list of adapter index sequences for a kit.
Examples:
{{ ilmn_i5_seqs('TruSeq DNA-RNA') }} --> ['TATAGCCT', 'ATAGAGGC', ...]
- ilmn_i7_adapters(kit: str, inst=None) list[tuple[str, str]] ¶
Fetch a list of i7 adapters for a given kit
- Parameters:
kit -- The name of the kit to get the adapters for
inst -- ignored
- Returns: The i7 adapters for a given kit as a list of
two-element lists. Each two-element list contains the adapter name and the adapter index sequence in that order. Note that the data source entry corresponding to kit must be of type "index adapters" to be included in this list.
Examples:
{{ilmn_i7_adapters('TruSeq DNA-RNA')}} --> [['A001', 'ATCACG'], ...]
- ilmn_i7_names(kit: str) list[str] ¶
Fetch i7 adapter names for a given kit
- Parameters:
kit -- Name of the Illumina kit
- Returns:
A list of i7 adapter names for a kit.
Examples:
{{ ilmn_i7_names('TruSeq DNA-RNA') }} --> ['A001', 'A002', ...]
- ilmn_i7_seq(kit: str, name: str) str ¶
- Parameters:
kit -- Name of the Illumina kit
name -- Name of the I5 or I7 adapter within the kit
- Returns:
The I5 or I7 adapter sequence
Examples:
{{ ilmn_i7_seq('TruSeq DNA-RNA', 'A001') }} --> 'ATCACG'
- ilmn_i7_seqs(kit: str) list[str] ¶
Fetch a list of i7 adapter sequences for a kit
- Parameters:
kit -- Name of the Illumina kit
- Returns:
A list of adapter index sequences for a kit.
Examples:
{{ ilmn_i7_seqs('TruSeq DNA-RNA') }} --> ['ATCACG', 'CGATGT', ...]
- ilmn_instruments() list[str] ¶
List known Illumina instrument types
- Returns:
A list of known Illumina instrument types.
Examples:
{{ ilmn_instruments() }} --> ['NextSeq', 'HiSeq 2000', 'HiSeq 2500', 'MiniSeq', 'MiSeq', 'HiSeq 4000']
- ilmn_kit_details(kit_name: str) dict[str, Any] ¶
Return configuration details for the named kit
- Parameters:
kit_name -- Name of a configured Illumina kit
- Returns:
Dictionary of configuration information for the kit
Examples:
{{ ilmn_kit_details('KAPA Dual Indexed Adapter Kit')["_type"] }} --> "dual indexed adapters"
Note
Valid keys depend on the the kit configuration, but typically available are:
_type
- The type of kit, normally one ofprimers
,dual index adapters
, orindex adapters
.uses_i5_index
-True
if the kit uses an i5 adapter/index,False
otherwise._source
- URL used as the source of the primers.Index 1 (i7) Adapters - a list of length-2 lists. The first element of each list is the adapter name. The second element of each list is the adapter sequence.
Index 2 (i5) Adapter - a dictionary with two keys:
MiSeq, HiSeq 2000/2500
- a list in the same shape as Index 1, but for theMiSeq
orientation of i5 adapters.MiniSeq, NextSeq, HiSeq 3000/4000
- a list in the same shape as Index 1, but for theNextSeq
orientation of i5 adapters.
- ilmn_kits(types: Sequence[str] = ('index adapters', 'primers', 'dual index adapters'), include_custom: bool = True) list[str] ¶
Get a list of kits matching the input parameters.
- Parameters:
types -- A Sequence of strings declaring the types of kits to include. Defaults to
['index adapters', 'primers']
.include_custom -- Boolean. If true the value "Custom" will be included in the return list of kits.
- Returns:
A list of known kits of the specified type(s).
Examples:
# a list of configured kit names: ['TruSeq DNA-RNA', 'TruSeq Diverse 27F 16s', ...] {{ ilmn_kits() }} --> ['TruSeq DNA-RNA', ..., 'Custom'] # a list of kits of type index adapters. {{ ilmn_kits(['index adapters']) }} --> ['TruSeq DNA-RNA', ..., 'Custom'] # a list of kits of type primers. {{ ilmn_kits(['primers']) }} --> ['TruSeq Diverse 27F 16s', ..., 'Custom'] # exclude custom kits {{ ilmn_kits(['primers'], include_custom=False) }} --> ['TruSeq Diverse 27F 16s', ...]
- ilmn_primer_names(kit: str) list[str] ¶
Fetch a list of primer names for a kit
- Parameters:
kit -- The name of the kit
- Returns:
The list of primer names for a kit, where the kit type is "primers". In L7|ESP, Illumina "primer" kits are kits with only one index per read.
Examples:
{{ ilmn_primer_names('TruSeq Diverse 27F 16s') }} --> ['1', '2', ...[]
- ilmn_primer_seq(kit: str, name: str) str ¶
Fetch a primer adapter sequence
- Parameters:
kit -- The name of the kit
name -- The name of the adapter within the kit
- Returns:
An index sequence for a given kit and primer name.
Examples:
{{ ilmn_primer_seq('TruSeq Diverse 27F 16s', '2') }} --> 'TGTCAC'
- ilmn_primer_seqs(kit: str) list[str] ¶
Fetch a list of primer sequences for a kit
- Parameters:
kit -- The name of the kit
- Returns:
A list of index sequences for a kit of type primers.
Examples:
{{ ilmn_primer_seqs('TruSeq Diverse 27F 16s') }} --> ['TTGAC', 'TGTCAC', ...]
- ilmn_primers(kit: str, inst: str = None) list[tuple[str, str]] ¶
Fetch a list of adapter names and sequences for a "primer" kit (!dual indexed)
- Parameters:
kit -- The name of the kit
inst -- Unused
- Returns:
The list of primers for a kit, where the kit type is "primers". In L7|ESP, Illumina "primer" kits are kits with only one index per read.
Examples:
{{ ilmn_primers('TruSeq Diverse 27F 16s') }} --> [['1', 'TTGAC'], ...]
- ilmn_seqs_for_indexid(kit: str, indexid: str) list[str] ¶
A generalized version of some of the other adapter lookups.
For _type == 'primers' returns the list [i7 index, 'NA']. For _type == 'index adapters', returns the list [i7 index]. For _type == 'dual index adapters', returns the list [i7 index, i5 index (NextSeq orientation)].
- Parameters:
kit -- Name of a configured Illumina kit
indexid -- Index ID
Examples:
{{ ilmn_seqs_for_indexid("KAPA Dual Indexed Adapter Kit", "A1") }} --> ['TATAGCCT', 'CGAGTAAT']
Note
Both "index adapters" and "dual indexed adapters" are used for paired-index sequencing. The "index adapters" type should be used when the i7 and i5 indexes are contained in separate source tubes and are specified with separate identifiers. The "dual index adapters" type should be used for cases where a single well or tube contains both an i7 and i5 adapter, and a single identifier is used for that particular combination of I7/I5 sequences. Single-index kits should always use _type="primers".
6.2.5. LIMS API¶
The LIMS API can be used for data linking, default column values, or when directly entering values in a Worksheet.
Variables¶
The LIMS API provides access to a number of useful context variables:
- Variable:
agent
- Object representing the current user. Direct access toagent
is deprecated. Use thecurrent_user
expression instead.- Variable:
sample
- Sample JSON, a dict with at least keysname
anduuid
{{sample['name']}}
Would give a value similar to:
"ESP000001"
.- Variable:
protocol_name
- Name of the current Protocol- Variable:
sample_index
- The current row index (0
for the first row, etc.)- Variable:
sample_sheet_uuid
- The UUID of the current Worksheet- Variable:
sample_sheet_name
- The name of the current Worksheet- Variable:
sample_to_row
- Dictionary that maps from Entity UUID to a particular row number in the Worksheet- Variable:
workflow_uuid
- The UUID of the current Workflow- Variable:
workflow_name
- The name of the current Workflow
Functions¶
- chain_info(hops: Union[str, int, list[int]] = 'anyhop') dict ¶
Return a
ChainInfo
object containing Workflow Chain data for the current row.- Parameters:
hops -- the "hops" to grab information for. For instance, if looking for information about the previous node in the experiment chain, "hops" would be
-1
. To fetch all hops in the chain, use"anyhop"
(the default).- Returns:
A dictionary of
int -> ChainInfo
objects, where the key is the "hop" and the value is aChainInfo
object containing Workflow Chain data for the current row. A hop of0
is the current node. Currently, this function will only return upstream Workflow Chain Node information since there are not normally downstream Workflow Chain Node in the Workflow Chain Instance at the point in time where the expression is evaluated.Properties of the returned object:
source_sample_uuid
- the Sample UUID of the current row in the Worksheetsource_sample_name
- the Sample name of the current row in the Worksheetsource_experiment_uuid
- the Experiment UUID of the current row in the Worksheetsource_experiment_name
- the Experiment name of the current row in the Worksheetexperiment_uuid
- the "target" Experiment UUID. For instance, forhops=-1
, it is theexperiment_uuid
of the previous Experiment in the Workflow Chain.experiment_name
- the "target" Experiment name. For instance, forhops=-1
, it is theexperiment_uuid
of the previous Experiment in the Workflow Chain.def_name
- Workflow Chain Definition namedef_uuid
- Workflow Chain Definition UUIDinstance_name
- Workflow Chain Instance nameinstance_uuid
- Workflow Chain Instance UUIDsource_node_name
- source Workflow Chain Node name. Source Workflow Chain Node is the "query root" Workflow Chain Node.source_node_uuid
- source Workflow Chain Node UUIDnode_name
- upstream Workflow Chain Node namenode_uuid
- upstream Workflow Chain Node UUIDwf_name
- upstream Workflow Definition namewf_uuid
- upstream Workflow Definition UUIDhops
- how many hops upstream this Workflow Chain Node is from the source Workflow Chain Node
Note
This expression is only safe for use in the LIMS context.
Examples
Given a Workflow Chain for "My Chain":
My Chain: chain: - Node A: workflow: WF A to: Node B - Node B: workflow: WF B to: Node C - Node C: workflow: WF C
And that Workflow "WF B" has a Protocol of type "Sample Protocol", suppose a User has submitted Sample "S1" in an Experiment "My Experiment" and then progressed the Sample "S1" through to Workflow Chain Node "Node C". In the process, the user created Sample "S2" as a child of Sample "S1". Furthermore, the individual Experiments at each Workflow Chain Node were named "My Experiment - A", "My Experiment - B", and "My Experiment - C". Then the following Expressions, evaluated in the context of a Worksheet "WF C" would evaluate as noted:
{{ chain_info()[-1].hops }} --> -1 {{ chain_info()[-1].source_sample_name }} --> 'S2' {{ chain_info()[-1].source_experiment_name }} --> 'My Experiment - C' {{ chain_info()[-1].experiment_name }} --> 'My Experiment - B' {{ chain_info()[-1].def_name }} --> 'My Chain' {{ chain_info()[-1].instance_name }} --> 'My Experiment' {{ chain_info()[-1].source_node_name }} --> 'Node C' {{ chain_info()[-1].node_name }} --> 'Node B' {{ chain_info()[-1].wf_name }} --> 'WF B' {{ chain_info()[-2].hops }} --> -2 {{ chain_info()[-2].source_sample_name }} --> 'S2' {{ chain_info()[-2].source_experiment_name }} --> 'My Experiment - C' {{ chain_info()[-2].experiment_name }} --> 'My Experiment - A' {{ chain_info()[-2].def_name }} --> 'My Chain' {{ chain_info()[-2].instance_name }} --> 'My Experiment' {{ chain_info()[-2].source_node_name }} --> 'Node C' {{ chain_info()[-2].node_name }} --> 'Node A' {{ chain_info()[-2].wf_name }} --> 'WF A' # Will raise a Key Error. {{ chain_info(-1)[-2].wf_name }}
- cell(column: str, protocol: Optional[str] = None, generation: int = 0) str ¶
Retrieve a value from a LIMS cell.
- Parameters:
column -- The column containing the desired values
protocol -- Name of the Protocol containing the column. If
protocol
isNone
, the current protocol is used.generation -- Where in the sample-lineage to look for a value.
0
is "the uuid of the Entity in the current protocol"-1
is the parent,-2
the grandparent, etc. Values > 0 are not supported at this time.generation
should only be used when grabbing data from a Protocol that is not present in the current Workflow.
- Returns:
The associated cell value, as a string.
Examples:
# Returned from the active protocol. {{ cell('Concentration') }} --> '35' # Returned from the "QC" protocol, either in the same workflow, # or from another workflow run on the same Entity. {{ cell('Concentration', 'QC') }} --> '35' # Returned from the "QC" protocol from a workflow run on the # parent of the current Entity {{ cell('Concentration', 'QC', -1) }} --> '35'
Note
The function prefers Protocol + column combinations in the current Workflow first, regardless of the
generation
setting. If a matching Protocol and column can't be found in the current Workflow, other Workflows will be searched, usinggeneration
to determine the correct sample id.The lookup across other Workflows will return the most recent, non-null value recorded in the specified
generation
.Using the returned value in non-string context requires explicit type-casting, as in:
{{ int(cell('Concentration'))/35 }}
This function used to be called
column_value
. The older reference is still supported for backwards compatibility, butcell
is the preferred name for the function as of L7|ESP 2.3.0.Deprecated Aliases:
column_value
- column_value_for_uuid(uuid: Union[str, list[str]], column: str, protocol: str, generation: int = 0) Union[str, list[str]] ¶
Fetch a LIMS cell value outside of LIMS context.
- Parameters:
uuid -- The UUID of the Entity to pull data for.
column -- The name of the column to pull data from.
protocol -- The name of the Protocol to pull data from.
generation -- Which Entity "generation" should have the requested LIMS value, where
0
= current Entity,-1
= parent Entity,-2
= grandparent, etc.
- Returns:
Associated column value, as a string or
None
(uuid=str
), or list of strings, possibly with null values (uuid=list[str]
).None
is used for Entities lacking the requests field. If the Entity lacks the requested field,None
is returned for that Entity, If multiple matches are found, returns the most recently updated non-null value.
Note
The difference between
cell
andcolumn_value_for_uuid
: The former should be used for Entities which are submitted to the worksheet whereascolumn_value_for_uuid
should be used to pull values from an arbitrary Entity UUID. For instance, if a drop-down in a workflow allows you to select a Entity based on some criteria (e.g.: EntityType), and you need another column to fetch values for a particular Protocol for the selected Entity.
- column_values(column: str, protocol: str = None) list ¶
Fetch all values from a LIMS field within the Worksheet.
- Parameters:
column -- The name of the column to pull data from.
protocol -- The name of the Protocol to pull data from. If
protocol
is unspecified, default to the Protocol that contains the function call.
- Returns:
Associated column values, as a list of strings.
Examples:
# Returned from active protocol {{ column_values('Concentration') }} --> ["35", "42", ...] # Returned from the "QC" protocol in the same workflow {{ column_values('Concentration', 'QC') }} --> ["35", "42" ...] # Returns the lowest concentration {{ min([float(x) for x in column_values('Concentration', 'QC')]) }}
Note
This function only returns values from Protocols and columns within the Worksheet being processed.
- experiment_name(self) str ¶
Get the current Entity's Experiment (WorkflowInstance) name
- Returns:
Name of the Experiment the current Entity is part of
Examples:
{{ experiment_name() }} --> 'Experiment 01'
- experiment_uuid(self) str ¶
Get the current Entity's Experiment (WorkflowInstance) uuid.
- Returns:
UUID of the Experiment the current Entity is part of
Examples:
{{ experiment_uuid() }} --> 'e6a1e079-dde1-4f3c-935d-fd6f3774f459'
- group_values(protocol: str, column: str) list ¶
Get the value of a column for all Entities in a single group of a grouped Protocol
- Parameters:
protocol -- The name of the Protocol to get values from, relative to the current Workflow. If
protocol
isNone
, the current Protocol is used.column -- The column containing the desired values
- Returns:
Column values for all the Entities in the current row's group.
Examples:
{{ group_values('Plate Prep', 'Wells') }} --> ['A1', 'B12', 'C9']
Note
This function is used to get the individual values for each Entity in an Entity Group from a column in the current Protocol (or another Protocol in the same Workflow).
Return the column values for all Entities in the Entity Group as a list. Values are added to the list based on the Entity order, so two lists of values can be zipped together to get multiple values for each Entity.
- is_node_selected(protocol: str = None, column: str = None, choices: Union[str, list[str]] = None, include_failed: bool = None) bool ¶
Workflow Chain Transition Rule function that returns
True
if the option(s) selected by the user matches the target Workflow Chain Node name- Parameters:
protocol -- In conjunction with
column
, where to grab the "Next Workflow" selection(s) from. Defaults to the final Protocol in the Workflow. Uses fixed ID.column -- The column to grab the "Next Workflow" selection(s) from. If unspecified, will try to use "next step", "next workflow", and "next action" in turn (case-insensitive). Uses fixed ID.
choices -- The option or options selected by the user for downstream transition. If
choices
is specified, it overridesprotocol
andcolumn
. Uses Workflow Chain Node name, NOT fixed ID.include_failed -- If
True
, failed samples are considered for the transition. IfFalse
, failed samples are specifically excluded. A value ofNone
triggers the default behavior - if the transition strategy is'resubmit'
, failed samples are considered, otherwise they are not.
- Returns:
True
if the target Workflow Chain Node was selected by the user andFalse
otherwise.
Examples
Given the same Workflow Chain configuration:
My Chain: chain: X: to: Y: if: "{{ is_node_selected() }}" Z: if: "{{ is_node_selected() }}"
With various values of the "Next Action" column from "Last Protocol"
# single-select picklist. {{ cell("Next Action", "Last Protocol") }} --> 'Y' # evaluated in the context of the "X->Y" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> True # evaluated in the context of the "X->Z" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> False # single-select picklist. {{ cell("Next Action", "Last Protocol") }} --> 'Z' # evaluated in the context of the "X->Y" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> False # evaluated in the context of the "X->Z" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> True # multi-select picklist. {{ cell("Next Action", "Last Protocol") }} --> ['Y', 'Z'] # evaluated in the context of the "X->Y" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> True # evaluated in the context of the "X->Z" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> True # multi-select picklist. {{ cell("Next Action", "Last Protocol") }} --> [] # evaluated in the context of the "X->Y" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> False # evaluated in the context of the "X->Z" transition. {{ is_node_selected(choices=cell('Next Action', 'Last Protocol')) }} --> False # Shorthand. Only works if protocol and column are in the current workflow. {{ is_node_selected('Last Protocol', 'Next Action') }} # Shortest shorthand. Will look for "Next Action", "Next Workflow" or "Next Step" # column in the last protocol of the workflow. {{ is_node_selected() }}
Note
This function is only useful in the context of transitioning a Workflow Chain (the transition "rule" expression). In every other context, the returned value will be
False
.This function pairs well with drop-down/multi-select columns using the
next_node_choices()
Expression function to create the options list.When
choices
is a string, this function will first attempt to JSON-decode the string in the event it is a JSON-encoded list.
- mes_ref(field: str = None, protocol: str = None, workflow: str = None, step: str = None, member: str = None) str ¶
Get a label for a numbered process element
- Parameters:
field -- The barcode of the field to reference. If
field
is unspecified, specifically return a Protocol reference.protocol -- The barcode of the Protocol to reference. If
protocol
is unspecified, default to the Protocol that contains the function call.workflow -- The barcode of the Workflow to reference. If
workflow
is unspecified, default to the Workflow that contains the function call.step -- The name of the step to reference. If
step
is unspecified, specifically return a Protocol reference.member -- The barcode of the WorkflowChain node to reference. If
member
is unspecified, default to the node that contains the function call.
- Returns:
Reference as a string in the form
'ELEMENT_NUMBER NAME'
.
Examples:
# Returned field from active protocol. {{ mes_ref('Concentration') }} --> "1.2.2.1 Concentration" # Returned field from the "QC" protocol in the active workflow. {{ mes_ref('Concentration', 'QC') }} --> "1.1.3.1 Concentration" # Returned the "QC" protocol from the active workflow. {{ mes_ref(protocol='QC') }} --> "1.1 QC"
Note
The function prefers
field
,protocol
, or (protocol
+field
) combinations in the current Workflow.
- nearest_upstream_entity(upstream_node: str) Optional[list[str]] ¶
Find the Entity or Entities from the upstream Workflow Chain Node connected to the current sample
- Parameters:
upstream_node -- Fixed ID for the upstream Workflow Chain Node.
- Returns:
List of UUIDs for the upstream Entity
Note
This function only makes sense in the context of Workflow Chains. The nearest upstream Entity is the Entity from which the current row is derived, traced through upstream Workflow Chain Transitions.
Examples:
{{ nearest_upstream_sample('Library Pooling') }} --> ['uuid', ...]
Deprecated Aliases:
nearest_upstream_sample
- next_node_choices(drop: Optional[str] = 'Finished', exclude: Optional[str] = None) list ¶
Returns a list of potential choices for the next Workflow Chain Node in the Workflow Chain.
The next choice is based on the active Workflow Chain for a given sample.
May only be used in the context of LIMS.
- Parameters:
drop -- A label that, if selected, means the sample will not be routed to any further Workflows. Default value is
"Finished"
. IfNone
, only valid downstream Workflow Chain Node names will be available for selection.exclude -- A list of Workflow Chain Node choices to exclude from the drop-down. Useful in situations where a Workflow Chain Transition is present for logical clarity but will never be directly "followed" (such as split/merge chains:
a -> b, a -> c, b -> d; c -> d
).
- Returns:
The list of Workflow Chain Nodes (names, not fixed IDs) downstream from the current Workflow for the current Entity row in the Worksheet, lexicographically sorted.
Examples:
Give a **Workflow Chain** configuration of: My Chain: chain: X: to: Y: if: "{{ True }}" Z: if: "{{ False }}" {{ next_node_choices() }} --> ['Finished', 'Y', 'Z'] {{ next_node_choices(drop=None) }} --> ['Y', 'Z'] {{ next_node_choices(drop='Stop Processing') }} --> ['Stop Processing', 'Y', 'Z']
Note
The returned list of options will use the Workflow Chain Node names, not the Workflow name.
This function makes certain assumptions about the context in which it is called. Generally, it should only be used in Protocols that use the same sample set as the last Protocol in a Workflow.
The next choice is based on the active Workflow Chain for a given Entity. May only be used in the context of LIMS
- next_node_choices_ht(drop: Optional[str] = 'Finished', exclude: Optional[str] = None) list ¶
Returns a list of potential choices for the next Workflow Chain Node in the Workflow Chain.
The next choice is based on the active Workflow Chain for a given sample.
May only be used in the context of LIMS.
- Parameters:
drop -- A label that, if selected, means the sample will not be routed to any further Workflows. Default value is
"Finished"
. IfNone
, only valid downstream Workflow Chain Node names will be available for selection.exclude -- A list of Workflow Chain Node choices to exclude from the drop-down. Useful in situations where a Workflow Chain Transition is present for logical clarity but will never be directly "followed" (such as split/merge chains:
a -> b, a -> c, b -> d; c -> d
).
- Returns:
The list of Workflow Chain Nodes (names, not fixed IDs) downstream from the current Workflow for the current Entity row in the Worksheet, lexicographically sorted.
Examples:
Give a **Workflow Chain** configuration of: My Chain: chain: X: to: Y: if: "{{ True }}" Z: if: "{{ False }}" {{ next_node_choices_ht() }} --> ['Finished', 'Y', 'Z'] {{ next_node_choices_ht(drop=None) }} --> ['Y', 'Z'] {{ next_node_choices_ht(drop='Stop Processing') }} --> ['Stop Processing', 'Y', 'Z']
Note
The returned list of options will use the Workflow Chain Node names, not the Workflow name.
This function makes certain assumptions about the context in which it is called. Generally, it should only be used in Protocols that use the same sample set as the last Protocol in a Workflow.
The next choice is based on the active Workflow Chain for a given Entity. May only be used in the context of LIMS
This function is supposed to be a drop-in replacement for next_node_choices, but with better memory, CPU, and time utilization characteristics for high throughput (ht) operations. However, it is provided as an experimental expression at this time. If it proves sufficiently stable and performant, it will replace the original next_node_choices with an alias for
next_node_choices_ht
for backwards compatibility. So it is safe to try this expression and, if it is working for you, continuing to use the expression indefinitely.
- project_name(self) str ¶
Project name associated with LIMS row
- Returns:
Name of the Project the current Sample/Experiment is submitted to.
- Examples::
{{ project_name() }} --> 'Project 01'
- row_count(self) int ¶
- Returns:
The number of rows in the active protocol
Examples:
{{ row_count() }} --> 96
- tagged_mes_ref(tags: list) str ¶
Get a label for an upstream numbered process element by tag list.
- Parameters:
tags -- The list of tags. An element must match all tags to match.
- Returns:
Reference as a string in the form
'ELEMENT_NUMBER NAME'
.
Examples:
# assuming the illumina kit field was the first field in the first protocol. {{ tagged_mes_ref(['esp:illumina', 'esp:kit']) }} --> "1.1.1.1 Kit"
Note
Steps are untaggable so they cannot be referenced by this function.
- TaggedMESReference.api_func(tags: list[str]) str ¶
Return a reference string to a field, protocol, or workflow.
- tagged_value(tags: list, generation: Union[str, int] = 0, sample_uuid: Union[str, list[str]] = None) Union[str, list[str]] ¶
Get values by tag
- Parameters:
tags -- The list of tags. A column must match all tags to match.
generation -- Where in the sample-lineage to look for a value.
0
is "the uuid in the current protocol,"-1
is the parent,-2
the grandparent, etc. Any value supported bysample_generation
may be used here.sample_uuid -- sample UUID(s) to use. If
None
, assumed to beself.ctx['sample']['uuid']
. If a list of UUIDs is provided, the result will be a list with corresponding results for each UUID.
- Returns:
Corresponding column value, as a string.
Examples:
# assuming the Illumina kit value was set to iTru for this sample most recently. {{ tagged_value(['esp:illumina', 'esp:kit']) }} --> "iTru"
Note
tagged_value
will look at LIMS values and entity custom fields. It is intended to be used in situations where a value may come from different "upstream" sources depending on the exact history of the entity.
- value_grouped_by(protocol: str, column: str, group_by: list) list ¶
Fetch list of values from the active LIMS Worksheet using custom grouping.
- Parameters:
protocol -- Name of the Protocol that contains
column
column -- Name of the column within
protocol
that contains the values to be groupedgroup_by -- list of
(protocol name, column name)
tuples that define the columns to group by.
- Returns:
A list of lists based on multiply and arbitrarily grouped column values.
Examples:
# would return uuid as grouped by protocol1.column1 (primary) and # protocol2.column2 (secondary). the number of lists returned is equal # to the length of the cartesian product of grouping column values. {{ value_grouped_by('protocol', 'uuid', [('protocol1', 'column1'), ('protocol2', 'column2')]) }} # returns [['uuid1', 'uuid2', ...], ['uuidn', 'uuidm', ...], ...] # Where the # of innert lists is equal to the number of "Well Group" values # in the "Sample Setup" sheet. {{ value_grouped_by('uuid', [('Sample Setup', 'Well Group')]) }}
Note
Can only be used for Protocols in the same Worksheet as the expression. Can only be used for Protocols where the sample set size of all grouping columns and the value column is the same.
- chain_cell(protocol: Union[str, list[str]], column: str, nodes: Union[str, list[str]] = None, hops: Union[int, list[int], str] = None, all_values: bool = False) Union[str, list[str]] ¶
Return a value from the Workflow Chain.
For values within the same Protocol or Workflow, use
cell
. If fetching the most-recently-set value for an Entity for a particular Protocol and column is sufficient, usecell
ortagged_value
. Usechain_cell
only if you must guarantee strict provenance of the source value. Furthermore,chain_cell
can currently only be used to fetch values across Workflow Chain boundaries where the Entity in the source Workflow Chain Node is the same Entity in the target Workflow Chain Node or when there's a direct ancestry relationship between them (parent-child, grandparent-grandchild, etc.).- Parameters:
protocol -- name(s) of the upstream Protocol(s) to look in for
column
.column -- name of the column
nodes -- name(s) of the Workflow Chain Node to fetch the value from. The fetched value will be the closest Workflow Chain Node up the realized Workflow Chain with matching name (unless
hops
is specified)."anynode"
is a valid value to ignore Workflow Chain Node entirely.hops -- upstream "hops" to consider. The current Workflow Chain Node is
hop == 0
, One Workflow Chain Node "up" from the current node is-1
, etc."anyhop"
is a valid value to ignore hops entirely.all_values -- If
True
, returns a list of values that match the criteria. IfFalse
, returns the value from the most recent Workflow Chain Node that matches the other criteria.
- Returns:
A string (all_values=False) or list of strings (all_values=True) of values.
- Return type:
Union[str, list[str]]
Examples:
# In this example, there is a Workflow Chain with a Workflow Chain Node "My Node" that has been visited three times so far. # The last time it was visited was the Workflow Chain Node immediately before the current Workflow Chain Instance. # It was visited in a loop three times in a row. {{ chain_cell("My Protocol", "My Column", "My Node", "anyhop", True) }} --> ["first", "second", "third"] {{ chain_cell("My Protocol", "My Column", "My Node", "anyhop", False) }} --> "third" {{ chain_cell("My Protocol", "My Column", "My Node", -1) }} --> "third" {{ chain_cell("My Protocol", "My Column", "My Node", -3) }} --> "first"
- chain_cell_ht(protocol: Union[str, list[str]], column: Union[str, list[str]], nodes: Union[str, list[str]] = None, hops: Union[int, list[int], str] = None, all_values: bool = False) Union[str, list[str]] ¶
Return a value from the Workflow Chain.
For values within the same Protocol or Workflow, use
cell
. If fetching the most-recently-set value for an Entity for a particular Protocol and column is sufficient, usecell
ortagged_value
. Usechain_cell
only if you must guarantee strict provenance of the source value. Furthermore,chain_cell
can currently only be used to fetch values across Workflow Chain boundaries where the Entity in the source Workflow Chain Node is the same Entity in the target Workflow Chain Node or when there's a direct ancestry relationship between them (parent-child, grandparent-grandchild, etc.).- Parameters:
protocol -- name(s) of the upstream Protocol(s) to look in for
column
.column -- name of the column
nodes -- name(s) of the Workflow Chain Node to fetch the value from. The fetched value will be the closest Workflow Chain Node up the realized Workflow Chain with matching name (unless
hops
is specified)."anynode"
is a valid value to ignore Workflow Chain Node entirely.hops -- upstream "hops" to consider. The current Workflow Chain Node is
hop == 0
, One Workflow Chain Node "up" from the current node is-1
, etc."anyhop"
is a valid value to ignore hops entirely.all_values -- If
True
, returns a list of values that match the criteria. IfFalse
, returns the value from the most recent Workflow Chain Node that matches the other criteria.
- Returns:
A string (all_values=False) or list of strings (all_values=True) of values.
- Return type:
Union[str, list[str]]
Examples:
# In this example, there is a Workflow Chain with a Workflow Chain Node "My Node" that has been visited three times so far. # The last time it was visited was the Workflow Chain Node immediately before the current Workflow Chain Instance. # It was visited in a loop three times in a row. {{ chain_cell("My Protocol", "My Column", "My Node", "anyhop", True) }} --> ["first", "second", "third"] {{ chain_cell("My Protocol", "My Column", "My Node", "anyhop", False) }} --> "third" {{ chain_cell("My Protocol", "My Column", "My Node", -1) }} --> "third" {{ chain_cell("My Protocol", "My Column", "My Node", -3) }} --> "first"
- hhmm_add(first: str, second: str) str ¶
Compute a time addition
- Parameters:
first -- The first time, in
HH:MM
format.second -- The second time, in
HH:MM
format.
- Returns:
The sum of the first and second times as a
HHMM
formatted string.
Examples:
{{ hhmm_add('13:05', '01:05') }} --> "1410"
Note
This function should only be used when it is certain you won't wrap the time to a new day. i.e. adding 2 hours to 23:00 is not supported.
- hhmm_diff(first: str, second: str) int ¶
Compute a difference in times
- Parameters:
first -- The first time, in
HH:MM
format.second -- The second time, in
HH:MM
format.
- Returns:
The difference between the first and second times, in seconds
Examples:
{{ hhmm_diff('13:05', '13:10') }} --> 300
Note
The times are assumed to occur on the same day.
- plate1536() list[str] ¶
Return a list of well names for a 1536-well plate.
Convenience wrapper for:
plate_wells(32, 48)
- plate24() list[str] ¶
Return a list of well names for a 24-well plate.
Convenience wrapper for:
plate_wells(4, 6)
- plate384() list[str] ¶
Return a list of well names for a 384-well plate.
Convenience wrapper for:
plate_wells(16, 24)
- plate96() list[str] ¶
Return a list of well names for a 96-well plate.
Convenience wrapper for:
plate_wells(8, 12)
- plate_wells(rows: int, cols: int) list[str] ¶
Enumerate a list of the well names for a plate with n rows and m columns.
- Parameters:
rows -- The number of rows in the plate
cols -- The number of columns in the plate
- Returns:
A list of well labels for the row-by-column plate.
Examples:
{{ plate_wells(8, 12) }} --> ['A01', 'A02', ... 'H11', 'H12']
Note
plate_wells
and the other plate expressions are useful for building plate manifests for plates that are created and consumed within a Workflow, and are therefore not tracked long-term.
- Q_(value: ~typing.Union[str, ~pint.quantity.build_quantity_class.<locals>.Quantity, ~numbers.Number], units: ~typing.Optional[~typing.Union[~pint.util.UnitsContainer, str, ~pint.quantity.build_quantity_class.<locals>.Quantity]] = None) Quantity ¶
Construct a
Quantity
.- Parameters:
value -- The quantity "value"
units -- The quantity units
Examples:
{{ Q_('35 ul') }} --> 35 <Unit('microliter')> {{ Q_(35, 'ul') }} --> 35 <Unit('microliter')> {{ Q_(35, Q_('50 ul')) }} --> 35 <Unit('microliter')>
6.2.6. Param Group API¶
The Param Group API provides access to parameters stored in Param Groups.
- param(groupname: str, param: str) str ¶
Lookup a parameter from a Param Group.
- Parameters:
groupname -- the name of the Param Group
param -- the parameter name in the Param Group
- Returns:
the value assigned to the key in the Param Group
Examples:
{{ param("References", "Current Human") }} --> 'hg38.fa'
- params(groupname: str) dict ¶
Fetch all parameters of a Param Group
- Parameters:
groupname -- the name of the Param Group
- Returns:
the dictionary of key-value pairs in the Param Group.
Examples:
{{ params('References') }} --> {"Current Human": "hg38.fa"}
6.2.7. Resource API¶
The Resource API provides general resource access functionality.
In L7|ESP, nearly everything is a Resource, including but not limited to:
Applets
Container Types
Containers
Entities (samples, assets, etc.)
Entity Classes
Entity Types
Experiments (Workflow Instances and Workflow Chain Instances)
Files
Inventory Item Types
Inventory Items
LIMS Worksheets
ParamGroup
Pipeline Instances
Pipelines
Projects
Protocols
Reports
Tasks
Workflow Chains
Workflows
- resource_dict(resource_uuid: str = None, resource_name: str = None, cls: str = None) dict ¶
Return the full
dict
for a Resource given its UUID or name.- Parameters:
resource_uuid -- The UUID of the Resource
resource_name -- The name of the Resource
cls -- The name of the Resource Class. If none, any Resource type matching the resource name will be returned. Only used in conjunction with
resource_name
. (Since ESP 3.0.0)
- Returns:
The JSON representation of the resource
Examples:
{{resource_dict(sample['sample_type_uuid'])}} -> { "name": "Generic sample", "uuid": "77777777-7777-4014-b701-000000000001", "desc": "Types for samples with no other classification", "meta": {"lab7_id_sequence": ["ESP SEQUENCE"]} }
Note
Either
resource_uuid
orresource_name
is required. If both are specified,resource_name
is ignored.
- session_timestamp(format_: str = None) str ¶
Provide the current UTC timestamp, with optional custom formatting
If no format is provided, result is ISO-8601-formatted. The timestamp is generated when the DB session is created so multiple calls will return the same value if they are made using the same session.
- Parameters:
format -- Optional format string. Default is ISO-8601-formatted. All standard Python format codes are supported.
- Returns:
The formatted date and time, current as of the time of the call.
Examples:
{{ session_timestamp() }} --> '2019-01-03T12:59:28.818039Z' {{ session_timestamp('%Y-%m-%d') }} --> '2019-01-03' {{ session_timestamp('%D') }} --> '01/03/19'
- current_datetime(format_: str = None) str ¶
Provide the current time, with optional custom formatting
If no format is provided, result is ISO-8601-formatted.
- Parameters:
format -- Optional format string. Default is ISO-8601-formatted. All standard Python format codes are supported.
- Returns:
The formatted date and time, current as of the time of the call.
Examples:
{{ current_datetime() }} --> '2019-01-03T12:59:28.818039' {{ current_datetime('%Y-%m-%d') }} --> '2019-01-03' {{ current_datetime('%D') }} --> '01/03/19'
- json_dumps(obj)¶
Convert an object into a JSON string (access to Python's
json.dumps
function).- Parameters:
obj -- Object to dump
- Returns:
The JSON serialization of
obj
.
Examples:
{{ json_dumps({'a': 'b'}) }} --> '{"a": "b"}'
- json_loads(s)¶
Parse a JSON string to object (access to Python's
json.loads
function).- Parameters:
s -- The string to load
- Returns:
The JSON object from the provided string.
Examples:
{{json_loads(param('group1', 'key1'))}} --> {'a': 'b'}
Note
This can be used to parse JSON from a Param Group value, as in the above example.
- resource_link_uuid(value)¶
Extracts the UUID from a resource link field value. If the value is null, empty string, etc., returns an empty string instead.
6.2.8. Entity API¶
The Entity API provides access to functionality, specific to working with Entities.
- entity_children(entity_uuid: str, flatten: bool = False) Union[list[dict[str, Any]], list[tuple[dict[str, Any], str]]] ¶
Fetch an Entity's children
- Parameters:
entity_uuid -- UUID of the parent Entity
flatten (
bool
) -- IfTrue
, result is returned as[{entity_dict}, ...]
. Otherwise, as[[{entity_dict}, 'begat'], ...]
. For backwards compatibility,flatten
isFalse
by default.
- Returns:
List of Entity children. The returned structure is identical to that returned by
entity_parents
, but for the Entity's children.
Examples:
{{ entity_children(sample['uuid']) }} --> [[{'uuid': '1abfadd7-5ed4-490c-96fb-a1e74b7b59aa', ...}, 'begat'], ...]
Note
This is a shortcut for
entity_generation(1, entity_uuid, False, flatten)
Deprecated Aliases:
sample_children
- entity_children_uuids(entity_uuid: str) list ¶
Fetch the UUIDs of an Entity's children.
- Parameters:
entity_uuid -- UUID of the parent Entity
- Returns:
Child Entity UUIDs as a list of strings.
Examples:
{{ entity_children_uuids(sample['uuid']) }} --> ['1abfadd7-5ed4-490c-96fb-a1e74b7b59aa', ...]
Note
This is a shortcut for
entity_generation(1, uuid, True, True)
Deprecated Aliases:
sample_children_uuids
- entity_exists(entity_name: str) bool ¶
Determine whether the given Entity exists by name.
- Parameters:
entity_name -- Name of the Entity to check for existence
- Returns:
Returns
True
if the named Entity exists, using exact matching for the Entity name.
Note
This function triggers one query per unique name, so should be used with care.
Deprecated Aliases:
sample_exists
- entity_generation(generation: Union[str, int], sample_uuid: Union[list[str], str] = None, uuids_only: bool = False, flatten: bool = True, traverse_labels: tuple = ('begat',), entity_uuids: Union[list[str], str] = None) Union[list[str], list[dict], list[tuple[dict, str]], list[list[str]], list[list[dict]], list[list[tuple[dict, str]]]] ¶
Fetch a generation of Entities relative to an input Entity
- Parameters:
generation -- The generation to fetch relative the provided or implied Entity UUID. (See note and examples).
sample_uuid -- Alias for
entity_uuids
. Will be removed in a future release. Usekwarg
-based UUIDs instead, as:entity_generation(-1, entity_uuids="UUID here")
uuids_only -- If
False
, a list ofdict
representations of the Entity are returned. IfTrue
, a list of UUIDs is returned.flatten -- If
True
(default) anduuids_only
isFalse
, list is returned as[{entitydict}, ...]
. IfFalse
anduuids_only
isFalse
, list is returned as[[{sampledict}, 'begat'], ...]
.flatten
should normally beTrue
and is provided for backwards compatibility withentity_parents
andentity_children
.entity_uuids -- The UUID of the
generation=0
entity. If unspecified, the expression context is searched in order forentity['uuid']
,entity_uuid
,sample['uuid']
,sample_uuid
. If these are not found, an error is raised.
- Returns:
The return value depends on the call arguments as follows
entity_uuids
flatten
uuids_only
Return Type
str
True
list[str]
str
True
False
list[dict]
list[str]
False
False
list[tuple[dict, str]]
list[str]
True
list[list[str]]
list[str]
True
False
list[list[dict]]
list[str]
False
False
list[list[tuple[dict, str]]]
The generation parameter controls exactly which generation(s) are returned.
0
means get the value from for the providedentity_uuid
,-1
means get it for the parent of the provided UUID,-2
the grandparent,1
the child,2
the grandchild, and so on.Generation may also be a string, in which case it follows the extended regex format
((all|closest|furthest)(up|down))?[^,]+(,[^,]+)*
. For instance:"allup:Specimen"
will return all ancestors of the current entity of typeSpecimen
,"closestup:Specimen"
will return the closest ancestor of typeSpecimen
,"furthestup:Specimen"
will return the most distant ancestors of typeSpecimen
."Specimen"
is equivalent to"closestup:Specimen"
,and multiple types may be comma-delimited, as
"Library,Illumina Library"
which would find the nearest ancestors of typeLibrary
orIllumina Library
.
Note
Multiple Entities may be returned if they fulfill the criteria.
For instance, consider a Entity hierarchy created by making two Illumina libraries, normalizing them, then pooling them:
Library 1 └── Library 3 └── Pool 1 Library 2 └── Library 4 └── Pool 1
Then a search on Pool 1 for non-0 generation returns as follows:
generation=-1
: Library 3 and Library 4generation=-2
: Library 1 and Library 2generation="nearest:Illumina Library"
: same asgeneration=-1
generation="furthest:Illumina Library"
: same asgeneration=-2
generation="all:Illumina Library"
: Libraries 1-4.
Now suppose a scientist has made libraries 5 and 6 with normalized libraries 7 and 8. Then they create Pool 2 by combining libraries 7 and 8 with pool 1, as:
Library 1 └── Library 3 └── Pool 1 └── Pool 2 Library 2 └── Library 4 └── Pool 1 └── Pool 2 Library 5 └── Library 7 └── Pool 2 Library 6 └── Library 8 └── Pool 2
Then a search on Pool 2 for non-0 generation returns as follows:
generation=-1
: Libraries 7 and 8 and Pool 1generation=-2
: Libraries 3 - 6. (3 and 4 via Pool 1)generation="nearest:Illumina Library"
: Libraries 3, 4, 7, and 8 (i.e. all normalized libraries)generation="furthest:Illumina Library"
: Libraries 1, 2, 5, and 6 (i.e. all unnormalized libraries)generation="all:Illumina Library"
: Libraries 1-8
Note
This function uses a recursive query and will pre-cache the results for all Entity in a Worksheet if the
sample_sets
andsample_set_index
keys are in the context and theentity_uuid
is unspecified or theentity_uuid
is equal to thesample['uuid']
orsample_uuid
context variables. Otherwise, one query will be executed per row of the Worksheet, although the resulting value will be cached.Examples:
# fetch the parent(s) of entity in "sample['uuid']" context variable # or "entity_uuid" context variable. {{ entity_generation(-1) }} --> [{"generation": -1, name: "SAM000001", "uuid": <parent uuid>, ...}, ...] # fetch the parent(s) of entity given by <uuid>. {{ entity_generation(-1, '<uuid>') }} --> [{"generation": -1, name: "SAM000001", "uuid": <parent uuid>, ...}, ...] # fetch the grandparent(s) of entity given by <uuid>. {{ entity_generation(-2, '<uuid>') }} --> [{"generation": -2, name: "SAM900001", "uuid": <grandparent uuid>, ...}, ...] # fetch the child/children of entity given by <uuid>. {{ entity_generation(1, '<uuid>') }} --> [{"generation": 1, name: "SAM000009", "uuid": <child uuid>, ...}, ...] # fetch the grandchild/grandchildren of entity given by <uuid>. {{ entity_generation(2, '<uuid>') }} --> [{"generation": 2, name: "SAM000013", "uuid": <grandchild uuid>, ...}, ...] # fetch the parent entity UUIDs. {{ entity_generation(1, uuids_only=True) }} --> ['UUID', ...] # fetch the child entities, unflattened. {{ entity_generation(1, flatten=False) }} --> [[{entity dict}, 'begat'], ...] # Fetch the nearest ``Illumina Library`` ancestors. {{ entity_generation('Illumina Library', '<pool uuid>') }} --> [{"generation": 1, name: "SAM000013", "uuid": <parent uuid>, ...}, ...] # equivalent to above, but explicitly calling out closestup. {{ entity_generation('closestup:Illumina Library', '<pool uuid>') }} --> [{"generation": 1, name: "SAM000013", "uuid": <parent uuid>, ...}, ...] # Fetch the most distant ``Illumina Library` ancestors. {{ entity_generation('furthestup:Illumina Library', '<pool uuid>') }} -->[{"generation": 1, name: "SAM000013", "uuid": <parent uuid>, ...}, ...]
Deprecated Aliases:
sample_generation
- entity_parent_uuids(entity_uuid: str) list ¶
Fetch the UUIDs of an Entity's parents.
- Parameters:
entity_uuid -- UUID of the child Entity
- Returns:
Parent Entity UUIDs as a list of strings.
Examples:
{{ entity_parent_uuids(sample['uuid']) }} --> ['1abfadd7-5ed4-490c-96fb-a1e74b7b59aa', ...]
Note
This is a shortcut for
entity_generation(-1, uuid, True, True)
Deprecated Aliases:
sample_parent_uuids
- entity_parents(entity_uuid: str, flatten: bool = False) Union[list[dict[str, Any]], list[tuple[dict[str, Any], str]]] ¶
Fetch an Entity's parents.
- Parameters:
entity_uuid -- UUID of the child Entity
flatten -- (
bool
) IfTrue
, result is returned as[{entity_dict}, ...]
. Otherwise, as[[{entity_dict}, 'begat'], ...]
. For backwards compatibility, flatten isFalse
by default.
- Returns:
Parent Entities, given an Entity UUID. Parents are returned as a list of entries, in which each entry is a list of two values. The first value is the parent Entity dictionary, and the second value can be ignored.
Examples:
{{ entity_parents(sample['uuid']) }} --> [[{'uuid': '1abfadd7-5ed4-490c-96fb-a1e74b7b59aa', ...}, 'begat'], ...]
Note
This is a shortcut for
entity_generation(-1, entity_uuid, False, flatten)
Deprecated Aliases:
sample_parents
- entity_type_id(sample_type_def_uuid: str = None, sample_uuid: str = None, entity_type_def_uuid: str = None, entity_uuid: str = None) str ¶
Return the human-readable fixed-id for the Entity Type.
- Parameters:
sample_type_def_uuid -- Alias for
entity_type_def_uuid
. Deprecated.sample_uuid -- Alias for
entity_uuid
. Deprecated.entity_type_def_uuid -- UUID of the Entity Type for which to retrieve the ID. Optional. Defaults to the definition UUID for the provided Entity corresponding to the provided
sample_uuid
.entity_uuid -- UUID of the Entity for which to retrieve the Entity Type ID. Only used if
sample_type_def_uuid
is not provided. In LIMS context, defaults to thesample_uuid
of the row being evaluated.
- Returns:
The human-readable fixed ID of the Entity Type for the specified definition UUID or Entity UUID.
Examples:
{{ entity_type_id() }} --> 'Illumina Library' # in LIMS context. {{ entity_type_id(entity_uuid=sample['uuid']) }} --> 'Illumina Library' # in LIMS context. {{ entity_type_id(entity_type_def_uuid=sample['def_uuid']) }} --> 'Illumina Library' # in LIMS context
- Note:
Introduced in 2.4.1.
Deprecated Aliases:
sample_type_id
- entity_type_name(sample_type_def_uuid=None, sample_uuid=None, entity_type_def_uuid: str = None, entity_uuid: str = None) str ¶
Get the Entity Type name of the Entity
- Parameters:
sample_type_def_uuid -- Alias for
entity_type_def_uuid
. Deprecated.sample_uuid -- Alias for
entity_uuid
. Deprecated.entity_type_def_uuid -- UUID of the Entity Type for which to retrieve the name. Optional. Defaults to the definition UUID for the provided Entity corresponding to the provided
sample_uuid
. Alias:sample_type_def_uuid
.entity_uuid -- UUID of the Entity for which to retrieve the Entity Type name. Only used if
sample_type_def_uuid
is not provided. In LIMS context, defaults to the UUID of the entity for the row being evaluated. In particular, the context is searched in order for:entity
,entity_uuid
,sample
,sample_uuid
. Ifentity
orsample
are found in the context, they are assumed to be a dictionary with a keyuuid
.
- Returns:
The name of the Entity Type for the specified definition UUID or Entity UUID.
Examples:
{{ entity_type_name() }} --> "Illumina Library" # in LIMS context. {{ entity_type_name(entity_uuid=sample['uuid']) }} --> "Illumina Library" # in LIMS context. {{ entity_type_name(entity_type_def_uuid=sample['def_uuid']) }} --> "Illumina Library" # in LIMS context
Note
In LIMS context, it is generally more efficient to call
entity_type_name()
for the current row than to callentity_value('entity_type_name')
, though both work. In other contexts, it depends on what other values are required, and the most efficient call may be tosample_generation
to fetch the full sample dictionaries.Deprecated Aliases:
sample_type_name
- entity_types(tags: list = None, namesonly: bool = True) Union[list[str], list[dict[str, Any]]] ¶
Return a list of Entity Types in the system
- Parameters:
tags -- (
List[str]
) List of tags to matchnamesonly -- (
bool
) IfTrue
(default), only Entity Type names are returned. Otherwise, a list of full Entity Typedict
is returned.
- Returns:
A list of Entity Types in the system. If
tags
is supplied, the returned types must match at least one of the tags.
Examples:
entity_types() --> ['Generic sample', 'Illumina Library', ...] entity_types(namesonly=False) --> [{'name': 'Generic sample', 'uuid': ...}, ...] entity_types(['orderable']) --> ['Sanger Sequencing Sample', ...] # only returns **Entity Types** tagged with the "orderable" tag.
Deprecated Aliases:
sample_types
- entity_value(varname: str, sample_uuid: Union[list[str], str] = None, generation: Union[str, int] = 0, index: int = -1, entity_uuids: Union[list[str], str] = None) Union[list[str], str] ¶
Return the value of an Entity field
- Parameters:
varname -- The variable to return. See note for details.
sample_uuid -- alias for
uuids
for backwards compatibility. This argument is deprecated and will be removed in a future release. When it is removed,entity_uuids
will become the second positional parameter. Callers should referenceentity_uuids
by keyword for future-proofing implementations. (i.e.entity_value('name', entity_uuids="...")
)generation -- Any value that can be passed to
sample_generation
can be used here.index -- If multiple samples are present at the specified generation, which of the samples (by index) to use. When the generations is fetched, the are ordered by creation date, so
0
would be the earliest-created sample and-1
would be the most recently created sample at the given generation.entity_uuids -- The UUID(s) of the
generation=0
entity. If unspecified, the expression context is searched in order forentity['uuid']
,entity_uuid
,sample['uuid']
,sample_uuid
. If these are not found, an error is raised. Ifentity_uuids
is a list of UUID strings, a list of values will be returned in the same length and order as the input.
- Returns:
A value or list of values, depending on the shape of
entity_uuids
.
Note
The
varname
can be any custom field fixed ID. It can also be one of:name
- Entity namedesc
- Entity descriptionurl
- (API) URL for the Entitymeta
- meta dict for the Entityuuid
- Entity uuidcls
- Resource Classdeleted
- true if the Entity is archived, false otherwisecreated_at
- created timestampupdated_at
- last modified timestampowner
- name of the current Entity owner (normally the Entity creator)entity_type_uuid
- UUID of the Entity's Entity Typesample_type_uuid
- alias ofentity_type_uuid
for backwards compatibilityentity_type
- UUID of the Entity's Entity Type (alias ofentity_type_uuid
for backwards compatibility)sample_type
- alias ofentity_type
for backwards compatibilityentity_type_name
- Name of the Entity's Entity Typesample_type_name
- alias ofentity_type_name
for backwards compatibilityin_workflow_instance
- whether this Entity has ever been in a workflowbarcode
- the Entity's barcode value.
Examples:
# barcode of current sample. Assumes LIMS context. {{ entity_value('barcode') }} --> "sample barcode" # Return value of "I7 Index" custom field for this sample (LIMS context) {{ entity_value('I7 Index') }} --> "ACGTACAT" # fetch the value of the I7 Index field for the nearest Illumina Library ancestor. LIMS context. {{ entity_value('I7 Index', generation='closestup:Illumina Library') }} --> "ACGTACAT" # fetch the value of the I7 Index field for the nearest Illumina Library ancestor for the provided sample uuids. entity_value('I7 Index', entity_uuids=['uuid1', 'uuid2', ...], generation='closestup:Illumina Library') --> [{"generation": 1, name: "SAM000009", "uuid": <child uuid>, ...}, ...]
Deprecated Aliases:
sample_value
- hid_for_uuid(uuid: str, sequence: str = 'lab7_sample_auto_id_seq', fmt: str = '%d', name: str = None, format_style: str = 'old') str ¶
Generate a human ID for a UUID/Sequence combination. If one already exists, return it.
- Parameters:
uuid -- UUID for which to generate a unique sequence value
sequence_name -- Name of DB Sequence to use for generating sequences
fmt -- A
%
-style Python format string used for formatting the returned value.name -- Provide a namespace for this
hid
. This allows for several distincthid
's to be generated for the same provided UUID.format_style --
"old"
(default) or"format"
. For old-style formatting,%
formatting is used. For"format"
, it usesstring.format
. When using format strings, the next value is available via positional specifiers or via thevalue
variable.
- Returns:
A unique sequence. Multiple calls to
hid_for_uuid
for the sameuuid
+sequence_name
+name
combination will return the same value.
Examples:
{{ str(hid_for_uuid(sample_sheet_uuid, 'lab7_sample_auto_id_seq')) + '_' + str(hid_for_uuid(sample_sheet_uuid, 'lab7_sample_auto_id_seq') }} --> "1234567_1234567" {{ str(hid_for_uuid(sample_sheet_uuid, 'lab7_sample_auto_id_seq', 'name1')) + '_' + str(hid_for_uuid(sample_sheet_uuid, 'lab7_sample_auto_id_seq', 'name1') + str(hid_for_uuid(sample_sheet_uuid, 'lab7_sample_auto_id_seq', 'name2') }} --> "1234568_1234568_1234569" {{ str(hid_for_uuid( sample_sheet_uuid, 'lab7_sample_auto_idd_seq', fmt='ABC%dEFG')) }} "ABC1234567EFG"
Note
The difference between
hid_for_uuid
andsequence_value
is the latter will return a new value for each new invocation, whereashid_for_uuid
only returns a new value if the resource identified by the UUID does not have one yet. This can be used to do things like generate a unique run sheet number, for instance.
- list_entities(sample_type: str, filters: Optional[dict[str, Any]] = None, displayField: str = 'name') list ¶
Returns a list of Entity names for a particular type of Entity
- Parameters:
sample_type -- Name of the Entity Type for which to list Entities
filters -- Additional filters to apply to the list. Valid filters: any filters accepted by
/api/entities
queries. Additionally, any custom field ID is valid.displayField -- Entity field name to use for display. Maybe be one of
name
,desc
,barcode
,uuid
, or a custom field ID.
- Returns:
List of Entity names matching the Entity Type.
Examples:
{{ list_entities('Generic sample') }} --> ['ESP000001', ...] {{ list_entities('Instrument', filters={'instrument_type': 'Centrifuge'}, displayField='My Field') --> ['Centrifuge 1', ...]
Note
The complete list of valid filter keys supported by
list_entities
is:entity_type
(alias:sample_type
) - exact match to Entity Type nameentity_type.like
(alias:sample_type.like
) - case-insensitive wildcard match to Entity Type nameentity_types
(alias:sample_types
) - list of Entity Type names (exact match)entity_type_uuids
(alias:sample_type_uuids
) - list of Entity Type UUIDsentity_class
(alias:workflowable_resource_class
) - exact match to Entity Class nameentity_class.like
(alias:workflowable_resource_class.like
) - case-insensitive wildcard match to Entity Class nameentity_class_uuid
(alias:workflowable_resource_class_uuid
) - Entity Class UUIDuuid
- Entity UUIDuuids
- list of Entity UUIDsname
- exact match to Entity namenames
- exact match to list of Entity namesname.like
- case-insensitive wildcard match to Entity namedesc
- exact match to Entity descriptiondesc.like
- case-insensitive wildcard match to Entity descriptionbarcode
- exact match to Entity barcodebarcode.like
- case-insensitive wildcard match to Entity barcodebarcodes
- exact match to list of Entity barcodescls
- match Entitycls
attributeclses
- match list of Entitycls
attributecreated_before
- match before this date, up to the date.created_after
- match after this date, down to the dateowner
- exact match to name of Entity creatorowner.like
- case-insensitive wildcard match to name of Entity creatortags
- case-insensitive exact-match to any of tags in the list of tagsalltags
- case-insensitive exact-match to all tags in the list of tagsusername
- Same asowner
username.like
- same asowner.like
Deprecated Aliases:
list_samples
- sequence_value(sequence: str = 'lab7_sample_auto_id_seq', fmt='%d', format_style: str = 'old') str ¶
Generate a formatted string from the next value in a user-defined Sequence.
The default result is simply
str(next_value())
.- Parameters:
sequence_name -- The name of the (DB) Sequence from which to generate values
fmt -- A Python format-string specifier.
format_style --
"old"
(default) or"format"
. For old-style formatting, % formatting is used. For"format"
, it usesstring.format
. When using format strings, the next value is available via positional specifiers or via thevalue
variable (see examples).
- Returns:
The next value in the named Sequence of values.
Examples:
{{ sequence_value('lab7_sample_auto_id_seq') }} --> '25' {{ sequence_value('lab7_sample_auto_id_seq, 'ABC_%d') }} --> 'ABC_26' {{ sequence_value('lab7_sample_auto_id_seq, 'ABC_{}') }} --> 'ABC_27' {{ sequence_value('lab7_sample_auto_id_seq, 'ABC_{value}') }} --> 'ABC_28'
Note
By default, the max value of a sequence as returned by L7|ESP is 2^63-1, or about 9.2 quintillion. (9.2*10^18).
6.2.9. User API¶
The User API supports operations related to L7|ESP Users. This API currently adds a single function to the expression language.
- current_user(include_email: bool = True) str ¶
Returns the name of the current User
- Parameters:
include_email -- (bool) whether to include the current User's e-mail in the return value (default:
True
) returned.- Returns:
The current User's name as a string, either
"user['name']"
or"user['name'] (user['email'])"
depending on the value ofinclude_email
.
Examples:
{{ current_user() }} --> "system admin (admin@localhost)" {{ current_user(false) }} --> "system admin"
- user_names(include_email: bool = True) list ¶
Return a list of the User names in the system.
- Parameters:
include_email -- whether to include email in the output (default:
True
)- Returns:
A list of all users in the system, including their e-mails.
Examples:
{{ user_names() }} --> ['system admin (admin@localhost)'] {{ user_names(False) }} --> ['system admin']
- workgroup_user_names(workgroup: str = None) list ¶
Return a list of the User names in the system tied to a particular Workgroup.
- Parameters:
workgroup -- (String) Name of the Workgroup to filter on. Optional. If unspecified, all Users will be returned.
- Returns:
A list of Users that belong to the specified Workgroup.
Examples:
{{ workgroup_user_names() }} --> ['User 1', 'User 2', ...] # Equivalent to `user_names()` {{ workgroup_user_names('QA') }} --> ['QA User 1', 'QA User 2'] # Only Users belonging to the "QA" Workgroup.
6.2.10. Location API¶
The Location API supports operations related to L7|ESP containers/locations.
- formatted_location(value: Union[str, dict[str, Any]]) str ¶
Expression call that returns a "pretty" LIMS Location cell value (
container name: <slot>[,...]
)- Parameters:
value -- The Location value to format, as a Python object or a JSON string.
- Returns:
A string showing the Container and slot names that contain the row under consideration.
Examples:
{{ formatted_location(cell('Location', 'Matrix 2D Details')) }} --> 'Plate X: A01'
Note
The rendered value looks similar or identical to that used by the native Location renderer column, but can be used in circumstances that the Location may be exported to external software to avoid exposing the internal JSON structure of how Locations are stored.
- location_name(value: Union[str, dict[str, Any]], container: int = 0) str ¶
Expression call that returns the name of a Location
- Parameters:
value -- The Location value to format, as a Python object or a JSON string
container -- The Container index to use. The underlying Container information format allows for associating multiple Containers with a single value, so Container is the index of the stored Container. Normally, this will be
0
. If the value is-1
, all associated Container names will be returned in a comma-separated list.
- Returns:
The name of the Container for the Location
Examples:
{{ location_name(cell('Location', 'Matrix 2D Details')) }} --> 'Plate X'
- location_path(location: Union[str, dict[str, Any]], levels: Union[str, list[int]] = '*') str ¶
Return the Container path given a particular location field value.
- Parameters:
location -- A Location cell value
levels -- One of
"*"
(all levels) or a list of levels e.g.[-1]
,[0, -1]
, where"0"
is the immediate location of the sample.
- Returns:
The Container path given a particular location field value.
Note
Container path will be in the format
container:slot -> container:slot -> ...
Examples:
# Examples assume a sample in slot A-A of Cryobox 1, which is in Rack position A1 of Rack 3, # which is in shelf 2 of freezer 4, and given a **Location** column named ``Location`` # which has the ``Cryobox 1 (A-A)`` location: {{ container_path(cell('Location')) }} --> 'freezer f:shelf 2 -> Rack 3:A1 -> Cryo Box 1:A-A' {{ container_path(cell('Location'), [0, -1]) }} --> 'Rack 3:A1 -> Cryo Box 1:A-A' {{ container_path(cell('Location'), [-2]) }} --> 'freezer f:shelf 2'
Deprecated Aliases:
container_path
- location_slot(value: Union[str, dict[str, Any]], container: int = 0, slot: int = 0) str ¶
Expression call that returns the "slot" for a Location
- Parameters:
value -- The Location value to format, as a Python object or a JSON string
container -- The container index to use. If the value is
-1
, the requested slot from all associated containers are returned as a comma-separated list. This will normally be0
.slot -- The slot index to use. If the value if
-1
, all slots from the requested container(s) are returned as a comma-separated list. This will be0
for common use-cases, such as a 96-well plate.
Examples:
{{ location_slot(cell('Location', 'Matrix 2D Details')) }} --> 'A01'
6.2.11. Inventory API¶
The inventory API supports operations related to inventory management, ordering, customers, etc.
- customers(self) list ¶
Get the list of known Customers.
- Returns:
A list of all Customer names in the system. If one of the current User's Workgroup names matches a Customer name, that name will be first in the list. Otherwise, the names are lexicographically ordered.
Note
This call will attempt to order the list so that the first Customer corresponds to a Workgroup the current User is in.
Deprecated Aliases:
customer_list
- item_status_options(self) list ¶
Return valid inventory item status options for this ESP Configuration.
- Returns:
The list of valid options, as read from the "statuses" key of the "inventory" configuration object. If the configuration or key is not found, returns the default status list:
['Quarantined', 'Recalled', 'Missing', 'Pending Verification', 'Verified']
- item_type_vendors(item_type: Union[str, Any] = None, names_only: bool = True) Union[list[str], list[dict[str, Any]]] ¶
Get list of valid vendors for an item type
- Parameters:
item_type -- The item type to get the vendors for. If not supplied, the context is examined for
sample_type_uuid
in thesample
context object. May be an item type UUID, name, or ItemType.names_only -- Whether to return only names or a full vendor object.
- Returns:
A list of valid vendor names (names_only=True) or vendor dictionaries (names_only=False) for the specified item type.
- service_types(names_only: bool = True) list ¶
Get the list of Service Types
- Parameters:
names_only -- If true, only Service Type names are returned. If false, additional Service Type data is returned.
- Returns:
A list of all Service Types in the system, either a list of names (
names_only=True
), or a list of JSON dictionaries with additional information, such as the base price, the price type, the scale price, the scale units, and any customer-specific pricing.
6.2.12. Project API¶
The project API supports operations related to projects.
- project_list(tags: list = None, namesonly: bool = True) Union[list[str], list[dict]] ¶
Fetch a list of projects
- Parameters:
tags -- List of tags for filtering the project list
namesonly -- Whether to return only names or the project list.
- Returns:
A list of projects or project names.
Examples:
# name of every project in the system. project_list() --> ['Project 1', 'Project 2', ...] # only projects tagged with study1 project_list(['study1']) --> ['Project 739', 'Project 740'] # full object dictionaries. project_list(namesonly=False) --> [{'name': 'Project 1', ...}, ...]
6.3. Expression Language Restrictions¶
For security purposes, the L7|ESP Expression Language only supports a subset of Python language features and standard library calls.
The following is a list of Python language features that are not allowed in L7|ESP Expression:
Any multi-statement command or block construct (e.g.,
if
,for
,while
,try
, etc). If the user cannot form a task on one line in Python, it will not be accepted.Generator expressions
Class (
class
) and function definitions (def
)Decorators
return
statementsAssignment (
=
)Explicit Assertions and exceptions
Code execution, including backquote statements and
exec
callsModule manipulation, including
from
andimport
Keywords typically used in block scoping such as
global
andwith
The following is a list of standard library calls and system-level objects that are not allowed in an L7|ESP Expression:
__import__
reload
compile
eval
execfile
globals
locals
vars
callable
isinstance
issubclass
super
type
id
dir
delattr
setattr
getattr
hasattr
classmethod
property
staticmethod
KeyboardInterrupt
SystemExit
buffer
memoryview
file
open
input
raw_input
apply
intern
print