Skip to content

Commit

Permalink
Merge pull request #314 from eriknw/tlz
Browse files Browse the repository at this point in the history
`tlz` package: `cytoolz` or `toolz`
  • Loading branch information
eriknw committed Nov 3, 2016
2 parents be198a6 + 0ff1118 commit fe56571
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ install:
script:
- export MAJOR_PYTHON_VERSION=`echo $TRAVIS_PYTHON_VERSION | cut -c 1`
- coverage run --source=toolz $(which nosetests)
--with-doctest
--with-doctest toolz/
- if [[ $TRAVIS_PYTHON_VERSION != pypy* ]]; then coverage report --show-missing --fail-under=100 ; fi
- if [[ $TRAVIS_PYTHON_VERSION != pypy* ]]; then pep8 --ignore=$PEP8_IGNORE --exclude=conf.py,tests,examples,bench -r --show-source . ; fi

Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
keywords='functional utility itertools functools',
packages=['toolz',
'toolz.sandbox',
'toolz.curried'],
'toolz.curried',
'tlz'],
package_data={'toolz': ['tests/*.py']},
long_description=(open('README.rst').read() if exists('README.rst')
else ''),
Expand Down
9 changes: 9 additions & 0 deletions tlz/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""``tlz`` mirrors the ``toolz`` API and uses ``cytoolz`` if possible.
The ``tlz`` package is installed when ``toolz`` is installed. It provides
a convenient way to use functions from ``cytoolz``--a faster Cython
implementation of ``toolz``--if it is installed, otherwise it uses
functions from ``toolz``.
"""

from . import _build_tlz
100 changes: 100 additions & 0 deletions tlz/_build_tlz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import sys
import types
import toolz
from toolz.compatibility import import_module


class TlzLoader(object):
""" Finds and loads ``tlz`` modules when added to sys.meta_path"""
def __init__(self):
self.always_from_toolz = set([
toolz.pipe,
])

def _load_toolz(self, fullname):
rv = {}
package, dot, submodules = fullname.partition('.')
try:
module_name = ''.join(['cytoolz', dot, submodules])
rv['cytoolz'] = import_module(module_name)
except ImportError:
pass
try:
module_name = ''.join(['toolz', dot, submodules])
rv['toolz'] = import_module(module_name)
except ImportError:
pass
if not rv:
raise ImportError(fullname)
return rv

def find_module(self, fullname, path=None): # pragma: py3 no cover
package, dot, submodules = fullname.partition('.')
if package == 'tlz':
return self

def load_module(self, fullname): # pragma: py3 no cover
if fullname in sys.modules: # pragma: no cover
return sys.modules[fullname]
spec = TlzSpec(fullname, self)
module = self.create_module(spec)
sys.modules[fullname] = module
self.exec_module(module)
return module

def find_spec(self, fullname, path, target=None): # pragma: no cover
package, dot, submodules = fullname.partition('.')
if package == 'tlz':
return TlzSpec(fullname, self)

def create_module(self, spec):
return types.ModuleType(spec.name)

def exec_module(self, module):
toolz_mods = self._load_toolz(module.__name__)
fast_mod = toolz_mods.get('cytoolz') or toolz_mods['toolz']
slow_mod = toolz_mods.get('toolz') or toolz_mods['cytoolz']
module.__dict__.update(toolz.merge(fast_mod.__dict__, module.__dict__))
package = fast_mod.__package__
if package is not None:
package, dot, submodules = package.partition('.')
module.__package__ = ''.join(['tlz', dot, submodules])
if not module.__doc__:
module.__doc__ = fast_mod.__doc__

# show file from toolz during introspection
module.__file__ = slow_mod.__file__

for k, v in fast_mod.__dict__.items():
tv = slow_mod.__dict__.get(k)
try:
hash(tv)
except TypeError:
tv = None
if tv in self.always_from_toolz:
module.__dict__[k] = tv
elif (
isinstance(v, types.ModuleType)
and v.__package__ == fast_mod.__name__
):
package, dot, submodules = v.__name__.partition('.')
module_name = ''.join(['tlz', dot, submodules])
submodule = import_module(module_name)
module.__dict__[k] = submodule


class TlzSpec(object):
def __init__(self, name, loader):
self.name = name
self.loader = loader
self.origin = None
self.submodule_search_locations = []
self.loader_state = None
self.cached = None
self.parent = None
self.has_location = False


tlz_loader = TlzLoader()
sys.meta_path.append(tlz_loader)
tlz_loader.exec_module(sys.modules['tlz'])
55 changes: 55 additions & 0 deletions toolz/tests/test_tlz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import toolz


def test_tlz():
import tlz
tlz.curry
tlz.functoolz.curry
assert tlz.__package__ == 'tlz'
assert tlz.__name__ == 'tlz'
import tlz.curried
assert tlz.curried.__package__ == 'tlz.curried'
assert tlz.curried.__name__ == 'tlz.curried'
tlz.curried.curry
import tlz.curried.operator
assert tlz.curried.operator.__package__ in (None, 'tlz.curried')
assert tlz.curried.operator.__name__ == 'tlz.curried.operator'
assert tlz.functoolz.__name__ == 'tlz.functoolz'
m1 = tlz.functoolz
import tlz.functoolz as m2
assert m1 is m2
import tlz.sandbox
try:
import tlzthisisabadname.curried
1/0
except ImportError:
pass
try:
import tlz.curry
1/0
except ImportError:
pass
try:
import tlz.badsubmodulename
1/0
except ImportError:
pass

assert toolz.__package__ == 'toolz'
assert toolz.curried.__package__ == 'toolz.curried'
assert toolz.functoolz.__name__ == 'toolz.functoolz'
try:
import cytoolz
assert cytoolz.__package__ == 'cytoolz'
assert cytoolz.curried.__package__ == 'cytoolz.curried'
assert cytoolz.functoolz.__name__ == 'cytoolz.functoolz'
except ImportError:
pass

assert tlz.__file__ == toolz.__file__
assert tlz.functoolz.__file__ == toolz.functoolz.__file__

assert tlz.pipe is toolz.pipe

assert 'tlz' in tlz.__doc__
assert tlz.curried.__doc__ is not None

0 comments on commit fe56571

Please sign in to comment.