Overview ======== .. topic:: 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 =================== .. graphviz:: example.dot Usage ===== .. topic:: 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'] .. topic:: 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')