Skip to content

Commit

Permalink
Merge pull request chaimleib#19 from chaimleib/develop
Browse files Browse the repository at this point in the history
Develop: 1.0.1
  • Loading branch information
chaimleib committed Dec 9, 2014
2 parents c12b483 + 400e691 commit f525d9b
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 8 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*.pyc
dist/
build/
*.rst

# Dev dependencies
pyandoc/
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Change log
==========

Version 1.0.1
-------------
- Fix: pip install failure because of failure to generate README.rst

Version 1.0.0
-------------
- Renamed from PyIntervalTree to intervaltree
Expand Down
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ clean-deps:
clean-temps:
rm -rf $(TEMPS)

install-testpypi:
pip install -i https://testpypi.python.org/pypi intervaltree

install-pypi:
pip install intervaltree

install-develop:
python setup.py develop

uninstall:
pip uninstall intervaltree

# Convert README to rst and check the result
rst: pydocutils pyandoc
python setup.py check --restructuredtext --strict
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ A mutable, self-balancing interval tree for Python 2 and 3. Queries may be by po

This library was designed to allow tagging text and time intervals, where the intervals include the lower bound but not the upper bound.

Installing
----------

pip install intervaltree

Features
--------

Expand Down
197 changes: 197 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
.. This file is automatically generated by setup.py from README.md.
intervaltree
============

A mutable, self-balancing interval tree for Python 2 and 3. Queries may
be by point, by range overlap, or by range envelopment.

This library was designed to allow tagging text and time intervals,
where the intervals include the lower bound but not the upper bound.

Installing
----------

::

pip install intervaltree

Features
--------

- Supports Python 2.6+ and Python 3.2+
- Initialize blank or from an iterable of ``Intervals`` in O(n \* log
n).
- Insertions

- ``tree[begin:end] = data``
- ``tree.add(interval)``
- ``tree.addi(begin, end, data)``
- ``tree.extend(list_of_interval_objs)``

- Deletions

- ``tree.remove(interval)`` (raises ``ValueError`` if not present)
- ``tree.discard(interval)`` (quiet if not present)
- ``tree.removei(begin, end, data)`` (short for
``tree.remove(Interval(begin, end, data))``)
- ``tree.discardi(begin, end, data)`` (short for
``tree.discard(Interval(begin, end, data))``)
- ``tree.remove_overlap(point)``
- ``tree.remove_overlap(begin, end)`` (removes all overlapping the
range)
- ``tree.remove_envelop(begin, end)`` (removes all enveloped in the
range)

- Overlap queries:

- ``tree[point]``
- ``tree[begin, end]``
- ``tree.search(point)``
- ``tree.search(begin, end)``

- Envelop queries:

- ``tree.search(begin, end, strict=True)``

- Membership queries:

- ``interval_obj in tree`` (this is fastest, O(1))
- ``tree.containsi(begin, end, data)``
- ``tree.overlaps(point)``
- ``tree.overlaps(begin, end)``

- Iterable:

- ``for interval_obj in tree:``
- ``tree.items()``

- Sizing:

- ``len(tree)``
- ``tree.is_empty()``
- ``not tree``
- ``tree.begin()`` (the ``begin`` coordinate of the leftmost interval)
- ``tree.end()`` (the ``end`` coordinate of the rightmost interval)

- Restructuring

- ``split_overlaps()``

- Copy- and typecast-able:

- ``IntervalTree(tree)`` (``Interval`` objects are same as those in
tree)
- ``tree.copy()`` (``Interval`` objects are shallow copies of those in
tree)
- ``set(tree)`` (can later be fed into ``IntervalTree()``)
- ``list(tree)`` (ditto)

- Equal-able
- Pickle-friendly
- Automatic AVL balancing

Examples
--------

- Getting started

::

from intervaltree import Interval, IntervalTree
t = IntervalTree()

- Adding intervals - any object works!

::

t[1:2] = "1-2"
t[4:7] = (4, 7)
t[5:9] = {5: 9}

- Query by point

::

ivs = t[6] # set([Interval(4, 7, (4, 7)), Interval(5, 9, {5: 9})])
iv = sorted(ivs)[0] # Interval(4, 7, (4, 7))

- Accessing an ``Interval`` object

::

iv.begin # 4
iv.end # 7
iv.data # (4, 7)

- Query by range

Note that ranges are inclusive of the lower limit, but non-inclusive of
the upper limit. So:

::

t[2:4] # set()

But:

::

t[1:5] # set([Interval(1, 2, '1-2'), Interval(4, 7, (4, 7))])

- Constructing from lists of ``Interval``\ s

We could have made a similar tree this way:

::

ivs = [(1, 2), (4, 7), (5, 9)]
t = IntervalTree(
Interval(begin, end, "%d-%d" % (begin, end)) for begin, end in ivs
)

Or, if we don't need the data fields:

::

t = IntervalTree(Interval(*iv) for iv in ivs)

- Removing intervals

::

t.remove( Interval(1, 2, "1-2") )
list(t) # [Interval(4, 7, '4-7'), Interval(5, 9, '5-9')]

t.remove( Interval(500, 1000, "Doesn't exist")) # raises ValueError
t.discard(Interval(500, 1000, "Doesn't exist")) # quietly does nothing

t.remove_overlap(5)
list(t) # []

We could also empty a tree by removing all intervals, from the lowest
bound to the highest bound of the ``IntervalTree``:

::

t.remove_overlap(t.begin(), t.end())

Future improvements
-------------------

See the issue tracker on GitHub.

Based on
--------

- Eternally Confuzzled's AVL tree
- Wikipedia's Interval Tree
- Heavily modified from Tyler Kahn's Interval Tree implementation in
Python (GitHub project)
- Incorporates modifications by konstantint

Copyright
---------

- Chaim-Leib Halbert, 2014

30 changes: 23 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@
try:
import pandoc
except ImportError as e:
print(sys.version_info)
raise e
print(e)
pandoc.PANDOC_PATH = 'pandoc' # until pyandoc gets updated


## CONFIG
version = '1.0.0'
version = '1.0.1'
create_rst = True


Expand All @@ -55,11 +54,21 @@ def run_tests(self):
sys.exit(pytest.main(self.test_args))


def get_rst():
if os.path.isdir('pyandoc/pandoc') and os.path.islink('pandoc'):
print("Generating README.rst from README.md")
return generate_rst()
elif os.path.isfile('README.rst'):
print("Reading README.rst")
return read_file('README.rst')
else:
print("No README.rst found!")
return read_file('README.md')

## Convert README to rst for PyPI
def rst_readme():
def generate_rst():
"""Converts Markdown to RST for PyPI"""
with open("README.md", "r") as readme:
md = readme.read()
md = read_file("README.md")

md = pypi_sanitize_markdown(md)
rst = markdown2rst(md)
Expand Down Expand Up @@ -137,6 +146,13 @@ def remove_markdown_links(md):


## Filesystem utilities
def read_file(path):
"""Reads file into string."""
with open(path, 'r') as f:
data = f.read()
return data


def mkdir_p(path):
"""Like `mkdir -p` in unix"""
if not path.strip():
Expand Down Expand Up @@ -182,7 +198,7 @@ def update_file(path, data):
version=version,
install_requires=[],
description='Mutable, self-balancing interval tree',
long_description=rst_readme(),
long_description=get_rst(),
classifiers=[ # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
Expand Down

0 comments on commit f525d9b

Please sign in to comment.