Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare for 1.2.1 #16

Merged
merged 9 commits into from
May 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
1.2.1
Enhancements:
* Some exception/error messages have been updated to print the entire original
-- albeit parsed -- YAML Path in addition to the present segment under
evaluation.

Bug Fixes:
* yaml-get version 1.0.2 now converts new-lines into "\n" character sequences
when writing output so that multi-line values remain one-result-per-line.
* Use of escape symbols for unusual characters (where demarcation would usually
be more intuitive) is now preserved. Thus, these two search phrases are now
identical:
array[.%" can't "]
array[.%\ can\'t\ ]
* The issue preventing some YAML Paths from being printable after parsing has
been fixed. Valid, parsed YAML Paths now correctly print into a re-parsable
form even with weird sequences and escapes. Note that superfluous whitespace
and other symbols are still removed or escaped when the YAML Path is printed,
so:
term [ key == "Superfluous spaces aren\'t kept." ]
correctly parses and prints as:
term[key=Superfluous\ spaces\ aren\'t\ kept.]

1.2.0
Enhancements:
* A new search operator, :, now enables capturing slices of Arrays (by 0-based
Expand Down
4 changes: 2 additions & 2 deletions bin/yaml-get
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ from yamlpath.eyaml import EYAMLPath
from yamlpath.wrappers import ConsolePrinter

# Implied Constants
MY_VERSION = "1.0.1"
MY_VERSION = "1.0.2"

def processcli():
"""Process command-line arguments."""
Expand Down Expand Up @@ -169,7 +169,7 @@ def main():
if isinstance(node, list) or isinstance(node, dict):
print(json.dumps(node))
else:
print("{}".format(node))
print("{}".format(str(node).replace("\n", r"\n")))

if __name__ == "__main__":
main()
74 changes: 62 additions & 12 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from yamlpath.parser import Parser
from yamlpath.exceptions import YAMLPathException
from yamlpath.wrappers import ConsolePrinter
from yamlpath.enums import PathSeperators
from yamlpath.enums import PathSeperators, PathSegmentTypes

@pytest.fixture
def parser():
Expand All @@ -19,6 +19,7 @@ def test_empty_str_path(parser):
assert parser.str_path("") == ""

@pytest.mark.parametrize("yaml_path,stringified", [
("&topArrayAnchor[0]", "&topArrayAnchor[0]"),
("aliases[&anchor]", "aliases[&anchor]"),
("a l i a s e s [ & a n c h o r ]", "aliases[&anchor]"),
("aliases[2]", "aliases[2]"),
Expand All @@ -27,6 +28,11 @@ def test_empty_str_path(parser):
("lookup::credentials.backend.database.password.hash", "lookup::credentials.backend.database.password.hash"),
("does::not[7].exist[4]", "does::not[7].exist[4]"),
("messy.messy.'dotted.sub.key'.child", r"messy.messy.dotted\.sub\.key.child"),
])
def test_happy_str_path_translations_simple(parser, yaml_path, stringified):
assert parser.str_path(yaml_path) == stringified

@pytest.mark.parametrize("yaml_path,stringified", [
('some[search="Name Here"]', r"some[search=Name\ Here]"),
('some[search=="Name Here"]', r"some[search=Name\ Here]"),
('some[search^"Name "]', r"some[search^Name\ ]"),
Expand Down Expand Up @@ -62,25 +68,32 @@ def test_empty_str_path(parser):
('some[!search < 42]', "some[search!<42]"),
('some[!search >= 5280]', "some[search!>=5280]"),
('some[!search <= 14000]', "some[search!<=14000]"),
])
def test_happy_str_path_translations_simple_searches(parser, yaml_path, stringified):
assert parser.str_path(yaml_path) == stringified

@pytest.mark.parametrize("yaml_path,stringified", [
(r'some[search =~ /^\d{5}$/]', r'some[search=~/^\d{5}$/]'),
])
def test_happy_str_path_translations_regex_searches(parser, yaml_path, stringified):
assert parser.str_path(yaml_path) == stringified

@pytest.mark.parametrize("yaml_path,stringified", [
('"aliases[&some_name]"', r'aliases\[\&some_name\]'),
('&topArrayAnchor[0]', '&topArrayAnchor[0]'),
('"&topArrayAnchor[0]"', r'\&topArrayAnchor\[0\]'),
('"&subHashAnchor.child1.attr_tst"', r'\&subHashAnchor\.child1\.attr_tst'),
("'&topArrayAnchor[!.=~/[Oo]riginal/]'", r"\&topArrayAnchor\[!\.=~/\[Oo\]riginal/\]"),
])
def test_happy_str_path_translations(parser, yaml_path, stringified):
def test_happy_str_path_translations_bad_quotes(parser, yaml_path, stringified):
assert parser.str_path(yaml_path) == stringified

@pytest.mark.parametrize("yaml_path,stringified", [
("aliases[.%' ']", r"aliases[.%\ ]"),
(r"aliases[.%\ ]", r"aliases[.%\ ]"),
])
def test_happy_str_path_translations_weird_escapes(parser, yaml_path, stringified):
assert parser.str_path(yaml_path) == stringified

# This will be a KNOWN ISSUE for this release. The fix for this may require a
# deep rethink of the Parser class. The issue here is that escaped characters
# in YAML Paths work perfectly well, but they can't be printed back to the
# screen in their pre-parsed form. So, when a user submits a YAML Path of
# "some\\escaped\\key", all printed forms of the key will become
# "someescapedkey" even though the path WILL find the requested data. This is
# only a stringification (printing) anomoly and hense, it will be LOW PRIORITY,
# tracked as a KNOWN ISSUE, for now.
@pytest.mark.xfail
@pytest.mark.parametrize("yaml_path,stringified", [
('key\\with\\slashes', 'key\\with\\slashes'),
])
Expand Down Expand Up @@ -154,3 +167,40 @@ def test_pretyped_pathsep(pathsep, compare):
def test_bad_pathsep():
with pytest.raises(YAMLPathException):
_ = Parser(None, pathsep="no such seperator!")

@pytest.mark.parametrize("yaml_path,strip_escapes", [
("some.hash.key", True),
("some.hash.key", False),
("/some/hash/key", True),
("/some/hash/key", False),
])
def test_repeat_parsings(parser, yaml_path, strip_escapes):
orig = parser._parse_path(yaml_path, strip_escapes)
comp = parser._parse_path(yaml_path, strip_escapes)
assert orig == comp

def test_no_dict_parsings(parser):
with pytest.raises(YAMLPathException):
_ = parser._parse_path({})

def test_list_to_deque_parsing(parser):
parsed_list = [
(PathSegmentTypes.KEY, 'aliases'),
(PathSegmentTypes.ANCHOR, 'secretIdentity')
]
verify_queue = deque([
(PathSegmentTypes.KEY, 'aliases'),
(PathSegmentTypes.ANCHOR, 'secretIdentity')
])
assert verify_queue == parser._parse_path(parsed_list)

def test_deque_to_deque_parsings(parser):
verify_queue = deque([
(PathSegmentTypes.KEY, 'aliases'),
(PathSegmentTypes.ANCHOR, 'secretIdentity')
])
assert verify_queue == parser._parse_path(verify_queue)

def test_none_to_empty_deque_parsings(parser):
verify_queue = deque()
assert verify_queue == parser._parse_path(None)
24 changes: 16 additions & 8 deletions tests/test_yamlpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from ruamel.yaml.scalarfloat import ScalarFloat
from ruamel.yaml.scalarint import ScalarInt

from yamlpath import YAMLPath
from yamlpath import YAMLPath, Parser
from yamlpath.exceptions import YAMLPathException
from yamlpath.enums import (
YAMLValueFormats,
Expand Down Expand Up @@ -161,11 +161,14 @@
]

@pytest.fixture
def yamlpath():
"""Returns a YAMLPath with a quiet logger."""
def quiet_logger():
args = SimpleNamespace(verbose=False, quiet=True, debug=False)
logger = ConsolePrinter(args)
return YAMLPath(logger)
return ConsolePrinter(args)

@pytest.fixture
def yamlpath(quiet_logger):
"""Returns a YAMLPath with a quiet logger."""
return YAMLPath(quiet_logger)

@pytest.fixture
def yamldata():
Expand Down Expand Up @@ -525,7 +528,7 @@ def test_nonexistant_path_segment_types(yamlpath, yamldata):
PathSegmentTypes = Enum('PathSegmentTypes', names)

with pytest.raises(NotImplementedError):
for _ in yamlpath._get_elements_by_ref(yamldata, (PathSegmentTypes.DNF, False)):
for _ in yamlpath._get_elements_by_ref(yamldata, (PathSegmentTypes.DNF, ("", False, False))):
pass

@pytest.mark.parametrize("sep,val", [
Expand All @@ -549,12 +552,12 @@ def test_append_list_element_value_error(yamlpath):

def test_get_elements_by_bad_ref(yamlpath, yamldata):
with pytest.raises(YAMLPathException):
for _ in yamlpath._get_elements_by_ref(yamldata, (PathSegmentTypes.INDEX, "4F")):
for _ in yamlpath._get_elements_by_ref(yamldata, (PathSegmentTypes.INDEX, ("bad_index[4F]", "4F", "4F"))):
pass

def test_get_elements_by_none_refs(yamlpath, yamldata):
tally = 0
for _ in yamlpath._get_elements_by_ref(None, (PathSegmentTypes.INDEX, "4F")):
for _ in yamlpath._get_elements_by_ref(None, (PathSegmentTypes.INDEX, ("bad_index[4F]", "4F", "4F"))):
tally += 1

for _ in yamlpath._get_elements_by_ref(yamldata, None):
Expand Down Expand Up @@ -582,3 +585,8 @@ def test_yamlpath_exception():
raise YAMLPathException("meh", "/some/path", "/some")
except YAMLPathException as ex:
_ = str(ex)

def test_premade_parser(quiet_logger):
premade = Parser(quiet_logger)
preload = YAMLPath(quiet_logger, parser=premade)
assert preload.parser == premade
1 change: 1 addition & 0 deletions yamlpath/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
import yamlpath.enums
import yamlpath
from yamlpath.yamlpath import YAMLPath
from yamlpath.parser import Parser
5 changes: 4 additions & 1 deletion yamlpath/enums/pathsearchmethods.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""Implements the PathSearchMethods enumeration."""
"""Implements the PathSearchMethods enumeration.

Copyright 2019 William W. Kimball, Jr. MBA MSIS
"""
from enum import Enum, auto


Expand Down
5 changes: 4 additions & 1 deletion yamlpath/enums/pathsegmenttypes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""Implements the PathSegmentTypes enumeration."""
"""Implements the PathSegmentTypes enumeration.

Copyright 2019 William W. Kimball, Jr. MBA MSIS
"""
from enum import Enum, auto


Expand Down
5 changes: 4 additions & 1 deletion yamlpath/enums/pathseperators.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""Implements the PathSeperators enumeration."""
"""Implements the PathSeperators enumeration.

Copyright 2019 William W. Kimball, Jr. MBA MSIS
"""
from enum import Enum, auto


Expand Down
5 changes: 4 additions & 1 deletion yamlpath/enums/yamlvalueformats.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
"""Implements the YAMLValueFormats enumeration."""
"""Implements the YAMLValueFormats enumeration.

Copyright 2019 William W. Kimball, Jr. MBA MSIS
"""
from enum import Enum, auto


Expand Down
6 changes: 6 additions & 0 deletions yamlpath/exceptions/eyamlcommand.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
"""Represents an exception that occurs during an EYAML command execution.

Copyright 2019 William W. Kimball, Jr. MBA MSIS
"""


class EYAMLCommandException(Exception):
pass