Code Monkey home page Code Monkey logo

poyo's Introduction

poyo

A lightweight YAML Parser for Python. ๐Ÿ“

poyo does not allow deserialization of arbitrary Python objects. Supported types are str, bool, int, float, NoneType as well as dict and list values.

โš ๏ธ Please note that poyo supports only a chosen subset of the YAML format that is required to parse cookiecutter user configuration files. poyo does not have support for serializing into YAML and is not compatible with JSON.

Installation

poyo is available on PyPI for Python versions 2.7 and newer and can be installed with pip:

pip install poyo

This package does not have any additional requirements. ๐Ÿ“ฆ

Usage

poyo comes with a parse_string() function, to load utf-8 encoded string data into a Python dict.

import codecs
import logging

from poyo import parse_string, PoyoException

logging.basicConfig(level=logging.DEBUG)

with codecs.open("tests/foobar.yml", encoding="utf-8") as ymlfile:
    ymlstring = ymlfile.read()

try:
    config = parse_string(ymlstring)
except PoyoException as exc:
    logging.error(exc)
else:
    logging.debug(config)

Example

Input YAML string

---
default_context: # foobar
    greeting: ใ“ใ‚“ใซใกใฏ
    email: "[email protected]"
    docs: true

    gui: FALSE
    123: 456.789
    # comment
    # allthethings
    'some:int': 1000000
    foo: "hallo #welt" #Inline comment :)
    longtext: >
        This is a multiline string.
        It can contain all manners of characters.

        Single line breaks are ignored,
        but blank linkes cause line breaks.
    trueish: Falseeeeeee
    blog   : raphael.codes
    relative-root: /          # web app root path (default: '')
    lektor: 0.0.0.0:5000      # local build
    doc_tools:
        # docs or didn't happen
        -    mkdocs
        - 'sphinx'

        - null
    # ไปŠๆ—ฅใฏ
zZz: True
NullValue: Null

# Block
# Comment

Hello World:
    # See you at EuroPython
    null: This is madness   # yo
    gh: https://github.com/{0}.git
"Yay #python": Cool!

Output Python dict

{
    u"default_context": {
        u"greeting": u"ใ“ใ‚“ใซใกใฏ",
        u"email": u"[email protected]",
        u"docs": True,
        u"gui": False,
        u"lektor": "0.0.0.0:5000",
        u"relative-root": "/",
        123: 456.789,
        u"some:int": 1000000,
        u"foo": u"hallo #welt",
        u"longtext": (
            u"This is a multiline string. It can contain all "
            u"manners of characters.\nSingle line breaks are "
            u"ignored, but blank linkes cause line breaks.\n"
        ),
        u"trueish": u"Falseeeeeee",
        u"blog": u"raphael.codes",
        u"doc_tools": [u"mkdocs", u"sphinx", None],
    },
    u"zZz": True,
    u"NullValue": None,
    u"Hello World": {
        None: u"This is madness",
        u"gh": u"https://github.com/{0}.git",
    },
    u"Yay #python": u"Cool!",
}

Logging

poyo follows the recommendations for logging in a library, which means it does not configure logging itself. Its root logger is named poyo and the names of all its children loggers track the package/module hierarchy. poyo logs to a NullHandler and solely on DEBUG level.

If your application configures logging and allows debug messages to be shown, you will see logging when using poyo. The log messages indicate which parser method is used for a given string as the parser deseralizes the config. You can remove all logging from poyo in your application by setting the log level of the poyo logger to a value higher than DEBUG.

Disable Logging

import logging

logging.getLogger("poyo").setLevel(logging.WARNING)

Example Debug Logging Config

import logging
from poyo import parse_string

logging.basicConfig(level=logging.DEBUG)

CONFIG = """
---
default_context: # foobar
    greeting: ใ“ใ‚“ใซใกใฏ
    gui: FALSE
    doc_tools:
        # docs or didn't happen
        -    mkdocs
        - 'sphinx'
    123: 456.789
"""

parse_string(CONFIG)

Example Debug Logging Messages

