Skip to content

Commit

Permalink
Merge pull request #49 from pepkit/dev
Browse files Browse the repository at this point in the history
version 0.12
  • Loading branch information
vreuter authored May 16, 2019
2 parents 9585745 + d3f468e commit ecfb2f8
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 55 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ Thumbs.db
build/
dist/
attmap.egg-info/

docs/autodoc_build
4 changes: 3 additions & 1 deletion attmap/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
""" Package-scope definitions """

from ._att_map_like import AttMapLike
from .attmap import AttMap
from .attmap_echo import AttMapEcho
from .helpers import *
Expand All @@ -10,5 +11,6 @@
AttributeDict = AttMap
AttributeDictEcho = AttMapEcho

__all__ = ["AttMap", "AttMapEcho", "AttributeDict", "AttributeDictEcho",
__all__ = ["AttMapLike", "AttMap", "AttMapEcho",
"AttributeDict", "AttributeDictEcho",
"OrdAttMap", "PathExAttMap", "get_data_lines"]
7 changes: 5 additions & 2 deletions attmap/_att_map_like.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
__author__ = "Vince Reuter"
__email__ = "[email protected]"

__all__ = ["AttMapLike"]


_LOGGER = get_logger(__name__)

Expand Down Expand Up @@ -134,13 +136,14 @@ def to_dict(self):
"""
return self._simplify_keyvalue(self.items(), dict)

def to_yaml(self):
def to_yaml(self, trailing_newline=True):
"""
Get text for YAML representation.
:param bool trailing_newline: whether to add trailing newline
:return str: YAML text representation of this instance.
"""
return "\n".join(self.get_yaml_lines())
return "\n".join(self.get_yaml_lines()) + ("\n" if trailing_newline else "")

def _data_for_repr(self):
"""
Expand Down
2 changes: 1 addition & 1 deletion attmap/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.11"
__version__ = "0.12"
42 changes: 0 additions & 42 deletions docs/autodoc_build/attmap.md

This file was deleted.

9 changes: 9 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.12] - 2019-05-16
### Added
- Export base `AttMapLike`.
### Changed
- By default, add trailing newline to YAML rendition of an attmap instance; [Issue 48](https://github.com/pepkit/attmap/issues/48)
- Better API docs
### Fixed
- Do not replace double slash in URL with single slash. See [Issue 46](https://github.com/pepkit/attmap/issues/46)

## [0.11] - 2019-05-16
### Added
- `get_yaml_lines` to get collection of YAML-ready lines from any attmap
Expand Down
27 changes: 27 additions & 0 deletions docs/howto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use cases and "how-to..."

## ...customize a subtype's text rendition
In a subclass, override `_excl_from_repr`, using key and/or type of value.

The most basic implementation is a no-op, excluding nothing:
```python
def _excl_from_repr(self, k, cls):
return False
```

To exclude by key, though, you can do something like:
```python
def _excl_from_repr(self, k, cls):
protected = ["reserved_metadata", "REZKEY"]
return k in protected
```

To exclude by value type, you can use something like:
```python
def _excl_from_repr(self, k, cls):
return issubclass(cls, BaseOmissionType)
```
where `BaseOmissionType` is a proxy for the name of some type of values that may
be stored in your mapping but that you prefer to not display in its text representation.

The two kinds of exclusion criteria may be combined as desired.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ nav:
- Home: README.md
- Reference:
- API: autodoc_build/attmap.md
- Howto: howto.md
- Support: support.md
- Contributing: contributing.md
- Changelog: changelog.md
Expand Down
2 changes: 1 addition & 1 deletion requirements/requirements-all.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ubiquerg>=0.0.5
ubiquerg>=0.2.1
29 changes: 24 additions & 5 deletions tests/test_packaging.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,38 @@
""" Validate what's available directly on the top-level import. """

from abc import ABCMeta
from collections import OrderedDict
from inspect import isclass, isfunction
import itertools
import pytest
import attmap
from attmap import *

__author__ = "Vince Reuter"
__email__ = "[email protected]"


@pytest.mark.parametrize(
["obj_name", "typecheck"],
[("AttMap", isclass), ("OrdAttMap", isclass), ("PathExAttMap", isclass),
("AttMapEcho", isclass), ("get_data_lines", isfunction)])
def get_base_check(*bases):
"""
Build function to validate an type's base classes.
:param bases: sequence of base types.
:return function(type) -> bool: function that checks a type's base classes
for equivalence with the sequence given here.
"""
return lambda obj: obj.__bases__ == bases


@pytest.mark.parametrize(["obj_name", "typecheck"], itertools.chain(*[
[("AttMapLike", f) for f in [isclass, lambda obj: obj.__metaclass__ == ABCMeta]],
[("AttMap", f) for f in [isclass, get_base_check(AttMapLike)]],
[("OrdAttMap", f) for f in [isclass, get_base_check(OrderedDict, AttMap)]],
[("PathExAttMap", f) for f in [isclass, get_base_check(OrdAttMap)]],
[("AttMapEcho", f) for f in [isclass, get_base_check(PathExAttMap)]],
[("get_data_lines", isfunction)]
]))
def test_top_level_exports(obj_name, typecheck):
""" At package level, validate object availability and type. """
import attmap
mod = attmap
try:
obj = getattr(mod, obj_name)
Expand Down
10 changes: 10 additions & 0 deletions tests/test_path_expansion.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,13 @@ def test_non_PathExAttMap_preserves_all_variables(path, fetch, env):
with TmpEnv(**env):
m[k] = path
assert path == fetch(m, k)


@pytest.mark.parametrize(["path", "expected"], [
("http://localhost", "http://localhost"),
("http://lh/$HOME/page.html", "http://lh/{}/page.html".format(os.environ["HOME"]))])
@pytest.mark.parametrize("fetch", [lambda m, k: m[k], lambda m, k: getattr(m, k)])
def test_url_expansion(path, expected, fetch):
key = "arbitrary"
m = PathExAttMap({key: path})
assert expected == fetch(m, key)
13 changes: 11 additions & 2 deletions tests/test_to_disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ def check_lines(m, explines, obs_fun, parse, check):


@pytest.mark.parametrize(
["funcname", "exp"], [("get_yaml_lines", ["{}"]), ("to_yaml", "{}")])
["funcname", "exp"], [("get_yaml_lines", ["{}"]), ("to_yaml", "{}\n")])
def test_empty(funcname, exp, maptype):
""" Verify behavior for YAML of empty attmap. """
assert exp == getattr(maptype({}), funcname)()


@pytest.mark.parametrize(
["get_obs", "parse_obs"],
[("get_yaml_lines", lambda ls: ls), ("to_yaml", lambda ls: ls.split("\n"))])
[("get_yaml_lines", lambda ls: ls), ("to_yaml", lambda ls: ls.split("\n")[:-1])])
def test_yaml(maptype, get_obs, parse_obs):
""" Tests for attmap repr as YAML lines or full text chunk. """
eq = lambda a, b: a == b
Expand All @@ -86,6 +86,15 @@ def test_disk_roundtrip(maptype, tmpdir, fmtlib):
assert recons == m.to_dict()


@pytest.mark.parametrize(
["args", "exp_newl_end"],
[(tuple(), True), ((False, ), False), ((True, ), True)])
def test_yaml_newline(args, exp_newl_end, maptype):
""" Map to_yaml adds newline by default but respect argument. """
data = {"randkey": "arbval"}
assert maptype(data).to_yaml(*args).endswith("\n") is exp_newl_end


@pytest.mark.parametrize(["data", "env_var", "fmtlib", "exp_res"], [
({"arbkey": os.path.join("$HOME", "leaf.md")}, "HOME", JSON_NAME,
["{{\"arbkey\": \"{}\"}}".format(os.path.join("$HOME", "leaf.md"))]),
Expand Down

0 comments on commit ecfb2f8

Please sign in to comment.