diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..eefe4ad --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,23 @@ +[bumpversion] +current_version = 0.1.0-alpha.0 +commit = True +tag = True +parse = (?P\d+)\.(?P\d+)\.(?P\d+)(-(?P[^.]*)\.(?P\d+))? +serialize = + {major}.{minor}.{patch}-{stage}.{devnum} + {major}.{minor}.{patch} + +[bumpversion:part:stage] +optional_value = stable +first_value = stable +values = + alpha + beta + stable + +[bumpversion:part:devnum] + +[bumpversion:file:setup.py] +search = version='{current_version}', +replace = version='{new_version}', + diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..fa7691e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,77 @@ +version: 2.0 + +# heavily inspired by https://raw.githubusercontent.com/pinax/pinax-wiki/6bd2a99ab6f702e300d708532a6d1d9aa638b9f8/.circleci/config.yml + +common: &common + working_directory: ~/repo + steps: + - checkout + - run: + name: merge pull request base + command: ./.circleci/merge_pr.sh + - run: + name: merge pull request base (2nd try) + command: ./.circleci/merge_pr.sh + when: on_fail + - run: + name: merge pull request base (3nd try) + command: ./.circleci/merge_pr.sh + when: on_fail + - restore_cache: + keys: + - cache-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + - run: + name: install dependencies + command: pip install --user tox + - run: + name: run tox + command: ~/.local/bin/tox -r + - save_cache: + paths: + - .hypothesis + - .tox + - ~/.cache/pip + - ~/.local + - ./eggs + key: cache-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + +jobs: + docs: + <<: *common + docker: + - image: circleci/python:3.6 + environment: + TOXENV: docs + lint: + <<: *common + docker: + - image: circleci/python:3.6 + environment: + TOXENV: lint + py36-core: + <<: *common + docker: + - image: circleci/python:3.6 + environment: + TOXENV: py36-core + py37-core: + <<: *common + docker: + - image: circleci/python:3.7 + environment: + TOXENV: py37-core + pypy3-core: + <<: *common + docker: + - image: pypy + environment: + TOXENV: pypy3-core +workflows: + version: 2 + test: + jobs: + - docs + - lint + - py36-core + - py37-core + - pypy3-core diff --git a/.circleci/merge_pr.sh b/.circleci/merge_pr.sh new file mode 100755 index 0000000..91eb47c --- /dev/null +++ b/.circleci/merge_pr.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +if [[ -n "${CIRCLE_PR_NUMBER}" ]]; then + PR_INFO_URL=https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pulls/$CIRCLE_PR_NUMBER + PR_BASE_BRANCH=$(curl -L "$PR_INFO_URL" | python -c 'import json, sys; obj = json.load(sys.stdin); sys.stdout.write(obj["base"]["ref"])') + git fetch origin +"$PR_BASE_BRANCH":circleci/pr-base + # We need these config values or git complains when creating the + # merge commit + git config --global user.name "Circle CI" + git config --global user.email "circleci@example.com" + git merge --no-edit circleci/pr-base +fi diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..5ff4880 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,38 @@ + _If this is a bug report, please fill in the following sections. +If this is a feature request, delete and describe what you would like with examples._ + +## What was wrong? + +### Code that produced the error + +```py +CODE_TO_REPRODUCE +``` + +### Full error output + +```sh +ERROR_HERE +``` + +### Expected Result + +_This section may be deleted if the expectation is "don't crash"._ + +```sh +EXPECTED_RESULT +``` + +### Environment + +```sh +# run this: +$ python -m eth_utils + +# then copy the output here: +OUTPUT_HERE +``` + +## How can it be fixed? + +Fill this section in if you know how this could or should be fixed. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..4ef27e5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ +## What was wrong? + +Issue # + +## How was it fixed? + +Summary of approach. + +### To-Do + +[//]: # (Stay ahead of things, add list items here!) +- [ ] Clean up commit history + +[//]: # (For important changes that should go into the release notes please add a newsfragment file as explained here: https://github.com/libp2p/py-libp2p/blob/master/newsfragments/README.md) + +[//]: # (See: https://py-libp2p.readthedocs.io/en/latest/contributing.html#pull-requests) +- [ ] Add entry to the [release notes](https://github.com/libp2p/py-libp2p/blob/master/newsfragments/README.md) + +#### Cute Animal Picture + +![put a cute animal picture link inside the parentheses]() diff --git a/.gitignore b/.gitignore index ff30aba..498eb39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,57 +1,133 @@ # Byte-compiled / optimized / DLL files -__pycache__/ *.py[cod] +__pycache__/ *$py.class # C extensions *.so # Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.egg-info/ -.installed.cfg *.egg +*.egg-info +dist +build +eggs +.eggs +parts +bin +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +venv* +.Python +downloads/ +wheels/ MANIFEST pip-wheel-metadata -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports -htmlcov/ -.tox/ .coverage -.coverage.* -.cache +.tox nosetests.xml +htmlcov/ +.coverage.* coverage.xml *.cover -.hypothesis/ .pytest_cache/ # Translations *.mo *.pot +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Complexity +output/*.html +output/*/index.html + +# Sphinx +docs/_build +docs/modules.rst +docs/*.internal.rst +docs/*._utils.* + +# Hypothese Property base testing +.hypothesis + +# tox/pytest cache +.cache + +# Test output logs +logs + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml + +# Sensitive or high-churn files: +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +# VIM temp files +*.sw[op] + +# mypy +.mypy_cache + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + # Django stuff: *.log local_settings.py @@ -64,9 +140,6 @@ instance/ # Scrapy stuff: .scrapy -# Sphinx documentation -docs/_build/ - # PyBuilder target/ @@ -86,10 +159,8 @@ celerybeat-schedule .env .venv env/ -venv/ ENV/ env.bak/ -venv.bak/ # Spyder project settings .spyderproject @@ -101,11 +172,5 @@ venv.bak/ # mkdocs documentation /site -# mypy -.mypy_cache/ - -# pycharm -.idea/ - # vscode .vscode/ diff --git a/.project-template/fill_template_vars.sh b/.project-template/fill_template_vars.sh new file mode 100755 index 0000000..f09e8ff --- /dev/null +++ b/.project-template/fill_template_vars.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +set -o errexit +set -o nounset +set -o pipefail + +PROJECT_ROOT=$(dirname $(dirname $(python -c 'import os, sys; sys.stdout.write(os.path.realpath(sys.argv[1]))' "$0"))) + +echo "What is your python module name?" +read MODULE_NAME + +echo "What is your pypi package name? (default: $MODULE_NAME)" +read PYPI_INPUT +PYPI_NAME=${PYPI_INPUT:-$MODULE_NAME} + +echo "What is your github project name? (default: $PYPI_NAME)" +read REPO_INPUT +REPO_NAME=${REPO_INPUT:-$PYPI_NAME} + +echo "What is your readthedocs.org project name? (default: $PYPI_NAME)" +read RTD_INPUT +RTD_NAME=${RTD_INPUT:-$PYPI_NAME} + +echo "What is your project name (ex: at the top of the README)? (default: $REPO_NAME)" +read PROJECT_INPUT +PROJECT_NAME=${PROJECT_INPUT:-$REPO_NAME} + +echo "What is a one-liner describing the project?" +read SHORT_DESCRIPTION + +_replace() { + local find_cmd=(find "$PROJECT_ROOT" ! -perm -u=x ! -path '*/.git/*' -type f) + + if [[ $(uname) == Darwin ]]; then + "${find_cmd[@]}" -exec sed -i '' "$1" {} + + else + "${find_cmd[@]}" -exec sed -i "$1" {} + + fi +} +_replace "s//$MODULE_NAME/g" +_replace "s//$PYPI_NAME/g" +_replace "s//$REPO_NAME/g" +_replace "s//$RTD_NAME/g" +_replace "s//$PROJECT_NAME/g" +_replace "s//$SHORT_DESCRIPTION/g" + +mkdir -p "$PROJECT_ROOT/$MODULE_NAME" +touch "$PROJECT_ROOT/$MODULE_NAME/__init__.py" diff --git a/.project-template/refill_template_vars.sh b/.project-template/refill_template_vars.sh new file mode 100755 index 0000000..6e7943f --- /dev/null +++ b/.project-template/refill_template_vars.sh @@ -0,0 +1,2 @@ +TEMPLATE_DIR=$(dirname $(readlink -f "$0")) +<"$TEMPLATE_DIR/template_vars.txt" "$TEMPLATE_DIR/fill_template_vars.sh" diff --git a/.project-template/template_vars.txt b/.project-template/template_vars.txt new file mode 100644 index 0000000..ce0a492 --- /dev/null +++ b/.project-template/template_vars.txt @@ -0,0 +1,6 @@ +libp2p +libp2p +py-libp2p +py-libp2p +py-libp2p +The Python implementation of the libp2p networking stack diff --git a/.pydocstyle.ini b/.pydocstyle.ini new file mode 100644 index 0000000..0d40aa8 --- /dev/null +++ b/.pydocstyle.ini @@ -0,0 +1,30 @@ +[pydocstyle] +; All error codes found here: +; http://www.pydocstyle.org/en/3.0.0/error_codes.html +; +; Ignored: +; D1 - Missing docstring error codes +; +; Selected: +; D2 - Whitespace error codes +; D3 - Quote error codes +; D4 - Content related error codes +select=D2,D3,D4 + +; Extra ignores: +; D200 - One-line docstring should fit on one line with quotes +; D203 - 1 blank line required before class docstring +; D204 - 1 blank line required after class docstring +; D205 - 1 blank line required between summary line and description +; D212 - Multi-line docstring summary should start at the first line +; D302 - Use u""" for Unicode docstrings +; D400 - First line should end with a period +; D401 - First line should be in imperative mood +; D412 - No blank lines allowed between a section header and its content +add-ignore=D200,D203,D204,D205,D212,D302,D400,D401,D412 + +; Explanation: +; D400 - Enabling this error code seems to make it a requirement that the first +; sentence in a docstring is not split across two lines. It also makes it a +; requirement that no docstring can have a multi-sentence description without a +; summary line. Neither one of those requirements seem appropriate. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d93175a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 The Ethereum Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile index a47b8ff..aec2421 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,17 @@ +CURRENT_SIGN_SETTING := $(shell git config commit.gpgSign) + +.PHONY: clean-pyc clean-build docs + +help: + @echo "clean-build - remove build artifacts" + @echo "clean-pyc - remove Python file artifacts" + @echo "lint - check style with flake8, etc" + @echo "lint-roll - auto-correct styles with isort, black, docformatter, etc" + @echo "test - run tests quickly with the default Python" + @echo "testall - run tests on every Python version with tox" + @echo "release - package and upload a release" + @echo "dist - package" + FILES_TO_LINT = libp2p tests tests_interop examples setup.py PB = libp2p/crypto/pb/crypto.proto \ libp2p/pubsub/pb/rpc.proto \ @@ -10,18 +24,6 @@ PYI = $(PB:.proto=_pb2.pyi) # Set default to `protobufs`, otherwise `format` is called when typing only `make` all: protobufs -format: - black $(FILES_TO_LINT) - isort --recursive $(FILES_TO_LINT) - docformatter -ir --pre-summary-newline $(FILES_TO_LINT) - -lintroll: - mypy -p libp2p -p examples --config-file mypy.ini - black --check $(FILES_TO_LINT) - isort --recursive --check-only $(FILES_TO_LINT) - docformatter --pre-summary-newline --check --recursive $(FILES_TO_LINT) - flake8 $(FILES_TO_LINT) - protobufs: $(PY) %_pb2.py: %.proto @@ -30,12 +32,81 @@ protobufs: $(PY) clean-proto: rm -f $(PY) $(PYI) -clean: - find . -name '__pycache__' -exec rm -rf {} + +clean: clean-build clean-pyc + +clean-build: rm -fr build/ rm -fr dist/ rm -fr *.egg-info +clean-pyc: + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -rf {} + + +lint: + mypy -p libp2p -p examples --config-file mypy.ini + flake8 $(FILES_TO_LINT) + black --check $(FILES_TO_LINT) + isort --recursive --check-only --diff $(FILES_TO_LINT) + docformatter --pre-summary-newline --check --recursive $(FILES_TO_LINT) + tox -elint # This is probably redundant, but just in case... + +lint-roll: + isort --recursive $(FILES_TO_LINT) + black $(FILES_TO_LINT) + docformatter -ir --pre-summary-newline $(FILES_TO_LINT) + $(MAKE) lint + +test: + pytest tests + +test-all: + tox + +build-docs: + sphinx-apidoc -o docs/ . setup.py "*conftest*" + $(MAKE) -C docs clean + $(MAKE) -C docs html + $(MAKE) -C docs doctest + ./newsfragments/validate_files.py + towncrier --draft --version preview + +docs: build-docs + open docs/_build/html/index.html + +linux-docs: build-docs + xdg-open docs/_build/html/index.html + package: clean python setup.py sdist bdist_wheel python scripts/release/test_package.py + +notes: + # Let UPCOMING_VERSION be the version that is used for the current bump + $(eval UPCOMING_VERSION=$(shell bumpversion $(bump) --dry-run --list | grep new_version= | sed 's/new_version=//g')) + # Now generate the release notes to have them included in the release commit + towncrier --yes --version $(UPCOMING_VERSION) + # Before we bump the version, make sure that the towncrier-generated docs will build + make build-docs + git commit -m "Compile release notes" + +release: clean + # require that you be on a branch that's linked to upstream/master + git status -s -b | head -1 | grep "\.\.upstream/master" + # verify that docs build correctly + ./newsfragments/validate_files.py is-empty + make build-docs + CURRENT_SIGN_SETTING=$(git config commit.gpgSign) + git config commit.gpgSign true + bumpversion $(bump) + git push upstream && git push upstream --tags + python setup.py sdist bdist_wheel + twine upload dist/* + git config commit.gpgSign "$(CURRENT_SIGN_SETTING)" + + +dist: clean + python setup.py sdist bdist_wheel + ls -l dist diff --git a/README.md b/README.md index 2fc0afd..9b79954 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,82 @@ -# py-libp2p [![Build Status](https://travis-ci.com/libp2p/py-libp2p.svg?branch=master)](https://travis-ci.com/libp2p/py-libp2p) [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/py-libp2p/Lobby) [![Freenode](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg)](https://webchat.freenode.net/?channels=%23libp2p) [![Matrix](https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg)](https://riot.permaweb.io/#/room/#libp2p:permaweb.io) [![Discord](https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord)](https://discord.gg/66KBrm2) +# py-libp2p +[![Join the chat at https://gitter.im/py-libp2p/Lobby](https://badges.gitter.im/py-libp2p/Lobby.png)](https://gitter.im/py-libp2p/Lobby) +[![Build Status](https://travis-ci.com/libp2p/py-libp2p.svg?branch=master)](https://travis-ci.com/libp2p/py-libp2p) +[![PyPI version](https://badge.fury.io/py/libp2p.svg)](https://badge.fury.io/py/libp2p) +[![Python versions](https://img.shields.io/pypi/pyversions/libp2p.svg)](https://pypi.python.org/pypi/libp2p) +[![Docs build](https://readthedocs.org/projects/py-libp2p/badge/?version=latest)](http://py-libp2p.readthedocs.io/en/latest/?badge=latest) +[![Freenode](https://img.shields.io/badge/freenode-%23libp2p-yellow.svg)](https://webchat.freenode.net/?channels=%23libp2p) +[![Matrix](https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg)](https://riot.permaweb.io/#/room/#libp2p:permaweb.io) +[![Discord](https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord)](https://discord.gg/66KBrm2)