DEBUG:poyo.parser:parse_blankline <- \n
DEBUG:poyo.parser:parse_blankline -> IGNORED
DEBUG:poyo.parser:parse_dashes <- ---\n
DEBUG:poyo.parser:parse_dashes -> IGNORED
DEBUG:poyo.parser:parse_section <- default_context: # foobar\n
DEBUG:poyo.parser:parse_str <- default_context
DEBUG:poyo.parser:parse_str -> default_context
DEBUG:poyo.parser:parse_section -> <Section name: default_context>
DEBUG:poyo.parser:parse_simple <-     greeting: \u3053\u3093\u306b\u3061\u306f\n
DEBUG:poyo.parser:parse_str <- greeting
DEBUG:poyo.parser:parse_str -> greeting
DEBUG:poyo.parser:parse_str <- \u3053\u3093\u306b\u3061\u306f
DEBUG:poyo.parser:parse_str -> \u3053\u3093\u306b\u3061\u306f
DEBUG:poyo.parser:parse_simple -> <Simple name: greeting, value: \u3053\u3093\u306b\u3061\u306f>
DEBUG:poyo.parser:parse_simple <-     gui: FALSE\n
DEBUG:poyo.parser:parse_str <- gui
DEBUG:poyo.parser:parse_str -> gui
DEBUG:poyo.parser:parse_false <- FALSE
DEBUG:poyo.parser:parse_false -> False
DEBUG:poyo.parser:parse_simple -> <Simple name: gui, value: False>
DEBUG:poyo.parser:parse_list <-     doc_tools:\n        # docs or didn't happen\n        -    mkdocs\n        - 'sphinx'\n
DEBUG:poyo.parser:parse_str <- mkdocs
DEBUG:poyo.parser:parse_str -> mkdocs
DEBUG:poyo.parser:parse_str <- 'sphinx'
DEBUG:poyo.parser:parse_str -> sphinx
DEBUG:poyo.parser:parse_str <- doc_tools
DEBUG:poyo.parser:parse_str -> doc_tools
DEBUG:poyo.parser:parse_list -> <Simple name: doc_tools, value: ['mkdocs', 'sphinx']>
DEBUG:poyo.parser:parse_simple <-     123: 456.789\n
DEBUG:poyo.parser:parse_int <- 123
DEBUG:poyo.parser:parse_int -> 123
DEBUG:poyo.parser:parse_float <- 456.789
DEBUG:poyo.parser:parse_float -> 456.789
DEBUG:poyo.parser:parse_simple -> <Simple name: 123, value: 456.789>
DEBUG:poyo.parser:parse_simple <-     docs: true\n
DEBUG:poyo.parser:parse_str <- docs
DEBUG:poyo.parser:parse_str -> docs
DEBUG:poyo.parser:parse_true <- true
DEBUG:poyo.parser:parse_true -> True
DEBUG:poyo.parser:parse_simple -> <Simple name: docs, value: True>

About this project

We created this project to work around installation issues with a cookiecutter version that depended on existing YAML parsers for Python. For more information please check out this GitHub issue.

Community

Would you like to contribute to poyo? You're awesome! ๐Ÿ˜ƒ

Please check out the good first issue label for tasks, that are good candidates for your first contribution to poyo. Your contributions are greatly appreciated! Every little bit helps and credit will always be given.

Everyone interacting in the poyo project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the PyPI Code of Conduct.

Join the poyo community! ๐ŸŒ๐ŸŒ๐ŸŒŽ

License

Distributed under the terms of the MIT license, poyo is free and open source software.

poyo's People

Contributors

eykd avatar hackebrot avatar ishanarora avatar lukaselmer avatar maebert avatar mrshu avatar um9i 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

poyo's Issues

Thanks!

Hey, I just wanted to say thanks for the library. I needed a simple YAML parser that I could strip down for a custom application, and poyo fits the bill. So far I've only stripped out even more features, but if I end up expanding the test suite or anything like that I'll be sure to submit a pull request. Thanks again!

Null values

