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
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
- 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
- classmethod cast_config(config)
Cast config to grouped regular expressions.
- 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
- get_pattern_list()
Fields / properties names (sorted) to be used when building names. Defaults to the keys of self.config
- 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
- property nice_name: str
This object’s pure name without fields not present in self.config.
- Return type
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
- 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
- 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'