Code Monkey home page Code Monkey logo

pretty-yaml's Introduction

pretty-yaml (or pyaml)

PyYAML-based python module to produce a bit more pretty and human-readable YAML-serialized data.

This module is for serialization only, see ruamel.yaml module for literate YAML parsing (keeping track of comments, spacing, line/column numbers of values, etc).

(side-note: to dump stuff parsed by ruamel.yaml with this module, use only YAML(typ='safe') there)

It's a small module, and for projects that only need part of its functionality, I'd recommend copy-pasting that in, instead of adding janky dependency.

Repository URLs:

Warning

Prime goal of this module is to produce human-readable output that can be easily diff'ed, manipulated and re-used, but maybe with occasional issues.

So please do not rely on the thing to produce output that can always be deserialized exactly to what was exported, at least - use PyYAML directly for that (but maybe with options from the next section).

What this module does and why

YAML is generally nice and easy format to read if it was written by humans.

PyYAML can a do fairly decent job of making stuff readable, and the best combination of parameters for such output that I've seen so far is probably this one:

>>> m = [123, 45.67, {1: None, 2: False}, 'some text']
>>> data = dict(a='asldnsa\nasldpáknsa\n', b='whatever text', ma=m, mb=m)
>>> yaml.safe_dump( data, sys.stdout,
  width=100, allow_unicode=True, default_flow_style=False )
a: 'asldnsa

  asldpáknsa

  '
b: whatever text
ma: &id001
- 123
- 45.67
- 1: null
  2: false
- some text
mb: *id001

pyaml (this module) tries to improve on that a bit, with the following tweaks:

  • Most human-friendly representation options in PyYAML (that I know of) are used as defaults - unicode, flow-style, width=100 (old default is 80).
  • Dump "null" values as empty values, if possible, which have the same meaning but reduce visual clutter and are easier to edit.
  • Dicts, sets, OrderedDicts, defaultdicts, namedtuples, enums, dataclasses, etc are represented as their safe YAML-compatible base (like int, list or mapping), with mappings key-sorted by default for more diff-friendly output.
  • Use shorter and simpler yes/no for booleans.
  • List items get indented, as they should be.
  • Attempt is made to pick more readable string representation styles, depending on the value, e.g.:

    >>> yaml.safe_dump(cert, sys.stdout)
    cert: '-----BEGIN CERTIFICATE-----
    
      MIIH3jCCBcagAwIBAgIJAJi7AjQ4Z87OMA0GCSqGSIb3DQEBCwUAMIHBMRcwFQYD
    
      VQQKFA52YWxlcm9uLm5vX2lzcDEeMBwGA1UECxMVQ2VydGlmaWNhdGUgQXV0aG9y
    ...
    
    >>> pyaml.p(cert):
    cert: |
      -----BEGIN CERTIFICATE-----
      MIIH3jCCBcagAwIBAgIJAJi7AjQ4Z87OMA0GCSqGSIb3DQEBCwUAMIHBMRcwFQYD
      VQQKFA52YWxlcm9uLm5vX2lzcDEeMBwGA1UECxMVQ2VydGlmaWNhdGUgQXV0aG9y
    ...
  • "force_embed" option (default=yes) to avoid having &id stuff scattered all over the output. Might be more useful to disable it in some specific cases though.
  • "&idXYZ" anchors, when needed, get labels from the keys they get attached to, not just meaningless enumerators, e.g. "&users_-_admin" instead.
  • "string_val_style" option to only apply to strings that are values, not keys, i.e:

    >>> pyaml.p(data, string_val_style='"')
    key: "value\nasldpáknsa\n"
    >>> yaml.safe_dump(data, sys.stdout, allow_unicode=True, default_style='"')
    "key": "value\nasldpáknsa\n"
  • Add vertical spacing (empty lines) between keys on different depths, to separate long YAML sections in the output visually, make it more seekable.
  • Discard end-of-document "..." indicators for simple values.

Result for the (rather meaningless) example above:

>>> pyaml.p(data, force_embed=False, vspacing=dict(split_lines=10))

a: |
  asldnsa
  asldpáknsa