Unlike pyyaml, poyo mistakes blank: as {'blank': {}} instead of {'blank': None}.

ValueError when parsing config.

Hello @hackebrot,

I'm trying out poyo as a replacement for pyyaml in one of my projects. The project's config file looks more or less like this:

bind: 0.0.0.0:8081      # address and port to bind on
allow-transfers: true   # allow log file downloads
relative-root: /        # web app root path (default: '')
commands: [tail, grep]  # allowed commands
wrap-lines: true        # initial line-wrapping state

files:
  - 'logs/apache/www.tailon.org/'

This currently breaks poyo in two places:

  1. Poyo tries to parse 0.0.0.0:8081 as a float. Here's the debug output I added to read_from_tag():
pattern: '(?P<quotes>[\'\\"]?).*(?P=quotes)'
group:  'bind'
string: 'bind'

pattern: '([-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?)'
group:  '0.0'
string: '0.0.0.0:8081'

Perhaps the regex can be fixed or read_from_tag() can continue trying patterns until the one that matches most 'fully' is found?

  1. The relative-root: / # web app root path (default: '') line breaks the parser, because of the : in the comment:
pattern: '(?P<quotes>[\'\\"]?).*(?P=quotes)'
group:  'relative-root: "/"    # web app root path (default'
string: 'relative-root: "/"    # web app root path (default'

pattern: '(?P<quotes>[\'\\"]?).*(?P=quotes)'
group:  "''"
string: "''"

Kind regards,
Georgi

Add flake8 settings to repo

Since flake8 is in the tests, it would be helpful to include the required settings in the repo. I have different default settings than the defaults in my home directory, so when putting together the changes for #5, flake8 passed for me locally but failed on Travis.

Escape sequences are not handled in strings

Consider the following YAML, which I'll call escape.yaml:

escaped_string: "line\twith\ttabs\nline without tabs"

This is allowed.
https://yaml.org/spec/history/2001-08-01.html#:~:text=In%20YAML%2C%20text%20scalars%20can,%5C%5C%20to%20represent%20the%20backslash.

In YAML, text scalars can be surrounded by quotes enabling escape sequences such as \n to represent a new line, \t to represent a tab, and \ to represent the backslash.

https://yaml.org/spec/1.1/current.html#escaping%20in%20double-quoted%20style/

