Skip to content

Commit

Permalink
Merge 8bdf1ea into c000794
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas-eschle committed Jul 26, 2018
2 parents c000794 + 8bdf1ea commit a3c6a9d
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 46 deletions.
33 changes: 33 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
checks:
python:
code_rating: true
duplicate_code: true
build:
environment:
python: '3.6.3'
dependencies:
# Runs before inferred commands
before:
- 'sudo apt-get install -y libyaml-dev'
- 'pip install Cython'
- 'pip install hypothesis'
nodes:
analysis:
project_setup:
override:
- 'true'
tests:
override:
- py-scrutinizer-run
-
command: pylint-run
use_website_config: true
environment:
node:
version: 6.0.0
tests: true
filter:
excluded_paths:
- '/tests/*'
dependency_paths:
- 'lib/*'
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ python:
- '3.4'
- '3.5'
- '3.6'
- "3.7-dev"
# - "3.7"
matrix:
include:
- os: osx
Expand Down
23 changes: 19 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
.. image:: https://travis-ci.org/Phynix/yamlloader.svg?branch=master
:target: https://travis-ci.org/Phynix/yamlloader
.. image:: https://img.shields.io/pypi/pyversions/yamlloader.svg
:target: https://pypi.org/project/yamlloader/
.. image:: https://landscape.io/github/Phynix/yamlloader/master/landscape.svg?style=flat
:target: https://landscape.io/github/Phynix/yamlloader/master
:alt: Code Health
Expand All @@ -15,7 +17,7 @@ yamlloader

This module provides loaders and dumpers for PyYAML. Currently, an OrderedDict loader/dumper is
implemented, allowing to keep items order
when loading resp. dumping a file from/to an OrderedDict.
when loading resp. dumping a file from/to an OrderedDict (Python 3.7: Also regular dicts are supported and are the default items to be loaded to. As of Python 3.7 preservation of insertion order is a language feature of regular dicts.)

This project was originally mirrored from
`yamlordereddict <https://github.com/fmenabe/python-yamlordereddictloader>`_
Expand All @@ -29,7 +31,7 @@ the much faster C-versions of the Loaders/Dumpers.

Install
-------
It is recommended to use the pip or anaconda version
There is a pip and a conda version available

.. code-block:: bash
Expand All @@ -39,7 +41,7 @@ or

.. code-block:: bash
$ conda install yamlloader -c phynix
$ conda install yamlloader -c phynix # it is also in conda-forge
But does [your special case here] also work?
Expand All @@ -58,11 +60,14 @@ C vs non-C version

A significant speedup can be reached by replacing the Loader* and Dumper* classes by CLoader*
and CDumper*. The package hereby relies on the implementations from PyYAML. If they have not
been compiled, *yamlloader* automatically falls back to the non-C versions.
been compiled, *yamlloader* **automatically** falls back to the non-C versions.

Therefore using the C-version is safe: if it is not available, the pure Python version is
automatically used.

Usage examples
==============


Loader usage
------------
Expand Down Expand Up @@ -101,3 +106,13 @@ Dumper usage
**Note:** For using the safe dumper (which produce standard YAML tags and does
not represent arbitrary Python objects), replace ``yamlloader.ordereddict.CDumper`` by
``yamlloader.ordereddict.CSafeDumper``.


FAQ
===

The C version does not work
---------------------------
Check if yaml.cyaml exists. If not, the cyaml module was not compiled during the installation of
yaml (pyyaml). Make sure that cython is installed (`pip install Cython`) and the yaml.h file is
there (apt: libyaml-dev).
8 changes: 6 additions & 2 deletions ci/install_conda.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O anaconda.sh;
PHYNIX_PYTHON_VERSION=$TRAVIS_PYTHON_VERSION;
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
PHYNIX_PYTHON_VERSION="3.6";
wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O anaconda.sh;
fi
fi

if [[ "$PHYNIX_PYTHON_VERSION" == "3.7-dev" ]]; then
PHYNIX_PYTHON_VERSION="3.7";
fi

bash anaconda.sh -b -p $HOME/anaconda > tmp.txt && echo "alive"
export PATH="$HOME/anaconda/bin:$PATH"
Expand Down
3 changes: 2 additions & 1 deletion ci/install_tester.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
# install test environment
conda install -y coverage > tmp.txt && echo "alive";
pip install coverage > tmp.txt && echo "alive";
#conda install -y coverage > tmp.txt && echo "alive";
pip install coveralls > tmp.txt && echo "alive";
pip install hypothesis
9 changes: 7 additions & 2 deletions ci/setup_env.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#!/usr/bin/env bash
conda create -q --name=yamlloader-env python=$PHYNIX_PYTHON_VERSION > tmp.txt && echo "alive"
source activate yamlloader-env
conda create -q --name=yamlloader_env python=$PHYNIX_PYTHON_VERSION > tmp.txt && echo "alive"
source activate yamlloader_env
if [[ "$PHYNIX_PYTHON_VERSION" == "3.7" ]]; then
pip install cython;
pip install PyYAML==3.13rc1;
fi