b: whatever text

ma: &ma
  - 123
  - 45.67
  - 1:
    2: no
  - some text

mb: *ma

(force_embed=False enabled deduplication with &ma anchor, vspacing is adjusted to split even this tiny output)


Extended example:

>>> pyaml.dump(data, vspacing=dict(split_lines=10))

destination:

  encoding:
    xz:
      enabled: yes
      min_size: 5120
      options:
      path_filter:
        - \.(gz|bz2|t[gb]z2?|xz|lzma|7z|zip|rar)$
        - \.(rpm|deb|iso)$
        - \.(jpe?g|gif|png|mov|avi|ogg|mkv|webm|mp[34g]|flv|flac|ape|pdf|djvu)$
        - \.(sqlite3?|fossil|fsl)$
        - \.git/objects/[0-9a-f]+/[0-9a-f]+$

  result:
    append_to_file:
    append_to_lafs_dir:
    print_to_stdout: yes

  url: http://localhost:3456/uri

filter:
  - /(CVS|RCS|SCCS|_darcs|\{arch\})/$
  - /\.(git|hg|bzr|svn|cvs)(/|ignore|attributes|tags)?$
  - /=(RELEASE-ID|meta-update|update)$

http:
  ca_certs_files: /etc/ssl/certs/ca-certificates.crt
  debug_requests: no
  request_pool_options:
    cachedConnectionTimeout: 600
    maxPersistentPerHost: 10
    retryAutomatically: yes

logging:

  formatters:
    basic:
      datefmt: '%Y-%m-%d %H:%M:%S'
      format: '%(asctime)s :: %(name)s :: %(levelname)s: %(message)s'

  handlers:
    console:
      class: logging.StreamHandler
      formatter: basic
      level: custom
      stream: ext://sys.stderr

  loggers:
    twisted:
      handlers:
        - console
      level: 0

  root:
    handlers:
      - console
    level: custom

Note that unless there are many moderately wide and deep trees of data, which are expected to be read and edited by people, it might be preferrable to directly use PyYAML regardless, as it won't introduce another (rather pointless in that case) dependency and a point of failure.

Features and Tricks

  • Pretty-print any yaml or json (yaml subset) file from the shell:

    % python -m pyaml /path/to/some/file.yaml
    % pyaml < myfile.yml
    % curl -s https://www.githubstatus.com/api/v2/summary.json | pyaml

    pipx install pyaml can be a good way to only install "pyaml" command-line script.

  • Process and replace json/yaml file in-place:

    % python -m pyaml -r mydata.yml
  • Easier "debug printf" for more complex data (all funcs below are aliases to same thing):

    pyaml.p(stuff)
    pyaml.pprint(my_data)
    pyaml.pprint('----- HOW DOES THAT BREAKS!?!?', input_data, some_var, more_stuff)
    pyaml.print(data, file=sys.stderr) # needs "from __future__ import print_function"
  • Force all string values to a certain style (see info on these in PyYAML docs):

    pyaml.dump(many_weird_strings, string_val_style='|')
    pyaml.dump(multiline_words, string_val_style='>')
    pyaml.dump(no_want_quotes, string_val_style='plain')

    Using pyaml.add_representer() (note *p*yaml) as suggested in this SO thread (or github-issue-7) should also work.

    See also this amazing reply to StackOverflow#3790454 for everything about the many different string styles in YAML.

  • Control indent and width of the results:

    pyaml.dump(wide_and_deep, indent=4, width=120)

    These are actually keywords for PyYAML Emitter (passed to it from Dumper), see more info on these in PyYAML docs.

  • Dump multiple yaml documents into a file: pyaml.dump_all([data1, data2, data3], dst_file)

    explicit_start=True is implied, unless overidden by explicit_start=False.

  • Control thresholds for vertical spacing of values (0 = always space stuff out), and clump all oneliner ones at the top:

    >>> pyaml.dump( data,
      sort_dicts=pyaml.PYAMLSort.oneline_group,
      vspacing=dict(split_lines=0, split_count=0) )
    
    chart:
      axisCenteredZero: no
      axisColorMode: text
      axisLabel: ''
      axisPlacement: auto
      barAlignment: 0
      drawStyle: line
      ...
    
      hideFrom:
        legend: no
        tooltip: no
        viz: no
    
      scaleDistribution:
        type: linear
    
      stacking:
        group: A
        mode: none

    Or same thing with cli tool -v/--vspacing option: pyaml -v 0/0g mydata.yaml