(see also e.g. https://yaml-multiline.info/ for some cases when escape sequences are ignored)

poyo appears to ignore escape sequences in quoted strings. Instead, it reads each backslash as a literal backslash.

>>> poyo.parse_string(open('escape.yaml').read())
{'escaped_string': 'line\\twith\\ttabs\\nline without tabs'}

I believe yaml.safe_load shows the correct behavior:

>>> yaml.safe_load(open('escape.yaml'))
{'escaped_string': 'line\twith\ttabs\nline without tabs'}
>>> print(yaml.safe_load(open('escape.yaml'))['escaped_string'])
line	with	tabs
line without tabs

Can't seem to parse what ruamel.yaml dumps

Eg:

Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ruamel import yaml
>>> from io import StringIO
>>> fh = StringIO()
>>> yaml.safe_dump({'foobar': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lobortis ligula sapien, eget luctus odio porta ut.'}, fh, indent=4, default_flow_style=False, allow_unicode=True)
>>> fh.getvalue()
'foobar: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lobortis\n    ligula sapien, eget luctus odio porta ut.\n'
>>> import poyo

>>> poyo.parse_string(fh.getvalue())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/python3.5/site-packages/poyo/parser.py", line 241, in parse_string
    return parser()
  File "/lib/python3.5/site-packages/poyo/parser.py", line 234, in __call__
    match = self.find_match()
  File "/lib/python3.5/site-packages/poyo/parser.py", line 224, in find_match
    ''.format(self.source[self.pos:])
poyo.exceptions.NoMatchException: None of the known patterns match for     ligula sapien, eget luctus odio porta ut.

keys are not trimmed

Version: 0.4.2
OS: OSX (but irrelevant)

I came across this issue when attempting to render a cookiecutter template from a user config
where there was a space between a key and the colon.

While this is very trivial, it is hard to root cause because the error message is something like
Error message: 'dict object' has no attribute 'python_3_6' and only careful examination of the dumped structure shows the problem

"interpreter_versions": {
            "python_2_7": "no",
            "python_3_5": "no",
            "python_3_6 ": "yes",
            "python_3_7": "yes"
        },

How to reproduce

If you take this (valid) YAML example and parse it through poyo

python_3_6 : yes

you get (note the space after the python_3_6 key

>>> from poyo import parse_string
>>> config = parse_string("python_3_6 : yes")
>>> config
{'python_3_6 ': 'yes'}

whereas it should have been {'python_3_6': 'yes'}

The parser fails to parse YAML file starting with "---"

Using this simple YAML file:


---
default_context:
  project_name: whazz
  version: 0.0.1
  year: 2016

I get this error

 cookiecutter.exceptions.InvalidConfiguration: Unable to parse YAML file /home/jenkins/workspace/gate-puppet-openstack-cookiecutter-puppet-3-cookiecutter-check/default-config.yaml. Error: None of the known patterns match for ---

According to the specification, a YAML file should start with "---" on
a line of its own: http://www.yaml.org/spec/1.2/spec.html#id2760395

If you change the test file like this :

diff --git a/tests/foobar.yml b/tests/foobar.yml
index a0d62ba..3c2cee2 100644
--- a/tests/foobar.yml
+++ b/tests/foobar.yml
@@ -1,3 +1,4 @@
+---
 default_context: # foobar
     greeting: ?????
     email: "[email protected]"

You can easily reproduce it.

Support to list of dicts?

It seems currently poyo doesn't support list of dicts, for example:

list_val:
  - key: key1
  - key: key2

Will be parsed intto:

{'list_val': ['key: key1', 'key: key2']}

And:

list_val:
  - key: key1
    value: value1
  - key: key2
    value: value2

Will just throw ValueError while parsing:

ValueError: Parent of ChildMixin instance needs to be a Container.

Is there any plan to support them?

I'm using poyo v0.4.0

Trailing space causes an irrelevant error

HI,

Here's an example of the problem:

poyo.parse_string("a: \n  a: 2")

Causes the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/lib/python3.8/site-packages/poyo/parser.py", line 280, in parse_string
    return parser()
  File "/python3.8/site-packages/poyo/parser.py", line 273, in __call__
    match = self.find_match()
  File "/python3.8/site-packages/poyo/parser.py", line 254, in find_match
    node = callback(match)
  File "/python3.8/site-packages/poyo/parser.py", line 67, in _wrapper
    result = wrapped_function(parser, match, **kwargs)
  File "/python3.8/site-packages/poyo/parser.py", line 166, in parse_simple
    value = self.read_from_tag(groups["value"])
  File "/python3.8/site-packages/poyo/parser.py", line 128, in read_from_tag
    raise NoTypeException(error_message.format(string))
poyo.exceptions.NoTypeException: Unable to determine type for "
 a: 2"

I'm not 100% sure if trailing spaces are actually allowed in yaml, but I was under the impression it's allowed because other parsers accept it.

If this parser doesn't accept trailing spaces, it should show a helpful message.

LIST pattern silently eats away anything between nonsibling LIST_ITEM patterns

LIST pattern silently eats away and anything between nonsibling LIST_ITEM patterns. The only exception is if a comment exists between lists.

For the following input

a:
  - 1
  - 2 # comment between a and b
b:
  - 3
  - 4
c:
  - 5
  - 6
# comment between c and d
d:
  - 7
  - 8

parse_string returns

{
    u'a': [
        1,
        2,
    ],
    u'b': [
        3,
        4,
        5,
        6,
    ],
    u'd': [
        7,
        8,
    ],
}

while the expected output is

{
    u'a': [
        1,
        2,
    ],
    u'b': [
        3,
        4,
    ],
    u'c': [
        5,
        6,
    ],
    u'd': [
        7,
        8,
    ],
}

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.