summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Peveler <matt.peveler@gmail.com>2021-01-30 05:09:50 +0000
committerMatthew Peveler <matt.peveler@gmail.com>2021-01-30 05:12:55 +0000
commitdc7c3f45a8f4daecb687f964120a9d9174257e60 (patch)
treebf6ab276931efb4e1b8ced0d35484b6d58357750
parentc939a02cb497244bac966a3e7513ee6007885c64 (diff)
downloadasciidoc-py3-dc7c3f45a8f4daecb687f964120a9d9174257e60.tar.gz
move Dict classes into own module
Signed-off-by: Matthew Peveler <matt.peveler@gmail.com>
-rw-r--r--.github/workflows/test.yml7
-rw-r--r--.gitignore5
-rw-r--r--asciidoc/a2x.py42
-rw-r--r--asciidoc/asciidoc.py59
-rw-r--r--asciidoc/collections.py69
-rw-r--r--tests/test_collections.py37
6 files changed, 120 insertions, 99 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index da94989..a3d3930 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -64,7 +64,10 @@ jobs:
texlive-latex-base \
xsltproc
- - run: python asciidoc/asciidoc.py --doctest
+ - run: pip install -U pytest
+
+ - run: python -m asciidoc.asciidoc --doctest
+ - run: python -m pytest
- run: time python tests/testasciidoc.py run
- run: git clean -x -f doc tests/data
@@ -94,5 +97,5 @@ jobs:
with:
python-version: ${{ env.python-version }}
- - run: python asciidoc/asciidoc.py --doctest
+ - run: python -m asciidoc.asciidoc --doctest
- run: python tests/testasciidoc.py run --number 6
diff --git a/.gitignore b/.gitignore
index 4520612..d93022a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,8 @@ MANIFEST
build/
dist/
*.egg-info/
+
+# test artifacts
+.coverage
+htmlcov/
+.pytest_cache/
diff --git a/asciidoc/a2x.py b/asciidoc/a2x.py
index d55eeda..4a23293 100644
--- a/asciidoc/a2x.py
+++ b/asciidoc/a2x.py
@@ -42,10 +42,8 @@ import zipfile
import xml.dom.minidom
import mimetypes
-try:
- from . import asciidoc
-except ImportError:
- import asciidoc
+from . import asciidoc
+from .collections import DefaultAttrDict as AttrDict
CONF_DIR = os.path.join(os.path.dirname(__file__), 'resources')
METADATA = {}
@@ -134,42 +132,6 @@ def flatten(array):
return ret
-class AttrDict(dict):
- """
- Like a dictionary except values can be accessed as attributes i.e. obj.foo
- can be used in addition to obj['foo'].
- If self._default has been set then it will be returned if a non-existent
- attribute is accessed (instead of raising an AttributeError).
- """
- def __getattr__(self, key):
- try:
- return self[key]
- except KeyError as k:
- if '_default' in self:
- return self['_default']
- else:
- raise AttributeError from k
-
- def __setattr__(self, key, value):
- self[key] = value
-
- def __delattr__(self, key):
- try:
- del self[key]
- except KeyError as k:
- raise AttributeError from k
-
- def __repr__(self):
- return '<AttrDict ' + dict.__repr__(self) + '>'
-
- def __getstate__(self):
- return dict(self)
-
- def __setstate__(self, value):
- for k, v in value.items():
- self[k] = v
-
-
def isexecutable(file_name):
return os.path.isfile(file_name) and os.access(file_name, os.X_OK)
diff --git a/asciidoc/asciidoc.py b/asciidoc/asciidoc.py
index 7ff72b0..b26a4c6 100644
--- a/asciidoc/asciidoc.py
+++ b/asciidoc/asciidoc.py
@@ -32,6 +32,8 @@ import zipfile
from ast import literal_eval
from collections import OrderedDict
+from .collections import AttrDict, InsensitiveDict
+
CONF_DIR = os.path.join(os.path.dirname(__file__), 'resources')
METADATA = {}
with open(os.path.join(os.path.dirname(__file__), '__metadata__.py')) as f:
@@ -69,63 +71,6 @@ class EAsciiDoc(Exception):
pass
-class AttrDict(dict):
- """
- Like a dictionary except values can be accessed as attributes i.e. obj.foo
- can be used in addition to obj['foo'].
- If an item is not present None is returned.
- """
- def __getattr__(self, key):
- try:
- return self[key]
- except KeyError:
- return None
-
- def __setattr__(self, key, value):
- self[key] = value
-
- def __delattr__(self, key):
- try:
- del self[key]
- except KeyError as k:
- raise AttributeError(k)
-
- def __repr__(self):
- return '<AttrDict ' + dict.__repr__(self) + '>'
-
- def __getstate__(self):
- return dict(self)
-
- def __setstate__(self, value):
- for k, v in list(value.items()):
- self[k] = v
-
-
-class InsensitiveDict(dict):
- """
- Like a dictionary except key access is case insensitive.
- Keys are stored in lower case.
- """
- def __getitem__(self, key):
- return dict.__getitem__(self, key.lower())
-
- def __setitem__(self, key, value):
- dict.__setitem__(self, key.lower(), value)
-
- def has_key(self, key):
- return key.lower() in self
-
- def get(self, key, default=None):
- return dict.get(self, key.lower(), default)
-
- def update(self, dict):
- for k, v in list(dict.items()):
- self[k] = v
-
- def setdefault(self, key, default=None):
- return dict.setdefault(self, key.lower(), default)
-
-
class Trace(object):
"""
Used in conjunction with the 'trace' attribute to generate diagnostic
diff --git a/asciidoc/collections.py b/asciidoc/collections.py
new file mode 100644
index 0000000..36cfded
--- /dev/null
+++ b/asciidoc/collections.py
@@ -0,0 +1,69 @@
+class AttrDict(dict):
+ """
+ Like a dictionary except values can be accessed as attributes i.e. obj.foo
+ can be used in addition to obj['foo'].
+ If an item is not present None is returned.
+ """
+ def __getattr__(self, key):
+ try:
+ return self[key]
+ except KeyError:
+ return None
+
+ def __setattr__(self, key, value):
+ self[key] = value
+
+ def __delattr__(self, key):
+ try:
+ del self[key]
+ except KeyError as k:
+ raise AttributeError(k)
+
+ def __repr__(self):
+ return '<AttrDict ' + dict.__repr__(self) + '>'
+
+ def __getstate__(self):
+ return dict(self)
+
+ def __setstate__(self, value):
+ for k, v in value.items():
+ self[k] = v
+
+
+class DefaultAttrDict(AttrDict):
+ def __getattr__(self, key):
+ try:
+ return self[key]
+ except KeyError as k:
+ if '_default' in self:
+ return self['_default']
+ else:
+ raise AttributeError from k
+
+
+class InsensitiveDict(dict):
+ """
+ Like a dictionary except key access is case insensitive.
+ Keys are stored in lower case.
+ """
+ def __getitem__(self, key):
+ return dict.__getitem__(self, key.lower())
+
+ def __setitem__(self, key, value):
+ dict.__setitem__(self, key.lower(), value)
+
+ def __delitem__(self, key):
+ dict.__delitem__(self, key.lower())
+
+ def get(self, key, default=None):
+ return dict.get(self, key.lower(), default)
+
+ def update(self, dict):
+ for k, v in dict.items():
+ self[k] = v
+
+ def setdefault(self, key, default=None):
+ return dict.setdefault(self, key.lower(), default)
+
+ def __contains__(self, key):
+ return key.lower() in dict(self)
diff --git a/tests/test_collections.py b/tests/test_collections.py
new file mode 100644
index 0000000..5007948
--- /dev/null
+++ b/tests/test_collections.py
@@ -0,0 +1,37 @@
+import pytest
+from asciidoc.collections import AttrDict, DefaultAttrDict, InsensitiveDict
+
+
+def test_attr_dict():
+ d = AttrDict()
+ d.a = 1
+ d['b'] = 2
+ assert d['a'] == 1
+ assert d.b == 2
+ del d['a']
+ del d.b
+ assert 'a' not in d
+ assert 'b' not in d
+ assert d.c is None
+
+ with pytest.raises(AttributeError):
+ del d.c
+
+
+def test_default_attr_dict():
+ d = DefaultAttrDict()
+ with pytest.raises(AttributeError):
+ d.a
+ d._default = 'test'
+
+ assert d.a == 'test'
+
+
+def test_insensitive_dict():
+ d = InsensitiveDict()
+ d['A'] = 1
+ assert d['a'] == 1
+ d['aBaBa'] = 2
+ assert 'AbAbA' in d
+ del d['abaBA']
+ assert ('ababa' in d) is False