astra.filename_templates#

This module provides two primary classes for generating filenames used by Astra when writing image files.

  • FilenameTemplates — simple templates using Python str.format.

  • JinjaFilenameTemplates — richer templates powered by Jinja2 when templates include template logic ({{ ... }}) at the cost of a slightly slower template rendering.

Key behavior#

  • Normalises imagetype values to a standard set (light, bias, dark, flat, default).

  • Validates templates against a set of test keyword arguments to catch formatting errors early.

  • Automatically selects the Jinja2-based implementation when input templates contain Jinja2 markers.

Quick example#

>>> from astra.image_handler import FilenameTemplates
>>> templates = FilenameTemplates()
>>> templates.render_filename(**templates.TEST_KWARGS)
'20240101/TestCamera_TestFilter_TestObject_300.123_2025-01-01_00-00-00.fits'

For details and advanced examples see the class docstrings for FilenameTemplates and JinjaFilenameTemplates.

Example configurations#

Example str.format() configurations#

The following is the default used by ASTRA in observatory_config.yaml.

filename_templates:
  object: "{action_date}/{device}_{filter_name}_{object_name}_{exptime:.3f}_{timestamp}.fits"
  calibration: "{action_date}/{device}_{imagetype}_{exptime:.3f}_{timestamp}.fits"
  flats: "{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits"
  autofocus: "autofocus/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits"
  calibrate_guiding: "calibrate_guiding/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits"
  pointing_model: "pointing_model/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits"
  default: "{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits"

Example Jinja2 configurations#

The following code would be identical to the default used by ASTRA in observatory_config.yaml, but using Jinja2 syntax. See the example in JinjaFilenameTemplates for more advanced examples using Jinja2 logic.

