From f5eca84844ac4fefc556e2f5ea2f07a25b2a7740 Mon Sep 17 00:00:00 2001 From: hjpotter92 Date: Sat, 27 Mar 2021 14:25:23 +0530 Subject: [PATCH] Add few more test cases. * Add basic documentation generation using sphinx. * Update travis-ci environment. --- .travis.yml | 19 +++++++--- README.md | 48 ------------------------ README.rst | 53 ++++++++++++++++++++++++++ docs/Makefile | 20 ++++++++++ docs/conf.py | 69 ++++++++++++++++++++++++++++++++++ docs/index.rst | 24 ++++++++++++ docs/modules.rst | 7 ++++ docs/sqspy.rst | 37 ++++++++++++++++++ requirements-doc.txt | 1 + requirements-test.txt | 6 +-- setup.py | 81 ++++++++++++++++++++++------------------ tests/base_test_case.py | 3 ++ tests/config.py | 5 ++- tests/test_connection.py | 3 +- tests/test_consumer.py | 13 +++++++ 15 files changed, 293 insertions(+), 96 deletions(-) delete mode 100644 README.md create mode 100644 README.rst create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/modules.rst create mode 100644 docs/sqspy.rst create mode 100644 requirements-doc.txt diff --git a/.travis.yml b/.travis.yml index 78683c2..dd9891f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,29 @@ -sudo: false +dist: focal +os: linux language: python +cache: pip + services: - docker -cache: - directories: - - "$HOME/.cache/pip" - - "$HOME/.pyenv" + python: - "3.6" - "3.7" - "3.8" + - "3.9" + - "3.10-dev" - "pypy3" - - "nightly" # nightly build + - "nightly" + before_install: - docker run -d -p 127.0.0.1:4100:4100 pafortin/goaws + install: - pip install -U boto3 codecov -r requirements-test.txt + script: - coverage run -m pytest + - coverage report -m + after_success: - codecov diff --git a/README.md b/README.md deleted file mode 100644 index 6d76238..0000000 --- a/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# sqspy - -[![codecov][codecov-badge]][codecov] [![Build Status][travis-badge]][travis] - -A more pythonic approach to SQS producer/consumer utilities. Heavily -inspired from the [the pySqsListener][1] package. - -## Install - -```Shell -pip install sqspy -``` - -## Usage - -```Python -from sqspy import Consumer - - -class MyWorker(Consumer): - def handle_message(self, body, attributes, message_attributes): - print(body) - - -listener = MyWorker('Q1', error_queue='EQ1') -listener.listen() -``` - -More documentation coming soon. - -## Why - -The mentioned project had a few issues which I faced while trying to -implement at my organisation. The local environment testing setup was -very flaky. The signatures for `sqs_listener` and `sqs_producer` were -very different from each other. - -This rewrite supports __python 3.6+ versions only__, and makes use of a -lot of newer python features. It also makes use of service resources (for -lazy calls) from the boto3 library instead of making calls via the low -level client. - - - [1]: https://pypi.org/project/pySqsListener/ "pySqsListener on PyPI" - [codecov-badge]: https://codecov.io/gh/hjpotter92/sqspy/branch/master/graph/badge.svg?token=6XLSO7NPF9 - [codecov]: https://codecov.io/gh/hjpotter92/sqspy - [travis-badge]: https://travis-ci.com/hjpotter92/sqspy.svg?branch=master - [travis]: https://travis-ci.com/hjpotter92/sqspy diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..8290715 --- /dev/null +++ b/README.rst @@ -0,0 +1,53 @@ +================ +Introduction +================ + +.. image:: https://pyup.io/repos/github/hjpotter92/sqspy/shield.svg + :target: https://pyup.io/repos/github/hjpotter92/sqspy/ + :alt: Updates +.. image:: https://readthedocs.org/projects/sqspy/badge/?version=latest + :target: https://sqspy.docs.hjpotter92.tech/en/latest/?badge=latest + :alt: Documentation Status +.. image:: https://travis-ci.com/hjpotter92/sqspy.svg?branch=master + :target: https://travis-ci.com/hjpotter92/sqspy + :alt: Build status + +A more pythonic approach to SQS producer/consumer utilities. Heavily +inspired from the `the pySqsListener +`_ package. + +Install +======== + +.. code-block:: shell + + pip install sqspy + +Usage +======== + +.. code-block:: python + + from sqspy import Consumer + + class MyWorker(Consumer): + def handle_message(self, body, attributes, message_attributes): + print(body) + + listener = MyWorker('Q1', error_queue='EQ1') + listener.listen() + +More documentation coming soon. + +Why +======== + +The mentioned project had a few issues which I faced while trying to +implement at my organisation. The local environment testing setup was +very flaky. The signatures for ``sqs_listener`` and ``sqs_producer`` +were very different from each other. + +This rewrite supports **python 3.6+ versions only**, and makes use of +a lot of newer python features. It also makes use of service resources +(for lazy calls) from the boto3 library instead of making calls via +the low level client. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..e00a701 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,69 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path.cwd().parent.absolute())) +sys.path.insert(0, str(pathlib.Path.cwd().absolute())) +from sqspy.about import VERSION + +# -- Project information ----------------------------------------------------- + +project = "sqspy" +copyright = "2021, hjpotter92" +author = "hjpotter92" + +# The full version, including alpha/beta/rc tags +release = VERSION + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosectionlabel", + "sphinx.ext.autosummary", + "sphinx.ext.intersphinx", + "sphinx.ext.viewcode", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = "alabaster" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ["_static"] + +# -- Options for enabled extensions ------------------------------------------ +intersphinx_mapping = { + "python": ("https://docs.python.org/3", None), + "boto3": ("https://boto3.rtfd.io/", None), +} diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..28292c4 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,24 @@ +.. sqspy documentation master file, created by + sphinx-quickstart on Thu Mar 25 16:11:47 2021. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to sqspy's documentation! +================================= + +.. include:: ../README.rst + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + modules + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..71dbb4d --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +sqspy +===== + +.. toctree:: + :maxdepth: 4 + + sqspy diff --git a/docs/sqspy.rst b/docs/sqspy.rst new file mode 100644 index 0000000..9dfe1f8 --- /dev/null +++ b/docs/sqspy.rst @@ -0,0 +1,37 @@ +sqspy package +============= + +Submodules +---------- + +sqspy._base module +------------------ + +.. automodule:: sqspy._base + :members: + :undoc-members: + :show-inheritance: + +sqspy.consumer module +--------------------- + +.. automodule:: sqspy.consumer + :members: + :undoc-members: + :show-inheritance: + +sqspy.producer module +--------------------- + +.. automodule:: sqspy.producer + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: sqspy + :members: + :undoc-members: + :show-inheritance: diff --git a/requirements-doc.txt b/requirements-doc.txt new file mode 100644 index 0000000..f832cf6 --- /dev/null +++ b/requirements-doc.txt @@ -0,0 +1 @@ +sphinx>=3.5.3 diff --git a/requirements-test.txt b/requirements-test.txt index c34e893..f8d7d19 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,3 @@ -coverage>=5.3 -pytest>=6.1.1 -Faker>=4.14.0 +coverage>=5.4 +pytest>=6.2.2 +Faker>=6.6.2 diff --git a/setup.py b/setup.py index 473805f..49c6b55 100644 --- a/setup.py +++ b/setup.py @@ -1,41 +1,50 @@ from pathlib import Path -from setuptools import setup, find_packages +from setuptools import find_packages, setup import sqspy.about as about -here = Path.cwd() -readme = here / "README.md" - - -setup( - name=about.NAME, - version=about.VERSION, - description="AWS SQS utility package for producing and consuming messages", - long_description=readme.read_text(), - long_description_content_type="text/markdown", - url="https://github.com/hjpotter92/sqspy", - author=about.AUTHOR.get("name"), - author_email=about.AUTHOR.get("email"), - license="MIT", - # See https://pypi.python.org/pypi?%3Aaction=list_classifiers - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - "Development Status :: 4 - Beta", - # Indicate who your project is intended for - "Intended Audience :: Developers", - "Topic :: Software Development :: Libraries", - # Pick your license as you wish (should match "license" above) - "License :: OSI Approved :: MIT License", - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - "Programming Language :: Python :: 3.7", - ], - # What does your project relate to? - keywords="aws sqs messages producer/consumer", - packages=find_packages(), - install_requires=["boto3"], -) +if __name__ == "__main__": + setup( + name=about.NAME, + version=about.VERSION, + description="AWS SQS utility package for producing and consuming messages", + long_description=Path("README.rst").read_text(), + url="https://github.com/hjpotter92/sqspy", + author=about.AUTHOR["name"], + author_email=about.AUTHOR["email"], + license="MIT", + include_package_data=True, + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: Implementation", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules", + ], + python_requires=">=3.6", + project_urls={ + "Documentation": "https://sqspy.rtfd.io/", + "Code coverage": "https://app.codecov.io/gh/hjpotter92/sqspy", + "Builds history": "https://travis-ci.com/hjpotter92/sqspy", + # "Changelog": "https://sqspy.rtfd.io/changelog", + }, + platforms=["any"], + tests_require=( + "codecov>=2.1.11", + "coverage>=5.4", + "pytest>=6.2.2", + ), + keywords="aws sqs messages producer consumer", + packages=find_packages(exclude=["docs", "tests", "tests.*"]), + install_requires=["boto3>=1"], + ) diff --git a/tests/base_test_case.py b/tests/base_test_case.py index 6682bed..0ad8b62 100644 --- a/tests/base_test_case.py +++ b/tests/base_test_case.py @@ -1,6 +1,9 @@ from unittest import TestCase + from faker import Faker + from sqspy import Consumer, Producer + from .config import TestConfig diff --git a/tests/config.py b/tests/config.py index ef3e6a9..d038105 100644 --- a/tests/config.py +++ b/tests/config.py @@ -1,8 +1,9 @@ from os import getenv +from typing import Union class TestConfig: aws_access_key_id: str = "XXXXXXXXXXXXXXXX" aws_secret_access_key: str = "XXXXXXXXXXXXXXXXXXXXXXXXXX" - endpoint_url: str = getenv("ENDPOINT_URL") - region_name: str = getenv("AWS_DEFAULT_REGION") or getenv("REGION_NAME") + endpoint_url: Union[None, str] = getenv("ENDPOINT_URL") + region_name: Union[None, str] = getenv("AWS_DEFAULT_REGION", getenv("REGION_NAME")) diff --git a/tests/test_connection.py b/tests/test_connection.py index 894a369..0202db8 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,13 +1,14 @@ from unittest import TestCase from botocore.exceptions import ( + EndpointConnectionError, NoCredentialsError, NoRegionError, - EndpointConnectionError, ) from sqspy import Consumer from sqspy._base import Base + from .config import TestConfig diff --git a/tests/test_consumer.py b/tests/test_consumer.py index 0c3e713..a0c3ed4 100644 --- a/tests/test_consumer.py +++ b/tests/test_consumer.py @@ -13,3 +13,16 @@ def test_queue_creation(self): def test_invalid_consumer(self): self.assertRaises(ValueError, ConsumerTest) + + def test_consumer_not_allowed_to_create_queue(self): + queue_name = self.fake.pystr(max_chars=10) + self.assertRaises(ValueError, self.get_consumer, queue_name, create_queue=False) + + def test_consumer_has_error_queue(self): + queue_name = self.fake.pystr(max_chars=10) + error_queue_name = f"error-{queue_name}" + consumer = self.get_consumer( + queue_name=queue_name, + error_queue=error_queue_name, + ) + self.assertEqual(consumer.queue_name, queue_name)