Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 24 additions & 225 deletions docs/source/Overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,237 +20,36 @@ Usage
Inherit from the class to use and assign a class attribute `config` as a
mapping of {field_name: regex_pattern} to use.

Name::
The interactive REPL below defines ``BasicName``, ``BasicPipe``,
``BasicFile`` and ``BasicPipeFile``, runs the overview examples, and keeps
the objects available at the prompt. Try changing ``n``, ``p``, ``f`` or
``pf`` after the examples finish running.

>>> 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'
.. raw:: html

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']
<py-repl
repl-title="naming built-ins"
theme="catppuccin-latte"
packages="naming"
src="_static/pyrepl/overview_builtins.py"
no-banner>
</py-repl>

.. 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}')
This REPL defines and runs the subclassing, field dropping, compound field,
path, and property-backed field examples. It leaves ``project_file``,
``dropper``, ``subdropper``, ``compound``, ``compound_by_dash``,
``file_path`` and ``property_field`` available for further experimentation.

Using properties as fields while solving names::
.. raw:: html

>>> 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')
<py-repl
repl-title="naming extensions"
theme="catppuccin-latte"
packages="naming"
src="_static/pyrepl/overview_extending.py"
no-banner>
</py-repl>
120 changes: 120 additions & 0 deletions docs/source/_static/pyrepl/overview_builtins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
"""Interactive Overview examples for the built-in naming classes."""

from pprint import pprint

from naming import File, Name, Pipe, PipeFile


class BasicName(Name):
config = dict(base=r'\w+')


class BasicPipe(Pipe):
config = dict(base=r'\w+')


class BasicFile(File):
config = dict(base=r'\w+')


class BasicPipeFile(PipeFile):
config = dict(base=r'\w+')


def show(expression, value):
print(f">>> {expression}")
pprint(value)


def run_name_example():
global n

print("\nName")
n = BasicName()
show("n.get()", n.get())
show("n.values", n.values)

print(">>> n.name = 'hello_world'")
n.name = 'hello_world'
show("n", n)
show("str(n)", str(n))
show("n.values", n.values)

print(">>> n.base = 'through_field_name'")
n.base = 'through_field_name'
show("n.values", n.values)
show("n.base", n.base)


def run_pipe_example():
global p

print("\nPipe")
p = BasicPipe()
show("p.get()", p.get())
show("p.get(version=10)", p.get(version=10))
show("p.get(output='data')", p.get(output='data'))
show("p.get(output='cache', version=7, index=24)", p.get(output='cache', version=7, index=24))

print(">>> p = BasicPipe('my_wip_data.1')")
p = BasicPipe('my_wip_data.1')
show("p.version", p.version)
show("p.values", p.values)
show("p.get(output='exchange')", p.get(output='exchange'))
show("p.name", p.name)

print(">>> p.output = 'exchange'")
p.output = 'exchange'
show("p.name", p.name)

print(">>> p.index = 101")
p.index = 101
print(">>> p.version = 7")
p.version = 7
show("p.name", p.name)
show("p.values", p.values)


def run_file_example():
global f

print("\nFile")
f = BasicFile()
show("f.get()", f.get())
show("f.get(suffix='png')", f.get(suffix='png'))

print(">>> f = BasicFile('hello.world')")
f = BasicFile('hello.world')
show("f.values", f.values)
show("f.suffix", f.suffix)

print(">>> f.suffix = 'abc'")
f.suffix = 'abc'
show("f.name", f.name)
show("f.path", f.path)


def run_pipefile_example():
global pf

print("\nPipeFile")
print(">>> pf = BasicPipeFile('wipfile.7.ext')")
pf = BasicPipeFile('wipfile.7.ext')
show("pf.values", pf.values)
show("[pf.get(index=x, output='render') for x in range(10)]", [
pf.get(index=x, output='render') for x in range(10)
])


def run_all_examples():
run_name_example()
run_pipe_example()
run_file_example()
run_pipefile_example()


def setup():
print("Loaded BasicName, BasicPipe, BasicFile, and BasicPipeFile.")
print("The overview examples are running now; use the prompt afterward to experiment.")
run_all_examples()
print("\nTry: n.base = 'new_value', p.get(version=12), f.suffix = 'txt', or pf.values")
Loading
Loading