filename_templates:
  object: "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ object_name }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  calibration: "{{ action_date }}/{{ device }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  flats: "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  autofocus: "autofocus/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  calibrate_guiding: "calibrate_guiding/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  pointing_model: "pointing_model/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"
  default: "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"

Classes

FilenameTemplates([object, calibration, ...])

Filename templates using Python str.format() syntax.

JinjaFilenameTemplates(object, calibration, ...)

Filename templates using jinja2.Template syntax.

class astra.filename_templates.FilenameTemplates(object: str = '{action_date}/{device}_{filter_name}_{object_name}_{exptime:.3f}_{timestamp}.fits', calibration: str = '{action_date}/{device}_{imagetype}_{exptime:.3f}_{timestamp}.fits', flats: str = '{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits', autofocus: str = 'autofocus/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits', calibrate_guiding: str = 'calibrate_guiding/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits', pointing_model: str = 'pointing_model/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits', default: str = '{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits')[source]#

Bases: object

Filename templates using Python str.format() syntax.

The templates can be customised by passing a dictionary to FilenameTemplates.from_dict(), which is the constructor used in astra. If the templates contain Jinja2 syntax, the jinja2.Template class will be used instead, which allows more advanced logic.

Examples

>>> from astra.image_handler import FilenameTemplates

Default templates

>>> templates = FilenameTemplates()
>>> templates.render_filename(
... **templates.TEST_KWARGS | {"action_type": "object", "imagetype": "light"}
... )
'20240101/TestCamera_TestFilter_TestObject_300.123_2025-01-01_00-00-00.fits'

Let’s create a template with more advanced logic using jinja2.Template syntax. As the following example illustrates, jinja2.Template supports more complex logic, than str.format() syntax, at the cost of a slightly slower template rendering performance.

>>> flat_template = (
...     # use subdirs
...     "{{ imagetype.split('_')[0].upper() }}/{{ device }}_"
...     # customise timestamp format
...     + "{{ datetime_timestamp.strftime('%Y%m%d_%H%M%S.%f')[:-5] }}_"
...     # Add custom logic
...     + "{{ 'Dusk' if (datetime_timestamp + datetime.timedelta(hours=5)).hour > 12 else 'Dawn' }}"
...     + "_sequence_{{ '%03d'|format(sequence_counter) }}"
...     + ".fits"
... )
>>> filename_templates = FilenameTemplates.from_dict(
...     {"flats": flat_template}
... )
>>> filename_templates.render_filename(
...     **filename_templates.TEST_KWARGS | {
...         "action_type": "flats", "imagetype": "Flat Frame"
...     }
... )
'FLAT/TestCamera_20250101_000000.0_Dawn_sequence_000.fits'

See also

JinjaFilenameTemplates for more advanced template logic using jinja2.Template.

object: str = '{action_date}/{device}_{filter_name}_{object_name}_{exptime:.3f}_{timestamp}.fits'#
calibration: str = '{action_date}/{device}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
flats: str = '{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
autofocus: str = 'autofocus/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
calibrate_guiding: str = 'calibrate_guiding/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
pointing_model: str = 'pointing_model/{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
default: str = '{action_date}/{device}_{filter_name}_{imagetype}_{exptime:.3f}_{timestamp}.fits'#
TEST_KWARGS = {'action_date': '20240101', 'action_datetime': datetime.datetime(2024, 1, 1, 0, 0), 'action_type': 'object', 'datetime': <module 'datetime' from '/home/runner/work/_temp/uv-python-dir/cpython-3.11.14-linux-x86_64-gnu/lib/python3.11/datetime.py'>, 'datetime_timestamp': datetime.datetime(2025, 1, 1, 0, 0), 'device': 'TestCamera', 'exptime': 300.123456, 'filter_name': 'TestFilter', 'imagetype': 'light', 'object_name': 'TestObject', 'sequence_counter': 0, 'timestamp': '2025-01-01_00-00-00'}#
SUPPORTED_ACTION_TYPES = ['object', 'calibration', 'flats', 'autofocus', 'calibrate_guiding', 'pointing_model', 'default']#
SUPPORTED_IMAGETYPES = ['light', 'bias', 'dark', 'flat', 'default']#
property SUPPORTED_ARGS: set[str]#
classmethod from_dict(template_dict: dict[str, str]) FilenameTemplates[source]#

Create FilenameTemplates from a dictionary.

If the templates contain Jinja2 syntax, the JinjaFilenameTemplates class will be used instead.

Examples

Basic Example using str.format() syntax:

>>> from astra.image_handler import FilenameTemplates
>>> templates = FilenameTemplates.from_dict(
...     {
...         "object": "{device}_{object_name}_{timestamp}.fits",
...         "flats": "{device}_FLAT_{timestamp}.fits"
...     }
... )
>>> type(templates)
<class 'astra.filename_templates.FilenameTemplates'>
>>> templates.render_filename(
...     **templates.TEST_KWARGS | {"action_type": "object", "imagetype": "light"}
... )
'TestCamera_TestObject_2025-01-01_00-00-00.fits'
>>> templates.render_filename(
...     **templates.TEST_KWARGS | {"action_type": "flats", "imagetype": "Flat Frame"}
... )
'TestCamera_FLAT_2025-01-01_00-00-00.fits'

Example using jinja2.Template syntax:

>>> from astra.image_handler import FilenameTemplates
>>> templates = FilenameTemplates.from_dict(
...     {
...         "object": "{{ device }}_{{ object_name }}_{{ timestamp }}.fits",
...         "flats": "{{ device }}_FLAT_{{ timestamp }}.fits"
...     }
... )
>>> type(templates)
<class 'astra.filename_templates.JinjaFilenameTemplates'>
>>> templates.render_filename(
...     **templates.TEST_KWARGS | {"action_type": "object", "imagetype": "light"}
... )
'TestCamera_TestObject_2025-01-01_00-00-00.fits'
>>> templates.render_filename(
...     **templates.TEST_KWARGS | {"action_type": "flats", "imagetype": "Flat Frame"}
... )
'TestCamera_FLAT_2025-01-01_00-00-00.fits'
render_filename(action_type, **kwargs) str[source]#
class astra.filename_templates.JinjaFilenameTemplates(object: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ object_name }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", calibration: str = "{{ action_date }}/{{ device }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", flats: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", autofocus: str = "autofocus/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", calibrate_guiding: str = "calibrate_guiding/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", pointing_model: str = "pointing_model/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", default: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits", _compiled_templates: dict[str, ~jinja2.environment.Template]=<factory>)[source]#

Bases: FilenameTemplates

Filename templates using jinja2.Template syntax.

Examples

Let’s create a template with more advanced logic using jinja2.Template syntax.

>>> from astra.image_handler import JinjaFilenameTemplates
>>> flat_template = (
...     # use subdirs
...     "{{ imagetype.split('_')[0].upper() }}/{{ device }}_"
...     # customise timestamp format
...     + "{{ datetime_timestamp.strftime('%Y%m%d_%H%M%S.%f')[:-5] }}_"
...     # Add custom logic
...     + "{{ 'Dusk' if (datetime_timestamp + datetime.timedelta(hours=5)).hour > 12 else 'Dawn' }}"
...     + "_sequence_{{ '%03d'|format(sequence_counter) }}"
...     + ".fits"
... )
>>> filename_templates = FilenameTemplates.from_dict(
...     {"flats": flat_template}
... )
>>> filename_templates.render_filename(
...     **filename_templates.TEST_KWARGS | {
...         "action_type": "flats", "imagetype": "Flat Frame"
...     }
... )
'FLAT/TestCamera_20250101_000000.0_Dawn_sequence_000.fits'
object: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ object_name }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
calibration: str = "{{ action_date }}/{{ device }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
flats: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
autofocus: str = "autofocus/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
calibrate_guiding: str = "calibrate_guiding/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
pointing_model: str = "pointing_model/{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
default: str = "{{ action_date }}/{{ device }}_{{ filter_name }}_{{ imagetype }}_{{ '%.3f'|format(exptime) }}_{{ timestamp }}.fits"#
render_filename(action_type, **kwargs) str[source]#