From 0fd335ffd6bb6033573877cd2ac582940d7a9f1f Mon Sep 17 00:00:00 2001 From: Hemna Date: Mon, 14 Dec 2020 09:50:39 -0500 Subject: [PATCH] Initial commit --- .github/workflows/python.yml | 22 +++ ChangeLog | 3 + LICENSE.txt | 176 +++++++++++++++++++++ MANIFEST.in | 5 + README.rst | 28 ++++ aprsd_slack_plugin/__init__.py | 17 ++ aprsd_slack_plugin/aprsd_slack_plugin.py | 79 ++++++++++ dev-requirements.in | 10 ++ dev-requirements.txt | 62 ++++++++ docs/.gitignore | 1 + docs/_static/.keep | 0 docs/_templates/.keep | 0 docs/clean_docs.py | 22 +++ docs/conf.py | 189 +++++++++++++++++++++++ docs/index.rst | 22 +++ pyproject.toml | 22 +++ requirements.in | 3 + requirements.txt | 16 ++ setup.cfg | 35 +++++ setup.py | 26 ++++ tests/__init__.py | 0 tests/test_plugin.py | 22 +++ tox.ini | 91 +++++++++++ 23 files changed, 851 insertions(+) create mode 100644 .github/workflows/python.yml create mode 100644 ChangeLog create mode 100644 LICENSE.txt create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 aprsd_slack_plugin/__init__.py create mode 100644 aprsd_slack_plugin/aprsd_slack_plugin.py create mode 100644 dev-requirements.in create mode 100644 dev-requirements.txt create mode 100644 docs/.gitignore create mode 100644 docs/_static/.keep create mode 100644 docs/_templates/.keep create mode 100644 docs/clean_docs.py create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 pyproject.toml create mode 100644 requirements.in create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100755 setup.py create mode 100644 tests/__init__.py create mode 100644 tests/test_plugin.py create mode 100644 tox.ini diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..cb35ef2 --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,22 @@ +name: python + +on: [push] + +jobs: + tox: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.6, 3.7, 3.8, 3.9] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox tox-gh-actions + - name: Test with tox + run: tox diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..2e954b8 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,3 @@ +CHANGES +======= +1.0.0 - First release working against APRSD 1.0.0 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..68c771a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,176 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..485b85d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include README.rst +include LICENSE.txt +include requirements.txt +include aprsd_slack_plugin/py.typed +recursive-exclude tests * diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..afc7a79 --- /dev/null +++ b/README.rst @@ -0,0 +1,28 @@ +aprsd_slack_plugin +================ + +.. image:: https://github.com/hemna/aprsd-slack-plugin/workflows/python/badge.svg + :target: https://github.com/hemna/aprsd-slack-plugin/actions + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://black.readthedocs.io/en/stable/ + +.. image:: https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336 + :target: https://timothycrosley.github.io/isort/ + +This project is a python plugin for the APRSD server daemon written by +Craig Lamparter. The plugin looks for location APRS commands from a ham +radio, then reports that location to a slack channel. This is basically a +location proxy. + +Requirements +------------ + +Python 3.6+. +APRSD - http://github.com/craigerl/aprsd + +.. note:: + + Because `Python 2.7 supports ended January 1, 2020 `_, new projects + should consider supporting Python 3 only, which is simpler than trying to support both. + As a result, support for Python 2.7 in this example project has been dropped. diff --git a/aprsd_slack_plugin/__init__.py b/aprsd_slack_plugin/__init__.py new file mode 100644 index 0000000..5407727 --- /dev/null +++ b/aprsd_slack_plugin/__init__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import pbr.version + +__version__ = pbr.version.VersionInfo("aprsd_slack_plugin").version_string() diff --git a/aprsd_slack_plugin/aprsd_slack_plugin.py b/aprsd_slack_plugin/aprsd_slack_plugin.py new file mode 100644 index 0000000..44805fa --- /dev/null +++ b/aprsd_slack_plugin/aprsd_slack_plugin.py @@ -0,0 +1,79 @@ +import logging + +from aprsd import plugin +from slack_sdk import WebClient +from slack_sdk.errors import SlackApiError + +LOG = logging.getLogger("APRSD") + + +class SlackCommandPlugin(plugin.APRSDPluginBase): + """SlackCommandPlugin. + + This APRSD plugin looks for the location command comming in + to aprsd, then fetches the caller's location, and then reports + that location string to the configured slack channel. + + To use this: + Create a slack bot for your workspace at api.slack.com. + A good source of information on how to create the app + and the tokens and permissions and install the app in your + workspace is here: + + https://api.slack.com/start/building/bolt-python + + + You will need the signing secret from the + Basic Information -> App Credentials form. + You will also need the Bot User OAuth Access Token from + OAuth & Permissions -> OAuth Tokens for Your Team -> + Bot User OAuth Access Token. + + Install the app/bot into your workspace. + + Edit your ~/.config/aprsd/aprsd.yml and add the section + slack: + signing_secret: + bot_token: + channel: + """ + + version = "1.0" + + # matches any string starting with h or H + command_regex = "^[lL]" + command_name = "location-slack" + + def _setup_slack(self): + """Create the slack require client from config.""" + + # signing_secret = self.config["slack"]["signing_secret"] + bot_token = self.config["slack"]["bot_token"] + self.swc = WebClient(token=bot_token) + + self.slack_channel = self.config["slack"]["channel"] + + def command(self, fromcall, message, ack): + LOG.info("SlackCommandPlugin") + + self._setup_slack() + + # now call the location plugin to get the location info + location_plugin = plugin.LocationPlugin(self.config) + location = location_plugin.command(fromcall, message, ack) + if location: + reply = location + + LOG.debug("Sending '{}' to slack channel '{}'".format(reply, self.slack_channel)) + try: + self.swc.chat_postMessage(channel=self.slack_channel, text=reply) + except SlackApiError as e: + LOG.error( + "Failed to send message to channel '{}' because '{}'".format( + self.slack_channel, str(e) + ) + ) + else: + LOG.debug("SlackCommandPlugin couldn't get location for '{}'".format(fromcall)) + + return None diff --git a/dev-requirements.in b/dev-requirements.in new file mode 100644 index 0000000..f0999e1 --- /dev/null +++ b/dev-requirements.in @@ -0,0 +1,10 @@ +tox +pytest +pytest-cov +mypy +flake8 +pep8-naming +black +isort +pbr +Sphinx diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..9ca8cf8 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,62 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile dev-requirements.in +# +alabaster==0.7.12 # via sphinx +appdirs==1.4.4 # via black, virtualenv +attrs==20.3.0 # via pytest +babel==2.9.0 # via sphinx +black==20.8b1 # via -r dev-requirements.in +certifi==2020.12.5 # via requests +chardet==3.0.4 # via requests +click==7.1.2 # via black +coverage==5.3 # via pytest-cov +distlib==0.3.1 # via virtualenv +docutils==0.16 # via sphinx +filelock==3.0.12 # via tox, virtualenv +flake8-polyfill==1.0.2 # via pep8-naming +flake8==3.8.4 # via -r dev-requirements.in, flake8-polyfill +idna==2.10 # via requests +imagesize==1.2.0 # via sphinx +iniconfig==1.1.1 # via pytest +isort==5.6.4 # via -r dev-requirements.in +jinja2==2.11.2 # via sphinx +markupsafe==1.1.1 # via jinja2 +mccabe==0.6.1 # via flake8 +mypy-extensions==0.4.3 # via black, mypy +mypy==0.790 # via -r dev-requirements.in +packaging==20.8 # via pytest, sphinx, tox +pathspec==0.8.1 # via black +pbr==5.5.1 # via -r dev-requirements.in +pep8-naming==0.11.1 # via -r dev-requirements.in +pluggy==0.13.1 # via pytest, tox +py==1.10.0 # via pytest, tox +pycodestyle==2.6.0 # via flake8 +pyflakes==2.2.0 # via flake8 +pygments==2.7.3 # via sphinx +pyparsing==2.4.7 # via packaging +pytest-cov==2.10.1 # via -r dev-requirements.in +pytest==6.2.0 # via -r dev-requirements.in, pytest-cov +pytz==2020.4 # via babel +regex==2020.11.13 # via black +requests==2.25.0 # via sphinx +six==1.15.0 # via tox, virtualenv +snowballstemmer==2.0.0 # via sphinx +sphinx==3.3.1 # via -r dev-requirements.in +sphinxcontrib-applehelp==1.0.2 # via sphinx +sphinxcontrib-devhelp==1.0.2 # via sphinx +sphinxcontrib-htmlhelp==1.0.3 # via sphinx +sphinxcontrib-jsmath==1.0.1 # via sphinx +sphinxcontrib-qthelp==1.0.3 # via sphinx +sphinxcontrib-serializinghtml==1.1.4 # via sphinx +toml==0.10.2 # via black, pytest, tox +tox==3.20.1 # via -r dev-requirements.in +typed-ast==1.4.1 # via black, mypy +typing-extensions==3.7.4.3 # via black, mypy +urllib3==1.26.2 # via requests +virtualenv==20.2.2 # via tox + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..73f8507 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +apidoc diff --git a/docs/_static/.keep b/docs/_static/.keep new file mode 100644 index 0000000..e69de29 diff --git a/docs/_templates/.keep b/docs/_templates/.keep new file mode 100644 index 0000000..e69de29 diff --git a/docs/clean_docs.py b/docs/clean_docs.py new file mode 100644 index 0000000..771bfd3 --- /dev/null +++ b/docs/clean_docs.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +"""Removes temporary Sphinx build artifacts to ensure a clean build. + +This is needed if the Python source being documented changes significantly. Old sphinx-apidoc +RST files can be left behind. +""" + +from pathlib import Path +import shutil + + +def main() -> None: + docs_dir = Path(__file__).resolve().parent + for folder in ("_build", "apidoc"): + delete_dir = docs_dir / folder + if delete_dir.exists(): + shutil.rmtree(delete_dir) + + +if __name__ == "__main__": + main() diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..434cf9d --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- 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 sys + +sys.path.insert(0, os.path.abspath("../aprsd_slack_plugin")) + + +# -- Project information ----------------------------------------------------- + +project = "fact" +copyright = "" +author = "a" + +# The short X.Y version +version = "" +# The full version, including alpha/beta/rc tags +release = "" + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# 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.doctest", + "sphinx.ext.todo", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = ".rst" + +# The master toctree document. +master_doc = "index" + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# 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"] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- 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" + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +html_theme_options = { + # Override the default alabaster line wrap, which wraps tightly at 940px. + "page_width": "auto", +} + +# 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"] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = "adoc" + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, "a.tex", "a Documentation", "a", "manual"), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [(master_doc, "a", "a Documentation", [author], 1)] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ( + master_doc, + "a", + "a Documentation", + author, + "a", + "One line description of project.", + "Miscellaneous", + ), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ["search.html"] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..3d89098 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +.. a documentation master file, created by + sphinx-quickstart on Wed Dec 19 18:34:22 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +``aprsd_slack_plugin`` Documentation +====================== + +.. include:: ../README.rst + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + apidoc/modules.rst + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3a5104b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,22 @@ +[build-system] +requires = ["setuptools>=46.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.black] +# Use the more relaxed max line length permitted in PEP8. +line-length = 99 +target-version = ["py36", "py37", "py38"] +# black will automatically exclude all files listed in .gitignore + +[tool.isort] +profile = "black" +line_length = 99 +force_sort_within_sections = true +# Inform isort of paths to import names that should be considered part of the "First Party" group. +src_paths = ["aprsd_slack_plugin"] +skip_gitignore = true +# If you need to skip/exclude folders, consider using skip_glob as that will allow the +# isort defaults for skip to remain without the need to duplicate them. + +[tool.coverage.run] +branch = true diff --git a/requirements.in b/requirements.in new file mode 100644 index 0000000..0e1f25b --- /dev/null +++ b/requirements.in @@ -0,0 +1,3 @@ +pbr +slack_sdk>=3.0 +slackeventsapi>=2.1.0 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6fe03cd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile +# +click==7.1.2 # via flask +flask==1.1.2 # via slackeventsapi +itsdangerous==1.1.0 # via flask, slackeventsapi +jinja2==2.11.2 # via flask, slackeventsapi +markupsafe==1.1.1 # via jinja2, slackeventsapi +pbr==5.5.1 # via -r requirements.in +pyee==7.0.4 # via slackeventsapi +slack-sdk==3.1.0 # via -r requirements.in +slackeventsapi==2.2.1 # via -r requirements.in +werkzeug==1.0.1 # via flask diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..78b8f69 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,35 @@ +[metadata] +name = aprsd_slack_plugin +summary = Amateur radio APRS daemon which listens for messages and responds +description-file = + README.rst +author = Walter A. Boring IV +author-email = something@somewhere.com +classifier = + Topic :: Communications :: Ham Radio + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Python :: 3.9 + +[global] +setup-hooks = + pbr.hooks.setup_hook + +[files] +packages = + aprsd_slack_plugin + +[build_sphinx] +source-dir = doc/source +build-dir = doc/build +all_files = 1 + +[upload_sphinx] +upload-dir = doc/build/html + +[mypy] +ignore_missing_imports = True +strict = True diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..70592f3 --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT +import setuptools + +# In python < 2.7.4, a lazy loading of package `pbr` will break +# setuptools if some other modules registered functions in `atexit`. +# solution from: http://bugs.python.org/issue15881#msg170215 +try: + import multiprocessing # noqa +except ImportError: + pass + +setuptools.setup(setup_requires=["pbr"], pbr=True) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_plugin.py b/tests/test_plugin.py new file mode 100644 index 0000000..ecee105 --- /dev/null +++ b/tests/test_plugin.py @@ -0,0 +1,22 @@ +import sys +import unittest + +from aprsd_slack_plugin import aprsd_slack_plugin as slack_plugin + +if sys.version_info >= (3, 2): + from unittest import mock +else: + import mock + + +class TestPlugin(unittest.TestCase): + @mock.patch.object(slack_plugin.SlackCommandPlugin, "command") + def test_plugin(self, mock_command): + mock_command.return_value = "" + + config = { + "slack": {"signing_secret": "something", "bot_token": "sometoken", "channel": "hemna"} + } + + p = slack_plugin.SlackCommandPlugin(config) + p.command("KM6LYW", "location", 1) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..4e4d9d4 --- /dev/null +++ b/tox.ini @@ -0,0 +1,91 @@ +[flake8] +# Use the more relaxed max line length permitted in PEP8. +max-line-length = 99 +# This ignore is required by black. +extend-ignore = E203 +extend-exclude = + venv + +# This is the configuration for the tox-gh-actions plugin for GitHub Actions +# https://github.com/ymyzk/tox-gh-actions +# This section is not needed if not using GitHub Actions for CI. +[gh-actions] +python = + 3.6: py36 + 3.7: py37 + 3.8: py38, fmt-check, lint + 3.9: py39 + +[tox] +# These are the default environments that will be run +# when ``tox`` is run without arguments. +envlist = + fmt-check + lint + py{36,37,38,39} +skip_missing_interpreters = true + +# Activate isolated build environment. tox will use a virtual environment +# to build a source distribution from the source tree. For build tools and +# arguments use the pyproject.toml file as specified in PEP-517 and PEP-518. +isolated_build = true + +[testenv] +deps = + -r{toxinidir}/requirements.txt + -r{toxinidir}/dev-requirements.txt +commands = + # Use -bb to enable BytesWarnings as error to catch str/bytes misuse. + # Use -Werror to treat warnings as errors. + {envpython} -bb -Werror -m pytest {posargs} + +[testenv:type-check] +skip_install = true +deps = + -r{toxinidir}/requirements.txt + -r{toxinidir}/dev-requirements.txt +commands = + mypy src tests + +[testenv:lint] +skip_install = true +deps = + -r{toxinidir}/dev-requirements.txt +commands = + flake8 aprsd_slack_plugin tests + +[testenv:docs] +skip_install = true +deps = + -r{toxinidir}/requirements.txt + -r{toxinidir}/dev-requirements.txt +changedir = {toxinidir}/docs +commands = + {envpython} clean_docs.py + sphinx-apidoc --force --output-dir apidoc {toxinidir}/aprsd_slack_plugin + sphinx-build -a -W . _build + +[testenv:fmt] +skip_install = true +deps = + -r{toxinidir}/dev-requirements.txt +commands = + isort aprsd_slack_plugin tests + black aprsd_slack_plugin tests + +[testenv:fmt-check] +skip_install = true +deps = + -r{toxinidir}/dev-requirements.txt +commands = + isort --check-only aprsd_slack_plugin tests + black --check aprsd_slack_plugin tests + +[testenv:licenses] +skip_install = true +recreate = true +deps = + -r{toxinidir}/requirements.txt + pip-licenses +commands = + pip-licenses {posargs}