Skip to content

Commit

Permalink
Merge branch 'master' of github.com:mlenzen/collections-extended
Browse files Browse the repository at this point in the history
  • Loading branch information
mlenzen committed Jan 28, 2019
2 parents 4e82ae9 + 17ae6c3 commit 41fcbb4
Show file tree
Hide file tree
Showing 40 changed files with 1,576 additions and 416 deletions.
4 changes: 2 additions & 2 deletions .bumpversion.cfg
@@ -1,9 +1,9 @@
[bumpversion]
current_version = 1.0.1
current_version = 1.0.2
commit = True
tag = True

[bumpversion:file:collections_extended/__init__.py]
[bumpversion:file:collections_extended/__version__.py]

[bumpversion:file:setup.py]

1 change: 1 addition & 0 deletions .gitignore
@@ -1,4 +1,5 @@
*.py[cod]
.pytest_cache

# C extensions
*.so
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -3,12 +3,12 @@
language: python

python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
# - "3.7"
- "pypy"
- "pypy3"

Expand Down
15 changes: 15 additions & 0 deletions CHANGES.rst
@@ -0,0 +1,15 @@
.. py:currentmodule:: collections_extended
Change Log
==========

Version 1.1
-----------

Unreleased

* Added :class:`IndexedDict`
* Improve efficiency for large bag operations
* Add :meth:`setlist.swap`
* Add :meth:`bag.count`, :class:`CountsView` & :class:`UniqueElementsView`
* Add :meth:`bag.is_subset` and :meth:`is_superset`
38 changes: 20 additions & 18 deletions CONTRIBUTING.rst
Expand Up @@ -33,6 +33,8 @@ This could always use more documentation, whether as part of the
official docs, in docstrings, or even on the web in blog posts,
articles, and such.

Documentation is built automatically on every push using Read the Docs.

Submit Feedback
~~~~~~~~~~~~~~~

Expand All @@ -59,33 +61,32 @@ Ready to contribute? Here's how to set up `collections-extended` for local devel
#. Fork the `collections-extended` repo on GitHub.
#. Clone your fork locally::

$ git clone git@github.com:your_name_here/collections-extended.git
$ git clone git@github.com:your_name_here/collections-extended.git

#. Install your local copy into a virtualenv::

$ cd collections-extended
$ pyvenv env
$ . env/bin/activate
$ pip install -r requirements-dev.txt
$ python setup.py develop
$ cd collections-extended
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install -r requirements.txt

#. Create a branch for local development::

$ git checkout -b name-of-your-bugfix-or-feature
$ git checkout -b name-of-your-bugfix-or-feature

#. Make your changes locally.

#. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox::

$ flake8
$ py.test
$ tox
$ flake8
$ py.test
$ tox

#. Commit your changes and push your branch to GitHub::

$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature
$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature

#. Submit a pull request through the GitHub website.

Expand All @@ -96,15 +97,16 @@ Before you submit a pull request, check that it meets these guidelines:

1. The pull request should include tests.
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
3. The pull request should work for all supported versions. Check
https://travis-ci.org/mlenzen/collections-extended/pull_requests
and make sure that the tests pass for all supported Python versions.
https://travis-ci.org/mlenzen/collections-extended/pull_requests
and make sure that the tests pass for all supported Python versions.

Tips
----

To run a subset of tests::

$ py.test tests/test_example.py
$ py.test tests/test_example.py
$ py.test tests/test_example.py::test_func
1 change: 1 addition & 0 deletions CONTRIBUTORS
Expand Up @@ -2,3 +2,4 @@ Mike Lenzen <m.lenzen@gmail.com> https://github.com/mlenzen
Caleb Levy <caleb.levy@berkeley.edu> https://github.com/caleblevy
Marein Könings <mail@marein.org> https://github.com/MareinK
Jad Kik <jadkik94@gmail.com> https://github.com/jadkik
Kuba Marek <blue.cube@seznam.cz> https://github.com/bluecube
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -47,4 +47,4 @@ docs:
#sphinx-apidoc -o docs/ collections_extended
make -C docs clean
make -C docs html
xdg-open docs/_build/html/index.html
#xdg-open docs/_build/html/index.html
27 changes: 21 additions & 6 deletions README.rst
Expand Up @@ -22,17 +22,19 @@ Overview
``collections_extended`` is a Python module providing
a ``bag`` class, AKA **multiset**,
a ``setlist`` class, which is a **unique list** or **ordered set**,
a ``bijection`` class and ``RangeMap`` which is a mapping from ranges to values.
a ``bijection`` class, ``RangeMap`` which is a mapping from ranges to values and
a ``IndexedDict`` class, which is an ordered mapping whose elements can be accessed using index,
in addition to key.
There are also frozen (hashable) varieties of bags and setlists.

Tested against Python 2.6, 2.7, 3.3, 3.4, 3.5, 3.6, PyPy & PyPy3.
Tested against Python 2.7, 3.3, 3.4, 3.5, 3.6, 3.7, PyPy & PyPy3.

Getting Started
===============

