Skip to content

Commit

Permalink
Merge pull request #15 from wwkimball/bugfix/lost_escape
Browse files Browse the repository at this point in the history
Bugfix/lost escape
  • Loading branch information
wwkimball committed May 13, 2019
2 parents 34cb896 + a5273ec commit d9e2b13
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 11 deletions.
10 changes: 10 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
1.2.1
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 preferred) is now preserved. Thus, these two search phrases are now
identical:
array[.%" can't "]
array[.%\ can\'t\ ]

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()
26 changes: 24 additions & 2 deletions tests/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,14 +68,30 @@ 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

@pytest.mark.parametrize("yaml_path,stringified", [
Expand Down
14 changes: 12 additions & 2 deletions yamlpath/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,13 @@ def str_path(self, yaml_path, **kwargs):
if method == PathSearchMethods.REGEX:
safe_term = "/{}/".format(term.replace("/", r"\/"))
else:
safe_term = str(term).replace(" ", r"\ ")
# Replace unescaped spaces with escaped spaces
safe_term = r"\ ".join(
list(map(
lambda ele: ele.replace(" ", r"\ ")
, term.split(r"\ ")
))
)
ppath += (
"["
+ str(attr)
Expand All @@ -137,6 +143,10 @@ def str_path(self, yaml_path, **kwargs):

add_sep = True

self.log.debug(
"Parser::str_path: Finished building <{}>{} from <{}>{}."
.format(type(ppath), ppath, type(yaml_path), yaml_path)
)
return ppath

def parse_path(self, yaml_path):
Expand Down Expand Up @@ -268,6 +278,7 @@ def _parse_path(self, yaml_path, strip_escapes=True):

if escape_next:
# Pass-through; capture this escaped character
escape_next = False
pass

elif capturing_regex:
Expand Down Expand Up @@ -544,7 +555,6 @@ def _parse_path(self, yaml_path, strip_escapes=True):

element_id += c
seeking_anchor_mark = False
escape_next = False

# Check for unterminated RegExes
if capturing_regex:
Expand Down
13 changes: 8 additions & 5 deletions yamlpath/yamlpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,12 @@ def _get_nodes(self, data, yaml_path):
matches = 0
if yaml_path:
(curtyp, curele) = curref = yaml_path.popleft()
unstripped_ele = curele[2]

self.log.debug(
("YAMLPath::_get_nodes: Seeking element <{}>{} in data of"
+ " type {}:"
).format(curtyp, curele, type(data))
).format(curtyp, unstripped_ele, type(data))
)
self.log.debug(data)
self.log.debug("")
Expand All @@ -184,9 +185,9 @@ def _get_nodes(self, data, yaml_path):
if node is not None:
matches += 1
self.log.debug(
("YAMLPath::_get_nodes: Found element {} in the data;"
+ " recursing into it..."
).format(curele)
("YAMLPath::_get_nodes: Found element <{}>{} in the"
+ " data and recursing into it...")
.format(curtyp, unstripped_ele)
)
for epn in self._get_nodes(node, yaml_path.copy()):
if epn is not None:
Expand Down Expand Up @@ -688,7 +689,9 @@ def _ensure_path(self, data, path, value=None):
if curtyp is PathSegmentTypes.ANCHOR:
raise NotImplementedError
elif curtyp is PathSegmentTypes.KEY:
data[stripped_ele] = self._default_for_child(path, value)
data[stripped_ele] = self._default_for_child(
path, value
)
for node in self._ensure_path(
data[stripped_ele], path, value
):
Expand Down

0 comments on commit d9e2b13

Please sign in to comment.