如果你和我一样,希望将编写的 Python 实用程序与同事共享,最好的方法是制作一个软件包:它很容易安装,而且不需要复制粘贴。
不过,如果对其中的方法不熟悉,可能会感到头痛。下面就分几步介绍创建 Python 包的方法,供大家参考。
基本结构 创建一个名为podsearch
的目录,进入这个目录,并创建一个虚拟环境(关于虚拟环境的文章,请参阅《Python 虚拟环境》 )
1 2 3 4 $ mkdir podsearch $ cd podsearch $ python3 -m venv env $ . env/bin/activate
然后在此目录中创建一个文件__init__.py
,并写入下述函数。
1 2 3 4 5 6 7 8 9 10 11 12 . ├── .gitignore └── podsearch └── __init__.py """Let's find some podcasts!""" __version__ = "0.1.0" def search(name, count=5): """Search podcast by name.""" raise NotImplementedError()
测试包 用传统的方法,比较麻烦,这里推荐一个工具:flit ,它可以简化一切。安装它:
安装之后,执行如下操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ flit init Module name [podsearch]: Author [Anton Zhiyanov]: Author email [m@antonz.org]: Home page [https://github.com/nalgeon/podsearch-py]: Choose a license (see http://choosealicense.com/ for more info) 1. MIT - simple and permissive 2. Apache - explicitly grants patent rights 3. GPL - ensures that code based on this is shared with the same terms 4. Skip - choose a license later Enter 1-4 [1]: 1 Written pyproject.toml; edit that file to add optional extra info.
在这里,用 flit 创建了pyproject.toml 文件,这是一个元数据文件,它具有将软件包发布到 PyPI 所需的一切配置。
当然,一定要在 TestPyPi](https://test.pypi.org/)(测试库)和 PyPI (主要的存储库)注册,这两个地方的账号是完全独立的,所以你需要两个。
在~/.pypirc
中设置对存储库的访问:
1 2 3 4 5 6 7 8 9 10 11 [distutils] index-servers = pypi pypitest [pypi] username: nalgeon # replace with your PyPI username [pypitest] repository: https://test.pypi.org/legacy/ username: nalgeon # replace with your TestPyPI username
并将包发布到测试存储库:
1 2 3 4 $ flit publish --repository pypitest Found 4 files tracked in git ... Package is at https://test.pypi.org/project/podsearch/
搞定!可以在 TestPyPi 上获取该软件包。
公共包 把文件中的代码修改一下,让它真的有用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # ... SEARCH_URL = "https://itunes.apple.com/search" @dataclass class Podcast: """Podcast metadata.""" id: str name: str author: str url: str feed: Optional[str] = None category: Optional[str] = None image: Optional[str] = None def search(name: str, limit: int = 5) -> List[Podcast]: """Search podcast by name.""" params = {"term": name, "limit": limit, "media": "podcast"} response = _get(url=SEARCH_URL, params=params) return _parse(response)
并发布到主存储库 PyPI 。
搞定!
为了使软件包更易于使用,我建议你再多做点事情。
文档 没有人喜欢写文档。但是如果没有文档,别人不了解你的东西,所以添加README.md
以及CHANGELOG.md
.
将readme.md
添加到pyproject.toml
,这样 PyPI 就会在这个包的页面上显示它:
1 description-file = "README.md"
指定所支持的最低 Python 版本:
1 requires-python = ">=3.7"
更新 __init__.py
中的版本,并通过flit publish
发布这个包:
测试 下面关注格式化(black
)、测试覆盖率(coverage
)、代码质量(flake8
、pylint
、mccabe
)和静态分析(mypy
)等,通过tox
来执行所有操作。
1 $ pip install black coverage flake8 mccabe mypy pylint pytest tox
在tox.ini
中创建 tox
配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 [tox] isolated_build = True envlist = py37,py38,py39 [testenv] deps = black coverage flake8 mccabe mypy pylint pytest commands = black podsearch flake8 podsearch pylint podsearch mypy podsearch coverage erase coverage run --include=podsearch/* -m pytest -ra coverage report -m
tox.ini 进行所有的检测:
1 2 3 4 5 6 7 8 9 10 11 12 13 $ tox -e py39 ... py39 run-test: commands[0] | black podsearch All done! ✨ 🍰 ✨ ... py39 run-test: commands[2] | pylint podsearch Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00) ... py39 run-test: commands[6] | coverage report -m TOTAL 100% ... py39: commands succeeded congratulations :)
太好了!测试通过,覆盖率100%。
云构建 每个可靠的开源项目都会在每次提交后运行云测试,所以此处亦然。
用 GitHub Actions 构建项目,用Codecov 检查测试覆盖率,用 Code Climate 检查代码质量。
必须注册Codecov和Code Climate(都支持GitHub登录),并在设置中启用包存储库。
之后,将GitHub Actions build config添加到.github/workflows/build.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 # ... jobs: build: runs-on: ubuntu-latest strategy: matrix: python-version: [3.7, 3.8, 3.9] env: USING_COVERAGE: "3.9" steps: - name: Checkout sources uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: $ - name: Install dependencies run: | python -m pip install --upgrade pip python -m pip install black coverage flake8 flit mccabe mypy pylint pytest tox tox-gh-actions - name: Run tox run: | python -m tox - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 if: contains(env.USING_COVERAGE, matrix.python-version) with: fail_ci_if_error: true
build.yml
GitHub通过“tox”进行测试,就像我们前面所做的一样。 tox-gh-actions
包 和USING_COVERAGE
设置确保tox
使用与GitHub Actions相同的Python版本,正如strategy.matrix
所要求的那样(参阅Hynek Schlawak 中的说明。)
最后一步将测试覆盖发送到Codecov。Code Climate不需要单独的步骤—它自动发现存储库的更改。
现在提交、推送和享受这一成果。让每个人都可以享受这一成果 - 把徽章添加到’ README.md ‘:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 [![PyPI Version][pypi-image]][pypi-url] [![Build Status][build-image]][build-url] [![Code Coverage][coverage-image]][coverage-url] [![Code Quality][quality-image]][quality-url] ... <!-- Badges --> [pypi-image]: https://img.shields.io/pypi/v/podsearch [pypi-url]: https://pypi.org/project/podsearch/ [build-image]: https://github.com/nalgeon/podsearch-py/actions/workflows/build.yml/badge.svg [build-url]: https://github.com/nalgeon/podsearch-py/actions/workflows/build.yml [coverage-image]: https://codecov.io/gh/nalgeon/podsearch-py/branch/main/graph/badge.svg [coverage-url]: https://codecov.io/gh/nalgeon/podsearch-py [quality-image]: https://api.codeclimate.com/v1/badges/3130fa0ba3b7993fbf0a/maintainability [quality-url]: https://codeclimate.com/github/nalgeon/podsearch-py
是不是很cool
任务自动化 tox
很好,但对开发不是很方便。运行诸如pylint、coverage
等单个命令会更快,但这些命令非常冗长,因此我们将把这些枯燥的东西自动化。
用 Makefile 为频繁的操作创建简短的别名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .DEFAULT_GOAL := help .PHONY : coverage deps help lint push testcoverage: ## Run tests with coverage coverage erase coverage run --include=podsearch/* -m pytest -ra coverage report -m deps: ## Install dependencies pip install black coverage flake8 mccabe mypy pylint pytest tox lint: ## Lint and static-check flake8 podsearch pylint podsearch mypy podsearch push: ## Push code with tags git push && git push --tags test: ## Run tests pytest -ra
Makefile
以下是我们的任务:
1 2 3 4 5 6 7 8 9 10 11 $ make help Usage: make [task] task help ------ ---- coverage Run tests with coverage deps Install dependencies lint Lint and static-check push Push code with tags test Run tests help Show help message
要使代码更简洁,请使用“make”调用来替换原始的build.yml
步骤:
1 2 3 4 5 6 7 - name: Install dependencies run: | make deps - name: Run tox run: | make tox
云发布 在GitHub可以运行flit publish
。我们来创建一个单独的工作流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 name: publish on: release: types: [created] jobs: publish: runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: "3.9" - name: Install dependencies run: | make deps - name: Publish to PyPi env: FLIT_USERNAME: ${{ secrets.PYPI_USERNAME }} FLIT_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | make publish
publish.yml
把PYPI_USERNAME
和 PYPI_PASSWORD
放在存储库设置((Settings > Secrets > New repository secret)中。使用你的PyPi用户名和密码,或者使用 API token .
现在,只要创建一个新版本,GitHub就会自动发布这个包。
正确配置下面的文件,能让你发布的内容更漂亮:
参考文献 https://antonz.org/python-packaging/?continueFlag=27ecc1d264efd99fc7f058dae314b3d9