Installation

It's a regular Python 3.8+ module/package, published on PyPI (as pyaml).

Module uses PyYAML for processing of the actual YAML files and should pull it in as a dependency.

Dependency on unidecode module is optional and only be used with force_embed=False keyword (defaults to True), and same-id objects or recursion within serialized data - i.e. only when generating &some_key_id anchors is actually needed. If module is unavailable at runtime, anchor ids might be less like their keys and maybe not as nice.

Using pip is how you generally install it, usually coupled with venv usage (which will also provide "pip" tool itself):

% pip install pyaml

Current-git version can be installed like this:

% pip install git+https://github.com/mk-fg/pretty-yaml

pip will default to installing into currently-active venv, then user's home directory (under ~/.local/lib/python...), and maybe system-wide when running as root (only useful in specialized environments like docker containers).

There are many other python packaging tools - pipenv, poetry, pdm, etc -use whatever is most suitable for specific project/environment. pipx can be used to install command-line script without a module.

More general info on python packaging can be found at packaging.python.org.

When changing code, unit tests can be run with python -m unittest from the local repository checkout.

pretty-yaml's People

Contributors

chrigl avatar davidfischer-ch avatar graingert avatar mk-fg avatar orivej avatar pr0ps avatar rosmo avatar sbraz avatar stephenbrown2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pretty-yaml's Issues

Using dump(data, safe=True) fails

Using dump with safe set to True causes an error

...
File ".../lib/python2.7/site-packages/pyaml/__init__.py", line 135, in dump
    yaml.dump_all([data], buff, Dumper=Dumper, default_flow_style=False, encoding='utf-8')
  File ".../lib/python2.7/site-packages/yaml/__init__.py", line 186, in dump_all
    explicit_start=explicit_start, explicit_end=explicit_end)
TypeError: __init__() got an unexpected keyword argument 'force_embed'

Two problems converting AWS Cloudformation templates