16 changes: 10 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,29 @@ def long_description():


setup(name='yamlloader',
version='0.5.2',
author='Jonas Eschle "Mayou36"',
author_email='jonas.eschle@phynix.science',
version='0.5.3',
author='Jonas Eschle "Mayou36", Johannes Lade "SebastianJL"',
author_email='jonas.eschle@phynix.science, johannes.lade@phynix.science',
maintainer='Jonas Eschle "Mayou36"',
maintainer_email='jonas.eschle@phynix.science',
url='https://github.com/Phynix/yamlloader',
download_url='https://github.com/Phynix/yamlloader',
license='MIT License',
description='YAML loader and dumper for PyYAML allowing to keep keys order.',
description='Ordered YAML loader and dumper for PyYAML.',
long_description=long_description(),
keywords=['YAML', 'loader', 'dumper', 'ordered', 'OrderedDict', 'pyyaml'],
classifiers=['Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators', 'Natural Language :: English',
'Intended Audience :: System Administrators',
'Intended Audience:: Science / Research',
'Natural Language :: English',
'License :: OSI Approved :: MIT License', 'Programming Language :: Python',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6', 'Topic :: Utilities'],
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Topic :: Utilities'],
packages=['yamlloader', 'yamlloader.ordereddict'],
python_requires=">=2.7",
install_requires=requirements,
Expand Down
56 changes: 45 additions & 11 deletions tests/test_ordereddict.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import yamlloader

PY_LE_36 = sys.version_info[:2] <= (3, 6)

long_settings = settings(max_examples=10, max_iterations=20, max_shrinks=10,
timeout=hypothesis.unlimited)
# long_settings = settings(max_examples=100, max_iterations=200, max_shrinks=100,
Expand All @@ -32,6 +34,7 @@
timeout=hypothesis.unlimited,
suppress_health_check=(hypothesis.HealthCheck.too_slow,))


# def create_tempfile(suffix=None):
# """Create a temporary file and remove it on exit "guaranteed".
#
Expand Down Expand Up @@ -98,21 +101,21 @@ def dict_val_strat(ascii_only=False):
st.integers())))


def get_extended_dict(ascii_only=False):
def get_extended_dict(ascii_only=False, dict_class=None):
def extend_dict(strategy):
new_dict = st.dictionaries(keys=copy.deepcopy(dict_keys_strat(ascii_only=ascii_only)),
values=strategy, dict_class=OrderedDict)
values=strategy, dict_class=dict_class)
return new_dict

return extend_dict


def recursive_dict_strat(ascii_only=False):
def recursive_dict_strat(ascii_only=False, dict_class=None):
return st.recursive(
base=st.dictionaries(keys=copy.deepcopy(dict_keys_strat(ascii_only=ascii_only)),
values=copy.deepcopy(dict_val_strat(ascii_only=ascii_only)),
dict_class=OrderedDict),
extend=get_extended_dict(ascii_only=ascii_only), max_leaves=5)
dict_class=dict_class),
extend=get_extended_dict(ascii_only=ascii_only, dict_class=dict_class), max_leaves=5)


