Hello community,

here is the log from the commit of package python-Arpeggio for openSUSE:Factory 
checked in at 2020-11-12 22:37:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-Arpeggio (Old)
 and      /work/SRC/openSUSE:Factory/.python-Arpeggio.new.24930 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-Arpeggio"

Thu Nov 12 22:37:01 2020 rev:10 rq:846972 version:1.10.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-Arpeggio/python-Arpeggio.changes  
2020-05-08 23:01:57.217445757 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-Arpeggio.new.24930/python-Arpeggio.changes   
    2020-11-12 22:37:25.742018862 +0100
@@ -1,0 +2,19 @@
+Sun Nov  1 19:43:14 UTC 2020 - Sebastian Wagner <[email protected]>
+
+- Update to version 1.10.1:
+ - Fix packaging, exclude examples from wheel.
+
+-------------------------------------------------------------------
+Sun Nov  1 16:56:10 UTC 2020 - Sebastian Wagner <[email protected]>
+
+- Update to version 1.10.0:
+ - Fix reporting duplicate rule names in `NoMatch` exception ([a1f14bede])
+ - Raise `AttributeError` when accessing unexisting rule name on parse tree 
node.
+    ([#82])
+ - Added `tree_str` method to parse tree nodes for nice string representation 
of
+    parse trees. ([#76])
+ - Added parse tree node suppression support and overriding of special Python
+    rule syntax. (#76)
+ - UnorderedGroup matching made deterministic ([#73])
+
+-------------------------------------------------------------------

Old:
----
  python-Arpeggio-1.9.2.tar.gz

New:
----
  python-Arpeggio-1.10.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-Arpeggio.spec ++++++
--- /var/tmp/diff_new_pack.LnniNF/_old  2020-11-12 22:37:26.542019697 +0100
+++ /var/tmp/diff_new_pack.LnniNF/_new  2020-11-12 22:37:26.546019701 +0100
@@ -18,14 +18,15 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-Arpeggio
-Version:        1.9.2
+Version:        1.10.1
 Release:        0
 Summary:        Packrat parser interpreter
 License:        MIT
 URL:            https://github.com/textX/Arpeggio/
-Source:         
https://github.com/textX/Arpeggio/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
-BuildRequires:  %{python_module pytest}
+Source:         
https://github.com/textX/Arpeggio/archive/%{version}.tar.gz#/%{name}-%{version}.tar.gz
+BuildRequires:  %{python_module pytest-runner}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 BuildArch:      noarch
@@ -40,22 +41,21 @@
 
 %prep
 %setup -q -n Arpeggio-%{version}
-sed -i -e '/pytest-runner/d' setup.py
+# remove shebang
+sed -i '1d' arpeggio/tests/regressions/issue_16/test_issue_16.py
 
 %build
 %python_build
 
 %install
 %python_install
-# do not install examples in generic folder, not needed really
-%python_expand rm -r %{buildroot}%{$python_sitelib}/examples
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
 %pytest arpeggio/tests
 
 %files %{python_files}
-%doc README.rst CHANGELOG.md AUTHORS.md
+%doc README.md CHANGELOG.md AUTHORS.md
 %license LICENSE
 %{python_sitelib}/*
 

++++++ python-Arpeggio-1.9.2.tar.gz -> python-Arpeggio-1.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/.gitignore 
new/Arpeggio-1.10.1/.gitignore
--- old/Arpeggio-1.9.2/.gitignore       2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/.gitignore      2020-11-01 20:37:36.000000000 +0100
@@ -8,7 +8,7 @@
 *.egg-info
 dist
 build
-eggs
+.eggs
 parts
 bin
 var
@@ -55,4 +55,5 @@
 site
 .cache
 venv
-.ropeproject
\ No newline at end of file
+.ropeproject
+coverage
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/.travis.yml 
new/Arpeggio-1.10.1/.travis.yml
--- old/Arpeggio-1.9.2/.travis.yml      2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/.travis.yml     2020-11-01 20:37:36.000000000 +0100
@@ -5,7 +5,14 @@
     - "3.5"
     - "3.6"
     - "3.7"
+    - "3.8"
+    - "3.9"
+
 install:
-    - python setup.py install
+    - ./install-test.sh
+
 script:
-    - py.test arpeggio/tests
+    - ./runtests.sh
+
+after_success:
+    - coveralls
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/CHANGELOG.md 
new/Arpeggio-1.10.1/CHANGELOG.md
--- old/Arpeggio-1.9.2/CHANGELOG.md     2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/CHANGELOG.md    2020-11-01 20:37:36.000000000 +0100
@@ -15,7 +15,33 @@
 ## [Unreleased]
 
 
-[Unreleased]: https://github.com/textX/Arpeggio/compare/v1.9.2...HEAD
+[Unreleased]: https://github.com/textX/Arpeggio/compare/1.10.1...HEAD
+
+
+## [1.10.1] (released: 2020-11-01)
+
+- Fix packaging, exclude examples from wheel.
+
+[1.10.1]: https://github.com/textX/Arpeggio/compare/v1.10.0...1.10.1
+
+
+## [1.10.0] (released: 2020-11-01)
+
+- Fix reporting duplicate rule names in `NoMatch` exception ([a1f14bede])
+- Raise `AttributeError` when accessing unexisting rule name on parse tree 
node.
+  ([#82])
+- Added `tree_str` method to parse tree nodes for nice string representation of
+  parse trees. ([#76])
+- Added parse tree node suppression support and overriding of special Python
+  rule syntax. (#76)
+- UnorderedGroup matching made deterministic ([#73])
+
+
+[a1f14bede]: 
https://github.com/textX/Arpeggio/commit/a1f14bedec14aa742c5a40c15be240d3a31addfa
+[#82]: https://github.com/textX/Arpeggio/issues/82
+[#76]: https://github.com/textX/Arpeggio/issues/76
+[#73]: https://github.com/textX/Arpeggio/issues/73
+[1.10.0]: https://github.com/textX/Arpeggio/compare/v1.9.2...1.10.0
 
 
 ## [v1.9.2] (released: 2019-10-05)
@@ -254,7 +280,7 @@
   - Basic error reporting.
   - Basic support for comments handling (needs refactoring)
   - Raw parse tree.
-  - Support for semantic actions with abbility to transform parse 
+  - Support for semantic actions with ability to transform parse
       tree to semantic representation - aka Abstract Semantic Graphs (see 
examples).
 
 [keepachangelog]: https://keepachangelog.com/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/CONTRIBUTING.md 
new/Arpeggio-1.10.1/CONTRIBUTING.md
--- old/Arpeggio-1.9.2/CONTRIBUTING.md  1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/CONTRIBUTING.md 2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,175 @@
+# Contributing
+
+Contributions are welcome, and they are greatly appreciated!. You can 
contribute
+code, documentation, tests, bug reports. Every little bit helps, and credit 
will
+always be given. If you plan to make a contribution it would be great if you
+first announce that on [the issue
+tracker](https://github.com/textX/Arpeggio/issues).
+
+You can contribute in many ways:
+
+
+## Types of Contributions
+
+
+### Report Bugs
+
+Report bugs at https://github.com/textX/Arpeggio/issues.
+
+If you are reporting a bug, please include:
+
+- Your operating system name and version.
+- Any details about your local setup that might be helpful in troubleshooting.
+- Detailed steps to reproduce the bug.
+
+
+### Fix Bugs
+
+Look through the GitHub issues for bugs. Anything tagged with "bug"
+and "help wanted" is open to whoever wants to implement it.
+
+
+### Implement Features
+
+Look through the GitHub issues for features. Anything tagged with "enhancement"
+and "help wanted" is open to whoever wants to implement it.
+
+
+### Write Documentation
+
+Arpeggio could always use more documentation, whether as part of the official
+Arpeggio docs, in docstrings, or even on the web in blog posts, articles, and
+such.
+
+#### How to Test the Documentation Locally
+
+Arpeggio is currently using `mkdocs`, a documentation generator, to generate 
the docs into html files. 
+
+To test the docs locally, you need to follow the first 3 instructions at the
+[Get Started!](#get-started) section
+
+1. Fork the repo (one-time effort)
+2. Clone your fork locally (one-time effort)
+3. Create a virtualenv for the fork and install the relevant libraries 
(one-time effort)
+
+Once you complete the above 3 instructions, you can now:
+
+4. Activate the virtualenv
+5. Run `mkdocs serve` at the root folder
+
+`mkdocs` will run a webserver that serves the documentation at 127.0.0.1:8000
+
+To make changes to the configurations, you can look at `mkdocs.yml`. For more
+information on how to use mkdocs, visit this [site](https://www.mkdocs.org).
+
+
+### Submit Feedback
+
+The best way to send feedback is to file an issue at 
https://github.com/textX/Arpeggio/issues.
+
+If you are proposing a feature:
+
+- Explain in detail how it would work.
+- Keep the scope as narrow as possible, to make it easier to implement.
+- Remember that this is a volunteer-driven project, and that contributions
+  are welcome :)
+
+
+## Get Started!
+
+Ready to contribute? Here's how to set up `Arpeggio` for local development.
+
+1. Fork the `Arpeggio` repo on GitHub.
+2. Clone your fork locally:
+
+        $ git clone [email protected]:your_name_here/Arpeggio.git
+
+3. Install your local copy into a virtualenv. This is how you set up your fork
+   for local development:
+
+        $ cd Arpeggio/
+        $ python -m venv venv
+        $ source venv/bin/activate
+        $ ./install-dev.sh 
+        
+    Previous stuff is needed only the first time. To continue working on 
Arpeggio
+    later you just do:
+    
+        $ cd Arpeggio/ 
+        $ source venv/bin/activate
+        
+    Note that on Windows sourcing syntax is a bit different. Check the docs for
+    virtualenv.
+        
+    An excellent overview of available tools for Python environments management
+    can be found
+    
[here](https://stackoverflow.com/questions/41573587/what-is-the-difference-between-venv-pyvenv-pyenv-virtualenv-virtualenvwrappe)
+    
+    To verify that everything is setup properly run tests:
+    
+        $ flake8
+        $ py.test tests/functional/
+
+4. Create a branch for local development::
+
+        $ git checkout -b name-of-your-bugfix-or-feature
+
+   Now you can make your changes locally.
+
+5. When you're done making changes, check that your changes pass flake8, the
+   tests, and have a look at the coverage:
+
+        $ flake8
+        $ py.test tests/functional/
+        $ coverage run --source textx -m py.test tests/functional
+        $ coverage report
+        
+   You can run all this at once with provided script `runtests.sh`
+   
+        $ ./runtests.sh
+
+   In case you have doubts, have also a look at the html rendered version of
+   the coverage results:
+
+        $ coverage html
+
+6. Commit your changes and push your branch to GitHub:
+
+        $ git add .
+        $ git commit -m "Your detailed description of your changes."
+        $ git push origin name-of-your-bugfix-or-feature
+
+7. Submit a pull request through the GitHub website.
+
+
+## Pull Request Guidelines
+
+Before you submit a pull request, check that it meets these guidelines:
+
+1. The pull request should include tests.
+2. If the pull request adds/changes functionality, the docs should be updated. 
+3. The pull request should work for Python 2.7, 3.4-3.9. Check
+   https://travis-ci.org/textX/Arpeggio/pull_requests and make sure that
+   the tests pass for all supported Python versions.
+
+
+## Tips
+
+To run a subset of tests:
+
+```
+$ py.test tests/functional/mytest.py
+```
+
+or a single test:
+
+```
+$ py.test tests/functional/mytest.py::some_test
+```
+
+## Credit
+
+This guide is based on the guide generated by
+[Cookiecutter](https://github.com/audreyr/cookiecutter) and
+[cookiecutter-pypackage](https://github.com/audreyr/cookiecutter-pypackage)
+project template.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/PULL_REQUEST_TEMPLATE.md 
new/Arpeggio-1.10.1/PULL_REQUEST_TEMPLATE.md
--- old/Arpeggio-1.9.2/PULL_REQUEST_TEMPLATE.md 1970-01-01 01:00:00.000000000 
+0100
+++ new/Arpeggio-1.10.1/PULL_REQUEST_TEMPLATE.md        2020-11-01 
20:37:36.000000000 +0100
@@ -0,0 +1,15 @@
+<!-- Please don't remove/change code review checklist -->
+
+## Code review checklist
+
+- [ ] Pull request represents a single change (i.e. not fixing 
disparate/unrelated things in a single PR)
+- [ ] Title summarizes what is changing
+- [ ] Commit messages are meaningful (see [this][commit messages] for details)
+- [ ] Tests have been included and/or updated
+- [ ] Docstrings have been included and/or updated, as appropriate
+- [ ] Standalone docs have been updated accordingly
+- [ ] Changelog(s) has/have been updated, as needed (see `CHANGELOG.md`, no 
need
+      to update for typo fixes and such).
+
+
+[commit messages]: https://chris.beams.io/posts/git-commit/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/README.md 
new/Arpeggio-1.10.1/README.md
--- old/Arpeggio-1.9.2/README.md        1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/README.md       2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,15 @@
+![](https://raw.githubusercontent.com/textX/Arpeggio/master/art/arpeggio-logo.png)
+
+[![PyPI 
Version](https://img.shields.io/pypi/v/Arpeggio.svg)](https://pypi.python.org/pypi/Arpeggio)
+![](https://img.shields.io/pypi/l/Arpeggio.svg)
+[![Build 
status](https://travis-ci.org/textX/Arpeggio.svg?branch=master)](https://travis-ci.org/textX/Arpeggio)
+[![Coverage 
Status](https://coveralls.io/repos/github/textX/Arpeggio/badge.svg)](https://coveralls.io/github/textX/Arpeggio)
+[![Documentation](https://img.shields.io/badge/docs-latest-green.svg)](http://textx.github.io/Arpeggio/latest/)
+
+Arpeggio is a recursive descent parser with memoization based on PEG grammars
+(aka Packrat parser).
+
+Documentation with tutorials is available 
[here](http://textx.github.io/Arpeggio/).
+
+**Note:** for a higher level parsing/language tool (i.e., a nicer interface to
+Arpeggio) see [textX](https://github.com/textX/textX).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/README.rst 
new/Arpeggio-1.10.1/README.rst
--- old/Arpeggio-1.9.2/README.rst       2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/README.rst      1970-01-01 01:00:00.000000000 +0100
@@ -1,30 +0,0 @@
-.. image:: 
https://raw.githubusercontent.com/textX/Arpeggio/master/art/arpeggio-logo.png
-   :height: 100
-
-Arpeggio - PEG parser
-=====================
-
-|pypi-badge| |license| |build-status| |docs|
-
-Arpeggio is a recursive descent parser with memoization based on PEG grammars
-(aka Packrat parser).
-
-Documentation with tutorials is available `here
-<http://textx.github.io/Arpeggio/>`_.
-
-**Note:** for a higher level parsing/language tool (i.e., a nicer interface to
-Arpeggio) see `textX <https://github.com/textX/textX>`_.
-
-
-.. |pypi-badge| image:: https://img.shields.io/pypi/v/Arpeggio.svg
-   :target: https://pypi.python.org/pypi/Arpeggio
-   :alt: PyPI Version
-
-.. |license| image:: https://img.shields.io/pypi/l/Arpeggio.svg
-
-.. |build-status| image:: 
https://travis-ci.org/textX/Arpeggio.svg?branch=master
-   :target: https://travis-ci.org/textX/Arpeggio
-
-.. |docs| image:: https://img.shields.io/badge/docs-latest-green.svg
-   :target: http://textx.github.io/Arpeggio/latest/
-   :alt: Documentation Status
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/arpeggio/__init__.py 
new/Arpeggio-1.10.1/arpeggio/__init__.py
--- old/Arpeggio-1.9.2/arpeggio/__init__.py     2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/arpeggio/__init__.py    2020-11-01 20:37:36.000000000 
+0100
@@ -13,13 +13,14 @@
 
 from __future__ import print_function, unicode_literals
 import sys
+from collections import OrderedDict
 import codecs
 import re
 import bisect
 from arpeggio.utils import isstr
 import types
 
-__version__ = "1.9.2"
+__version__ = "1.10.1"
 
 if sys.version < '3':
     text = unicode
@@ -88,8 +89,8 @@
         if not self.rules:
             err_message = "Not expected input"
         else:
-            what_is_expected = ["{}".format(rule_to_exp_str(r))
-                                for r in self.rules]
+            what_is_expected = OrderedDict.fromkeys(
+                ["{}".format(rule_to_exp_str(r)) for r in self.rules])
             what_str = " or ".join(what_is_expected)
             err_message = "Expected {}".format(what_str)
 
@@ -121,31 +122,31 @@
 
     Attributes:
         debug (bool): If true debugging messages will be printed.
-        _current_ident(int): Current identation level for prints.
+        _current_indent(int): Current indentation level for prints.
     """
 
     def __init__(self, **kwargs):
 
         self.debug = kwargs.pop("debug", False)
         self.file = kwargs.pop("file", sys.stdout)
-        self._current_ident = 0
+        self._current_indent = 0
 
         super(DebugPrinter, self).__init__(**kwargs)
 
-    def dprint(self, message, ident_change=0):
+    def dprint(self, message, indent_change=0):
         """
         Handle debug message. Print to the stream specified by the 'file'
         keyword argument at the current indentation level. Default stream is
         stdout.
         """
-        if ident_change < 0:
-            self._current_ident += ident_change
+        if indent_change < 0:
+            self._current_indent += indent_change
 
-        print(("%s%s" % ("   " * self._current_ident, message)),
+        print(("%s%s" % ("   " * self._current_indent, message)),
               file=self.file)
 
-        if ident_change > 0:
-            self._current_ident += ident_change
+        if indent_change > 0:
+            self._current_indent += indent_change
 
 
 # ---------------------------------------------------------
@@ -169,6 +170,9 @@
         suppress (bool): If this is set to True than no ParseTreeNode will be
             created for this ParsingExpression. Default False.
     """
+
+    suppress = False
+
     def __init__(self, *elements, **kwargs):
 
         if len(elements) == 1:
@@ -183,7 +187,8 @@
             nodes = [nodes]
         self.nodes = nodes
 
-        self.suppress = kwargs.get('suppress', False)
+        if 'suppress' in kwargs:
+            self.suppress = kwargs['suppress']
 
         # Memoization. Every node cache the parsing results for the given input
         # positions.
@@ -558,7 +563,7 @@
 
         # Prefetching
         append = results.append
-        nodes_to_try = set(self.nodes)
+        nodes_to_try = list(self.nodes)
         sep = self.sep.parse if self.sep else None
         result = None
         sep_result = None
@@ -582,7 +587,7 @@
             c_loc_pos = parser.position
             match = True
             all_optionals_fail = True
-            for e in set(nodes_to_try):
+            for e in list(nodes_to_try):
                 try:
                     result = e.parse(parser)
                     if result:
@@ -611,7 +616,7 @@
             parser.eolterm = old_eolterm
 
         if not match:
-            # Unsucessful match of the whole PE - full backtracking
+            # Unsuccessful match of the whole PE - full backtracking
             parser.position = c_pos
             parser._nm_raise(self, c_pos, parser)
 
@@ -714,8 +719,8 @@
     """
     Base class for all classes that will try to match something from the input.
     """
-    def __init__(self, rule_name, root=False):
-        super(Match, self).__init__(rule_name=rule_name, root=root)
+    def __init__(self, rule_name, root=False, **kwargs):
+        super(Match, self).__init__(rule_name=rule_name, root=root, **kwargs)
 
     @property
     def name(self):
@@ -806,8 +811,9 @@
 
     '''
     def __init__(self, to_match, rule_name='', root=False, ignore_case=None,
-                 multiline=None, str_repr=None, re_flags=re.MULTILINE):
-        super(RegExMatch, self).__init__(rule_name, root)
+                 multiline=None, str_repr=None, re_flags=re.MULTILINE,
+                 **kwargs):
+        super(RegExMatch, self).__init__(rule_name, root, **kwargs)
         self.to_match_regex = to_match
         self.ignore_case = ignore_case
         self.multiline = multiline
@@ -860,8 +866,9 @@
         ignore_case(bool): If case insensitive match is needed.
             Default is None to support propagation from global parser setting.
     """
-    def __init__(self, to_match, rule_name='', root=False, ignore_case=None):
-        super(StrMatch, self).__init__(rule_name, root)
+    def __init__(self, to_match, rule_name='', root=False, ignore_case=None,
+                 **kwargs):
+        super(StrMatch, self).__init__(rule_name, root, **kwargs)
         self.to_match = to_match
         self.ignore_case = ignore_case
 
@@ -905,6 +912,7 @@
         return hash(self.to_match)
 
 
+
 # HACK: Kwd class is a bit hackish. Need to find a better way to
 #       introduce different classes of string tokens.
 class Kwd(StrMatch):
@@ -1020,6 +1028,10 @@
             # If default actions are enabled
             return visitor.visit__default__(self, children)
 
+    def tree_str(self, indent=0):
+        return '{}{} [{}-{}]'.format('  ' * indent, self.rule.name,
+                                     self.position, self.position_end)
+
 
 class Terminal(ParseTreeNode):
     """
@@ -1069,6 +1081,10 @@
     def __repr__(self):
         return self.desc
 
+    def tree_str(self, indent=0):
+        return '{}: {}'.format(super(Terminal, self).tree_str(indent),
+                               self.value)
+
     def __eq__(self, other):
         return text(self) == text(other)
 
@@ -1128,6 +1144,11 @@
     def __repr__(self):
         return "[ %s ]" % ", ".join([repr(x) for x in self])
 
+    def tree_str(self, indent=0):
+        return '{}\n{}'.format(super(NonTerminal, self).tree_str(indent),
+                               '\n'.join([c.tree_str(indent + 1)
+                                          for c in self]))
+
     def __getattr__(self, rule_name):
         """
         Find a child (non)terminal by the rule name.
@@ -1167,6 +1188,10 @@
                     nodes.append(n)
                     rule = n.rule
 
+        if rule is None:
+            # If rule is not found resort to default behavior
+            return self.__getattribute__(rule_name)
+
         result = NonTerminal(rule=rule, nodes=nodes, _filtered=True)
         self._expr_cache[rule_name] = result
         return result
@@ -1714,7 +1739,8 @@
 
 class ParserPython(Parser):
 
-    def __init__(self, language_def, comment_def=None, *args, **kwargs):
+    def __init__(self, language_def, comment_def=None, syntax_classes=None,
+                 *args, **kwargs):
         """
         Constructs parser from python statements and expressions.
 
@@ -1723,9 +1749,14 @@
                 the root rule of the grammar.
             comment_def (python function): A python function that defines
                 the root rule of the comments grammar.
+            syntax_classes (dict): Overrides of special syntax parser
+                expression classes (StrMatch, Sequence, OrderedChoice).
+
         """
         super(ParserPython, self).__init__(*args, **kwargs)
 
+        self.syntax_classes = syntax_classes if syntax_classes else {}
+
         # PEG Abstract Syntax Graph
         self.parser_model = self._from_python(language_def)
 
@@ -1758,6 +1789,10 @@
         __rule_cache = {"EndOfFile": EndOfFile()}
         __for_resolving = []  # Expressions that needs crossref resolvnih
         self.__cross_refs = 0
+        _StrMatch = self.syntax_classes.get('StrMatch', StrMatch)
+        _OrderedChoice = self.syntax_classes.get('OrderedChoice',
+                                                 OrderedChoice)
+        _Sequence = self.syntax_classes.get('Sequence', Sequence)
 
         def inner_from_python(expression):
             retval = None
@@ -1798,9 +1833,10 @@
                     self.dprint("New rule: {} -> {}"
                                 .format(rule_name, retval.__class__.__name__))
 
-            elif type(expression) is text or isinstance(expression, StrMatch):
+            elif type(expression) is text or isinstance(expression, _StrMatch):
                 if type(expression) is text:
-                    retval = StrMatch(expression, ignore_case=self.ignore_case)
+                    retval = _StrMatch(expression,
+                                       ignore_case=self.ignore_case)
                 else:
                     retval = expression
                     if expression.ignore_case is None:
@@ -1835,7 +1871,7 @@
                 if any((isinstance(x, CrossRef) for x in retval.nodes)):
                     __for_resolving.append(retval)
 
-            elif isinstance(expression, Sequence) or \
+            elif isinstance(expression, _Sequence) or \
                     isinstance(expression, Repetition) or \
                     isinstance(expression, SyntaxPredicate) or \
                     isinstance(expression, Decorator):
@@ -1846,9 +1882,9 @@
 
             elif type(expression) in [list, tuple]:
                 if type(expression) is list:
-                    retval = OrderedChoice(expression)
+                    retval = _OrderedChoice(expression)
                 else:
-                    retval = Sequence(expression)
+                    retval = _Sequence(expression)
 
                 retval.nodes = [inner_from_python(e) for e in expression]
                 if any((isinstance(x, CrossRef) for x in retval.nodes)):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Arpeggio-1.9.2/arpeggio/tests/regressions/issue_20/test_issue_20.py 
new/Arpeggio-1.10.1/arpeggio/tests/regressions/issue_20/test_issue_20.py
--- old/Arpeggio-1.9.2/arpeggio/tests/regressions/issue_20/test_issue_20.py     
2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/arpeggio/tests/regressions/issue_20/test_issue_20.py    
2020-11-01 20:37:36.000000000 +0100
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 #######################################################################
 # Name: test_optional_in_choice
-# Purpose: Optional matches always succeds but should not stop alternative
+# Purpose: Optional matches always succeeds but should not stop alternative
 #          probing on failed match.
 # Author: Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
 # Copyright: (c) 2015 Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Arpeggio-1.9.2/arpeggio/tests/regressions/issue_73/test_issue_73.py 
new/Arpeggio-1.10.1/arpeggio/tests/regressions/issue_73/test_issue_73.py
--- old/Arpeggio-1.9.2/arpeggio/tests/regressions/issue_73/test_issue_73.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/arpeggio/tests/regressions/issue_73/test_issue_73.py    
2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,33 @@
+from __future__ import unicode_literals
+import pytest
+from arpeggio import ParserPython, UnorderedGroup, Optional, \
+    EOF, NoMatch
+
+
+def test_nondeterministic_unordered_group():
+
+    def root():
+        return 'word1', UnorderedGroup(some_rule, 'word2', some_rule), EOF
+
+    def some_rule():
+        return Optional('word2'), Optional('word3')
+
+    content = '''word1 word2 '''
+
+    # If the 'word2' from unordered group in the `root` rule matches first
+    # the input parses, else it fails.
+    # We repeat parser construction and parsing many times to check
+    # if it fails every time. The current fix will iterate in order from left
+    # to right and repeat matching until all rules in a unordered group
+    # succeeds.
+    fail = 0
+    success = 0
+    for _ in range(100):
+        try:
+            parser = ParserPython(root)
+            parser.parse(content)
+            success += 1
+        except NoMatch:
+            fail += 1
+
+    assert fail == 100
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/Arpeggio-1.9.2/arpeggio/tests/test_ptnode_navigation_expressions.py 
new/Arpeggio-1.10.1/arpeggio/tests/test_ptnode_navigation_expressions.py
--- old/Arpeggio-1.9.2/arpeggio/tests/test_ptnode_navigation_expressions.py     
2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/arpeggio/tests/test_ptnode_navigation_expressions.py    
2020-11-01 20:37:36.000000000 +0100
@@ -64,3 +64,7 @@
 
     assert hasattr(result, "bar")
     assert hasattr(result, "baz")
+
+    # Test that accessing an invalid rule name raises AttributeError
+    with pytest.raises(AttributeError):
+        result.unexisting
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/arpeggio/tests/test_suppression.py 
new/Arpeggio-1.10.1/arpeggio/tests/test_suppression.py
--- old/Arpeggio-1.9.2/arpeggio/tests/test_suppression.py       2019-10-05 
12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/arpeggio/tests/test_suppression.py      2020-11-01 
20:37:36.000000000 +0100
@@ -9,7 +9,7 @@
 
 from __future__ import unicode_literals
 import pytest  # noqa
-from arpeggio import ParserPython, Sequence
+from arpeggio import ParserPython, Sequence, StrMatch, RegExMatch
 
 
 def test_sequence_suppress():
@@ -23,3 +23,45 @@
 
     result = parser.parse("one two three four")
     assert result[0] == "four"
+
+
+def test_suppress_string_match():
+    """
+    Test that string matches with suppress=True do not produce parse tree
+    nodes.
+    """
+
+    class SuppressStrMatch(StrMatch):
+        suppress = True
+
+    def grammar():
+        return "one", "two", SuppressStrMatch("three"), "four"
+
+    parser = ParserPython(grammar)
+
+    result = parser.parse("one two three four")
+    assert len(result) == 3
+    assert result[1] == "two"
+    assert result[2] == "four"
+
+
+def test_register_syntax_classes_suppress():
+    """
+    Test suppressing by overriding special syntax forms (lists - OrderedChoice,
+    tuples - Sequences and string - StrMatch).
+    """
+
+    class SuppressStrMatch(StrMatch):
+        suppress = True
+
+    def grammar():
+        return "one", "two", RegExMatch(r'\d+'), "three"
+
+    parser = ParserPython(grammar,
+                          syntax_classes={'StrMatch': SuppressStrMatch})
+
+    result = parser.parse("one two 42 three")
+
+    # Only regex will end up in the tree
+    assert len(result) == 1
+    assert result[0] == "42"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/about/contributing.md 
new/Arpeggio-1.10.1/docs/about/contributing.md
--- old/Arpeggio-1.9.2/docs/about/contributing.md       2019-10-05 
12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/docs/about/contributing.md      2020-11-01 
20:37:36.000000000 +0100
@@ -1,35 +1,6 @@
 # Contributions
 
-If you want to contribute to the Arpeggio project.
-
----
-
-Arpeggio is open for contributions. You can contribute code, documentation,
-tests, bug reports.  If you plan to make a contribution it would be great if 
you
-first announce that on the discussion forum.
-
-For bug reports please use github [issue 
tracker](https://github.com/textX/Arpeggio/issues/).
-
-For code/doc/test contributions do the following:
-
-1. Fork the [project on github](https://github.com/textX/Arpeggio/).
-1. Clone your fork.
-
-    To clone source repository with git and install for development do:
-
-        $ git clone [email protected]:your_user_name/Arpeggio.git
-        $ cd Arpeggio
-        $ python setup.py develop
-
-1. Make a branch for the new feature and switch to it.
-1. Make one or more commits.
-1. Push your branch to github.
-1. Make a pull request. I will look at the changes and if everything is ok I 
will pull it in.
-
-!!! note
-    For code contributions please try to adhere to the [PEP-8 
guidelines](http://legacy.python.org/dev/peps/pep-0008/).
-    Although I am not strict in that regard it is useful to have a common 
ground for
-    coding style. To make things easier use tools for code checking (PyLint,
-    PyFlakes, pep8 etc.).
+If you want to contribute to the Arpeggio project please see the [contribution
+guide](https://github.com/textX/textX/Arpeggio/master/CONTRIBUTING.md).
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/configuration.md 
new/Arpeggio-1.10.1/docs/configuration.md
--- old/Arpeggio-1.9.2/docs/configuration.md    2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/docs/configuration.md   2020-11-01 20:37:36.000000000 
+0100
@@ -98,7 +98,7 @@
 parser = ParserPython(calc, reduce_tree=True)
 ```
 
-In this configuration non-terminals with single child will be removed from the
+In this configuration non-terminals a with single child will be removed from 
the
 parse tree.
 
 <a href="../images/calc_parse_tree.dot.png" target="_blank"><img 
src="../images/calc_parse_tree.dot.png"/></a>
@@ -107,7 +107,7 @@
 
 <a href="../images/calc_parse_tree_reduced.dot.png" target="_blank"><img 
src="../images/calc_parse_tree_reduced.dot.png"/></a>
 
-Notice the removal of each non-terminal with single child.
+Notice the removal of each non-terminal with a single child.
 
 !!! warning
     Be aware that [semantic analysis](semantics.md) operates on nodes of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/grammars.md 
new/Arpeggio-1.10.1/docs/grammars.md
--- old/Arpeggio-1.9.2/docs/grammars.md 2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/docs/grammars.md        2020-11-01 20:37:36.000000000 
+0100
@@ -39,7 +39,7 @@
 
 During parsing each successfully matched rule will create a parse tree node. At
 the end of parsing a complete [parse tree](parse_trees.md) of the input will be
-returned. .
+returned.
 
 In Arpeggio each PEG rule consists of atomic parsing expression which can be:
 
@@ -63,10 +63,13 @@
     - **Optional** - matches given expression but will not fail if match can't 
be
       done. Matched input is consumed.
     - **Unordered group** - matches given expressions in any order. Each given
-      expression must be matched exacltly once. Matched input is consumed.
+      expression must be matched exactly once. Expressions are repeatedly tried
+      from left to right until any succeeds, the process is repeated ignoring
+      already matched expressions, thus the behavior is deterministic. Matched
+      input is consumed.
     - **And predicate** - succeeds if given expression matches at current
       location but does not consume any input.
-    - **Not predicate** - succeeds if given expression **does not** matches at
+    - **Not predicate** - succeeds if given expression **does not** match at
       current location but does not consume any input.
 
 PEG grammars in Arpeggio may be written twofold:
@@ -150,6 +153,43 @@
 some more usable form (see [Semantic analysis - 
Visitors](semantics.md#visitors))
 
 
+### Overriding of special rule classes
+
+As we noted above some parsing rules are mapped to Python types (`Sequence` to
+a tuple, `OrderedChoice` to a list and `StrMatch` to a string). Sometimes it is
+useful to override classes that will be instantiated by Arpeggio to provide
+altered behavior.
+
+For example, if we want to [suppress all string
+matches](parse_trees.md#suppressing-parse-tree-nodes) we can register our 
version
+of `StrMatch` which sets `suppress` to `True`:
+
+```python
+class SuppressStrMatch(StrMatch):
+    suppress = True
+
+def grammar():
+    return "one", "two", RegExMatch(r'\d+'), "three"
+
+parser = ParserPython(grammar,
+                      syntax_classes={'StrMatch': SuppressStrMatch})
+
+result = parser.parse("one two 42 three")
+
+# Only regex will end up in the tree
+assert len(result) == 1
+assert result[0] == "42"
+
+```
+
+We use `syntax_classes` parameter to `ParserPython` of `dict` type where keys
+are names of the original classes and values are our modified class. Now,
+Arpeggio will instantiate our class whenever it encounters Python string in the
+grammar.
+
+This feature is, obviously, only available for grammars written in Python.
+
+
 ## Grammars written in PEG notations
 
 Grammars can also be specified using PEG notation. There are actually two of
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/parse_trees.md 
new/Arpeggio-1.10.1/docs/parse_trees.md
--- old/Arpeggio-1.9.2/docs/parse_trees.md      2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/docs/parse_trees.md     2020-11-01 20:37:36.000000000 
+0100
@@ -119,8 +119,83 @@
 ```
 
 
+## Printing parse trees
+
+Elements of the parse tree has `tree_str` method which can be used to print the
+tree.
+
+For example:
+
+```python
+...
+parse_tree = parser.parse(some_input)
+print(parse_tree.tree_str())
+```
+
+Result might look something like:
+
+```
+simpleLanguage=Sequence [0-191]
+  keyword=Kwd(function) [0-8]: function
+  symbol=RegExMatch(\w+) [9-12]: fak
+  parameterlist=Sequence [13-20]
+    symbol=RegExMatch(\w+) [13-14]: n
+    symbol=RegExMatch(\w+) [16-17]: x
+    symbol=RegExMatch(\w+) [19-20]: p
+  block=Sequence [22-191]
+    StrMatch({) [22-23]: {
+    statement=Sequence [28-189]
+      ifstatement=Sequence [28-188]
+        keyword=Kwd(if) [28-30]: if
+        StrMatch(() [31-32]: (
+        expression=OrderedChoice [32-36]
+          operation=Sequence [32-36]
+            symbol=RegExMatch(\w+) [32-33]: n
+            operator=RegExMatch(\+|\-|\*|\/|\=\=) [33-35]: ==
+            literal=RegExMatch(\d*\.\d*|\d+|".*?") [35-36]: 0
+        StrMatch()) [36-37]: )
+        block=Sequence [38-93]
+          StrMatch({) [38-39]: {
+          statement=Sequence [78-87]
+            returnstatement=Sequence [78-86]
+              keyword=Kwd(return) [78-84]: return
+              expression=OrderedChoice [85-86]
+                literal=RegExMatch(\d*\.\d*|\d+|".*?") [85-86]: 0
+            StrMatch(;) [86-87]: ;
+
+```
+
+Each line contains information about the rule and the span of the input where
+the match occurred.
+
+
 ## Parse tree reduction
 
 Parser can be configured to create a reduced parse tree. More information can 
be
 found [here](configuration.md#parse-tree-reduction).
 
+
+## Suppressing parse tree nodes
+
+This feature is available for `ParserPython` only. Rule classes may have a 
class
+level `suppress` attribute set to `True`. Parse tree nodes produced by these
+rules will be removed from the resulting parse tree. This may be handy to 
reduce
+syntax noise from the punctuation and such in the resulting parse tree.
+
+```python
+class SuppressStrMatch(StrMatch):
+    suppress = True
+
+def grammar():
+    return "one", "two", SuppressStrMatch("three"), "four"
+
+parser = ParserPython(grammar)
+
+result = parser.parse("one two three four")
+assert len(result) == 3
+assert result[1] == "two"
+assert result[2] == "four"
+```
+
+This feature can nicely be combined with [overriding of special rule
+classes](grammars.md#overriding-of-special-rule-classes).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/troubleshooting.md 
new/Arpeggio-1.10.1/docs/troubleshooting.md
--- old/Arpeggio-1.9.2/docs/troubleshooting.md  2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/docs/troubleshooting.md 2020-11-01 20:37:36.000000000 
+0100
@@ -33,7 +33,7 @@
 again in the same spot of the input string.
 
 Although, there are techniques to handle left-recursion in top-down parsers
-automatically, Arpeggio does not implements them and a classic approach of
+automatically, Arpeggio does not implement them and a classic approach of
 [removing left
 
recursion](https://en.wikipedia.org/wiki/Left_recursion#Removing_left_recursion)
 must be used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/tutorials/calc.md 
new/Arpeggio-1.10.1/docs/tutorials/calc.md
--- old/Arpeggio-1.9.2/docs/tutorials/calc.md   2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/docs/tutorials/calc.md  2020-11-01 20:37:36.000000000 
+0100
@@ -46,7 +46,7 @@
 ```
 
 !!! note
-    Notice that the order of precendence is from lower to upper.
+    Notice that the order of precedence is from lower to upper.
     The deeper is the grammar rule, the tighter is the bonding.
 
 - Each factor is either a number or an expression inside brackets. The prefix
@@ -99,7 +99,7 @@
 parse_tree = parser.parse(input_expr)
 ```
 
-By ordering operation in the grammar form lower to upper precendence we have
+By ordering operation in the grammar form lower to upper precedence we have
 got the parse tree where the priority is retained. This will help us to easier
 make an expression evaluation.
 
@@ -177,7 +177,7 @@
 ```python
     def visit_expression(self, node, children):
         """
-        Adds or substracts terms.
+        Adds or subtracts terms.
         Term nodes will be already evaluated.
         """
         expr = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/docs/tutorials/csv.md 
new/Arpeggio-1.10.1/docs/tutorials/csv.md
--- old/Arpeggio-1.9.2/docs/tutorials/csv.md    2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/docs/tutorials/csv.md   2020-11-01 20:37:36.000000000 
+0100
@@ -127,7 +127,7 @@
 $ python csv.py
 ```
 
-**Congratulations!! You have successfuly parsed CSV file.**
+**Congratulations!! You have successfully parsed CSV file.**
 
 This parse tree is [visualized](../debugging.md#visualization) below (Tip: The
 image is large. Click on it to see it in a separate tab and to be able to use
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/examples/calc/calc.py 
new/Arpeggio-1.10.1/examples/calc/calc.py
--- old/Arpeggio-1.9.2/examples/calc/calc.py    2019-10-05 12:55:30.000000000 
+0200
+++ new/Arpeggio-1.10.1/examples/calc/calc.py   2020-11-01 20:37:36.000000000 
+0100
@@ -68,7 +68,7 @@
 
     def visit_expression(self, node, children):
         """
-        Adds or substracts terms.
+        Adds or subtracts terms.
         Term nodes will be already evaluated.
         """
         if self.debug:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/install-dev.sh 
new/Arpeggio-1.10.1/install-dev.sh
--- old/Arpeggio-1.9.2/install-dev.sh   1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/install-dev.sh  2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+pip install --upgrade pip || exit 1
+pip install -e .[dev] || exit 1
+./install-test.sh
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/install-test.sh 
new/Arpeggio-1.10.1/install-test.sh
--- old/Arpeggio-1.9.2/install-test.sh  1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/install-test.sh 2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+pip install --upgrade pip || exit 1
+pip install -e .[test] || exit 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/runtests.sh 
new/Arpeggio-1.10.1/runtests.sh
--- old/Arpeggio-1.9.2/runtests.sh      1970-01-01 01:00:00.000000000 +0100
+++ new/Arpeggio-1.10.1/runtests.sh     2020-11-01 20:37:36.000000000 +0100
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Run all tests and generate coverage report
+
+coverage run --omit="arpeggio/tests/*" --source arpeggio -m py.test 
arpeggio/tests || exit 1
+coverage report --fail-under 90 || exit 1
+# Run this to generate html report
+# coverage html --directory=coverage
+#flake8 || exit 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/setup.cfg 
new/Arpeggio-1.10.1/setup.cfg
--- old/Arpeggio-1.9.2/setup.cfg        2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/setup.cfg       2020-11-01 20:37:36.000000000 +0100
@@ -1,6 +1,59 @@
 [metadata]
-description-file = README.rst
-license_file = LICENSE
+name = Arpeggio
+author = Igor R. Dejanovic
+author_email = [email protected]
+license = MIT
+description = Packrat parser interpreter
+keywords = parser, PEG, packrat, library, interpreter
+url = https://github.com/textX/Arpeggio
+download_url=
+long_description = file: README.md
+long_description_content_type = text/markdown
+classifiers =
+    Development Status :: 5 - Production/Stable
+    Intended Audience :: Developers
+    Intended Audience :: Information Technology
+    Intended Audience :: Science/Research
+    Topic :: Software Development :: Interpreters
+    Topic :: Software Development :: Compilers
+    Topic :: Software Development :: Libraries :: Python Modules
+    License :: OSI Approved :: MIT License
+    Operating System :: OS Independent
+    Programming Language :: Python :: 2
+    Programming Language :: Python :: 2.7
+    Programming Language :: Python :: 3
+    Programming Language :: Python :: 3.4
+    Programming Language :: Python :: 3.5
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+
+[options]
+packages = find:
+include_package_data = True
+setup_requires =
+    pytest-runner
+    wheel
+tests_require = pytest
+
+[options.packages.find]
+exclude =
+    arpeggio.tests
+    examples
+    examples.*
+
+[options.extras_require]
+dev =
+    wheel
+    mkdocs
+    mike
+    twine
+test =
+     flake8
+     coverage
+     coveralls
+     pytest
 
 [bdist_wheel]
 universal=1
@@ -10,4 +63,11 @@
 
 [tool:pytest]
 addopts = --verbose
-python_files = arpeggio/tests/*.py 
\ No newline at end of file
+python_files = arpeggio/tests/*.py 
+
+[flake8]
+ignore = E741,W503
+max-line-length = 90
+exclude = .git/*,.eggs/*,
+          build/*,site/*,venv*,
+          .ropeproject/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Arpeggio-1.9.2/setup.py new/Arpeggio-1.10.1/setup.py
--- old/Arpeggio-1.9.2/setup.py 2019-10-05 12:55:30.000000000 +0200
+++ new/Arpeggio-1.10.1/setup.py        2020-11-01 20:37:36.000000000 +0100
@@ -4,7 +4,7 @@
 # Name: arpeggio.py
 # Purpose: PEG parser interpreter
 # Author: Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
-# Copyright: (c) 2009-2019 Igor R. Dejanović <igor DOT dejanovic AT gmail DOT 
com>
+# Copyright: (c) Igor R. Dejanović <igor DOT dejanovic AT gmail DOT com>
 # License: MIT License
 #
 # Arpeggio is an implementation of packrat parser interpreter based on PEG
@@ -12,32 +12,19 @@
 # Parsers are defined using python language construction or PEG language.
 ###############################################################################
 
-import codecs
 import os
 import sys
-from setuptools import setup, find_packages
+from setuptools import setup
 
 VERSIONFILE = "arpeggio/__init__.py"
 VERSION = None
-for line in codecs.open(VERSIONFILE, "r", encoding='utf-8').readlines():
+for line in open(VERSIONFILE, "r").readlines():
     if line.startswith('__version__'):
         VERSION = line.split('"')[1]
 
 if not VERSION:
     raise RuntimeError('No version defined in arpeggio/__init__.py')
 
-README = codecs.open(os.path.join(os.path.dirname(__file__), 'README.rst'),
-                     'r', encoding='utf-8').read()
-
-NAME = 'Arpeggio'
-DESC = 'Packrat parser interpreter'
-AUTHOR = 'Igor R. Dejanovic'
-AUTHOR_EMAIL = '[email protected]'
-LICENSE = 'MIT'
-URL = 'https://github.com/textX/Arpeggio'
-DOWNLOAD_URL = 'https://github.com/textX/Arpeggio/archive/v{}.tar.gz'\
-    .format(VERSION)
-
 if sys.argv[-1].startswith('publish'):
     if os.system("pip list | grep wheel"):
         print("wheel not installed.\nUse `pip install wheel`.\nExiting.")
@@ -55,40 +42,4 @@
         print("  git push --tags")
     sys.exit()
 
-setup(
-    name=NAME,
-    version=VERSION,
-    description=DESC,
-    long_description=README,
-    author=AUTHOR,
-    author_email=AUTHOR_EMAIL,
-    maintainer=AUTHOR,
-    maintainer_email=AUTHOR_EMAIL,
-    license=LICENSE,
-    url=URL,
-    download_url=DOWNLOAD_URL,
-    packages=find_packages(),
-    setup_requires=['pytest-runner'],
-    tests_require=['pytest'],
-    test_suite="arpeggio.tests",
-    keywords="parser packrat peg",
-    classifiers=[
-        'Development Status :: 5 - Production/Stable',
-        'Intended Audience :: Developers',
-        'Intended Audience :: Information Technology',
-        'Intended Audience :: Science/Research',
-        'Topic :: Software Development :: Interpreters',
-        'Topic :: Software Development :: Compilers',
-        'Topic :: Software Development :: Libraries :: Python Modules',
-        'License :: OSI Approved :: MIT License',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.4',
-        'Programming Language :: Python :: 3.5',
-        'Programming Language :: Python :: 3.6',
-        'Programming Language :: Python :: 3.7'
-        ]
-
-)
+setup(version=VERSION)
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/[email protected]

Reply via email to