Package: example-pypi-package
Example PyPI (Python Package Index) Package & Tutorial / Instruction / Workflow for 2021This is an examplePyPI(Python Package Index) package set up with automated tests and package publishing using GitHub Actions CI/CD. It is made primarily for GitHub + VS Code (Windows / Mac / Linux) users who are about to write and publish their first PyPI package. The package could serve as a starter / boilerplate and the tutorial could give you a quick and concise explaination to solve some small but annoying problems you might encounter, such as package / module name confusion, and VS Code test configuration issues.Differences from pypa/sampleproject (click to show/hide)This example package is inspired by / based on theofficial sample project pypa/sampleproject, but this package:is a simplified version of pypa/sampleproject (and theofficial Python Packaging User Guide)uses GitHub Actions for both testing and publishing, instead of Travis CIis tested when pushingmasterormainbranch, and is published when create a releaseincludes test files in the source distributionusessetup.cfgforversion single-sourcing(setuptools 46.4.0+)has.vscode\settings.jsonandvscode.envwhich addssrc/folder toPYTHONPATH, so that test files don't have linting errors and may run with pytest in VS Codedoes not use flake8 for automated linting - it is sometimes too strict and inflexible, you may use pylint locally insteadhas this tutorial that covers everything you need to know in one page. Everything that might not be very useful, is hidden in collapsible sections that you can click to showhas.editorconfigfileMake necessary changesFork, clone or download the repositorygithub.com/tomchen/example_pypi_package.Package, module nameMany use a same package and module name, you could definitely do that. But this example package and its module's names are different:example_pypi_packageandexamplepy.Openexample_pypi_packagefolder with Visual Studio Code,Ctrl+Shift+F(Windows / Linux) orCmd+Shift+F(MacOS) to find all occurrences of both names and replace them with your package and module's names. Also remember to change the name of the foldersrc/examplepy.Simply and very roughly speaking, package name is used inpip install <PACKAGENAME>and module name is used inimport <MODULENAME>. Both names should consist of lowercase basic letters (a-z). They may have underscores (_) if you really need them. Hyphen-minus (-) should not be used.You'll also need to make sure the URL "https://pypi.org/project/example-pypi-package/" (replaceexample-pypi-packageby your package name, with all_becoming-) is not occupied.Details on naming convention (click to show/hide)Underscores (_) can be used but such use is discouraged. Numbers can be used if the name does not start with a number, but such use is also discouraged.Name starting with a number and/or containing hyphen-minus (-) should not be used: although technically legal, such name causes a lot of trouble − users have to useimportlibto import it.Don't be fooled by the URL "pypi.org/project/example-pypi-package/" and the name "example-pypi-package" on pypi.org. pypi.org and pip system convert all_to-and use the latter on the website / inpipcommand, but the real name is still with_, which users should use when importing the package.There's alsonamespaceto use if you need sub-packages.Other changesMake necessary changes insetup.py.The package's version number__version__is insrc/examplepy/__init__.py. You may want to change that.The example package is designed to be compatible with Python 3.6, 3.7, 3.8, 3.9, and will be tested against these versions. If you need to change the version range, you should change:classifiers,python_requiresinsetup.pyenvlistintox.inimatrix: python:in.github/workflows/test.ymlIf you plan to upload toTestPyPIwhich is a playground ofPyPIfor testing purpose, changetwine upload --repository pypi dist/*totwine upload --repository testpypi dist/*in the file.github/workflows/release.yml.Developmentpippip is a Python package manager. You already have pip if you use Python 3.4 and later version which include it by default. Readthisto know how to check whether pip is installed. Readthisif you need to install it.Use VS CodeVisual Studio Code is the most popular code editor today, our example package is configured to work with VS Code.Install VS Code extension "Python"."Python" VS Code extension will suggest you install pylint. Also, the example package is configured to use pytest with VS Code + Python extensions, so, install pylint and pytest:pipinstallpylintpytest(It's likely you will be prompted to install them, if that's the case, you don't need to type and execute the command)vscode.env's content is nowPYTHONPATH=/;src/;${PYTHONPATH}which is good for Windows. If you use Linux or MacOS, you need to change it toPYTHONPATH=/:src/:${PYTHONPATH}(replacing;with:). If the PATH is not properly set, you'll see linting errors in test files and pytest won't be able to runtests/test_*.pyfiles correctly.Close and reopen VS Code. You can now click the lab flask icon in the left menu and run all tests there, with pytest. pytest seems better than the standard unittest framework, it supportsunittestthus you can keep usingimport unittestin your test files.The example package also has a.editorconfigfile. You may install VS Code extension "EditorConfig for VS Code" that uses the file. With current configuration, the EditorConfig tool can automatically use spaces (4 spaces for .py, 2 for others) for indentation, setUTF-8encoding,LFend of lines, trim trailing whitespaces in non Markdown files, etc.In VS Code, you can go to File -> Preferences -> Settings, type "Python Formatting Provider" in the search box, and choose one of the three Python code formatting tools (autopep8, black and yapf), you'll be prompted to install it. The shortcuts for formatting of a code file areShift+Alt+F(Windows);Shift+Option (Alt)+F(MacOS);Ctrl+Shift+I(Linux).Write your packageInsrc/examplepy/(examplepyshould have been replaced by your module name) folder, renamemodule1.pyand write your code in it. Add more module .py files if you need to.Write your testsIntests/folder, renametest_module1.py(totest_*.py) and write your unit test code (withunittest) in it. Add moretest_*.pyfiles if you need to.The testing tool `tox` will be used in the automation with GitHub Actions CI/CD. If you want to use `tox` locally, click to read the "Use tox locally" sectionUse tox locallyInstall tox and run it:pipinstalltox
toxIn our configuration, tox runs a check of source distribution usingcheck-manifest(which requires your repo to be git-initialized (git init) and added (git add .) at least), setuptools's check, and unit tests using pytest. You don't need to install check-manifest and pytest though, tox will install them in a separate environment.The automated tests are run against several Python versions, but on your machine, you might be using only one version of Python, if that is Python 3.9, then run:tox-epy39If you add more files to the root directory (example_pypi_package/), you'll need to add your file tocheck-manifest --ignorelist intox.ini.Thanks to GitHub Actions' automated process, you don't need to generate distribution files locally. But if you insist, click to read the "Generate distribution files" sectionGenerate distribution filesInstall toolsInstall or upgradesetuptoolsandwheel:python-mpipinstall--user--upgradesetuptoolswheel(Ifpython3is the command on your machine, changepythontopython3in the above command, or add a linealias python=python3to~/.bashrcor~/.bash_aliasesfile if you use bash on Linux)GeneratedistFromexample_pypi_packagedirectory, run the following command, in order to generate production version for source distribution (sdist) indistfolder:pythonsetup.pysdistbdist_wheelInstall locallyOptionally, you can install dist version of your package locally before uploading toPyPIorTestPyPI:pipinstalldist/example_pypi_package-0.1.0.tar.gz(You may need to uninstall existing package first:pipuninstallexample_pypi_packageThere may be several installed packages with the same name, so runpip uninstallmultiple times until it says no more package to remove.)Upload to PyPIRegister on PyPI and get tokenRegister an account onPyPI, go toAccount settings § API tokens, "Add API token". The PyPI token only appears once, copy it somewhere. If you missed it, delete the old and add a new token.(Register aTestPyPIaccount if you are uploading to TestPyPI)Set secret in GitHub repoOn the page of your newly created or existing GitHub repo, clickSettings->Secrets->New repository secret, theNameshould bePYPI_API_TOKENand theValueshould be your PyPI token (which starts withpypi-).Push or releaseThe example package has automated tests and upload (publishing) already set up with GitHub Actions:Every time yougit pushyourmasterormainbranch, the package is automatically tested against the desired Python versions with GitHub Actions.Every time a new release (either the initial version or an updated version) is created, the package is automatically uploaded to PyPI with GitHub Actions.View it on pypi.orgAfter your package is published on PyPI, go tohttps://pypi.org/project/example-pypi-package/(_becomes-). Copy the command on the page, execute it to download and install your package from PyPI. (or test.pypi.org if you use that)If you publish the package to PyPI manually, click to readInstall TwineInstall or upgrade Twine:python-mpipinstall--user--upgradetwineCreate a.pypircfile in your$HOME(~) directory, its content should be:[pypi]username=__token__password=<PyPI token>(Use[testpypi]instead of[pypi]if you are uploading toTestPyPI)Replace<PyPI token>with your real PyPI token (which starts withpypi-).(if you don't manually create$HOME/.pypirc, you will be prompted for a username (which should be__token__) and password (which should be your PyPI token) when you run Twine)UploadRun Twine to upload all of the archives underdistfolder:python-mtwineupload--repositorypypidist/*(usetestpypiinstead ofpypiif you are uploading toTestPyPI)UpdateWhen you finished developing a newer version of your package, do the following things.Modify the version number__version__insrc\examplepy__init__.py.Delete all old versions indist.Run the following command again to regeneratedist:pythonsetup.pysdistbdist_wheelRun the following command again to uploaddist:python-mtwineupload--repositorypypidist/*(usetestpypiinstead ofpypiif needed)ReferencesPython Packaging Authority (PyPA)'s sample projectPyPA's Python Packaging User GuideStackoverflow questions and answersGitHub Actions Guides: Building and testing Python