.. code-block:: python
>>> from collections_extended import bag, setlist, bijection, RangeMap
>>> from collections_extended import bag, setlist, bijection, RangeMap, IndexedDict
>>> from datetime import date
>>> b = bag('abracadabra')
>>> b.count('a')
Expand Down Expand Up @@ -93,6 +95,17 @@ Getting Started
>>> us_presidents[date(2021, 3, 1)]
'Someone New'
>>> idict = IndexedDict()
>>> idict['a'] = "A"
>>> idict['b'] = "B"
>>> idict['c'] = "C"
>>> idict.get(key='a')
'A'
>>> idict.get(index=2)
'C'
>>> idict.index('b')
1
Installation
============

Expand All @@ -104,7 +117,7 @@ Usage

Classes
=======
There are six new classes provided:
There are seven new classes provided:

Bags
----
Expand All @@ -123,9 +136,11 @@ frozensetlist
Mappings
--------
bijection
A one-to-one mapping.
A one-to-one mapping.
RangeMap
A mapping from ranges (of numbers/dates/etc)
A mapping from ranges (of numbers/dates/etc)
IndexedDict
A mapping that keeps insertion order and allows access by index.

:Author: Michael Lenzen
:Copyright: 2018 Michael Lenzen
Expand Down
4 changes: 2 additions & 2 deletions RELEASE_CHECKLIST.rst
Expand Up @@ -17,8 +17,8 @@ Release Checklist
deactivate

#. Check the PyPI listing page to make sure that the README displays properly.
If not, copy and paste the RestructuredText into http://rst.ninjs.org/ to
find out what broke the formatting.
If not, copy and paste the RestructuredText into http://rst.ninjs.org/ to
find out what broke the formatting.

New Python Versions
-------------------
Expand Down
12 changes: 8 additions & 4 deletions collections_extended/__init__.py
@@ -1,27 +1,31 @@
"""collections_extended contains a few extra basic data structures."""
from ._compat import Collection
from .bags import bag, frozenbag
from .bags import bag, frozenbag, CountsView, UniqueElementsView
from .setlists import setlist, frozensetlist
from .bijection import bijection
from .range_map import RangeMap, MappedRange

__version__ = '1.0.1'
from .indexed_dict import IndexedDict
from ._version import __version__

__all__ = (
'collection',
'setlist',
'frozensetlist',
'bag',
'frozenbag',
'CountsView',
'UniqueElementsView',
'bijection',
'RangeMap',
'MappedRange',
'Collection',
'IndexedDict',
'__version__',
)


def collection(iterable=None, mutable=True, ordered=False, unique=False):
"""Return a Collection with the specified properties.
"""Return a :class:`Collection` with the specified properties.
Args:
iterable (Iterable): collection to instantiate new collection from.
Expand Down
81 changes: 81 additions & 0 deletions collections_extended/_util.py
@@ -1,4 +1,7 @@
"""util functions for collections_extended."""
from functools import wraps
import textwrap
import warnings


def hash_iterable(it):
Expand All @@ -14,3 +17,81 @@ def hash_iterable(it):
for value in it:
hash_value = hash((hash_value, value))
return hash_value


class Sentinel(object):
"""A class to create sentinel objects.
The benefits vs. object() are a good repr it is picklable.
Inspired by https://pypi.org/project/sentinels/
"""

_registry = {}

def __getnewargs__(self):
return self._name,

def __new__(cls, _name):
"""Find the Sentinel object with name or create a new one."""
try:
return cls._registry[_name]
except KeyError:
new = super(Sentinel, cls).__new__(cls)
cls._registry[_name] = new
return new

def __init__(self, name):
super(Sentinel, self).__init__()
self._name = name

def __repr__(self):
return '<%s>' % self._name

def __bool__(self):
return False

def __eq__(self, other):
if other.__class__ == self.__class__:
return self._name == other._name
return False


NOT_SET = Sentinel('not_set')


def deprecated(msg, dep_version):
"""Decorate a function, method or class to mark as deprecated.
Raise DeprecationWarning and add a deprecation notice to the docstring.
"""
def wrapper(func):
docstring = func.__doc__ or ''
docstring_msg = '.. deprecated:: {version} {msg}'.format(
version=dep_version,
msg=msg,
)
if docstring:
# We don't know how far to indent this message
# so instead we just dedent everything.
string_list = docstring.splitlines()
first_line = string_list[0]
remaining = textwrap.dedent(''.join(string_list[1:]))
docstring = '\n'.join([
first_line,
remaining,
'',
docstring_msg,
])
else:
docstring = docstring_msg
func.__doc__ = docstring

@wraps(func)
def inner(*args, **kwargs):
warnings.warn(msg, category=DeprecationWarning, stacklevel=2)
return func(*args, **kwargs)

return inner

return wrapper
2 changes: 2 additions & 0 deletions collections_extended/_version.py
@@ -0,0 +1,2 @@
"""Module to store version so it can be imported in other modules."""
__version__ = '1.0.2'

0 comments on commit 41fcbb4

Please sign in to comment.