Skip to content

Commit

Permalink
Add more docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas Misk committed Jun 8, 2021
1 parent 9dd4a04 commit bbb946d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 20 deletions.
8 changes: 4 additions & 4 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
# -- Options for HTMLHelp output ---------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'the_visitorsdoc'
htmlhelp_basename = 'visitor_design_pattern_doc'


# -- Options for LaTeX output ------------------------------------------
Expand Down Expand Up @@ -138,7 +138,7 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'the_visitors',
(master_doc, 'visitor_design_pattern',
'Visitor Design Pattern Documentation',
[author], 1)
]
Expand All @@ -150,10 +150,10 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'the_visitors',
(master_doc, 'visitor_design_pattern',
'Visitor Design Pattern Documentation',
author,
'the_visitors',
'visitor_design_pattern',
'One line description of project.',
'Miscellaneous'),
]
Expand Down
125 changes: 109 additions & 16 deletions visitor_design_pattern/visitor_design_pattern.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
"""
Visitor Design Pattern main module
This module defines the main component exposed by the visitor-design-pattern package:
- visitor class decorator
- traverse method decorator
- prefix method decorator
- infix method decorator
- suffix method decorator
- Visitable interface
"""

import inspect
Expand All @@ -14,6 +20,7 @@


def _visit(self, node, mode, *args, **kwargs):

for visitable_type in self.VISITABLE_TYPES[mode]:
if isinstance(node, visitable_type):
method = type(self).VISITABLE_TYPES[mode][visitable_type]
Expand All @@ -29,23 +36,23 @@ def _visit(self, node, mode, *args, **kwargs):
)


def visit_prefix(self, node, *args, **kwargs):
def _visit_prefix(self, node, *args, **kwargs):
return self._visit(node, 'prefix', *args, **kwargs)


def visit_infix(self, node, *args, **kwargs):
def _visit_infix(self, node, *args, **kwargs):
return self._visit(node, 'infix', *args, **kwargs)


def visit_suffix(self, node, *args, **kwargs):
def _visit_suffix(self, node, *args, **kwargs):
return self._visit(node, 'suffix', *args, **kwargs)


def do_nothing(self, *_, **__):
def _do_nothing(self, *_, **__):
pass


class Wrapper():
class _Wrapper():

def __init__(self, method) -> None:
self.method = method
Expand All @@ -65,6 +72,26 @@ def __call__(self, *args, **kwargs):

def visitor(traversal_mode=None):

"""
visitor class decorator
Mark a class cls as visitor. This initializes the supported
VISITABLE_TYPES dict in cls, and gather the different visit method
marked with the `traverse`, `prefix`, `infix` or `suffix` decorators
Usage:
.. code:: python
@visitor()
def MyVisitor():
...
Parameters:
- traversal_mode: None, "prefix", "infix" or "suffix"
Specifying a non None traversal_mode prevents other modes to be used in the decorated visitor
"""

def actual_class_wrapper(cls):

cls.VISITABLE_TYPES = {
Expand Down Expand Up @@ -92,24 +119,24 @@ def actual_class_wrapper(cls):
type_annotation = arg_spec.annotations[visitable_argname]

for mode in modes:
cls.VISITABLE_TYPES[mode][type_annotation] = Wrapper(method)
cls.VISITABLE_TYPES[mode][type_annotation] = _Wrapper(method)

setattr(cls, '_visit', _visit)
setattr(cls, 'visit_prefix', visit_prefix)
setattr(cls, 'visit_infix', visit_infix)
setattr(cls, 'visit_suffix', visit_suffix)
setattr(cls, 'visit_prefix', _visit_prefix)
setattr(cls, 'visit_infix', _visit_infix)
setattr(cls, 'visit_suffix', _visit_suffix)

if traversal_mode == 'prefix':
setattr(cls, 'visit_infix', do_nothing)
setattr(cls, 'visit_suffix', do_nothing)
setattr(cls, 'visit_infix', _do_nothing)
setattr(cls, 'visit_suffix', _do_nothing)

if traversal_mode == 'infix':
setattr(cls, 'visit_prefix', do_nothing)
setattr(cls, 'visit_suffix', do_nothing)
setattr(cls, 'visit_prefix', _do_nothing)
setattr(cls, 'visit_suffix', _do_nothing)

if traversal_mode == 'suffix':
setattr(cls, 'visit_infix', do_nothing)
setattr(cls, 'visit_prefix', do_nothing)
setattr(cls, 'visit_infix', _do_nothing)
setattr(cls, 'visit_prefix', _do_nothing)

return cls

Expand All @@ -118,6 +145,32 @@ def actual_class_wrapper(cls):

def traverse(traversal_mode):

"""
visit method decorator
Mark a method as visit method
Usage:
.. code:: python
@visitor()
def MyVisitor():
@traverse("prefix")
def my_visit_method(self, node: Type):
...
...
Parameters:
- traversal_mode: "prefix", "infix" or "suffix" or list
The specified mode defines when the visit method should be called
when traversing the structure.
A list of multiple modes can be specified.
"""

if isinstance(traversal_mode, str):
traversal_mode = [traversal_mode]

Expand All @@ -139,20 +192,60 @@ def actual_decorator(method):


def prefix():

"""
prefix visit method decorator
Equivalent to traverse('prefix')
"""

return traverse('prefix')


def infix():

"""
infix visit method decorator
Equivalent to traverse('infix')
"""

return traverse("infix")


def suffix():

"""
suffix visit method decorator
Equivalent to traverse('suffix')
"""

return traverse("suffix")


class VisitableInterface():

"""
Base class for visited nodes of the data structure
"""

def accept(self, visitor, parent_res=None):

"""
Default accept method
This method implement the base logic of the traversal.
A complex data structure may need a custom implementation.
In that case users may subclass the VisitableInterface and
implement their own traversal logic.
Parameters:
- visitor: class decorated by the visitor class decorator
- parent_res: return value of the prefix call of visitor on the current node's parent
"""

prefix_res = visitor.visit_prefix(self, parent_res=parent_res)
visited_attrs = {}
for i, (key, value) in enumerate(self.__dict__.items()):
Expand Down

0 comments on commit bbb946d

Please sign in to comment.