Skip to content

Commit

Permalink
fix: UTF-8 values would end in tracebacks (fixes #51)
Browse files Browse the repository at this point in the history
Signed-off-by: Valentin Lab <valentin.lab@kalysto.org>
  • Loading branch information
vaab committed Dec 15, 2020
1 parent 4b85b16 commit e6c8aa9
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Usage
define here a common YAML input for the next examples::

$ cat <<EOF > test.yaml
name: "MyName !!"
name: "MyName !! héhé" ## using encoding, and support comments !
subvalue:
how-much: 1.1
how-many: 2
Expand All @@ -119,7 +119,7 @@ General browsing struct and displaying simple values
Simple query of simple attribute::

$ cat test.yaml | shyaml get-value name
MyName !!
MyName !! héhé

Query nested attributes by using '.' between key labels::

Expand Down Expand Up @@ -363,7 +363,7 @@ So::
break
fi
echo "---"
done | shyaml get-value -y ingests.0.id
done | shyaml get-value -y ingests.0.id ## docshtest: ignore-if LIBYAML
tag-1
...
---
Expand Down Expand Up @@ -691,7 +691,7 @@ Empty documents
When provided with an empty document, ``shyaml`` will consider the
document to hold a ``null`` value::

$ echo | shyaml get-value -y
$ echo | shyaml get-value -y ## docshtest: ignore-if LIBYAML
null
...

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
setup(
setup_requires=['d2to1'],
extras_require={'test': [
"docshtest==0.0.2",
"docshtest==0.0.3",
]},
d2to1=True
)
35 changes: 31 additions & 4 deletions shyaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import os.path
import re
import textwrap
import locale

import yaml

Expand Down Expand Up @@ -443,6 +444,10 @@ def die(msg, errlvl=1, prefix="Error: "):

SIMPLE_TYPES = (str if PY3 else basestring, int, float, type(None))
COMPLEX_TYPES = (list, dict)
if PY3:
STRING_TYPES = (str, )
else:
STRING_TYPES = (unicode, str)

## these are not composite values
ACTION_SUPPORTING_STREAMING=["get-type", "get-length", "get-value"]
Expand All @@ -455,7 +460,7 @@ def magic_dump(value):
instance). But complex type are written in a YAML useable format.
"""
return str(value) if isinstance(value, SIMPLE_TYPES) \
return "%s" % value if isinstance(value, SIMPLE_TYPES) \
else yaml_dump(value)


Expand All @@ -474,6 +479,7 @@ def type_name(value):
return type(value).__name__ if isinstance(value, EncapsulatedNode) else \
"struct" if isinstance(value, dict) else \
"sequence" if isinstance(value, (tuple, list)) else \
"str" if isinstance(value, STRING_TYPES) else \
type(value).__name__


Expand Down Expand Up @@ -585,7 +591,7 @@ def act(action, value, dump=yaml_dump):
termination = "\0" if action.endswith("-0") else "\n"

if action == "get-value":
return str(dump(value))
return "%s" % dump(value)
elif action in ("get-values", "get-values-0"):
if isinstance(value, dict):
return "".join("".join((dump(k), termination,
Expand All @@ -612,7 +618,7 @@ def act(action, value, dump=yaml_dump):
method = value.keys if action.startswith("keys") else \
value.items if action.startswith("key-values") else \
value.values
output = (lambda x: termination.join(str(dump(e)) for e in x)) \
output = (lambda x: termination.join("%s" % dump(e) for e in x)) \
if action.startswith("key-values") else \
dump
return "".join("".join((str(output(k)), termination)) for k in method())
Expand Down Expand Up @@ -787,7 +793,7 @@ def main(args): ## pylint: disable=too-many-branches
if opts.get("loader") is LineLoader:
sys.stdout.flush()

print(output, end="")
safe_print(output)
if opts.get("loader") is LineLoader:
sys.stdout.flush()
except (InvalidPath, ActionTypeError) as e:
Expand All @@ -798,6 +804,27 @@ def main(args): ## pylint: disable=too-many-branches
except InvalidAction as e:
die("'%s' is not a valid action.\n%s"
% (e.args[0], USAGE))
##
## Safe print
##

## Note that locale.getpreferredencoding() does NOT follow
## PYTHONIOENCODING by default, but ``sys.stdout.encoding`` does. In
## PY2, ``sys.stdout.encoding`` without PYTHONIOENCODING set does not
## get any values set in subshells. However, if _preferred_encoding
## is not set to utf-8, it leads to encoding errors.
_preferred_encoding = os.environ.get("PYTHONIOENCODING") or \
locale.getpreferredencoding()

def safe_print(content):
if not PY3:
if isinstance(content, unicode):
content = content.encode(_preferred_encoding)

print(content, end='')
sys.stdout.flush()




def entrypoint():
Expand Down

0 comments on commit e6c8aa9

Please sign in to comment.