diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 7491cf47..f5384618 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -3,14 +3,14 @@ current_version = 0.1.5 commit = True tag = True parse = (?P\d+)\.(?P\d+)\.(?P\d+)(-(?P[^.]*)\.(?P\d+))? -serialize = +serialize = {major}.{minor}.{patch}-{stage}.{devnum} {major}.{minor}.{patch} [bumpversion:part:stage] optional_value = stable first_value = stable -values = +values = alpha beta stable @@ -20,4 +20,3 @@ values = [bumpversion:file:setup.py] search = version="{current_version}", replace = version="{new_version}", - diff --git a/.circleci/config.yml b/.circleci/config.yml index fa7691e6..f70d22cf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,4 +1,4 @@ -version: 2.0 +version: 2.1 # heavily inspired by https://raw.githubusercontent.com/pinax/pinax-wiki/6bd2a99ab6f702e300d708532a6d1d9aa638b9f8/.circleci/config.yml @@ -14,64 +14,233 @@ common: &common command: ./.circleci/merge_pr.sh when: on_fail - run: - name: merge pull request base (3nd try) + name: merge pull request base (3rd try) command: ./.circleci/merge_pr.sh when: on_fail - restore_cache: keys: - - cache-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + - cache-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} - run: name: install dependencies - command: pip install --user tox + command: | + python -m pip install --upgrade pip + python -m pip install tox - run: name: run tox - command: ~/.local/bin/tox -r + command: python -m tox run -r - save_cache: paths: - .hypothesis - .tox - ~/.cache/pip - ~/.local - - ./eggs - key: cache-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + key: cache-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + +orbs: + win: circleci/windows@5.0.0 + +windows-wheel-steps: + windows-wheel-setup: &windows-wheel-setup + executor: + name: win/default + shell: bash.exe + working_directory: C:\Users\circleci\project\py-libp2p + environment: + TOXENV: windows-wheel + restore-cache-step: &restore-cache-step + restore_cache: + keys: + - cache-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + install-pyenv-step: &install-pyenv-step + run: + name: install pyenv + command: | + pip install pyenv-win --target $HOME/.pyenv + echo 'export PYENV="$HOME/.pyenv/pyenv-win/"' >> $BASH_ENV + echo 'export PYENV_ROOT="$HOME/.pyenv/pyenv-win/"' >> $BASH_ENV + echo 'export PYENV_USERPROFILE="$HOME/.pyenv/pyenv-win/"' >> $BASH_ENV + echo 'export PATH="$PATH:$HOME/.pyenv/pyenv-win/bin"' >> $BASH_ENV + echo 'export PATH="$PATH:$HOME/.pyenv/pyenv-win/shims"' >> $BASH_ENV + source $BASH_ENV + pyenv update + install-latest-python-step: &install-latest-python-step + run: + name: install latest python version and tox + command: | + LATEST_VERSION=$(pyenv install --list | grep -E "${MINOR_VERSION}\.[0-9]+$" | tail -1) + echo "installing python version $LATEST_VERSION" + pyenv install $LATEST_VERSION + pyenv global $LATEST_VERSION + python3 -m pip install --upgrade pip + python3 -m pip install tox + run-tox-step: &run-tox-step + run: + name: run tox + command: | + echo 'running tox with' $(python3 --version) + python3 -m tox run -r + save-cache-step: &save-cache-step + save_cache: + paths: + - .tox + key: cache-v1-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "setup.py" }}-{{ checksum "tox.ini" }} + +docs: &docs + docker: + - image: common + steps: + - run: + name: install latexpdf dependencies + command: | + sudo apt-get update + sudo apt-get install latexmk tex-gyre texlive-fonts-extra jobs: docs: - <<: *common + <<: *docs docker: - - image: circleci/python:3.6 + - image: cimg/python:3.8 environment: TOXENV: docs - lint: + + py38-core: <<: *common docker: - - image: circleci/python:3.6 + - image: cimg/python:3.8 environment: - TOXENV: lint - py36-core: + TOXENV: py38-core + py39-core: <<: *common docker: - - image: circleci/python:3.6 + - image: cimg/python:3.9 environment: - TOXENV: py36-core - py37-core: + TOXENV: py39-core + py310-core: <<: *common docker: - - image: circleci/python:3.7 + - image: cimg/python:3.10 environment: - TOXENV: py37-core - pypy3-core: + TOXENV: py310-core + py311-core: <<: *common docker: - - image: pypy + - image: cimg/python:3.11 environment: - TOXENV: pypy3-core + TOXENV: py311-core + py312-core: + <<: *common + docker: + - image: cimg/python:3.12 + environment: + TOXENV: py312-core + + py38-lint: + <<: *common + docker: + - image: cimg/python:3.8 + environment: + TOXENV: py38-lint + py39-lint: + <<: *common + docker: + - image: cimg/python:3.9 + environment: + TOXENV: py39-lint + py310-lint: + <<: *common + docker: + - image: cimg/python:3.10 + environment: + TOXENV: py310-lint + py311-lint: + <<: *common + docker: + - image: cimg/python:3.11 + environment: + TOXENV: py311-lint + py312-lint: + <<: *common + docker: + - image: cimg/python:3.12 + environment: + TOXENV: py312-lint + + py38-wheel: + <<: *common + docker: + - image: cimg/python:3.8 + environment: + TOXENV: py38-wheel + py39-wheel: + <<: *common + docker: + - image: cimg/python:3.9 + environment: + TOXENV: py39-wheel + py310-wheel: + <<: *common + docker: + - image: cimg/python:3.10 + environment: + TOXENV: py310-wheel + py311-wheel: + <<: *common + docker: + - image: cimg/python:3.11 + environment: + TOXENV: py311-wheel + py312-wheel: + <<: *common + docker: + - image: cimg/python:3.12 + environment: + TOXENV: py312-wheel + + py311-windows-wheel: + <<: *windows-wheel-setup + steps: + - checkout + - <<: *restore-cache-step + - <<: *install-pyenv-step + - run: + name: set minor version + command: echo "export MINOR_VERSION='3.11'" >> $BASH_ENV + - <<: *install-latest-python-step + - <<: *run-tox-step + - <<: *save-cache-step + + py312-windows-wheel: + <<: *windows-wheel-setup + steps: + - checkout + - <<: *restore-cache-step + - <<: *install-pyenv-step + - run: + name: set minor version + command: echo "export MINOR_VERSION='3.12'" >> $BASH_ENV + - <<: *install-latest-python-step + - <<: *run-tox-step + - <<: *save-cache-step + workflows: version: 2 test: jobs: - docs - - lint - - py36-core - - py37-core - - pypy3-core + - py38-core + - py39-core + - py310-core + - py311-core + - py312-core + - py38-lint + - py39-lint + - py310-lint + - py311-lint + - py312-lint + - py38-wheel + - py39-wheel + - py310-wheel + - py311-wheel + - py312-wheel + - py311-windows-wheel + - py312-windows-wheel diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4ef27e52..85ec186d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,10 +11,8 @@ Summary of approach. [//]: # (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) +- [ ] Add entry to the [release notes](https://github.com/libp2p/py-libp2p/blob/main/newsfragments/README.md) #### Cute Animal Picture diff --git a/.gitignore b/.gitignore index 498eb397..43bc1435 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__/ *.egg-info dist build +.build eggs .eggs parts @@ -21,7 +22,9 @@ develop-eggs .installed.cfg lib lib64 +pip-wheel-metadata venv* +.venv* .Python downloads/ wheels/ @@ -61,15 +64,37 @@ docs/modules.rst docs/*.internal.rst docs/*._utils.* -# Hypothese Property base testing +# Blockchain +chains + +# Hypothesis Property base testing .hypothesis # tox/pytest cache .cache +.pytest_cache + +# pycache +__pycache__/ # Test output logs logs +# VIM temp files +*.sw[op] + +# mypy +.mypy_cache + +# macOS +.DS_Store + +# pyenv +.python-version + +# vs-code +.vscode + ### 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 @@ -96,32 +121,33 @@ logs # Mongo Explorer plugin: .idea/mongoSettings.xml -# VIM temp files -*.sw[op] +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# For a more precise, explicit template, see: +# https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 -# mypy -.mypy_cache +## General +.idea/* +.idea_modules/* ## File-based project format: *.iws +## IntelliJ +out/ + ## Plugin-specific files: -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin +### JIRA plugin atlassian-ide-plugin.xml -# Crashlytics plugin (for Android Studio and IntelliJ) +### Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties +# END JetBrains section + # 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. @@ -146,9 +172,6 @@ target/ # Jupyter Notebook .ipynb_checkpoints -# pyenv -.python-version - # celery beat schedule file celerybeat-schedule @@ -172,5 +195,3 @@ env.bak/ # mkdocs documentation /site -# vscode -.vscode/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..82870756 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,52 @@ +exclude: '.project-template|docs/conf.py|.bumpversion.cfg' +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-yaml + - id: check-toml + - id: end-of-file-fixer + - id: trailing-whitespace +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: [--py38-plus] +- repo: https://github.com/psf/black + rev: 19.3b0 + hooks: + - id: black +- repo: https://github.com/PyCQA/flake8 + rev: 3.7.9 + hooks: + - id: flake8 + additional_dependencies: + - flake8-bugbear==23.9.16 + exclude: setup.py +- repo: https://github.com/PyCQA/autoflake + rev: v2.2.1 + hooks: + - id: autoflake +- repo: https://github.com/pycqa/isort + rev: 4.3.21 + hooks: + - id: isort +- repo: https://github.com/pycqa/pydocstyle + rev: 6.3.0 + hooks: + - id: pydocstyle + additional_dependencies: + - tomli # required until >= python311 +- repo: https://github.com/executablebooks/mdformat + rev: 0.7.17 + hooks: + - id: mdformat + additional_dependencies: + - mdformat-gfm +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.780 + hooks: + - id: mypy + additional_dependencies: + - mypy-protobuf + exclude: tests/ diff --git a/.project-template/fill_template_vars.py b/.project-template/fill_template_vars.py new file mode 100644 index 00000000..52ceb02b --- /dev/null +++ b/.project-template/fill_template_vars.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import os +import sys +import re +from pathlib import Path + + +def _find_files(project_root): + path_exclude_pattern = r"\.git($|\/)|venv|_build" + file_exclude_pattern = r"fill_template_vars\.py|\.swp$" + filepaths = [] + for dir_path, _dir_names, file_names in os.walk(project_root): + if not re.search(path_exclude_pattern, dir_path): + for file in file_names: + if not re.search(file_exclude_pattern, file): + filepaths.append(str(Path(dir_path, file))) + + return filepaths + + +def _replace(pattern, replacement, project_root): + print(f"Replacing values: {pattern}") + for file in _find_files(project_root): + try: + with open(file) as f: + content = f.read() + content = re.sub(pattern, replacement, content) + with open(file, "w") as f: + f.write(content) + except UnicodeDecodeError: + pass + + +def main(): + project_root = Path(os.path.realpath(sys.argv[0])).parent.parent + + module_name = input("What is your python module name? ") + + pypi_input = input(f"What is your pypi package name? (default: {module_name}) ") + pypi_name = pypi_input or module_name + + repo_input = input(f"What is your github project name? (default: {pypi_name}) ") + repo_name = repo_input or pypi_name + + rtd_input = input( + f"What is your readthedocs.org project name? (default: {pypi_name}) " + ) + rtd_name = rtd_input or pypi_name + + project_input = input( + f"What is your project name (ex: at the top of the README)? (default: {repo_name}) " + ) + project_name = project_input or repo_name + + short_description = input("What is a one-liner describing the project? ") + + _replace("", module_name, project_root) + _replace("", pypi_name, project_root) + _replace("", repo_name, project_root) + _replace("", rtd_name, project_root) + _replace("", project_name, project_root) + _replace("", short_description, project_root) + + os.makedirs(project_root / module_name, exist_ok=True) + Path(project_root / module_name / "__init__.py").touch() + Path(project_root / module_name / "py.typed").touch() + + +if __name__ == "__main__": + main() diff --git a/.project-template/fill_template_vars.sh b/.project-template/fill_template_vars.sh deleted file mode 100755 index f09e8ffe..00000000 --- a/.project-template/fill_template_vars.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/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.py b/.project-template/refill_template_vars.py new file mode 100644 index 00000000..03ab7c0c --- /dev/null +++ b/.project-template/refill_template_vars.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import os +import sys +from pathlib import Path +import subprocess + + +def main(): + template_dir = Path(os.path.dirname(sys.argv[0])) + template_vars_file = template_dir / "template_vars.txt" + fill_template_vars_script = template_dir / "fill_template_vars.py" + + with open(template_vars_file, "r") as input_file: + content_lines = input_file.readlines() + + process = subprocess.Popen( + [sys.executable, str(fill_template_vars_script)], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + + for line in content_lines: + process.stdin.write(line) + process.stdin.flush() + + stdout, stderr = process.communicate() + + if process.returncode != 0: + print(f"Error occurred: {stderr}") + sys.exit(1) + + print(stdout) + + +if __name__ == "__main__": + main() diff --git a/.project-template/refill_template_vars.sh b/.project-template/refill_template_vars.sh deleted file mode 100755 index 6e7943fb..00000000 --- a/.project-template/refill_template_vars.sh +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE_DIR=$(dirname $(readlink -f "$0")) -<"$TEMPLATE_DIR/template_vars.txt" "$TEMPLATE_DIR/fill_template_vars.sh" diff --git a/.pydocstyle.ini b/.pydocstyle.ini deleted file mode 100644 index 0d40aa88..00000000 --- a/.pydocstyle.ini +++ /dev/null @@ -1,30 +0,0 @@ -[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/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000..e55e07e4 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,20 @@ +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.8" + +sphinx: + configuration: docs/conf.py + fail_on_warning: true + +python: + install: + - method: pip + path: . + extra_requirements: + - docs + +# Build all formats for RTD Downloads - htmlzip, pdf, epub +formats: all diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a412fa1c..00000000 --- a/.travis.yml +++ /dev/null @@ -1,37 +0,0 @@ -language: python - -matrix: - include: - - python: 3.6-dev - dist: xenial - env: TOXENV=py36-test - - python: 3.7 - dist: xenial - env: TOXENV=py37-test - - python: 3.7 - dist: xenial - env: TOXENV=lint - - python: 3.7 - dist: xenial - env: TOXENV=docs - - python: 3.7 - dist: xenial - env: TOXENV=py37-interop GOBINPKG=go1.13.8.linux-amd64.tar.gz - sudo: true - before_install: - - wget https://dl.google.com/go/$GOBINPKG - - sudo tar -C /usr/local -xzf $GOBINPKG - - export GOPATH=$HOME/go - - export GOROOT=/usr/local/go - - export PATH=$GOROOT/bin:$GOPATH/bin:$PATH - - ./tests_interop/go_pkgs/install_interop_go_pkgs.sh - -install: - - pip install --upgrade pip - - pip install tox - -script: - - tox - -notifications: - slack: py-libp2p:RK0WVoQZhQXLgIKfHNPL1TR2 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d93175ab..00000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -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/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..d4cc47d3 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,12 @@ +include LICENSE-APACHE +include LICENSE-MIT +include README.md + +recursive-include tests * + +global-include *.pyi + +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] +prune .tox +prune venv* diff --git a/Makefile b/Makefile index 203391f4..55e939ed 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,11 @@ CURRENT_SIGN_SETTING := $(shell git config commit.gpgSign) 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 "lint - fix linting issues with pre-commit" @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 "docs - generate docs and open in browser (linux-docs for version on linux)" + @echo "notes - consume towncrier newsfragments/ and update release notes in docs/" + @echo "release - package and upload a release (does not run notes target)" @echo "dist - package" FILES_TO_LINT = libp2p tests tests_interop examples setup.py @@ -38,7 +38,6 @@ 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 {} + @@ -47,37 +46,36 @@ clean-pyc: 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 -e lint # 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 + @pre-commit run --all-files --show-diff-on-failure || ( \ + echo "\n\n\n * pre-commit should have fixed the errors above. Running again to make sure everything is good..." \ + && pre-commit run --all-files --show-diff-on-failure \ + ) test: pytest tests -test-all: - tox - build-docs: sphinx-apidoc -o docs/ . setup.py "*conftest*" "libp2p/tools/interop*" $(MAKE) -C docs clean $(MAKE) -C docs html $(MAKE) -C docs doctest - ./newsfragments/validate_files.py - towncrier --draft --version preview + +build-docs-ci: + $(MAKE) -C docs latexpdf + $(MAKE) -C docs epub -docs: build-docs +validate-newsfragments: + python ./newsfragments/validate_files.py + towncrier build --draft --version preview + +check-docs: build-docs validate-newsfragments + +check-docs-ci: build-docs build-docs-ci validate-newsfragments + +docs: check-docs open docs/_build/html/index.html -linux-docs: build-docs +linux-docs: check-docs xdg-open docs/_build/html/index.html package: clean @@ -85,17 +83,23 @@ package: clean python scripts/release/test_package.py notes: +check-bump: +ifndef bump + $(error bump must be set, typically: major, minor, patch, or devnum) +endif + +notes: check-bump # 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) + towncrier build --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" + git commit -m "Compile release notes for v$(UPCOMING_VERSION)" -release: clean - # require that you be on a branch that's linked to upstream/master - git status -s -b | head -1 | grep "\.\.upstream/master" +release: check-bump clean + # require that upstream is configured for ethereum/py-libp2p + @git remote -v | grep -E "upstream\tgit@github.com:ethereum/py-libp2p.git \(push\)|upstream\thttps://(www.)?github.com/ethereum/py-libp2p \(push\)" # verify that docs build correctly ./newsfragments/validate_files.py is-empty make build-docs @@ -103,11 +107,11 @@ release: clean git config commit.gpgSign true bumpversion $(bump) git push upstream && git push upstream --tags - python setup.py sdist bdist_wheel + python -m build twine upload dist/* git config commit.gpgSign "$(CURRENT_SIGN_SETTING)" dist: clean - python setup.py sdist bdist_wheel + python -m build ls -l dist diff --git a/README.md b/README.md index 39f694b2..31192c54 100644 --- a/README.md +++ b/README.md @@ -73,11 +73,15 @@ Note that tests/libp2p/test_libp2p.py contains an end-to-end messaging test betw ### Release setup +<<<<<<< HEAD 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 +======= +To release a new version: +>>>>>>> template The protobuf description in this repository was generated by `protoc` at version `3.7.1`. diff --git a/docs/Makefile b/docs/Makefile index 3ecaf132..50b91f92 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -85,17 +85,17 @@ 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 "# qcollectiongenerator $(BUILDDIR)/qthelp/libp2p.qhcp" @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/web3.qhc" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/libp2p.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 "# mkdir -p $$HOME/.local/share/devhelp/libp2p" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/libp2p" @echo "# devhelp" epub: diff --git a/docs/conf.py b/docs/conf.py index ebff89ba..a8467702 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,45 +15,46 @@ # 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('.')) +# 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: +DIR = os.path.dirname("__file__") +with open(os.path.join(DIR, "../setup.py"), "r") as f: for line in f: - if 'version=' in line: + 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' +# 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', + "sphinx.ext.autodoc", + "sphinx.ext.doctest", + "sphinx.ext.intersphinx", + "sphinx_rtd_theme", ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = ".rst" # The encoding of source files. -#source_encoding = 'utf-8-sig' +# source_encoding = 'utf-8-sig' # The master toctree document. -master_doc = 'index' +master_doc = "index" # General information about the project. -project = 'py-libp2p' +project = "py-libp2p" copyright = '2019, The Ethereum Foundation' __version__ = setup_version @@ -62,176 +63,179 @@ __version__ = setup_version # built documents. # # The short X.Y version. -version = '.'.join(__version__.split('.')[:2]) +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 +# language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' +# 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', + "_build", + "modules.rst", ] # The reST default role (used for this markup: `text`) to use for all # documents. -#default_role = None +# default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# 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 +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' +pygments_style = "sphinx" # A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] +# modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# 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' +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 = {} +# 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 +# html_title = None # A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None +# 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 +# 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 +# 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'] +# 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 = [] +# 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' +# 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 +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. -#html_additional_pages = {} +# html_additional_pages = {} # If false, no module index is generated. -#html_domain_indices = True +# html_domain_indices = True # If false, no index is generated. -#html_use_index = True +# html_use_index = True # If true, the index is split into individual pages for each letter. -#html_split_index = False +# html_split_index = False # If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True +# html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True +# html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = 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 = '' +# html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None +# html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'libp2pdoc' +htmlhelp_basename = "libp2pdocs" # -- 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': '', + # 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'), + ( + "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 +# latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. -#latex_use_parts = False +# latex_use_parts = False # If true, show page references after internal links. -#latex_show_pagerefs = False +# latex_show_pagerefs = False # If true, show URL addresses after external links. -#latex_show_urls = False +# latex_show_urls = False # Documents to append as an appendix to all manuals. -#latex_appendices = [] +# latex_appendices = [] # If false, no module index is generated. -#latex_domain_indices = True +# latex_domain_indices = True # -- Options for manual page output --------------------------------------- @@ -239,12 +243,17 @@ latex_documents = [ # 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) + ( + "index", + "libp2p", + "py-libp2p Documentation", + ["The Ethereum Foundation"], + 1, + ) ] # If true, show URL addresses after external links. -#man_show_urls = False +# man_show_urls = False # -- Options for Texinfo output ------------------------------------------- @@ -253,34 +262,41 @@ man_pages = [ # (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'), + ( + "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 = [] +# texinfo_appendices = [] # If false, no module index is generated. -#texinfo_domain_indices = True +# texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' +# texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False +# texinfo_no_detailmenu = False # -- Intersphinx configuration ------------------------------------------------ intersphinx_mapping = { - 'python': ('https://docs.python.org/3.6', None), + "python": ("https://docs.python.org/3.10", None), } # -- Doctest configuration ---------------------------------------- import doctest -doctest_default_flags = (0 +doctest_default_flags = ( + 0 | doctest.DONT_ACCEPT_TRUE_FOR_1 | doctest.ELLIPSIS | doctest.IGNORE_EXCEPTION_DETAIL diff --git a/docs/_static/.suppress-sphinx-build-warning b/libp2p/py.typed similarity index 100% rename from docs/_static/.suppress-sphinx-build-warning rename to libp2p/py.typed diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 79ac9c1f..00000000 --- a/mypy.ini +++ /dev/null @@ -1,18 +0,0 @@ -[mypy] - -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 -incremental = False -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 diff --git a/newsfragments/README.md b/newsfragments/README.md index 09a10ddc..177d6492 100644 --- a/newsfragments/README.md +++ b/newsfragments/README.md @@ -6,15 +6,17 @@ 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: +`` is an issue number, and `` is one of: -* `feature` -* `bugfix` -* `performance` -* `doc` -* `internal` -* `removal` -* `misc` +- `breaking` +- `bugfix` +- `deprecation` +- `docs` +- `feature` +- `internal` +- `misc` +- `performance` +- `removal` So for example: `123.feature.rst`, `456.bugfix.rst` @@ -23,5 +25,5 @@ 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. +`towncrier build --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 index c0e9b289..02b0e3ef 100755 --- a/newsfragments/validate_files.py +++ b/newsfragments/validate_files.py @@ -3,23 +3,24 @@ # 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', + ".breaking.rst", + ".bugfix.rst", + ".deprecation.rst", + ".docs.rst", + ".feature.rst", + ".internal.rst", + ".misc.rst", + ".performance.rst", + ".removal.rst", } ALLOWED_FILES = { - 'validate_files.py', - 'README.md', + "validate_files.py", + "README.md", } THIS_DIR = pathlib.Path(__file__).parent @@ -27,17 +28,18 @@ 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', ) + 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': + 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") + raise RuntimeError( + f"Strange: arguments {sys.argv} were validated, but not found" + ) diff --git a/pyproject.toml b/pyproject.toml index f92e5664..ef7ae331 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,86 @@ +[tool.autoflake] +remove_all_unused_imports = true +exclude = "__init__.py" + +[tool.isort] +combine_as_imports = false +extra_standard_library = "pytest" +force_grid_wrap = 1 +force_sort_within_sections = true +known_third_party = "anyio,factory,lru,p2pclient,pytest,noise" +known_first_party = "libp2p" +multi_line_output = 3 +profile = "black" +skip_glob= "*_pb2*.py, *.pyi" + +[tool.mypy] +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 +incremental = false +strict_optional = false +strict_equality = true +warn_redundant_casts = true +warn_return_any = false +warn_unused_configs = true +warn_unused_ignores = true + + +[tool.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 +# D415 - First line should end with a period, question mark, or exclamation point +add-ignore = "D200,D203,D204,D205,D212,D302,D400,D401,D412,D415" + +# 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. + +[tool.pytest.ini_options] +addopts = "-v --showlocals --durations 50 --maxfail 10" +xfail_strict = true +log_format = "%(levelname)8s %(asctime)s %(filename)20s %(message)s" +log_date_format = "%m-%d %H:%M:%S" + [tool.towncrier] -# Read https://github.com/libp2p/py-libp2p/newsfragments/README.md for instructions +# Read https://github.com/ethereum/py-libp2p/blob/main/newsfragments/README.md for instructions package = "libp2p" filename = "docs/release_notes.rst" directory = "newsfragments" underlines = ["-", "~", "^"] -title_format = "libp2p v{version} ({project_date})" -issue_format = "`#{issue} `__" +title_format = "py-libp2p v{version} ({project_date})" +issue_format = "`#{issue} `__" [[tool.towncrier.type]] -directory = "feature" -name = "Features" +directory = "breaking" +name = "Breaking Changes" showcontent = true [[tool.towncrier.type]] @@ -18,18 +89,18 @@ name = "Bugfixes" showcontent = true [[tool.towncrier.type]] -directory = "performance" -name = "Performance improvements" +directory = "deprecation" +name = "Deprecations" showcontent = true [[tool.towncrier.type]] -directory = "doc" +directory = "docs" name = "Improved Documentation" showcontent = true [[tool.towncrier.type]] -directory = "removal" -name = "Deprecations and Removals" +directory = "feature" +name = "Features" showcontent = true [[tool.towncrier.type]] @@ -39,27 +110,15 @@ showcontent = true [[tool.towncrier.type]] directory = "misc" -name = "Miscellaneous changes" +name = "Miscellaneous Changes" showcontent = false -[tool.black] -target_version = ['py37'] -include = '\.pyi?$' -exclude = ''' +[[tool.towncrier.type]] +directory = "performance" +name = "Performance Improvements" +showcontent = true -( - /( - \.eggs # exclude a few common directories in the - | \.git # root of the project - | \.hg - | \.mypy_cache - | \.tox - | \.venv - | _build - | buck-out - | build - | dist - )/ - | \w*_pb2\w*\.py # pb2 files -) -''' +[[tool.towncrier.type]] +directory = "removal" +name = "Removals" +showcontent = true diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 2cbf228f..00000000 --- a/pytest.ini +++ /dev/null @@ -1,9 +0,0 @@ -[pytest] -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 deleted file mode 100644 index 3ef37020..00000000 --- a/requirements-docs.txt +++ /dev/null @@ -1 +0,0 @@ -.[doc] diff --git a/setup.py b/setup.py index 795aa1ff..1ed91f39 100644 --- a/setup.py +++ b/setup.py @@ -2,46 +2,36 @@ # -*- coding: utf-8 -*- import os -from setuptools import find_packages, setup +from setuptools import ( + find_packages, + setup, +) extras_require = { + "dev": [ + "build>=0.9.0", + "bumpversion>=0.5.3", + "ipython", + "pre-commit>=3.4.0", + "tox>=4.0.0", + "twine", + "wheel", + ], + "docs": [ + "sphinx>=6.0.0", + "sphinx_rtd_theme>=1.0.0", + "towncrier>=21,<22", + ], "test": [ - "pytest>=4.6.3,<5.0.0", - "pytest-xdist>=1.30.0", + "pytest>=7.0.0", + "pytest-xdist>=2.4.0", "pytest-trio>=0.5.2", "factory-boy>=2.12.0,<3.0.0", ], - "lint": [ - "flake8==3.7.9", # flake8 is not semver: it has added new warnings at minor releases - "isort==4.3.21", - "mypy==0.780", # mypy is not semver: it has added new warnings at minor releases - "mypy-protobuf==1.15", - "black==19.3b0", - "flake8-bugbear>=19.8.0,<20", - "docformatter>=1.3.1,<2", - "trio-typing~=0.5.0", - ], - "doc": [ - "Sphinx>=2.2.1,<3", - "sphinx_rtd_theme>=0.4.3,<=1", - "towncrier>=19.2.0, <20", - ], - "dev": [ - "bumpversion>=0.5.3,<1", - "pytest-watch>=4.1.0,<5", - "wheel", - "twine", - "ipython", - "setuptools>=36.2.0", - "tox>=3.13.2,<4.0.0", - ], } extras_require["dev"] = ( - extras_require["dev"] - + extras_require["test"] - + extras_require["lint"] - + extras_require["doc"] + extras_require["dev"] + extras_require["docs"] + extras_require["test"] ) fastecdsa = [ @@ -58,7 +48,6 @@ fastecdsa = [ "fastecdsa==1.7.5;sys_platform!='win32'", ] - with open("./README.md") as readme: long_description = readme.read() @@ -93,21 +82,22 @@ setup( name="libp2p", # *IMPORTANT*: Don't manually change the version here. Use `make bump`, as described in readme version="0.1.5", - description="libp2p implementation written in python", + description="""libp2p: The Python implementation of the libp2p networking stack""", long_description=long_description, long_description_content_type="text/markdown", - maintainer="The Ethereum Foundation", - maintainer_email="snakecharmers@ethereum.org", + author="The Ethereum Foundation", + author_email="snakecharmers@ethereum.org", url="https://github.com/libp2p/py-libp2p", include_package_data=True, install_requires=install_requires, - python_requires=">=3.6,<4", + python_requires=">=3.8, <4", extras_require=extras_require, py_modules=["libp2p"], license="MIT/APACHE2.0", zip_safe=False, keywords="libp2p p2p", packages=find_packages(exclude=["tests", "tests.*"]), + package_data={"libp2p": ["py.typed"]}, classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -115,8 +105,11 @@ setup( "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "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.11", + "Programming Language :: Python :: 3.12", ], platforms=["unix", "linux", "osx"], ) diff --git a/tests/core/conftest.py b/tests/core/conftest.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/core/test_import.py b/tests/core/test_import.py deleted file mode 100644 index 325444f9..00000000 --- a/tests/core/test_import.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_import(): - import libp2p # noqa: F401 diff --git a/tests/core/test_import_and_version.py b/tests/core/test_import_and_version.py new file mode 100644 index 00000000..b9e96e4c --- /dev/null +++ b/tests/core/test_import_and_version.py @@ -0,0 +1,4 @@ +def test_import_and_version(): + import libp2p + + assert isinstance(libp2p.__version__, str) diff --git a/tox.ini b/tox.ini index b1e5cdcd..6e3cf447 100644 --- a/tox.ini +++ b/tox.ini @@ -1,66 +1,67 @@ -# Reference: https://github.com/ethereum/ethereum-python-project-template/blob/master/tox.ini - -# TODO: consider pypy3 support [tox] -envlist = - py{36,37}-test - py37-interop - lint +envlist= + py{38,39,310,311,312}-core + py{38,39,310,311,312}-lint + py{38,39,310,311,312}-wheel + windows-wheel docs -[isort] -combine_as_imports=False -force_sort_within_sections=True -include_trailing_comma=True -known_third_party=anyio,factory,lru,p2pclient,pytest,noise -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 +exclude=venv*,.tox,docs,build,*_pb2*.py +extend-ignore=E203 +max-line-length=88 +per-file-ignores=__init__.py:F401 [testenv] usedevelop=True -commands = - test: pytest {posargs:tests/} - docs: make build-docs -basepython = +commands= + core: pytest {posargs:tests/} + docs: make check-docs-ci +basepython= docs: python - py37: python3.7 - py36: python3.6 -extras = + windows-wheel: python + py38: python3.8 + py39: python3.9 + py310: python3.10 + py311: python3.11 + py312: python3.12 +extras= test - docs: doc -whitelist_externals = make -deps = -passenv = CI TRAVIS TRAVIS_* + docs +allowlist_externals=make,pre-commit -[testenv:lint] -basepython = python3 -extras = lint -commands = - 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 {toxinidir}/libp2p {toxinidir}/tests tests_interop examples setup.py - docformatter --pre-summary-newline --check --recursive libp2p tests tests_interop examples setup.py +[testenv:py{38,39,310,311,312}-lint] +deps=pre-commit +commands= + pre-commit install + pre-commit run --all-files --show-diff-on-failure -[testenv:py37-interop] -deps = - p2pclient -passenv = CI TRAVIS TRAVIS_* GOPATH -extras = test -commands = - pytest tests_interop/ -basepython = - py37: python3.7 +[testenv:py{38,39,310,311,312}-wheel] +deps= + wheel + build[virtualenv] +allowlist_externals= + /bin/rm + /bin/bash +commands= + python -m pip install --upgrade pip + /bin/rm -rf build dist + python -m build + /bin/bash -c 'python -m pip install --upgrade "$(ls dist/libp2p-*-py3-none-any.whl)" --progress-bar off' + python -c "import libp2p" +skip_install=true + +[testenv:windows-wheel] +deps= + wheel + build[virtualenv] +allowlist_externals= + bash.exe +commands= + python --version + python -m pip install --upgrade pip + bash.exe -c "rm -rf build dist" + python -m build + bash.exe -c 'python -m pip install --upgrade "$(ls dist/libp2p-*-py3-none-any.whl)" --progress-bar off' + python -c "import libp2p" +skip_install=true