- py-libp2p hex logo +py-libp2p hex logo

## WARNING py-libp2p is an experimental and work-in-progress repo under heavy development. We do not yet recommend using py-libp2p in production environments. +The Python implementation of the libp2p networking stack + +Read more in the [documentation on ReadTheDocs](https://py-libp2p.readthedocs.io/). [View the change log](https://py-libp2p.readthedocs.io/en/latest/releases.html). + ## Sponsorship This project is graciously sponsored by the Ethereum Foundation through [Wave 5 of their Grants Program](https://blog.ethereum.org/2019/02/21/ethereum-foundation-grants-program-wave-5/). ## Maintainers The py-libp2p team consists of: -[@zixuanzh](https://github.com/zixuanzh) [@alexh](https://github.com/alexh) [@stuckinaboot](https://github.com/stuckinaboot) [@robzajac](https://github.com/robzajac) +[@zixuanzh](https://github.com/zixuanzh) [@alexh](https://github.com/alexh) [@stuckinaboot](https://github.com/stuckinaboot) [@robzajac](https://github.com/robzajac) [@carver](https://github.com/carver) ## Development py-libp2p requires Python 3.7 and the best way to guarantee a clean Python 3.7 environment is with [`virtualenv`](https://virtualenv.pypa.io/en/stable/) ```sh +git clone git@github.com:libp2p/py-libp2p.git +cd py-libp2p virtualenv -p python3.7 venv . venv/bin/activate -pip3 install -r requirements_dev.txt -python setup.py develop +pip install -e .[dev] ``` -## Testing +### Testing Setup + +During development, you might like to have tests run on every file save. + +Show flake8 errors on file change: -After installing our requirements (see above), you can: ```sh -cd tests -pytest +# Test flake8 +when-changed -v -s -r -1 libp2p/ tests/ -c "clear; flake8 libp2p tests && echo 'flake8 success' || echo 'error'" ``` + +Run multi-process tests in one command, but without color: + +```sh +# in the project root: +pytest --numprocesses=4 --looponfail --maxfail=1 +# the same thing, succinctly: +pytest -n 4 -f --maxfail=1 +``` + +Run in one thread, with color and desktop notifications: + +```sh +cd venv +ptw --onfail "notify-send -t 5000 'Test failure ⚠⚠⚠⚠⚠' 'python 3 test on py-libp2p failed'" ../tests ../libp2p +``` + Note that tests/libp2p/test_libp2p.py contains an end-to-end messaging test between two libp2p hosts, which is the bulk of our proof of concept. + +### Release setup + +Releases follow the same basic pattern as releases of some tangentially-related projects, +like Trinity. See [Trinity's release instructions]( +https://trinity-client.readthedocs.io/en/latest/contributing.html#releasing). + ## Requirements The protobuf description in this repository was generated by `protoc` at version `3.7.1`. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..3280093 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/web3.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/web3.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/web3" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/web3" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_static/.suppress-sphinx-build-warning b/docs/_static/.suppress-sphinx-build-warning new file mode 100644 index 0000000..e69de29 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..54b210a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,288 @@ +# -*- coding: utf-8 -*- +# +# py-libp2p documentation build configuration file, created by +# sphinx-quickstart on Thu Oct 16 20:43:24 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# 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. +#sys.path.insert(0, os.path.abspath('.')) + +import os + +DIR = os.path.dirname('__file__') +with open (os.path.join(DIR, '../setup.py'), 'r') as f: + for line in f: + if 'version=' in line: + setup_version = line.split('\'')[1] + break + +# -- 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.intersphinx', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'py-libp2p' +copyright = '2019, The Ethereum Foundation' + +__version__ = setup_version +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '.'.join(__version__.split('.')[:2]) +# The full version, including alpha/beta/rc tags. +release = __version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [ + '_build', + 'modules.rst', +] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- 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 = 'sphinx_rtd_theme' + +# 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 = {} + +# Add any paths that contain custom themes here, relative to this directory. + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# 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'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'libp2pdoc' + + +# -- 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': '', +} + +# 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 = [ + ('index', 'libp2p.tex', 'py-libp2p Documentation', + 'The Ethereum Foundation', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'libp2p', 'py-libp2p Documentation', + ['The Ethereum Foundation'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- 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 = [ + ('index', 'py-libp2p', 'py-libp2p Documentation', + 'The Ethereum Foundation', 'py-libp2p', 'The Python implementation of the libp2p networking stack', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +# -- Intersphinx configuration ------------------------------------------------ + +intersphinx_mapping = { + 'python': ('https://docs.python.org/3.6', None), +} + +# -- Doctest configuration ---------------------------------------- + +import doctest + +doctest_default_flags = (0 + | doctest.DONT_ACCEPT_TRUE_FOR_1 + | doctest.ELLIPSIS + | doctest.IGNORE_EXCEPTION_DETAIL + | doctest.NORMALIZE_WHITESPACE +) diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..8fa151f --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,20 @@ +py-libp2p +============================== + +The Python implementation of the libp2p networking stack + +Contents +-------- + +.. toctree:: + :maxdepth: 3 + + libp2p + release_notes + + +Indices and tables +------------------ + +* :ref:`genindex` +* :ref:`modindex` diff --git a/docs/release_notes.rst b/docs/release_notes.rst new file mode 100644 index 0000000..63786ac --- /dev/null +++ b/docs/release_notes.rst @@ -0,0 +1,9 @@ +Release Notes +============= + +.. towncrier release notes start + +v0.1.0-alpha.1 +-------------- + +- Launched repository, claimed names for pip, RTD, github, etc diff --git a/mypy.ini b/mypy.ini index 7762413..fffd2aa 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,16 +1,20 @@ [mypy] -warn_unused_ignores = True -ignore_missing_imports = True -strict_optional = False + check_untyped_defs = True disallow_incomplete_defs = True disallow_untyped_defs = True disallow_any_generics = True disallow_untyped_calls = True +disallow_untyped_decorators = True +disallow_subclassing_any = False +ignore_missing_imports = True +strict_optional = False +warn_unused_ignores = True +strict_equality = True warn_redundant_casts = True +warn_return_any = False warn_unused_configs = True warn_unreachable = True -strict_equality = True [mypy-libp2p.kademlia.*] ignore_errors = True diff --git a/newsfragments/README.md b/newsfragments/README.md new file mode 100644 index 0000000..09a10dd --- /dev/null +++ b/newsfragments/README.md @@ -0,0 +1,27 @@ +This directory collects "newsfragments": short files that each contain +a snippet of ReST-formatted text that will be added to the next +release notes. This should be a description of aspects of the change +(if any) that are relevant to users. (This contrasts with the +commit message and PR description, which are a description of the change as +relevant to people working on the code itself.) + +Each file should be named like `..rst`, where +`` is an issue numbers, and `` is one of: + +* `feature` +* `bugfix` +* `performance` +* `doc` +* `internal` +* `removal` +* `misc` + +So for example: `123.feature.rst`, `456.bugfix.rst` + +If the PR fixes an issue, use that number here. If there is no issue, +then open up the PR first and use the PR number for the newsfragment. + +Note that the `towncrier` tool will automatically +reflow your text, so don't try to do any fancy formatting. Run + `towncrier --draft` to get a preview of what the release notes entry + will look like in the final release notes. diff --git a/newsfragments/validate_files.py b/newsfragments/validate_files.py new file mode 100755 index 0000000..c0e9b28 --- /dev/null +++ b/newsfragments/validate_files.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +# Towncrier silently ignores files that do not match the expected ending. +# We use this script to ensure we catch these as errors in CI. + +import os +import pathlib +import sys + +ALLOWED_EXTENSIONS = { + '.bugfix.rst', + '.doc.rst', + '.feature.rst', + '.internal.rst', + '.misc.rst', + '.performance.rst', + '.removal.rst', +} + +ALLOWED_FILES = { + 'validate_files.py', + 'README.md', +} + +THIS_DIR = pathlib.Path(__file__).parent + +num_args = len(sys.argv) - 1 +assert num_args in {0, 1} +if num_args == 1: + assert sys.argv[1] in ('is-empty', ) + +for fragment_file in THIS_DIR.iterdir(): + + if fragment_file.name in ALLOWED_FILES: + continue + elif num_args == 0: + full_extension = "".join(fragment_file.suffixes) + if full_extension not in ALLOWED_EXTENSIONS: + raise Exception(f"Unexpected file: {fragment_file}") + elif sys.argv[1] == 'is-empty': + raise Exception(f"Unexpected file: {fragment_file}") + else: + raise RuntimeError("Strange: arguments {sys.argv} were validated, but not found") diff --git a/pyproject.toml b/pyproject.toml index b15cc88..ba94a6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,46 @@ +[tool.towncrier] +# Read https://github.com/libp2p/py-libp2p/newsfragments/README.md for instructions +package = "libp2p" +filename = "docs/release_notes.rst" +directory = "newsfragments" +underlines = ["-", "~", "^"] +issue_format = "`#{issue} `__" + +[[tool.towncrier.type]] +directory = "feature" +name = "Features" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bugfixes" +showcontent = true + +[[tool.towncrier.type]] +directory = "performance" +name = "Performance improvements" +showcontent = true + +[[tool.towncrier.type]] +directory = "doc" +name = "Improved Documentation" +showcontent = true + +[[tool.towncrier.type]] +directory = "removal" +name = "Deprecations and Removals" +showcontent = true + +[[tool.towncrier.type]] +directory = "internal" +name = "Internal Changes - for py-libp2p Contributors" +showcontent = true + +[[tool.towncrier.type]] +directory = "misc" +name = "Miscellaneous changes" +showcontent = false + [tool.black] target_version = ['py37'] include = '\.pyi?$' diff --git a/pytest.ini b/pytest.ini index 29cd7bb..2cbf228 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,6 +1,9 @@ [pytest] -addopts= --showlocals --durations 50 --maxfail 10 +addopts= -v --showlocals --durations 50 --maxfail 10 python_paths= . xfail_strict=true log_format = %(levelname)8s %(asctime)s %(filename)20s %(message)s log_date_format = %m-%d %H:%M:%S + +[pytest-watch] +runner= pytest --failed-first --maxfail=1 --no-success-flaky-report diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 0000000..ba1ee49 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1 @@ +libp2p[doc] diff --git a/scripts/release/test_package.py b/scripts/release/test_package.py new file mode 100644 index 0000000..89ef36a --- /dev/null +++ b/scripts/release/test_package.py @@ -0,0 +1,52 @@ +from pathlib import Path +import subprocess +from tempfile import TemporaryDirectory +import venv + + +def create_venv(parent_path): + venv_path = parent_path / 'package-smoke-test' + venv.create(venv_path, with_pip=True) + subprocess.run([venv_path / 'bin' / 'pip', 'install', '-U', 'pip', 'setuptools'], check=True) + return venv_path + + +def find_wheel(project_path): + wheels = list(project_path.glob('dist/*.whl')) + + if len(wheels) != 1: + raise Exception( + f"Expected one wheel. Instead found: {wheels} in project {project_path.absolute()}" + ) + + return wheels[0] + + +def install_wheel(venv_path, wheel_path, extras=()): + if extras: + extra_suffix = f"[{','.join(extras)}]" + else: + extra_suffix = "" + + subprocess.run( + [ + venv_path / 'bin' / 'pip', + 'install', + f"{wheel_path}{extra_suffix}" + ], + check=True, + ) + + +def test_install_local_wheel(): + with TemporaryDirectory() as tmpdir: + venv_path = create_venv(Path(tmpdir)) + wheel_path = find_wheel(Path('.')) + install_wheel(venv_path, wheel_path) + print("Installed", wheel_path.absolute(), "to", venv_path) + print(f"Activate with `source {venv_path}/bin/activate`") + input("Press enter when the test has completed. The directory will be deleted.") + + +if __name__ == '__main__': + test_install_local_wheel() diff --git a/setup.py b/setup.py index eead1bf..4ef43fb 100644 --- a/setup.py +++ b/setup.py @@ -1,35 +1,44 @@ -import setuptools - -py_classifiers = [f"Programming Language :: Python :: {version}" for version in ["3.7"]] - +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from setuptools import find_packages, setup extras_require = { "test": [ - "factory-boy>=2.12.0,<3.0.0", "pytest>=4.6.3,<5.0.0", + "pytest-xdist>=1.30.0,<2", "pytest-asyncio>=0.10.0,<1.0.0", - "pytest-xdist>=1.30.0", + "factory-boy>=2.12.0,<3.0.0", ], "lint": [ - "mypy>=0.701,<1.0", + "flake8==3.7.9", # flake8 is not semver: it has added new warnings at minor releases + "isort==4.3.21", + "mypy==0.740", # mypy is not semver: it has added new warnings at minor releases "mypy-protobuf==1.15", "black==19.3b0", - "isort==4.3.21", - "flake8>=3.7.7,<4.0.0", - "flake8-bugbear", + "flake8-bugbear>=19.8.0,<20", + "docformatter>=1.3.1,<2", + ], + "doc": [ + "Sphinx>=1.6.5,<2", + "sphinx_rtd_theme>=0.4.3,<=1", + "towncrier>=19.2.0, <20", ], "dev": [ "bumpversion>=0.5.3,<1", - "docformatter", + "pytest-watch>=4.1.0,<5", + "wheel", + "twine", + "ipython", "setuptools>=36.2.0", "tox>=3.13.2,<4.0.0", - "twine", - "wheel", ], } extras_require["dev"] = ( - extras_require["test"] + extras_require["lint"] + extras_require["dev"] + extras_require["dev"] + + extras_require["test"] + + extras_require["lint"] + + extras_require["doc"] ) @@ -37,26 +46,17 @@ with open("./README.md") as readme: long_description = readme.read() -setuptools.setup( +setup( name="libp2p", - description="libp2p implementation written in python", + # *IMPORTANT*: Don't manually change the version here. Use `make bump`, as described in readme version="0.1.2", + description="libp2p implementation written in python", long_description=long_description, long_description_content_type="text/markdown", maintainer="The Ethereum Foundation", maintainer_email="snakecharmers@ethereum.org", - url="https://github.com/ethereum/py-libp2p", - license="MIT/APACHE2.0", - platforms=["unix", "linux", "osx"], - classifiers=[ - "Development Status :: 4 - Beta", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "License :: OSI Approved :: Apache Software License", - "Natural Language :: English", - ] - + py_classifiers, - python_requires=">=3.7,<4", + url="https://github.com/libp2p/py-libp2p", + include_package_data=True, install_requires=[ "pycryptodome>=3.9.2,<4.0.0", "base58>=1.0.3,<2.0.0", @@ -69,8 +69,21 @@ setuptools.setup( "fastecdsa==1.7.4", "pynacl==1.3.0", ], + python_requires=">=3.7,<4", extras_require=extras_require, - packages=setuptools.find_packages(exclude=["tests", "tests.*"]), + py_modules=["libp2p"], + license="MIT/APACHE2.0", zip_safe=False, keywords="libp2p p2p", + packages=find_packages(exclude=["tests", "tests.*"]), + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: Apache Software License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + ], + platforms=["unix", "linux", "osx"], ) diff --git a/tests/core/conftest.py b/tests/core/conftest.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/core/test_import.py b/tests/core/test_import.py new file mode 100644 index 0000000..325444f --- /dev/null +++ b/tests/core/test_import.py @@ -0,0 +1,2 @@ +def test_import(): + import libp2p # noqa: F401 diff --git a/tox.ini b/tox.ini index 3fc294a..de4f8f1 100644 --- a/tox.ini +++ b/tox.ini @@ -1,48 +1,58 @@ -# Reference: https://github.com/ethereum/py_ecc/blob/d0da74402210ea1503ef83b3c489d5b5eba7f7bf/tox.ini +# Reference: https://github.com/ethereum/ethereum-python-project-template/blob/master/tox.ini +# TODO: consider py36 and pypy3 support [tox] envlist = py37-test py37-interop lint - -[flake8] -max-line-length = 100 -exclude = *_pb2*.py -ignore = E203, W503 -max-complexity = 18 -select = B,C,E,F,W,T4,B9 + docs [isort] +combine_as_imports=False force_sort_within_sections=True -known_third_party=pytest,p2pclient,pexpect -multi_line_output=3 include_trailing_comma=True -force_grid_wrap=0 -use_parentheses=True +known_third_party=hypothesis,pytest,p2pclient,pexpect,factory +known_first_party=libp2p line_length=88 +multi_line_output=3 +use_parentheses=True +force_grid_wrap=0 skip_glob= *_pb2*.py *.pyi +[flake8] +max-line-length = 100 +exclude = venv*,.tox,docs,build,*_pb2*.py +ignore = E203, W503 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 + [testenv] +usedevelop=True +commands = + test: pytest {posargs:tests/} + docs: make build-docs +basepython = + docs: python + py37: python3.7 +extras = + test + docs: doc +whitelist_externals = make deps = passenv = CI TRAVIS TRAVIS_* -extras = test -commands = - test: pytest tests/ -basepython = - py37: python3.7 [testenv:lint] basepython = python3 -extras = dev +extras = lint commands = - mypy -p libp2p -p examples --config-file {toxinidir}/mypy.ini + mypy -p {toxinidir}/libp2p -p examples --config-file {toxinidir}/mypy.ini + flake8 {toxinidir}/libp2p {toxinidir}/tests tests_interop examples setup.py black --check libp2p tests tests_interop examples setup.py - isort --recursive --check-only --diff libp2p tests tests_interop examples setup.py + isort --recursive --check-only --diff {toxinidir}/libp2p {toxinidir}/tests tests_interop examples setup.py docformatter --pre-summary-newline --check --recursive libp2p tests tests_interop examples setup.py - flake8 libp2p tests tests_interop examples setup.py [testenv:py37-interop] deps =