diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..cdcac18 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,4 @@ +[run] +branch = True +source = psraw +include = psraw/*.py diff --git a/.gitignore b/.gitignore index 9d82d1e..03422f4 100644 --- a/.gitignore +++ b/.gitignore @@ -84,5 +84,3 @@ ENV/ # Spyder project settings .spyderproject - -test.py diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..78637dc --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: python +python: + - "2.7" + - "3.6" +install: source ./ci/travis_install.sh +script: bash ./ci/travis_test.sh +cache: apt +sudo: false +after_success: + - coveralls diff --git a/README.md b/README.md index 7aec82a..6a42977 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ PSRAW === -[![PyPI version](https://badge.fury.io/py/psraw.svg)](https://badge.fury.io/py/psraw) +[![PyPI version](https://badge.fury.io/py/psraw.svg)](https://badge.fury.io/py/psraw) [![Coverage Status](https://coveralls.io/repos/github/teaearlgraycold/psraw/badge.svg?branch=master)](https://coveralls.io/github/teaearlgraycold/psraw?branch=master) [![Build Status](https://travis-ci.org/teaearlgraycold/psraw.svg?branch=master)](https://travis-ci.org/teaearlgraycold/psraw) [![Code Health](https://landscape.io/github/teaearlgraycold/psraw/master/landscape.svg?style=flat)](https://landscape.io/github/teaearlgraycold/psraw/master) pushshift reddit API wrapper diff --git a/ci/travis_install.sh b/ci/travis_install.sh new file mode 100644 index 0000000..d2b1cac --- /dev/null +++ b/ci/travis_install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +pip install praw +pip install nose +pip install coverage coveralls + +python --version +python -c "import praw; print('praw %s' % praw.__version__)" +python setup.py build_ext --inplace diff --git a/ci/travis_test.sh b/ci/travis_test.sh new file mode 100644 index 0000000..4c602cd --- /dev/null +++ b/ci/travis_test.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +python --version +python -c "import praw; print('praw %s' % praw.__version__)" +nosetests -sv --with-coverage diff --git a/psraw/base.py b/psraw/base.py index d953319..7c125e7 100644 --- a/psraw/base.py +++ b/psraw/base.py @@ -14,6 +14,9 @@ def limit_chunk(limit, limit_max): :param limit: The total number of items requested :param limit_max: The maximum number of items that can be requested at once """ + if limit_max < 1: + raise ValueError('limit_max must be > 0') + limits = [] x = 0 @@ -59,6 +62,8 @@ def endpoint_func(r, **kwargs): if coerced_kwargs.get('sort', None) == 'asc': direction = 'after' + # Loop over the API request, since multiple may be required if the + # specified limit is greater than LIMIT_MAX for limit in limit_chunk(coerced_kwargs['limit'], LIMIT_MAX): coerced_kwargs['limit'] = limit url = '{}{}?{}'.format(BASE_ADDRESS, config['url'], urlencode(coerced_kwargs)) @@ -70,6 +75,8 @@ def endpoint_func(r, **kwargs): if len(data) < limit: raise StopIteration + # On subsequent requests, specify that we only want results from + # before or after the last item we were sent coerced_kwargs[direction] = data[-1]['created_utc'] endpoint_func.__name__ = name diff --git a/test.py b/test.py new file mode 100644 index 0000000..c3fd5fe --- /dev/null +++ b/test.py @@ -0,0 +1,2 @@ +from test.test_endpoints import * +from test.test_helpers import * diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/test_endpoints.py b/test/test_endpoints.py new file mode 100644 index 0000000..6b74d51 --- /dev/null +++ b/test/test_endpoints.py @@ -0,0 +1,10 @@ +import praw +import psraw +from psraw.endpoints import ENDPOINTS, sort_type + + +def test_psraw_exports(): + """psraw exports a function for every endpoint specified in ENDPOINTS""" + endpoint_names = set(ENDPOINTS.keys()) + psraw_exports = set(dir(psraw)) + assert endpoint_names.issubset(psraw_exports) diff --git a/test/test_helpers.py b/test/test_helpers.py new file mode 100644 index 0000000..e248ee1 --- /dev/null +++ b/test/test_helpers.py @@ -0,0 +1,69 @@ +import praw +from psraw.base import limit_chunk, coerce_kwarg_types +from psraw.endpoints import ENDPOINTS, sort_type + + +test_config = { + 'params': { + 'foo': str, + 'bar': int + }, + 'return_type': praw.models.Comment, + 'url': '/foo/bar' +} + + +def test_limit_chunk_1(): + """limit_chunk returns an array as expected with two positive arguments""" + chunks = limit_chunk(333, 100) + assert chunks == [100, 100, 100, 33] + + +def test_limit_chunk_2(): + """limit_chunk raises a ValueError when given a limit_max < 1""" + try: + limit_chunk(100, 0) + assert False + except ValueError: + pass + + +def test_limit_chunk_3(): + """limit_chunk returns an empty list if limit is < 1""" + chunks = limit_chunk(-1, 100) + assert chunks == [] + + +def test_coerce_kwarg_types_1(): + """coerce_kwarg_types raises a ValueError when passed an unspecified argument""" + try: + kwargs = {'foobar': 24} + coerced_kwargs = coerce_kwarg_types(kwargs, test_config['params']) + assert False + except ValueError: + pass + + +def test_coerce_kwarg_types_2(): + """coerce_kwarg_types converts parameter types""" + kwargs = { + 'foo': 24, + 'bar': 25 + } + coerced_kwargs = coerce_kwarg_types(kwargs, test_config['params']) + assert isinstance(coerced_kwargs['foo'], str) + assert isinstance(coerced_kwargs['bar'], int) + + +def test_sort_type_1(): + """sort_type returns the value passed in if it is a valid direction""" + assert sort_type('asc') == 'asc' + + +def test_sort_type_2(): + """sort_type raises a ValueError if the value passed in is not a direction""" + try: + sort_type('foobar') + assert False + except ValueError: + pass