diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..a51310c --- /dev/null +++ b/.flake8 @@ -0,0 +1,9 @@ +[flake8] +max-line-length = 88 + +exclude= + .git + .eggs + .pytest_cache + env.egg-info + test_env.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..914ee8b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.coverage +.eggs/ +.pytest_cache/ +env.egg-info/ +__pycache__/ diff --git a/.travis.yml b/.travis.yml index f387bd5..ced47b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,12 @@ matrix: - python: 3.8-dev - python: nightly -script: make test install: - - pip install nose + - pip install pytest pytest-cov flake8 flake8-bugbear python-coveralls + +script: + - flake8 + - python3 setup.py test + +after_success: + - coveralls diff --git a/Makefile b/Makefile deleted file mode 100644 index e08717a..0000000 --- a/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -test: - nosetests tests.py \ No newline at end of file diff --git a/env.py b/env.py index 59f8402..5abe83b 100644 --- a/env.py +++ b/env.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- +"""Parses env variables into a human friendly dictionary.""" from os import environ -try: +try: # pragma: no cover from urllib.parse import urlparse as _urlparse -except ImportError: +except ImportError: # pragma: no cover from urlparse import urlparse as _urlparse def lower_dict(d): """Lower cases string keys in given dict.""" - _d = {} for k, v in d.items(): @@ -22,8 +22,7 @@ def lower_dict(d): def urlparse(d, keys=None): - """Returns a copy of the given dictionary with url values parsed.""" - + """Return a copy of the given dictionary with url values parsed.""" d = d.copy() if keys is None: @@ -36,10 +35,11 @@ def urlparse(d, keys=None): def prefix(prefix): - """Returns a dictionary of all environment variables starting with - the given prefix, lower cased and stripped. """ + Return dictionary with all environment variables starting with prefix. + The elements of the dictionary are all lower cased and stripped of prefix. + """ d = {} e = lower_dict(environ.copy()) @@ -57,10 +57,11 @@ def prefix(prefix): def map(**kwargs): - """Returns a dictionary of the given keyword arguments mapped to their - values from the environment, with input keys lower cased. """ + Return a dictionary of the given keyword arguments mapped to os.environ. + The input keys are lower cased for both the passed in map and os.environ. + """ d = {} e = lower_dict(environ.copy()) diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..e5230a1 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts = --cov=env --cov-report term-missing \ No newline at end of file diff --git a/setup.py b/setup.py index d8b8653..cf404de 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """ -env.py +Setup file for env package. + ~~~~~~ Mapping environment variables can be a bit of a pain. @@ -31,11 +32,37 @@ Or have a bit more control:: """ from setuptools import setup +from setuptools.command.test import test as TestCommand +import sys + + +class PyTest(TestCommand): + """pytest command runner.""" + + user_options = [('pytest-args=', 'a', "Arguments to pass into py.test")] + + def initialize_options(self): + """Initialize the options for pytest.""" + TestCommand.initialize_options(self) + + def finalize_options(self): + """Finalize the options for pytest.""" + TestCommand.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + """Run the pytest runner.""" + import pytest + + errno = pytest.main([]) + sys.exit(errno) + setup( name='env', version='0.1.1', - url='https://github.com/kennethreitz/env', + url='https://github.com/MasterOdin/env', license='BSD', author='Kenneth Reitz', author_email='me@kennethreitz.com', @@ -45,6 +72,8 @@ setup( zip_safe=False, include_package_data=True, platforms='any', + tests_require=['pytest', 'pytest-cov'], + cmdclass={'test': PyTest}, classifiers=[ 'Environment :: Web Environment', 'Intended Audience :: Developers', @@ -57,6 +86,7 @@ setup( 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Libraries :: Python Modules' ] diff --git a/test_env.py b/test_env.py new file mode 100644 index 0000000..41d3fac --- /dev/null +++ b/test_env.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +"""Test env module.""" + +import env +import os +import mock + +try: + from urlparse import urlparse as _urlparse +except ImportError: + from urllib.parse import urlparse as _urlparse + +SEARCH_PREFIX = 'env1' +MATCH_DATA = {'env1TESTS1': 'aA', 'ENV1tests2': 'bB', 'env1tests3': 'cC'} +NO_MATCH_DATA = {'env2TESTS4': 'dD', 'ENV2tests5': 'eE', 'env2tests6': 'fF'} +ALL_DATA = {**MATCH_DATA, **NO_MATCH_DATA} + + +def test_lower_dict(): + lowereddict = env.lower_dict(MATCH_DATA) + + assert len(lowereddict) == len(MATCH_DATA) + + for item in MATCH_DATA: + assert MATCH_DATA[item] == lowereddict[item.lower()] + + +def test_lower_dict_non_string_key(): + mixed_key_dict = {0: 'aA', 'env1TEST1': 'bB'} + lowereddict = env.lower_dict(mixed_key_dict) + expected_dict = {0: 'aA', 'env1test1': 'bB'} + + assert len(lowereddict) == len(mixed_key_dict) + + for item in expected_dict: + assert expected_dict[item] == lowereddict[item] + + +def test_urlparse(): + urldata = {'url1': 'http://env1.test', 'url2': 'ftp://env2.test'} + + parseddata = env.urlparse(urldata) + + assert len(parseddata) == len(urldata) + + for item in urldata: + assert _urlparse(urldata[item]) == parseddata[item] + + +@mock.patch.dict(os.environ, ALL_DATA, clear=True) +def test_prefix(): + prefixsearch = env.prefix(SEARCH_PREFIX) + + assert len(prefixsearch) == len(MATCH_DATA) + + for item in MATCH_DATA: + assert MATCH_DATA[item] == prefixsearch[item.lower()[len(SEARCH_PREFIX):]] + + +@mock.patch.object( + env, + 'lower_dict', + return_value={0: 'test', 'env1test1': 'bB'} +) +def test_prefix_non_string_key(mock_func): + prefixsearch = env.prefix(SEARCH_PREFIX) + + assert len(prefixsearch) == 1 + assert prefixsearch['test1'] == 'bB' + + +@mock.patch.dict(os.environ, ALL_DATA, clear=True) +def test_map(): + mapdata = {'a': 'env1tests1', 'b': 'env1tests2', 'c': 'env1tests3'} + originaldata = {'env1tests1': 'aA', 'env1tests2': 'bB', 'env1tests3': 'cC'} + + mapsearch = env.map(a='env1tests1', b='env1tests2', c='env1tests3') + + assert len(mapsearch) == len(mapdata) + + for item in mapdata: + assert originaldata[mapdata[item]] == mapsearch[item] diff --git a/tests.py b/tests.py deleted file mode 100644 index 1e1c3e1..0000000 --- a/tests.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import env -from os import environ - -try: - from urlparse import urlparse as _urlparse -except ImportError: - from urllib.parse import urlparse as _urlparse - -searchprefix = 'env1' -matchdata = {'env1TESTS1': 'aA', 'ENV1tests2': 'bB', 'env1tests3': 'cC'} -nomatchdata = {'env2TESTS4': 'dD', 'ENV2tests5': 'eE', 'env2tests6': 'fF'} - -for matchvalue in matchdata: - environ[matchvalue] = matchdata[matchvalue] - -for nomatchvalue in nomatchdata: - environ[nomatchvalue] = nomatchdata[nomatchvalue] - -def compare_values(a, b): - assert a == b - -def test_lower_dict(): - lowereddict = env.lower_dict(matchdata) - - yield compare_values, len(lowereddict), len(matchdata) - - for item in matchdata: - yield compare_values, matchdata[item], lowereddict[item.lower()] - -def test_urlparse(): - urldata = {'url1': 'http://env1.test', 'url2': 'ftp://env2.test'} - - parseddata = env.urlparse(urldata) - - yield compare_values, len(parseddata), len(urldata) - - for item in urldata: - yield compare_values, _urlparse(urldata[item]), parseddata[item] - -def test_prefix(): - prefixsearch = env.prefix(searchprefix) - - yield compare_values, len(prefixsearch), len(matchdata) - - for item in matchdata: - yield compare_values, matchdata[item], prefixsearch[item.lower()[len(searchprefix):]] - -def test_map(): - mapdata = {'a': 'env1tests1', 'b': 'env1tests2', 'c': 'env1tests3'} - originaldata = {'env1tests1': 'aA', 'env1tests2': 'bB', 'env1tests3': 'cC'} - - mapsearch = env.map(a='env1tests1', b='env1tests2', c='env1tests3') - - yield compare_values, len(mapsearch), len(mapdata) - - for item in mapdata: - yield compare_values, originaldata[mapdata[item]], mapsearch[item] diff --git a/tox.ini b/tox.ini index b8b4df4..8f72bf2 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,9 @@ [tox] -envlist = py{27,34,35,36} +envlist = py{27,34,35,36,37} skip_missing_interpreters = True [testenv] deps = - nose - coverage -commands = {envpython} ./setup.py nosetests {posargs} + pytest + pytest-cov +commands = {envpython} pytest {posargs}