Expressions

Expressions are Python code snippets that compute dynamic values, which can be referenced in operation steps using template syntax.

Basic Usage

Define expressions that evaluate to values:

dyngle:
  operations:
    greet:
      expressions:
        greeting: "'Hello ' + name + '!'"
      steps:
        - echo "{{greeting}}"

Run it:

echo "name: Alice" | dyngle run greet

Output:

Hello Alice!

Expression Scopes

Global Expressions

Defined under dyngle: and available to all operations:

dyngle:
  expressions:
    timestamp: "datetime.now()"
    author: "'Francis Potter'"
  operations:
    log:
      - echo "[{{timestamp}}] Log by {{author}}"

Local Expressions

Defined within a specific operation:

dyngle:
  operations:
    say-hello:
      expressions:
        count: len(name)
      steps:
        - echo "Hello {{name}}! Your name has {{count}} characters."

Local expressions override global expressions with the same name.

Expression Context

Expressions evaluate in a context that includes:

  • Data values - Referenced directly as Python variables
  • Built-in functions - len(), str(), etc.
  • Standard library modules - datetime, math, etc.
  • Special functions - get(), format(), dtformat(), Path()
  • Command arguments - Available as the args array

Referencing Data

Data values can be referenced directly:

dyngle:
  operations:
    greet:
      expressions:
        message: "'Hello ' + name"
      steps:
        - echo "{{message}}"

Hyphenated Names

YAML keys can contain hyphens. To reference them in expressions:

Option 1: Replace hyphens with underscores:

dyngle:
  operations:
    greet:
      expressions:
        message: "'Hello ' + first_name"  # References 'first-name'
      steps:
        - echo "{{message}}"

Option 2: Use the get() function:

dyngle:
  operations:
    greet:
      expressions:
        message: "'Hello ' + get('first-name')"
      steps:
        - echo "{{message}}"

Special Functions

get()

Retrieve values from the data context:

dyngle:
  expressions:
    full-greeting: "'Hello ' + get('first-name') + ' ' + get('last-name')"

The get() function can also reference other expressions:

dyngle:
  expressions:
    greeting: "'Hello'"
    full-greeting: "get('greeting') + ' ' + name"

format()

Render a template string using the current data context:

dyngle:
  values:
    first-name: Alice
    last-name: Smith
  operations:
    greet:
      expressions:
        full-greeting: format('Hello, {{first-name}} {{last-name}}!')
      steps:
        - echo "{{full-greeting}}"

The format() function supports all template syntax, including nested properties:

dyngle:
  operations:
    weather-report:
      expressions:
        report: format('Temperature in {{location.city}} is {{weather.temperature}} degrees')
      steps:
        - echo "{{report}}"

See Data and Templates for more about template syntax.

dtformat()

Format datetime objects as strings:

dyngle:
  expressions:
    now: "datetime.now()"
    timestamp: "dtformat(get('now'), '%Y-%m-%d %H:%M:%S')"
  operations:
    log:
      - echo "[{{timestamp}}] Event occurred"

Path()

Create path objects (restricted to current working directory):

dyngle:
  expressions:
    config-file: "Path('.dyngle.yml')"
    exists: "get('config-file').exists()"

args

Access command-line arguments passed to the operation:

dyngle:
  operations:
    greet-arg:
      expressions:
        name: "args[0] if args else 'World'"
      steps:
        - echo "Hello {{name}}!"

Run it:

dyngle run greet-arg Alice

YAML Structure Syntax

Instead of string-based Python expressions, you can use native YAML structures:

Dictionaries

dyngle:
  operations:
    api-call:
      expressions:
        request-body:
          user: get('username')
          email: get('email')
          timestamp: "datetime.now()"
      steps:
        - echo "Request: {{request-body}}"

Arrays

dyngle:
  expressions:
    coordinates:
      - get('latitude')
      - get('longitude')
      - get('altitude')

Nested Structures

dyngle:
  expressions:
    config:
      server:
        host: format("{{server-host}}")
        port: "int(get('server-port'))"
      database:
        name: format("{{db-name}}")
        connection:
          - format("{{db-host}}")
          - "int(get('db-port'))"

Important Notes:

  • Each string in a YAML structure is evaluated as a Python expression
  • Numbers, booleans, and None pass through unchanged
  • String literals require Python string syntax: "'literal string'"
  • Access nested properties in templates using dot notation: {{config.server.host}}
  • Access array elements in expressions using Python brackets: get('coordinates')[0]

Available Python Features

Expressions support:

Built-in types and functions:

  • str(), int(), float(), bool(), len(), etc.

Standard library modules:

  • datetime - Date and time operations
  • math - Mathematical functions
  • Path() - File path operations (restricted to current directory)

Data structures:

  • Lists, dictionaries, tuples
  • List comprehensions
  • Dictionary comprehensions

Operators:

  • Arithmetic: +, -, *, /, //, %, **
  • Comparison: ==, !=, <, >, <=, >=
  • Logical: and, or, not
  • String: concatenation, formatting

Control flow (in comprehensions):

  • if/else in expressions
  • for loops in comprehensions

Expression Examples

String manipulation

dyngle:
  expressions:
    uppercase-name: "name.upper()"
    initials: "'.'.join([word[0] for word in name.split()])"

Mathematical operations

dyngle:
  expressions:
    circle-area: "math.pi * radius ** 2"
    rounded: "round(get('circle-area'), 2)"

Date and time

dyngle:
  expressions:
    now: "datetime.now()"
    today: "get('now').date()"
    formatted-date: "dtformat(get('now'), '%B %d, %Y')"

List operations

dyngle:
  values:
    numbers: [1, 2, 3, 4, 5]
  expressions:
    doubled: "[n * 2 for n in get('numbers')]"
    sum-numbers: "sum(get('numbers'))"
    max-number: "max(get('numbers'))"

Conditional logic

dyngle:
  expressions:
    environment: "get('env') if get('env') else 'development'"
    log-level: "'DEBUG' if get('environment') == 'development' else 'INFO'"

Next Steps