loaders = [yamlloader.ordereddict.Loader,
Expand All @@ -139,7 +142,6 @@ def recursive_dict_strat(ascii_only=False):
safe_loaders = [yamlloader.ordereddict.SafeLoader, yamlloader.ordereddict.CSafeLoader]
safe_dumpers = [yamlloader.ordereddict.SafeDumper, yamlloader.ordereddict.CSafeDumper]


loaderdumper = [(l, d) for l in loaders for d in dumpers]


Expand Down Expand Up @@ -174,9 +176,22 @@ def test_SafeLoadCombinations(self):
# self.dumper = yamlloader.ordereddict.CDumper
# self.loaddump()

def loaddump_ascii_only(self):
if not PY_LE_36:
self.loaddumb_ascii_only_pyg36()
self.loaddump_ascii_only_pyle36()

@long_settings
@given(recursive_dict_strat(ascii_only=True, dict_class=dict))
def loaddumb_ascii_only_pyg36(self, dict_to_save):
self._load_dump_ascii_only(dict_to_save)

@long_settings
@given(recursive_dict_strat(ascii_only=True))
def loaddump_ascii_only(self, dict_to_save):
@given(recursive_dict_strat(ascii_only=True, dict_class=OrderedDict))
def loaddump_ascii_only_pyle36(self, dict_to_save):
self._load_dump_ascii_only(dict_to_save)

def _load_dump_ascii_only(self, dict_to_save):
if self.loader in safe_loaders and self.dumper not in safe_dumpers:
return
try:
Expand All @@ -188,9 +203,22 @@ def loaddump_ascii_only(self, dict_to_save):
# hypothesis.assume(False)
self.loaddump(dict_to_save=dict_to_save)

def loaddump_unicode(self):
if not PY_LE_36:
self.loaddump_unicode_pyge37()
self.loaddump_unicode_pyle36()

@long_settings
@given(recursive_dict_strat())
def loaddump_unicode(self, dict_to_save):
@given(recursive_dict_strat(dict_class=dict))
def loaddump_unicode_pyge37(self, dict_to_save):
self._loaddump_unicode(dict_to_save=dict_to_save)

@long_settings
@given(recursive_dict_strat(dict_class=OrderedDict))
def loaddump_unicode_pyle36(self, dict_to_save):
self._loaddump_unicode(dict_to_save=dict_to_save)

def _loaddump_unicode(self, dict_to_save):

def convert_nested_dict(dictionary, convert_from=None, convert_to=dict):
new_dict = {}
Expand All @@ -203,8 +231,9 @@ def convert_nested_dict(dictionary, convert_from=None, convert_to=dict):
new_dict[key] = val
return new_dict

dict_conv_to_save = convert_nested_dict(dict_to_save, convert_from=OrderedDict,
dict_conv_to_save = convert_nested_dict(dict_to_save, convert_from=(OrderedDict, dict),
convert_to=dict)
# Test if dumping with yaml normally is possible
try:
dumbed_dict = yaml.dump(dict_conv_to_save, Dumper=yaml_dumpers[self.dumper])
dict_loaded = yaml.load(dumbed_dict, Loader=yaml_loaders[self.loader])
Expand Down Expand Up @@ -232,6 +261,11 @@ def loaddump(self, dict_to_save, loader=None, dumper=None):
dumbed_dict = yaml.dump(dict_to_save, Dumper=dumper)
dict_loaded = yaml.load(dumbed_dict, Loader=loader)
self.assertEqual(dict_to_save, dict_loaded)
self.assertListEqual(list(dict_to_save.keys()), list(dict_loaded.keys()))
if PY_LE_36:
self.assertEqual(type(dict_to_save), type(dict_loaded))
else:
self.assertEqual(dict, type(dict_loaded))


class TestAssumptions(TestCase):
Expand Down
6 changes: 3 additions & 3 deletions yamlloader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
raise RuntimeError("You are using Python < 2.7. This is not supported. "
"Please upgrade your distribution and/or packages.")

__version__ = "0.5.2"
__author__ = 'Jonas Eschle "Mayou36"'
__email__ = "jonas.eschle@phynix.science"
__version__ = "0.5.3"
__author__ = 'Jonas Eschle "Mayou36", Johannes Lade'
__email__ = 'jonas.eschle@phynix.science, johannes.lade@phynix.science'

__all__ = ['ordereddict']
42 changes: 27 additions & 15 deletions yamlloader/ordereddict/dumpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@


def represent_ordereddict(self, data):
"""
Parameters
----------
data : dict, OrderedDict
Returns
-------
mapping
"""
return self.represent_mapping('tag:yaml.org,2002:map', data.items())


Expand All @@ -20,12 +30,15 @@ def __init__(self, *args, **kwargs):
sub_doc = self.__doc__
if sub_doc is None:
sub_doc = ""
self.__doc__ = """Dump `:py:class:~collections.OrderedDict` to YAML preserving the order."""
self.__doc__ = """Dump :py:class:~`collections.OrderedDict` and :py:class:`dict` (py37+)
to YAML preserving the order."""
self.__doc__ += sub_doc
super(OrderedDumperMixin, self).__init__(*args, **kwargs)
self.add_representer(OrderedDict, type(self).represent_ordereddict)
if not yamlloader.settings.PY_LE_36:
self.add_representer(dict, type(self).represent_ordereddict)

represent_ordereddict = represent_ordereddict
represent_ordereddict = staticmethod(represent_ordereddict)


doc_extension_Cversion = """
Expand All @@ -44,17 +57,16 @@ class SafeDumper(OrderedDumperMixin, yaml.SafeDumper):
"""


if not hasattr(yaml, 'CDumper') and yamlloader.settings.ALLOW_NON_C_FALLBACK:
yaml.CDumper = yaml.Dumper



class CDumper(OrderedDumperMixin, yaml.CDumper):
__doc__ = doc_extension_Cversion


if not hasattr(yaml, 'CSafeDumper') and yamlloader.settings.ALLOW_NON_C_FALLBACK:
yaml.CSafeDumper = yaml.SafeDumper
if not hasattr(yaml, 'CDumper'):
if yamlloader.settings.ALLOW_NON_C_FALLBACK:
CDumper = Dumper
else:
class CDumper(OrderedDumperMixin, yaml.CDumper):
__doc__ = doc_extension_Cversion

class CSafeDumper(OrderedDumperMixin, yaml.CSafeDumper):
__doc__ = doc_extension_Cversion
if not hasattr(yaml, 'CSafeDumper'):
if yamlloader.settings.ALLOW_NON_C_FALLBACK:
CSafeDumper = SafeDumper
else:
class CSafeDumper(OrderedDumperMixin, yaml.CSafeDumper):
__doc__ = doc_extension_Cversion

0 comments on commit a3c6a9d

Please sign in to comment.