Welcome to naming’s documentation!

Overview

Name Objects

This package provides an interface for dealing with naming conventions; from defining them, to identifying names and creating new ones.

Each Name object has a config attribute that contains the fields and regex patterns of the convention to follow. Names can also drop fields from their parent classes with the drop attribute, or they can merge / split fields with the join attribute.

Composition Example

strict digraph example { // nodes creation, shape and style defined here bgcolor=invis { node [style="rounded, filled" shape=box] class, File, Pipe, BasicPipeFile } { node [style=filled margin=0 width=1 height=0.46 shape=polygon fixedsize=true skew=0.4] format, file_format, pipe_format, pipefile_format } { node [shape=none] config_patterns, file_config_patterns, pipe_config_patterns, pipefile_config_patterns } { node [style="dashed, filled" shape=box] example, file_example, pipe_example, pipefile_example } // connections, labels and color related updates by higher level groups subgraph legend { edge[style=invis] // connect with invisible edges to emulate a legend class, format, example, config_patterns [color=gray40 fillcolor=gray95] config_patterns [label="field=pattern" fontcolor=gray22] class -> config_patterns -> format -> example } File, file_format, file_example [color=lightgoldenrod3 fillcolor=lemonchiffon1] file_format [label=".{suffix}"] file_example [label=".ext"] // escape the inverse slash so generated image displays one file_config_patterns [label="suffix = \\w+" fontcolor=lightgoldenrod4] Pipe, pipe_format, pipe_example [color=lightskyblue4 fillcolor=lightblue] pipe_format [label=".{pipe}"] pipe_example [label=".1 .1.out .1.out.101"] pipe_config_patterns [label="version = \\d+ output = \\w+? index = \\d+?"] BasicPipeFile, pipefile_format, pipefile_example [color=mediumorchid4 fillcolor=plum2] pipefile_format [skew=0.15 width=2 label="{base}.{pipe}.{suffix}"] pipefile_example [label="wip_data.7.ext pipe_data.7.out.ext indexed_data.7.out.101.ext"] pipefile_config_patterns [label="base = \\w+" fontcolor=mediumorchid4] edge [color=gray36 arrowhead=vee] Pipe -> pipe_config_patterns -> pipe_format -> pipe_example File -> file_config_patterns -> file_format -> file_example BasicPipeFile -> pipefile_config_patterns -> pipefile_format -> pipefile_example {Pipe, File} -> BasicPipeFile }

Usage

Built-ins & config attribute

Inherit from the class to use and assign a class attribute config as a mapping of {field_name: regex_pattern} to use.

Name:

>>> from naming import Name
>>> class BasicName(Name):
...     config = dict(base=r'\w+')
...
>>> n = BasicName()
>>> n.get()  # no name has been set on the object, convention is solved with {missing} fields
'{base}'
>>> n.values
{}
>>> n.name = 'hello_world'
>>> n
Name("hello_world")
>>> str(n)  # cast to string
'hello_world'
>>> n.values
{'base': 'hello_world'}
>>> # modify name and get values from field names
>>> n.base = 'through_field_name'
>>> n.values
{'base': 'through_field_name'}
>>> n.base
'through_field_name'

Pipe:

>>> from naming import Pipe
>>> class BasicPipe(Pipe):
...     config = dict(base=r'\w+')
...
>>> p = BasicPipe()
>>> p.get()
'{base}.{pipe}'
>>> p.get(version=10)
'{base}.10'
>>> p.get(output='data')
'{base}.data.{version}'
>>> p.get(output='cache', version=7, index=24)
'{base}.cache.7.24'
>>> p = BasicPipe('my_wip_data.1')
>>> p.version
'1'
>>> p.values
{'base': 'my_wip_data', 'pipe': '.1', 'version': '1'}
>>> p.get(output='exchange')  # returns a new string
'my_wip_data.exchange.1'
>>> p.name
'my_wip_data.1'
>>> p.output = 'exchange'  # mutates the object
>>> p.name
'my_wip_data.exchange.1'
>>> p.index = 101
>>> p.version = 7
>>> p.name
'my_wip_data.exchange.7.101'
>>> p.values
{'base': 'my_wip_data', 'pipe': '.exchange.7.101', 'output': 'exchange', 'version': '7', 'index': '101'}

File:

>>> from naming import File
>>> class BasicFile(File):
...     config = dict(base=r'\w+')
...
>>> f = BasicFile()
>>> f.get()
'{basse}.{suffix}'
>>> f.get(suffix='png')
'{base}.png'
>>> f = BasicFile('hello.world')
>>> f.values
{'base': 'hello', 'suffix': 'world'}
>>> f.suffix
'world'
>>> f.suffix = 'abc'
>>> f.name
'hello.abc'
>>> f.path
WindowsPath('hello.abc')

PipeFile:

>>> from naming import PipeFile
>>> class BasicPipeFile(PipeFile):
...     config = dict(base=r'\w+')
...
>>> p = BasicPipeFile('wipfile.7.ext')
>>> p.values
{'base': 'wipfile', 'pipe': '.7', 'version': '7', 'suffix': 'ext'}
>>> [p.get(index=x, output='render') for x in range(10)]
['wipfile.render.7.0.ext',
'wipfile.render.7.1.ext',
'wipfile.render.7.2.ext',
'wipfile.render.7.3.ext',
'wipfile.render.7.4.ext',
'wipfile.render.7.5.ext',
'wipfile.render.7.6.ext',
'wipfile.render.7.7.ext',
'wipfile.render.7.8.ext',
'wipfile.render.7.9.ext']

Extending Names

The config, drop and join attributes are merged on subclasses.

Inheriting from an existing name:

>>> class ProjectFile(BasicPipeFile):
...     config = dict(year='[0-9]{4}',
...                   user='[a-z]+',
...                   another='(constant)',
...                   last='[a-zA-Z0-9]+')
...
>>> pf = ProjectFile('project_data_name_2017_christianl_constant_iamlast.data.17.abc', sep='_')
>>> pf.values
{'base': 'project_data_name',
'year': '2017',
'user': 'christianl',
'another': 'constant',
'last': 'iamlast',
'pipe': '.data.17',
'output': 'data',
'version': '17',
'suffix': 'abc'}
>>> pf.nice_name  # no pipe & suffix fields
'project_data_name_2017_christianl_constant_iamlast'
>>> pf.year
'2017'
>>> pf.year = 'nondigits'  # mutating with invalid fields raises a ValueError
Traceback (most recent call last):
...
ValueError: Can't set field 'year' with invalid value 'nondigits' on 'ProjectFile("project_data_name_2017_christianl_constant_iamlast.data.17.abc")'. A valid field value should match pattern: '[0-9]{4}'
>>> pf.year = 1907
>>> pf
ProjectFile("project_data_name_1907_christianl_constant_iamlast.data.17.abc")
>>> pf.suffix
'abc'
>>> pf.sep = '  '  # you can set the separator to a different set of characters
>>> pf.name
'project_data_name   1907   christianl   constant   iamlast.data.17.abc'

Dropping fields from bases:

>>> class Dropper(BasicPipeFile):
...     config = dict(without=r'[a-zA-Z0-9]+', basename=r'[a-zA-Z0-9]+')
...     drop=('base',)
...
>>> d = Dropper()
>>> d.get()
'{without}_{basename}.{pipe}.{suffix}'
>>> # New subclasses will drop the 'base' field as well
>>> Subdropper = type('Dropper', (Dropper,), dict(config=dict(subdrop='[\w]')))
>>> s = Subdropper()
>>> s.get()
'{without}_{basename}_{subdrop}.{pipe}.{suffix}'

Setting compound fields:

>>> # splitting the 'base' field into multiple joined fields
>>> class Compound(BasicPipeFile):
...     config=dict(first=r'\d+', second=r'[a-zA-Z]+')
...     join=dict(base=('first', 'second'))
...
>>> c = Compound()
>>> c.get()  # we see the original field 'base'
'{base}.{pipe}.{suffix}'
>>> c.get(first=50, second='abc')  # providing each field to join will work
'50abc.{pipe}.{suffix}'
>>> c.name = c.get(base='101dalmatians', version=1, suffix='png')  # providing the key field will also work
>>> c.nice_name
'101dalmatians'
>>> c.get(first=200)
'200dalmatians.1.png'
>>> class CompoundByDash(Compound):
...     join_sep = '-'  # you can specify the string to join compounds
...
>>> c = CompoundByDash('101-dalmatians.1.png')
>>> c.get(first=300)
'300-dalmatians.1.png'

Defining path rules for File subclasses:

>>> from naming import File
>>> class FilePath(File):
...     config = dict(base=r'\w+', extrafield='[a-z0-9]+')
...     def get_path_pattern_list(self):
...         # As an example we are returning the pattern list from the name object (base, extrafield)
...         return super().get_pattern_list()
...
>>> fp = FilePath()
>>> fp.get()
'{base} {extrafield}.{suffix}'
>>> # path attribute will vary depending on the OS
>>> fp.path
WindowsPath('{base}/{extrafield}/{base} {extrafield}.{suffix}')

Using properties as fields while solving names:

>>> from naming import PipeFile
>>> class PropertyField(PipeFile):
...     config = dict(base=r'\w+', extrafield='[a-z0-9]+')
...
...     @property
...     def nameproperty(self):
...         return 'staticvalue'
...
...     @property
...     def pathproperty(self):
...         return 'path_field'
...
...     def get_path_pattern_list(self):
...         result = super().get_pattern_list()
...         result.append('pathproperty')
...         return result
...
...     def get_pattern_list(self):
...         result = super().get_pattern_list()
...         result.append('nameproperty')
...         return result
...
>>> pf = PropertyField()
>>> pf.get()
'{base} {extrafield} staticvalue.{pipe}.{suffix}'
>>> pf.name = 'simple props staticvalue.1.abc'
>>> pf.values
{'base': 'simple',
'extrafield': 'props',
'nameproperty': 'staticvalue',
'pipe': '.1',
'version': '1',
'suffix': 'abc'}
>>> pf.path
WindowsPath('simple/props/path_field/simple props staticvalue.1.abc')

Class List

Name

Inheritance diagram of naming.Name

class naming.Name(name='', sep=' ')[source]

Base class for name objects.

Each subclass may have its own config attribute that should be a dictionary in the form of {field: pattern} where pattern is a valid regular expression.

Classes may as well have a drop iterable attribute representing the fileds they want to ignore from their bases and a join dictionary attribute for nesting existing fields into new ones (or to override other fields).

All field names should be unique. No duplicates are allowed.

Example:
>>> from naming import Name
>>> class MyName(Name):
...     config = dict(base=r'\w+')
...
>>> n = MyName()
>>> n.get()  # no name has been set on the object, convention is solved with {missing} fields
'{base}'
>>> n.values
{}
>>> n.name = 'hello_world'
>>> n
Name("hello_world")
>>> str(n)  # cast to string
'hello_world'
>>> n.values
{'base': 'hello_world'}
>>> # modify name and get values from field names
>>> n.base = 'through_field_name'
>>> n.values
{'base': 'through_field_name'}
>>> n.base
'through_field_name'
static cast(value, name='')

Cast value to a grouped regular expression when name is provided.

Return type

str

classmethod cast_config(config)

Cast config to grouped regular expressions.

Return type

Dict[str, str]

get(**values)

Get a new name string from this object’s name values.

Parameters

values – Variable keyword arguments where the key should refer to a field on this object that will use the provided value to build the new name.

Return type

str

get_pattern_list()

Fields / properties names (sorted) to be used when building names. Defaults to the keys of self.config

Return type

List[str]

config = mappingproxy({})
join = mappingproxy({})
property name: str

This object’s solved name.

Raises

ValueError – If an invalid string is provided when setting the attribute.

Return type

str

property nice_name: str

This object’s pure name without fields not present in self.config.

Return type

str

property sep: str

The string that acts as a separator of all the fields in the name.

Return type

str

property values: Dict[str, str]

The field values of this object’s name as a dictionary in the form of {field: value}.

Return type

Dict[str, str]

File

Inheritance diagram of naming.File

class naming.File(name='', sep=' ')[source]

Inherited by: naming.PipeFile

File Name objects. All named files are expected to have a suffix (extension) after a dot.

Field

Characters

suffix

Any amount of word characters

Example:
>>> from naming import File
>>> class MyFile(File):
...     config = dict(base=r'\w+')
...
>>> f = MyFile()
>>> f.get()
'{basse}.{suffix}'
>>> f.get(suffix='png')
'{base}.png'
>>> f = MyFile('hello.world')
>>> f.values
{'base': 'hello', 'suffix': 'world'}
>>> f.suffix
'world'
>>> f.suffix = 'abc'
>>> f.name
'hello.abc'
>>> f.path
WindowsPath('hello.abc')

Pipe

Inheritance diagram of naming.Pipe

class naming.Pipe(name='', sep=' ')[source]

Inherited by: naming.PipeFile

Pipeline names have a field pipe which is composed of distinctive elements that make a resource unique.

Field

Characters

Description

version

One or more digits

Required field that helps track important states of a pipeline resource during its lifecycle.

This allows for history revision, rollbacks and comparisons.

output

One or more word characters

Optional field used when the produced data can be separated into meaningful distinct streams, e.g:

  • Left or right channel of a track.

  • Beauty, specular, diffuse render passes.

  • Body, eyes, hair textures.

index

One or more digits

Position of an element within the pipeline resource when it is a sequence, e.g:

  • A frame of a rendered shot.

  • UDIM textures.

  • Chunks of a cache.

If used, the output field must also exist. This is to prevent ambiguity when solving the fields.

Composed Fields

pipe

Combination of unique fields in the form of: (.{output})*.{version}.{index}**

* optional field. ** exists only when output is there as well.

Example:
>>> from naming import Pipe
>>> class MyPipe(Pipe):
...     config = dict(base=r'\w+')
...
>>> p = MyPipe()
>>> p.get()
'{base}.{pipe}'
>>> p.get(version=10)
'{base}.10'
>>> p.get(output='data')
'{base}.data.{version}'
>>> p.get(output='cache', version=7, index=24)
'{base}.cache.7.24'
>>> p = MyPipe('my_wip_data.1')
>>> p.version
'1'
>>> p.values
{'base': 'my_wip_data', 'pipe': '.1', 'version': '1'}
>>> p.get(output='exchange')  # returns a new string
'my_wip_data.exchange.1'
>>> p.name
'my_wip_data.1'
>>> p.output = 'exchange'  # mutates the object
>>> p.name
'my_wip_data.exchange.1'
>>> p.index = 101
>>> p.version = 7
>>> p.name
'my_wip_data.exchange.7.101'
>>> p.values
{'base': 'my_wip_data', 'pipe': '.exchange.7.101', 'output': 'exchange', 'version': '7', 'index': '101'}

PipeFile

Inheritance diagram of naming.PipeFile

class naming.PipeFile(name='', sep=' ')[source]

A convenience mixin for pipeline files in a project.

Example:
>>> from naming import PipeFile
>>> class MyPipeFile(PipeFile):
...     config = dict(base=r'\w+')
...
>>> p = MyPipeFile('wipfile.7.ext')
>>> p.values
{'base': 'wipfile', 'pipe': '.7', 'version': '7', 'suffix': 'ext'}
>>> [p.get(index=x, output='render') for x in range(10)]
['wipfile.render.7.0.ext',
'wipfile.render.7.1.ext',
'wipfile.render.7.2.ext',
'wipfile.render.7.3.ext',
'wipfile.render.7.4.ext',
'wipfile.render.7.5.ext',
'wipfile.render.7.6.ext',
'wipfile.render.7.7.ext',
'wipfile.render.7.8.ext',
'wipfile.render.7.9.ext']
>>> class ProjectFile(MyPipeFile):
...     config = dict(year='[0-9]{4}',
...                   user='[a-z]+',
...                   another='(constant)',
...                   last='[a-zA-Z0-9]+')
...
>>> pf = ProjectFile('project_data_name_2017_christianl_constant_iamlast.data.17.abc', sep='_')
>>> pf.values
{'base': 'project_data_name',
'year': '2017',
'user': 'christianl',
'another': 'constant',
'last': 'iamlast',
'pipe': '.data.17',
'output': 'data',
'version': '17',
'suffix': 'abc'}
>>> pf.nice_name  # no pipe & suffix fields
'project_data_name_2017_christianl_constant_iamlast'
>>> pf.year
'2017'
>>> pf.year = 'nondigits'  # mutating with invalid fields raises a ValueError
Traceback (most recent call last):
...
ValueError: Can't set field 'year' with invalid value 'nondigits' on 'ProjectFile("project_data_name_2017_christianl_constant_iamlast.data.17.abc")'. A valid field value should match pattern: '[0-9]{4}'
>>> pf.year = 1907
>>> pf
ProjectFile("project_data_name_1907_christianl_constant_iamlast.data.17.abc")
>>> pf.suffix
'abc'
>>> pf.sep = '  '  # you can set the separator to a different set of characters
>>> pf.name
'project_data_name   1907   christianl   constant   iamlast.data.17.abc'

Indices and tables