diff --git a/docs/source/Overview.rst b/docs/source/Overview.rst
index b7009d1..83cbc07 100644
--- a/docs/source/Overview.rst
+++ b/docs/source/Overview.rst
@@ -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']
+
+
.. 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')
+
+
diff --git a/docs/source/_static/pyrepl/overview_builtins.py b/docs/source/_static/pyrepl/overview_builtins.py
new file mode 100644
index 0000000..b7dbdaf
--- /dev/null
+++ b/docs/source/_static/pyrepl/overview_builtins.py
@@ -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")
diff --git a/docs/source/_static/pyrepl/overview_extending.py b/docs/source/_static/pyrepl/overview_extending.py
new file mode 100644
index 0000000..baceeb9
--- /dev/null
+++ b/docs/source/_static/pyrepl/overview_extending.py
@@ -0,0 +1,162 @@
+"""Interactive Overview examples for extending naming classes."""
+
+from pprint import pprint
+
+from naming import File, PipeFile
+
+
+class BasicPipeFile(PipeFile):
+ config = dict(base=r'\w+')
+
+
+class ProjectFile(BasicPipeFile):
+ config = dict(
+ year='[0-9]{4}',
+ user='[a-z]+',
+ another='(constant)',
+ last='[a-zA-Z0-9]+',
+ )
+
+
+class Dropper(BasicPipeFile):
+ config = dict(without=r'[a-zA-Z0-9]+', basename=r'[a-zA-Z0-9]+')
+ drop = ('base',)
+
+
+Subdropper = type('Dropper', (Dropper,), dict(config=dict(subdrop=r'[\w]')))
+
+
+class Compound(BasicPipeFile):
+ config = dict(first=r'\d+', second=r'[a-zA-Z]+')
+ join = dict(base=('first', 'second'))
+
+
+class CompoundByDash(Compound):
+ join_sep = '-'
+
+
+class FilePath(File):
+ config = dict(base=r'\w+', extrafield='[a-z0-9]+')
+
+ def get_path_pattern_list(self):
+ # The path is solved from the same fields used in the name.
+ return super().get_pattern_list()
+
+
+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
+
+
+def show(expression, value):
+ print(f">>> {expression}")
+ pprint(value)
+
+
+def run_project_file_example():
+ global project_file
+
+ print("\nInheriting from an existing name")
+ print(">>> project_file = ProjectFile('project_data_name_2017_christianl_constant_iamlast.data.17.abc', sep='_')")
+ project_file = ProjectFile('project_data_name_2017_christianl_constant_iamlast.data.17.abc', sep='_')
+ show("project_file.values", project_file.values)
+ show("project_file.nice_name", project_file.nice_name)
+ show("project_file.year", project_file.year)
+
+ print(">>> project_file.year = 'nondigits'")
+ try:
+ project_file.year = 'nondigits'
+ except ValueError as exc:
+ print(f"ValueError: {exc}")
+
+ print(">>> project_file.year = 1907")
+ project_file.year = 1907
+ show("project_file", project_file)
+ show("project_file.suffix", project_file.suffix)
+
+ print(">>> project_file.sep = ' '")
+ project_file.sep = ' '
+ show("project_file.name", project_file.name)
+
+
+def run_dropper_example():
+ global dropper, subdropper
+
+ print("\nDropping fields from bases")
+ dropper = Dropper()
+ show("dropper.get()", dropper.get())
+
+ subdropper = Subdropper()
+ show("subdropper.get()", subdropper.get())
+
+
+def run_compound_example():
+ global compound, compound_by_dash
+
+ print("\nSetting compound fields")
+ compound = Compound()
+ show("compound.get()", compound.get())
+ show("compound.get(first=50, second='abc')", compound.get(first=50, second='abc'))
+
+ print(">>> compound.name = compound.get(base='101dalmatians', version=1, suffix='png')")
+ compound.name = compound.get(base='101dalmatians', version=1, suffix='png')
+ show("compound.nice_name", compound.nice_name)
+ show("compound.get(first=200)", compound.get(first=200))
+
+ print(">>> compound_by_dash = CompoundByDash('101-dalmatians.1.png')")
+ compound_by_dash = CompoundByDash('101-dalmatians.1.png')
+ show("compound_by_dash.get(first=300)", compound_by_dash.get(first=300))
+
+
+def run_file_path_example():
+ global file_path
+
+ print("\nDefining path rules for File subclasses")
+ file_path = FilePath()
+ show("file_path.get()", file_path.get())
+ show("file_path.path", file_path.path)
+
+
+def run_property_field_example():
+ global property_field
+
+ print("\nUsing properties as fields while solving names")
+ property_field = PropertyField()
+ show("property_field.get()", property_field.get())
+
+ print(">>> property_field.name = 'simple props staticvalue.1.abc'")
+ property_field.name = 'simple props staticvalue.1.abc'
+ show("property_field.values", property_field.values)
+ show("property_field.path", property_field.path)
+
+
+def run_all_examples():
+ run_project_file_example()
+ run_dropper_example()
+ run_compound_example()
+ run_file_path_example()
+ run_property_field_example()
+
+
+def setup():
+ print("Loaded ProjectFile, Dropper, Compound, FilePath, and PropertyField examples.")
+ print("The extension examples are running now; use the prompt afterward to experiment.")
+ run_all_examples()
+ print("\nTry: project_file.year = 2026, dropper.get(), compound.get(first=404), or property_field.values")
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 06e18a8..d05ed3d 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -151,7 +151,10 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-# html_static_path = ['_static']
+html_static_path = ['_static']
+html_js_files = [
+ 'https://cdn.jsdelivr.net/npm/pyrepl-web@0.3.0/dist/pyrepl.js',
+]
# -- Options for HTMLHelp output ------------------------------------------
diff --git a/setup.cfg b/setup.cfg
index d99230b..d7879fd 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -24,4 +24,4 @@ packages = find:
# docs dependencies install:
# conda install --channel conda-forge pygraphviz
# python -m pip install sphinx myst-parser sphinx-toggleprompt sphinx-copybutton sphinx-togglebutton sphinx-hoverxref sphinx_autodoc_typehints sphinx_rtd_theme
-docs = sphinx; myst-parser; sphinx-toggleprompt; sphinx-copybutton; sphinx-togglebutton; sphinx-hoverxref; sphinx_autodoc_typehints; sphinx_rtd_theme
+docs = sphinx<9; myst-parser; sphinx-toggleprompt; sphinx-copybutton; sphinx-togglebutton; sphinx-hoverxref; sphinx_autodoc_typehints<3.6; sphinx_rtd_theme