Tools: Guide to publish your first PyPI library ๐Ÿš€

Tools: Guide to publish your first PyPI library ๐Ÿš€

Source: Dev.to

Why to create a py package? ๐Ÿค”๐Ÿ ## ๐Ÿ“‚ Folder structure needed (yes, structure matters) ## Content of pyproject.toml โค๏ธโ€๐Ÿ”ฅ ## Contents of MANIFEST.in (donโ€™t skip ๐Ÿ™) ## Key rules ๐Ÿšจ ## Requirements ๐Ÿ“‹ ## Steps to create & upload ๐Ÿš€ ## Install build tools ๐Ÿ› ๏ธ ## Build your package ๐Ÿ“ฆ ## Upload to testPyPI (optional but smart ๐Ÿง ) ## Upload to real PyPI ๐ŸŒ ## Something more ๐Ÿ‘€ ## Common mistakes โŒ ## Pro tips ๐Ÿ’ก ๐Ÿ‘€ Do you also want to be included in that elite, mysterious, and totally brag-worthy list of contributors for a public PyPI package? Yes? No? Still scrolling like itโ€™s an Instagram reel? ๐Ÿ“ฑ Cool, letโ€™s fix that. Before you start dreaming about PyPI fame (and GitHub stars ๐ŸŒŸ that your relatives wonโ€™t understand), pause for a reality check. First, decide if your project is actually PyPI-worthy. Before touching configs, sanity-check that your project is reusable (no hardcoded paths, credentials, or โ€œworks only on my laptopโ€ local files ๐Ÿ’ปโŒ) & has a clear entry point (functions/CLI). If your script is โ€œrun once and forgetโ€ โ€” PyPI is overkill ๐Ÿ’€ If others (or future-you, after 3 months of memory loss ๐Ÿง ) can reuse it โ†’ publish it ๐Ÿš€ Think of it like the World Cup ๐Ÿ โ€” not every gully cricketer makes it to the squad, but the good ones do ๐Ÿ˜‰ Same rules apply here. Just like Indiaโ€™s budget announcements ๐Ÿ“Š โ€” boring, structured, but very important. Mess this up, and PyPI will treat your package the way Twitter treats breaking news โ€” harshly ๐Ÿ˜ฌ๐Ÿฆ. This is the heart of deployment. Mess this up and your package dies faster than a government promise during elections ๐Ÿ—ณ๏ธ๐Ÿ˜Œ. Yes, every line matters. No, PyPI doesnโ€™t care if โ€œit worked locallyโ€ ๐Ÿ˜ŒโŒ. Ensures non-code files are packaged. Skipping this is like hosting the World Cup final without a trophy ๐Ÿ† โ€” technically possible, emotionally devastating. Without this, your PyPI page may break. And users will judge you silently ๐Ÿค. There are some key rules while uploading your package on the PyPI website. These are non-negotiable โ€” like ICC rules during finals ๐Ÿ˜ค๐Ÿ: ; PyPI account can be created from here & tutorial for the same is in this youtube video TestPyPI account can be created from here & tutorial for the same is in this youtube video Yes, two accounts. No, PyPI doesnโ€™t trust you immediately โ€” neither should it ๐Ÿ˜Œ๐Ÿ”. If this executes successfully (pray to the Python gods ๐Ÿ๐Ÿ™), it will create: If it fails โ€” congrats ๐ŸŽ‰, youโ€™re officially learning ๐Ÿคจ Then install your uploaded package from testPyPI: Test import + functionality here. Break things now, not in production ๐Ÿ˜ฌ๐Ÿ”ฅ. ; make sure dist/* uploads everything inside dist/. And boom ๐Ÿ’ฅ โ€” Congratulations, youโ€™ve just uploaded your own package! ๐ŸŽ‰๐ŸŽ‰ Take a moment. Screenshot it. Flex on LinkedIn ๐Ÿ˜Ž. โŒ Hardcoded paths โŒ Forgot README / LICENSE โŒ Version conflict โŒ Import errors due to bad structure โŒ Uploading secrets accidentally (this one hurts the most ๐Ÿ’€๐Ÿ”) โœ… Add CLI using entry-points โœ… Automate release via GitHub Actions โœ… Tag versions (v0.1.0) โœ… Add __version__ inside package โœ… Use ruff / black before publishing Clean code = happy users ๐Ÿ˜Š. Hope youโ€™ve successfully created your first package on PyPI ๐Ÿ๐ŸŽฏ Do share your package name in comments โ€” letโ€™s hype each other like World Cup fans ๐Ÿ‡ฎ๐Ÿ‡ณ๐Ÿ. Iโ€™ve recently committed pyshrink. Do check it out ๐Ÿ‘€โœจ. Also, if youโ€™ve got questions, confusion, or existential doubts about packaging โ€” comment it out ๐Ÿ’ฌ๐Ÿ˜„. Author ๐Ÿ˜Ž Nitin Kumar Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK: my_package/ โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ””โ”€โ”€ my_package/ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”œโ”€โ”€ core.py โ”‚ โ””โ”€โ”€ utils.py โ”‚ โ”œโ”€โ”€ tests/ โ”‚ โ””โ”€โ”€ test_basic.py โ”‚ โ”œโ”€โ”€ README.md โ”œโ”€โ”€ LICENSE โ”œโ”€โ”€ pyproject.toml โ”œโ”€โ”€ MANIFEST.in โ””โ”€โ”€ .gitignore Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: my_package/ โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ””โ”€โ”€ my_package/ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”œโ”€โ”€ core.py โ”‚ โ””โ”€โ”€ utils.py โ”‚ โ”œโ”€โ”€ tests/ โ”‚ โ””โ”€โ”€ test_basic.py โ”‚ โ”œโ”€โ”€ README.md โ”œโ”€โ”€ LICENSE โ”œโ”€โ”€ pyproject.toml โ”œโ”€โ”€ MANIFEST.in โ””โ”€โ”€ .gitignore CODE_BLOCK: my_package/ โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ””โ”€โ”€ my_package/ โ”‚ โ”œโ”€โ”€ __init__.py โ”‚ โ”œโ”€โ”€ core.py โ”‚ โ””โ”€โ”€ utils.py โ”‚ โ”œโ”€โ”€ tests/ โ”‚ โ””โ”€โ”€ test_basic.py โ”‚ โ”œโ”€โ”€ README.md โ”œโ”€โ”€ LICENSE โ”œโ”€โ”€ pyproject.toml โ”œโ”€โ”€ MANIFEST.in โ””โ”€โ”€ .gitignore CODE_BLOCK: [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "my-package" version = "0.1.0" description = "Utility to validate API responses using schema rules" readme = "README.md" license = { file = "LICENSE" } authors = [ { name = "FIRSTNAME LASTNAME", email = "[email protected]" } ] requires-python = ">=3.8" dependencies = [ ] [project.urls] Homepage = "https://github.com/yourname/my-package" Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "my-package" version = "0.1.0" description = "Utility to validate API responses using schema rules" readme = "README.md" license = { file = "LICENSE" } authors = [ { name = "FIRSTNAME LASTNAME", email = "[email protected]" } ] requires-python = ">=3.8" dependencies = [ ] [project.urls] Homepage = "https://github.com/yourname/my-package" CODE_BLOCK: [build-system] requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "my-package" version = "0.1.0" description = "Utility to validate API responses using schema rules" readme = "README.md" license = { file = "LICENSE" } authors = [ { name = "FIRSTNAME LASTNAME", email = "[email protected]" } ] requires-python = ">=3.8" dependencies = [ ] [project.urls] Homepage = "https://github.com/yourname/my-package" CODE_BLOCK: include README.md include LICENSE Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: include README.md include LICENSE CODE_BLOCK: include README.md include LICENSE COMMAND_BLOCK: pip install --upgrade build twine Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: pip install --upgrade build twine COMMAND_BLOCK: pip install --upgrade build twine CODE_BLOCK: python -m build Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: python -m build CODE_BLOCK: python -m build CODE_BLOCK: dist/ โ”œโ”€โ”€ my_package-0.1.0-py3-none-any.whl โ””โ”€โ”€ my_package-0.1.0.tar.gz Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: dist/ โ”œโ”€โ”€ my_package-0.1.0-py3-none-any.whl โ””โ”€โ”€ my_package-0.1.0.tar.gz CODE_BLOCK: dist/ โ”œโ”€โ”€ my_package-0.1.0-py3-none-any.whl โ””โ”€โ”€ my_package-0.1.0.tar.gz CODE_BLOCK: twine upload --repository testpypi dist/* Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: twine upload --repository testpypi dist/* CODE_BLOCK: twine upload --repository testpypi dist/* COMMAND_BLOCK: pip install --index-url https://test.pypi.org/simple/ my-package Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: pip install --index-url https://test.pypi.org/simple/ my-package COMMAND_BLOCK: pip install --index-url https://test.pypi.org/simple/ my-package CODE_BLOCK: twine upload dist/* Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: twine upload dist/* CODE_BLOCK: twine upload dist/* - Name must be unique on PyPI (yes, utils, helpers, test-lib are already taken ๐Ÿ˜‘) - Version must follow semver - Once uploaded โ†’ cannot overwrite the same version (PyPI never forgets ๐Ÿ˜ˆ) - A sample project which should adhere to these conditions - Any code editor. Iโ€™m using VS Code here (because obviously ๐Ÿ’™) - A valid package name should be unique โš ๏ธ - A PyPI & test.pypi Account - build โ†’ creates wheel & source - twine โ†’ uploads to PyPI (your final boss ๐ŸŽฎ)