AWS CloudFormation templates now support YAML, and we're converting a lot of JSON using pyaml and enjoy it, but for one thing:

                        "Value": {
                            "Fn::Join": [
                                "",
                                [
                                    "apac-",
                                    {
                                        "Ref": "Environment"
                                    },
                                    "-",
                                    {
                                        "Ref": "EnvironmentName"
                                    },
                                    "-",

Here is what the above translates to (via print pyaml.dump(json.load(sys.stdin))):

          Value:
            Fn::Join:
              -
              - - apac-
                - Ref: Environment
                - -
                - Ref: EnvironmentName
                - -

There are two problems. The first, we need an empty string as the value after "Fn::Join". This may not be a problem with YAML, but AWS won't accept it-- it would be nice to have an option to print empty strings.

The second I think may be a bug-- the lines that read "- -" need the second dash in quotes to clarify that it's not a YAML formatting mark, but actually content.

To use these, we have to manually change to the following:

          Value:
            Fn::Join:
              - ''
              - - apac-
                - Ref: Environment
                - '-'
                - Ref: EnvironmentName
                - '-'

Serialization bug

Given the data:

{'foo': ['bar:', 'baz']}

pyaml serializes this as:

foo:
  - bar:
  - baz

which then gets deserialized by yaml as:

{'foo': [{'bar': None}, 'baz']}

This is different to the original data. I'm not sure if this is a problem with pyaml, yaml, or something else. The problem is fixed by forcing quotes around "bar:" in the output:

foo:
  - "bar:"
  - baz

This can be achieved by:

pyaml.dump(data, stream, string_val_style="double-quoted")

Sample code to reproduce the problem:

import yaml
import pyaml
import StringIO
data = {"foo": ["bar:", "baz"]}
print data
stream = StringIO.StringIO()
pyaml.dump(data, stream)
print stream.getvalue()
data2 = yaml.load(stream.getvalue())
print data2

RepresenterError: 'cannot represent an object' for custom object

Real simple example:

import pyaml
class Car:
    def __init__(self):
        self.make  = 'Honda'
car = Car()
pyaml.dump(car)

Output:
RepresenterError: ('cannot represent an object', <__main__.Car object at 0x7fe5f1af0c10>)

tested pyaml.dump(car.__dict__) works fine
tested import yaml; yaml.dump(car) works fine. output:
'!!python/object:__main__.Car\nmake: Honda\n (this is the output I would expect...)

What am I missing?

pyaml output stringified inexplicably in places

from pyaml import dumps
with open("foobar.yaml", "w") as f2:
    x = {}
    x["y"] = []
    x["y"].append("0.5.1")
    x["y"].append("0.51")
    x["y"].append("0.7.1")
    print(dumps(x, safe=True, indent=1).decode('utf-8'), file=f2)

makes...

y:
- 0.5.1
- '0.51'
- 0.7.1

But it is not clear why one of the list entries is in quotes and the others not.

Cannot install with Python 3.6 on Windows 10

Hi,

Using Pip, the pyaml fails to install on Windows 10 with Python 3.6. But if I use Python 3.5, the installation works fine.

> python -m pip install pyaml
Collecting pyaml
  Using cached pyaml-17.8.0-py2.py3-none-any.whl
Collecting PyYAML (from pyaml)
  Using cached PyYAML-3.12.tar.gz
Building wheels for collected packages: PyYAML
  Running setup.py bdist_wheel for PyYAML ... error
  Complete output from command C:\Users\code\venv36\Scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\code\\AppData\\Local\\Temp\\pip-build-pq03dgna\\PyYAML\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d C:\Users\code\AppData\Local\Temp\tmp0t79bxfmpip-wheel- --python-tag cp36:
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build\lib.win-amd64-3.6
  creating build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\composer.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\constructor.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\cyaml.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\dumper.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\emitter.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\error.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\events.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\loader.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\nodes.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\parser.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\reader.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\representer.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\resolver.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\scanner.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\serializer.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\tokens.py -> build\lib.win-amd64-3.6\yaml
  copying lib3\yaml\__init__.py -> build\lib.win-amd64-3.6\yaml
  running build_ext
  creating build\temp.win-amd64-3.6
  creating build\temp.win-amd64-3.6\Release
  checking if libyaml is compilable
  error: [WinError 3] The system cannot find the path specified: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\PlatformSDK\\lib'

  ----------------------------------------
  Failed building wheel for PyYAML
  Running setup.py clean for PyYAML
Failed to build PyYAML
Installing collected packages: PyYAML, pyaml
  Running setup.py install for PyYAML ... error
    Complete output from command C:\Users\\code\\venv36\Scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\code\\AppData\\Local\\Temp\\pip-build-pq03dgna\\PyYAML\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\code\AppData\Local\Temp\pip-pezzmj2e-record\install-record.txt --single-version-externally-managed --compile --install-headers C:\Users\code\venv36\include\site\python3.6\PyYAML:
    running install
    running build
    running build_py
    creating build
    creating build\lib.win-amd64-3.6
    creating build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\composer.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\constructor.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\cyaml.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\dumper.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\emitter.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\error.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\events.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\loader.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\nodes.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\parser.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\reader.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\representer.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\resolver.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\scanner.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\serializer.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\tokens.py -> build\lib.win-amd64-3.6\yaml
    copying lib3\yaml\__init__.py -> build\lib.win-amd64-3.6\yaml
    running build_ext
    creating build\temp.win-amd64-3.6
    creating build\temp.win-amd64-3.6\Release
    checking if libyaml is compilable
    error: [WinError 3] The system cannot find the path specified: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\PlatformSDK\\lib'

    ----------------------------------------
Command "C:\Users\code\venv36\Scripts\python.exe -u -c "import setuptools, tokenize;__file__='C:\\Users\\code\\AppData\\Local\\Temp\\pip-build-pq03dgna\\PyYAML\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\code\AppData\Local\Temp\pip-pezzmj2e-record\install-record.txt --single-version-externally-managed --compile --install-headers C:\Users\code\venv36\include\site\python3.6\PyYAML" failed with error code 1 in C:\Users\code\AppData\Local\Temp\pip-build-pq03dgna\PyYAML\

Default to safe=True?

Currently, pyaml.dump defaults to safe=False. Maybe it could be changed to safe=True by default (security by default)?

Would there be any noticeable difference from that and do you think safe=True would limit normal use cases?

If you disagree with changing the default, maybe the docs can be updated to use the safe=True where possible?

See also: Make load safe_load

Thanks for your nice library!

openapi.yaml is invalid after re-formatting

I tried to apply the formatter to an OpenAPI spec, (ex1.

It appears to me that after running python -m pyaml -r ./juice_users/openapi/openapi.yaml, the spec is broken and cannot be used anymore with the OpenAPI generator.

Is there something I could do to prevent breaking my spec file?

TypeError: must be str, not bytes in Python 3

In [7]: pyaml.pprint("a")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-768996862cc6> in <module>()
----> 1 pyaml.pprint("a")

/Users/aaronmeurer/Documents/pretty-yaml/pyaml/__init__.py in pprint(*data, **dump_kws)
    169         dst = dump_kws.pop('file', dump_kws.pop('dst', sys.stdout))
    170         if len(data) == 1: data, = data
--> 171         dump(data, dst=dst, **dump_kws)
    172
    173 p, _p = pprint, print

/Users/aaronmeurer/Documents/pretty-yaml/pyaml/__init__.py in dump(data, dst, safe, force_embed, vspacing, string_val_style)
    161                 return buff.getvalue().decode('utf-8')
    162         else:
--> 163                 dst.write(buff.getvalue())
    164
    165 def dumps(data, **dump_kws):

TypeError: must be str, not bytes

dump() arguments: stream vs dst

There is tiny incompatibility with PyYAML:

PyYAML: dump(data, stream=None, ...)
https://github.com/yaml/pyyaml/blob/main/lib/yaml/__init__.py#L248

pretty-yaml: dump(data, dst=None, ...)
https://github.com/mk-fg/pretty-yaml/blob/master/pyaml/__init__.py#L164

As a result:

>>> yaml.dump({}, stream=sys.stdout)
{}

>>> pyaml.dump({}, stream=sys.stdout)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/xxx/.local/lib/python3.10/site-packages/pyaml/__init__.py", line 181, in dump
    yaml.dump_all( data, buff, Dumper=Dumper,
TypeError: dump_all() got multiple values for argument 'stream'

Make it able to load ”relaxed” YAML files

I wrote a simple wrapper around the yaml library that gives me some additional features:

  • comments
  • inline comments
  • warnings about mixed spaces and tabs
  • warnings about lines that contain ambiguous # characters (could be comment or a URL anchor)

I use it for loading configuration files for my systems. Comments are really helpful for admins who run these systems, as the config file also acts as a source of documentation.

Basically, it is the same philosophy, but aimed at the opposite end - reading YAML files written in a humane fashion.

Would you agree with adding this relaxed reading feature to this module? Here's a draft: ralienpp@cd7de49

Test regression with Python 3.11: DumpTests.test_enum

On Python 3.11, the test suite fails with the 23.5.7 release:

_________________________________________________________ DumpTests.test_enum _________________________________________________________

self = <pyaml.tests.test_dump.DumpTests testMethod=test_enum>

    def test_enum(self):
    	c = test_const.heartbeat
    	d1 = {'a': c, 'b': c.value, c: 'testx'}
    	self.assertEqual(d1['a'], d1['b'])
    	s = pyaml.dump(d1)
    	d2 = yaml.safe_load(s)
    	self.assertEqual(d1['a'], d2['a'])
    	self.assertEqual(d1['a'], c)
    	self.assertEqual(d1[c], 'testx')
>   	self.assertIn('a: 123 # test_const.heartbeat', s)
E    AssertionError: 'a: 123 # test_const.heartbeat' not found in 'a: 123 # 123\nb: 123\n123: testx\n'

pyaml/tests/test_dump.py:399: AssertionError

The test passes on Python 3.10.

pyaml converts integer-like strings to integers

For example:

(ae.venv)bash-3.2$ python
Python 2.7.12 (default, Nov  7 2016, 14:33:03) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyaml
>>> pyaml.dump({"foo": "1"})
u'foo: 1\n'

Is this intended behavior? The problem is that the data we read back from this sort of YAML is different to what was written.

Deprecation warning

Hello.
Your lib uses pyyaml==4.2b4
But it raises a warning in Python 3.7

  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/__init__.py", line 72, in load
    return loader.get_single_data()
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/constructor.py", line 37, in get_single_data
    return self.construct_document(node)
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/constructor.py", line 46, in construct_document
    for dummy in generator:
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/constructor.py", line 398, in construct_yaml_map
    value = self.construct_mapping(node)
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/constructor.py", line 204, in construct_mapping
    return super().construct_mapping(node, deep=deep)
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/site-packages/yaml/constructor.py", line 126, in construct_mapping
    if not isinstance(key, collections.Hashable):
  File "/Users/myrik/.local/share/virtualenvs/esentai-e7Q7McuI/lib/python3.7/collections/__init__.py", line 52, in __getattr__
    DeprecationWarning, stacklevel=2)
DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

Release pyaml 16.2.1

I just almost started fixing "Quote strings that start with [" but noticed it's been merged as #17 about 6 months ago.

Short-term I can pip-install from source, but could you please release a version with that fix?

Thanks!

missing margin/maxwidth option

From the documentation:

Attempt is made to pick more readable string representation styles, depending on the value

It would be nice if the user could provide as an option what the default maxwidth of a line should be. Peeking at the code this seems to be fixed to a constant, aka 120 chars, however in plenty of cases it is desirable to have a different maximum width (my terminal might be smaller or larger).

NameError: name 'unicode' is not defined

I can install PyYAML and pyaml but only PyYAML works.

Here I install PyYAML

install PyYAML

(vi_sys_pkgs)$ pip install PyYAML
.. ,, ..
.. ,, .. lots of output with warnings but ..
Successfully installed PyYAML
Cleaning up...

PyYAML WORKS
(vi1)$ python3 -c 'import yaml'
(vi1)$ # no output
At this point 'yaml' works when used in python.

Now for pyaml ..

install pyaml

(vi_sys_pkgs)$ pip install pyaml
Downloading/unpacking pyaml
Downloading pyaml-13.07.1.tar.gz
Running setup.py egg_info for package pyaml
Requirement already satisfied (use --upgrade to upgrade): PyYAML in ./lib/python3.3/site-packages (from pyaml)
Installing collected packages: pyaml
Running setup.py install for pyaml
Successfully installed pyaml
Cleaning up...

pyaml DOES NOT WORK

(vi1)$ python3 -c 'import pyaml'
Traceback (most recent call last):
File "", line 1, in
File "/adp/wd/vi1/lib/python3.3/site-packages/pyaml/init.py", line 9, in
def dump(data, dst=unicode, safe=False, force_embed=False, vspacing=None):
NameError: name 'unicode' is not defined

Do you know what may be wrong here?

pretty-yaml creates output not readable by itself for escaped strings

For escaped input such as

"|\U000F1988\U0002CB8D\U0003176D\xA2\U000E5BCA\xEC\xCB": "\U0001C716\U000E5AE3\x92\
  d\x8C\xD9"

which PYYaml does parse.

pretty-yaml produces unescaped output, ie.:

T2�x𳑡򶺳򗄌x.?¯𜿨¬: y񒟴񉲺񢤮𭀟𺭽Ê�𞛎

which PYYaml does not parse.

Why does it sort my keys in alphabet order?

I am using pyaml formatter with Neoformater in Neo Vim.

This is my docker-compose.yml before formatting:

version: 3

services:
  web:
    build: .
    ports:
      - 3000:3000

After formatting:

services:
  web:
    build: .
    ports:
      - 3000:3000
version: 3

Is there a way for me to prevent it from ordering my keys in alphabet order?

pyaml not compatible with ruamel.yaml

Given the following test yaml:

# This is a commented YAML file
replica: 1

image:
  repository: docker/python
  pull: IfNotPresent

imagePullSecrets:
  - name: docker-secret

and the following test python:

#!/usr/bin/env python3
from pathlib import Path
import pyaml
from ruamel.yaml import YAML

yaml = YAML()
test_file = Path("./test.yaml")
test_load = yaml.load(test_file)
pyaml.p(test_load)

I get the following error:

Traceback (most recent call last):
  File "./test_yaml.py", line 9, in <module>
    pyaml.p(test_load)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyaml/__init__.py", line 208, in pprint
    dump(data, dst=dst, **dump_kws)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyaml/__init__.py", line 188, in dump
    yaml.dump_all( data, buff, Dumper=Dumper,
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/yaml/__init__.py", line 278, in dump_all
    dumper.represent(data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/yaml/representer.py", line 27, in represent
    node = self.represent_data(data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/yaml/representer.py", line 58, in represent_data
    node = self.yaml_representers[None](self, data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyaml/__init__.py", line 37, in represent_undefined
    elif isinstance(data, OrderedDict): return dumper.represent_odict(data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyaml/__init__.py", line 29, in represent_odict
    node_value = dumper.represent_data(item_value)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/yaml/representer.py", line 58, in represent_data
    node = self.yaml_representers[None](self, data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyaml/__init__.py", line 40, in represent_undefined
    return super(PrettyYAMLDumper, dumper).represent_undefined(data)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/yaml/representer.py", line 231, in represent_undefined
    raise RepresenterError("cannot represent an object", data)
yaml.representer.RepresenterError: ('cannot represent an object', [ordereddict([('name', 'docker-secret')])])

Given that ruamel is mentioned in the docs for parsing, pyaml should be able to handle the results.

The problem is likely that ruamel creates and uses it's own subclass of OrderedDict:

https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/constructor.py#l20

https://sourceforge.net/p/ruamel-yaml/code/ci/default/tree/compat.py#l23

pyaml could do something like:

try:
	from ruamel.yaml.compat import ordereddict
	PrettyYAMLDumper.add_representer(ordereddict, PrettyYAMLDumper.represent_odict)
except ImportError:
    pass

dump fails on numpy arrays

I am trying to dump a dictionary with a numpy array. It works with yaml package, but fails here with pyaml:

dd = dict(a="b", b="c", c=(0,1,2), d= np.r_[4,5,6])
print(yaml.dump(dd, default_flow_style=False))
print("-"*20)
print(pyaml.dump(dd))
...
/usr/local/lib/python3.6/site-packages/pyaml/__init__.py in represent_undefined(dumper, data)
     34                 elif isinstance(data, OrderedDict): return dumper.represent_odict(data)
     35                 elif isinstance(data, dict): return dumper.represent_dict(data)
---> 36                 return super(PrettyYAMLDumper, dumper).represent_undefined(data)
     37 
     38         def serialize_node(self, node, parent, index):

/usr/local/lib/python3.6/site-packages/yaml/representer.py in represent_undefined(self, data)
    227 
    228     def represent_undefined(self, data):
--> 229         raise RepresenterError("cannot represent an object: %s" % data)
    230 
    231 SafeRepresenter.add_representer(type(None),

RepresenterError: cannot represent an object: [4 5 6]

Format and write into file

Hi,
Great project....
Just wanted to check if there is a way to input a file, prettify it and then write back to the same file?

Thanks

23.5.9 from pypi installs empty directory

When trying to build 23.5.9, the build installs an empty directory with just an UNKNOWN-0.0.0-py3.10.egg-info subdir.

On macOS (though this shouldn't matter):

$ /sw/bin/python3.10 setup.py build
running build
$ PYTHONPATH=/sw/build.build/pyaml-py310-23.5.9-1/pyaml-23.5.9/build/lib /sw/bin/python3.10 -m unittest || exit 2
......................
----------------------------------------------------------------------
Ran 22 tests in 0.125s

OK
$ /sw/bin/python3.10 setup.py install --root=/sw/build.build/root-pyaml-py310-23.5.9-1
running install
/sw/lib/python3.10/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
running build
running install_egg_info
running egg_info
creating UNKNOWN.egg-info
writing UNKNOWN.egg-info/PKG-INFO
writing dependency_links to UNKNOWN.egg-info/dependency_links.txt
writing top-level names to UNKNOWN.egg-info/top_level.txt
writing manifest file 'UNKNOWN.egg-info/SOURCES.txt'
reading manifest file 'UNKNOWN.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
adding license file 'COPYING'
writing manifest file 'UNKNOWN.egg-info/SOURCES.txt'
Copying UNKNOWN.egg-info to /sw/build.build/root-pyaml-py310-23.5.9-1/sw/lib/python3.10/site-packages/UNKNOWN-0.0.0-py3.10.egg-info
running install_scripts

The commands finish cleanly, but the installation directory is empty except for those files inside the UNKNOWN.egg-info directory.
I've also tried with a build based process, but the results are the same.
pyaml-21.10.1 built and installed fine w/ a full tree.

Making pretty-yaml work on python 2.6

I think it may be as simple as replacing a few {foo, bar}s with set(foo, bar) - is there any reason why 2.6 isn't supported? As it is, means any project relying on pretty-yaml has to be 2.7+ also.

% cannot start any token

So, recently I've tried this module to generate .yml files and came across an issue. If a line starts with a percentage sign, then this line ends up unquotted in the generated .yml file:

hello: %world

The problem occurs when you try to load it with yaml.safe_load() which results in:

found character '%' that cannot start any token

I'm really not sure if it is supposed to be like that (bug or feature?), because I'm not really familiar with this format yet and there might be different specifications, but if former then all we need to change is add % in this line, I think.

I don't understand why we can't pretty print long unicode strings with newlines

>>> print pyaml.dump({'a': 'asldnsa\nasldknsa\n'})
a: |
  asldnsa
  asldknsa
>>> print pyaml.dump({'a': u'asldnsa\nasldpáknsa\n'})
a: "asldnsa\nasldp\xE1knsa\n"

I tried to read the source and inspect it, but couldn't figure out where is the problem.
Is this solvable? If I know all the values I'm trying to print are UTF-8 strings, not bytes or anything else, is it possible to patch pyaml to allow me to print them beautifully? How?

Release new version to pypi

Hey hey,

This thing is pretty sweet. I like the fix for the max iterations. Do you think you could push it back up to the package index?

Thanks,

Josh

Multiline String as block and quoted Strings

Hi!

I have some OpenAPI schema definition, that I'm extracting via ApiSpec.

    ---
    x-extension: value
    post:
      # headline/name of the resource
      operationId: users create
      summary: Register user
      description: |
        Imagine all the users living for today

        Imagine there's no countries
        It isn't hard to do
        Nothing to kill or die for
        And no religion too

        Imagine all the users living life in peace, you
        You may say I'm a dreamer
        But I'm not the only one
        I hope some day you'll join us
        And the world will be as one

      security:
        - APIKeyHeader: []

      # this will appear as grouping in the left-side menu
      tags:
      - Legacy API

      consumes:
      - application/json
      produces:
      - application/json

      parameters:
      - in: body
        name: body
        description: Foo bar
        required: true
        schema:
          $ref: '#/components/schemas/FooBodySchema'

Apispec is doing all the heavy lifting, but I changed the yaml library to pretty-yaml to get rid of the Python type hints.

Question

Given the yaml above, how can I accomplish to receive multiline blocks as a block

      description: |
        Imagine all the users living for today

        Imagine there's no countries
        It isn't hard to do
        Nothing to kill or die for
        And no religion too

and

have single line Strings quoted

        schema:
          $ref: '#/components/schemas/FooBodySchema'

Currently I'm using

pyaml.dump(my_spec, safe=True, force_embed=False, vspacing=[2, 1], string_val_style='"')

which unfortunately puts the mutline Strings in simple quotes as well.

Thank you :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.