Skip to content

Commit

Permalink
Added PyPI badge to README. Made README PyPI compatible and added cha…
Browse files Browse the repository at this point in the history
…ngelog to it. Changed status from alpha to production ready. Added compatible version to PyPI classifiers. Changed indentation in README to prevent editors from assuming 2 spaces is 1 tab. Added another short example to README.
  • Loading branch information
runfalk committed Dec 22, 2015
1 parent 8cf6f4a commit d3c5782
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 13 deletions.
46 changes: 35 additions & 11 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
Spans
=====
|test-status| |test-coverage| |documentation-status|
|test-status| |test-coverage| |documentation-status| |pypi-version|

Spans is a pure Python implementation of PostgreSQL's range types [#]_. Range types
are conveinent when working with intervals of any kind. Every time you've found
yourself working with date_start and date_end, an interval may have been what
you were looking for.
you were actually looking for.

Here is an example on how to use ranges to determine if something happened in
the 90s.

.. code-block:: python
>>> from spans import *
>>> from datetime import *
>>> the90s = daterange(date(1990, 1, 1), date(2000, 1, 1))
>>> date(1996, 12, 4) in the90s
True
>>> date(2000, 1, 1) in the90s
False
>>> the90s.union(daterange(date(2000, 1, 1), date(2010, 1, 1)))
daterange([datetime.date(1990, 1, 1), datetime.date(2010, 1, 1))))
If you are making a booking application for a bed and breakfast hotel and want
to ensure no room gets double booked:
Expand Down Expand Up @@ -112,16 +127,25 @@ For a deeper set of examples please refer to ``types.py`` and ``settypes.py``.
.. [#] https://www.github.com/runfalk/psycospans
.. |test-status| image:: https://travis-ci.org/runfalk/spans.svg
:alt: Test status
:scale: 100%
:target: https://travis-ci.org/runfalk/spans
:alt: Test status
:scale: 100%
:target: https://travis-ci.org/runfalk/spans
.. |test-coverage| image:: https://codecov.io/github/runfalk/spans/coverage.svg?branch=master
:alt: Test coverage
:scale: 100%
:target: https://codecov.io/github/runfalk/spans?branch=master
:alt: Test coverage
:scale: 100%
:target: https://codecov.io/github/runfalk/spans?branch=master
.. |documentation-status| image:: https://readthedocs.org/projects/spans/badge/
:alt: Documentation status
:scale: 100%
:target: http://spans.readthedocs.org/en/latest/
:alt: Documentation status
:scale: 100%
:target: http://spans.readthedocs.org/en/latest/
.. |pypi-version| image:: https://badge.fury.io/py/spans.svg
:alt: PyPI version status
:scale: 100%
:target: https://pypi.python.org/pypi/Spans/
.. Include changelog on PyPI
.. include:: doc/changelog.rst
115 changes: 113 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,117 @@

from setuptools import setup

class RstPreProcessor(object):
def __init__(self):
self.roles = {}
self.blocks = {}
self.replaces = {}

def add_block(self, block, callback=None):
if callback is None:
def wrapper(callback):
self.add_block(block, callback)
return callback
return wrapper
self.blocks[block] = callback

def add_role(self, role, callback=None):
if callback is None:
def wrapper(callback):
self.add_role(role, callback)
return callback
return wrapper
self.roles[role] = callback

def add_replacement(self, search, replacement):
self.replaces[search] = replacement

def _block_dispatch(self, match):
if match.group("block") not in self.blocks:
return match.group(0)

return self.blocks[match.group("block")](
self,
match.group("block"),
match.group("args"),
match.group("extra"),
match.group("content"))

def _role_dispatch(self, match):
if match.group(1) not in self.roles:
return match.group(0)

return self.roles[match.group("role")](
self,
match.group("role"),
match.group("args"),
match.group("content"))

def process(self, text):
# Process blocks
text = re.sub(
"\.\.\s+(?:(?P<extra>\S+)\s+)?(?P<block>[^\n:]+)::"
"\s+(?P<args>[^\n]+)(?:\n\n?(?P<content>.*?)\n\n(?=\S))?",
self._block_dispatch,
text,
flags=re.DOTALL)

# Process roles
text = re.sub(
":(?P<role>[A-Za-z0-9_]+)(?:\s+(?P<args>[A-Za-z0-9_]+))?:"
"`(?P<content>[^`]*)`",
self._role_dispatch,
text,
flags=re.MULTILINE)

# Run replaces
for search, replacement in self.replaces.items():
text = text.replace(search, replacement)

return text


rst_pre_processor = RstPreProcessor()

@rst_pre_processor.add_role("meth")
@rst_pre_processor.add_role("class")
@rst_pre_processor.add_role("attr")
def role_simplyfier(processor, role, argument, content):
extra = {
"meth": "()"
}

if content.startswith("~"):
return "``{}``".format(content[1:].split(".")[-1] + extra.get(role, ""))
else:
return "``{}``".format(content + extra.get(role, ""))

@rst_pre_processor.add_block("image")
def image_remover(processor, block, args, extra, content):
if extra is not None:
processor.add_replacement(extra, "")
return ""

@rst_pre_processor.add_block("include")
def includer(processor, block, args, extra, content):
with open(args) as fp:
return fp.read().rstrip()

def rst_preprocess(file):
"""
Preprocess rST file to support Sphinx like include directive. Includes are
relative to the current working directory.
"""

with open(file) as fp:
return re.sub(
"^\.\.\s+include:: (.*?)$",
lambda x: (rst_preprocess(x.group(1)) or "").rstrip(),
fp.read(),
flags=re.MULTILINE)

with open("README.rst") as fp:
long_desc = fp.read()
long_desc = rst_pre_processor.process(fp.read())

with open("LICENSE") as fp:
license = fp.read()
Expand All @@ -31,12 +140,14 @@
packages=["spans"],
install_requires=requirements,
classifiers=(
"Development Status :: 3 - Alpha",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Topic :: Utilities"
),
zip_safe=False,
Expand Down

0 comments on commit d3c5782

Please sign in to comment.