{"id":18365934,"url":"https://github.com/rssr25/perfect-python-packaging","last_synced_at":"2025-04-10T13:29:14.761Z","repository":{"id":94746198,"uuid":"590116767","full_name":"rssr25/perfect-python-packaging","owner":"rssr25","description":"Learn how to create python packages to contribute your code on PyPI. :D","archived":false,"fork":false,"pushed_at":"2024-03-28T10:30:36.000Z","size":35,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-15T20:19:24.371Z","etag":null,"topics":["open-source","packages","python","python-package-example","python-packaging","python3","wiki"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rssr25.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-17T17:36:12.000Z","updated_at":"2024-06-19T11:45:00.000Z","dependencies_parsed_at":"2024-12-24T00:41:28.587Z","dependency_job_id":"be79b1ae-8775-44c2-9fd1-3abf38252e6f","html_url":"https://github.com/rssr25/perfect-python-packaging","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rssr25%2Fperfect-python-packaging","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rssr25%2Fperfect-python-packaging/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rssr25%2Fperfect-python-packaging/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rssr25%2Fperfect-python-packaging/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rssr25","download_url":"https://codeload.github.com/rssr25/perfect-python-packaging/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248225701,"owners_count":21068078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["open-source","packages","python","python-package-example","python-packaging","python3","wiki"],"created_at":"2024-11-05T23:15:25.220Z","updated_at":"2025-04-10T13:29:14.745Z","avatar_url":"https://github.com/rssr25.png","language":"Python","readme":"# How to package python packages (perfectly).\nThis is a text version of the youtube video: [Publishing (Perfect) Python Packages on PyPi](https://www.youtube.com/watch?v=GIF3LaRqgXo) (unfortunately it is not available anymore)\n\nThis guide assumes that you have some useful python code that is general enough to publish. :)\n\n1. Create a directory with the name of your package. In the example above we have `helloworld`\n\n2. Create `helloworld/src` source directory where your modules (the functionality (code) you want to package for other developers) sit. Each module is a `.py` file.\n\n3. Create `helloworld/setup.py` write the following:\n```python\n\nfrom setuptools import setup\n\nsetup(\n        name= 'helloworld', \n        version='0.0.1', \n        description='Say hello!', \n        py_modules=[\"helloworld\"],\n        package_dir={'': 'src'},\n    ) \n\n```\nNotice that we are using `setuptools` here, which is not a third-party dependency anymore. Think of the above code as a configuration for now. The arguments of this function tells `pip` how to install your package. This is the bare minumum information that you provide.\n\n`name`: the package name you want people to use when they run the command `pip install name_of_package`\n\n`version`: `0.0.x` indicates an unstable version. When you upload a package for the first time you are likely to make mistakes. It is safer to have `0.0.1` for now.\n\n`description`: self-explanatory\n\n`py_modules`: the modules that the package uses, usually they sit in `src` dir.\n\n`package_dir`: tells `setuptools` where our code is.\n\n\u003cbr\u003e\n\n4. Let's check if the package has been correctly created. Build the package using `python setup.py bdist_wheel`. You should have the following new stuff.\n\n    - `\\helloworld\\build` directory which contains two more folders. The `build\\lib` directory contains our modules.\n    - `\\helloworld\\dist` which constains our python wheel for distribuition.\n    - `\\src\\helloword.egg-info`\n\n\u003cbr\u003e\n\n5. Check if the package is installing correctly using `pip install -e .` where `.` is the current directory where `setup.py` file is. The `-e` flag prevents the installation of this package in your system Python distribution.\n\n\u003cbr\u003e\n\n6. You can now check the installation of the package in your Python interpreter:\n\n```python\n$ python\n\u003e\u003e\u003e from helloworld import hello_world\n\u003e\u003e\u003e hello_world(\"Rahul\")\nHello Rahul!\n\u003e\u003e\u003e \n```\n\nCongratulations! You have created your first package which you can upload to the PyPI. However, this guide is about uploading a \"perfect\" python package. So let's perfect it!\n\n\u003chr\u003e\n\n## Cleaning up a little\nLet's clean-up our project a little. We see that we have created some files that are not necessary to push on github. Head to [gitignore.io](https://www.gitignore.io) and search for `python`. It will spit out a text that we will put in a `.gitignore` file which does some housekeeping for the files that are not necessary to push on GitHub.\n\nCreate a `.gitignore` file for your repository and paste the output of your search on `gioignore.io`.\n\n## License?\nIf you are going to publish your code, you need to license it. Without a license we haven't given permission to distribute our code. People can look at it but not copy it yet! So we need a `license.txt` file. If you don't know ins and outs of licenses [ChooseALicense](https://choosealicense.com) is a good place to understand the permissions and restrictions of different licenses.\n\n## Classifiers make life easier. :heart:\nWe need to set-up some classifiers so that people searching on PyPi can find our package based on a criteria. For example, a programmer searching for some package may write a classifer to search for it to run on Python 3.7, etc. You can provide this information in classifiers.\n\n```python\nsetup( \n    ... #other arguments to setup() :)\n    classifiers=[\n        \"Programming Language :: Python :: 3\",\n        \"Programming Language :: Python :: 3.6\",\n        \"Programming Language :: Python :: 3.7\",\n        \"License :: OSI Approved :: GNU General Public License v2 or later (GPLV2+)!\",\n        \"Operating System :: OS Independent\",\n    ],\n)\n```\nTo know more about classifiers, head to [Classifers](https://pypi.org/classifiers). There are a bunch of classifiers, try them and apply all the useful classifiers to your project.\n\n## Documentation is your :massage:\nBefore we jump onto documenting the code, we need to know in which format you want to write the documentation. There are generally two choices at the moment.\n\n\n|  ReStructured Text | Markdown         |\n|--------------------|------------------|\n| Pythonic           | More widespread  |\n|  Powerful          | Simpler          |\n|  Can use Sphinx    | Can use MkDocs   |\n\nReStructured Text is written in Python and widely used in the Python community. It is a Python solution. If you have a project that uses code from multiple languages then probably you are more familiar with MarkDown. It is more simpler but also less powerful. Both of these are supported by [readthedocs.org](https://readthedocs.org) :)\n\nOnce we have decided from the two choices above, we need to have soem sections in the document that are more or less quite general to any documentation. They are as follows (we use markdown for example here)\n\n1. A `readme.md` file that has:\n    - Title: the title of the project and a small paragraph describing what the project does. \n\n        ```markdown\n        # Hello World\n        This is an example project demonstrating how to publish a Python module to PyPi.\n        ```\n    - Installation: A section telling how to install the project\n        ```markdown\n        ## Installation\n        Run the following to install:\n           pip install helloworld\n    \n    - Some example code to tell how to use the code\n\n        ```markdown\n        from helloworld import say_hello\n        # Generate \"Hello, World!\"\n        say_hello ()\n        # Generate \"Hello, Everybody!\"\n        say_hello(\"Everybody\")\n        ```\n2. Other stuff that you want the developers to pay attention to.\n\nOnce we have written this, we would also like to publish this on PyPi. It will be really nice to make this readme.md as the official description of the project on PyPi. Now, PyPi can use markdown directly to incorporate your .md readme(s) directly into the package.\n\n```python\nfrom setuptools import setup\n\nwith open (\"READMEmd\", \"r\") as fh:\n    long_description = fh.read ()\n\nsetup(\n    ... #other stuff written before\n    long_description=long_description,\n    long_description_content_type=\"text/markdown\",\n)\n```\n\n## Add your Library dependencies\nYou must have seen in a lot of python projects there are dependencies that make your project work. You can add the dependencies directly in the `setup()` function like below.\n\n```python\nsetup(\n    install_requires = [\n        \"blessings ~= 1.7\", #this is an example of a dependency\n    ],\n)\n```\n\nAdd the dependency in your `setup.py` and check if it installs everything using `pip install -e .`\n\n## Test with `pytest`\nTo ensure that everything is working fine, after installation, it makes sense to run some tests. But, we don't have any tests with us and it makes no sense to check every function randomly in your package to make sure the things work.\n\nFor testing `pytest` is a good recommendation. But in order to run some tests using `pytest` we need more dependencies. This time they are not library dependencies as discussed in the previous section, but they are \u003cb\u003edevelopment dependencies\u003c/b\u003e. \n\nIn order to add these development dependencies in `setup()` function, add them as extras. A lot of people use `requirements.txt` for these development dependencies, well you can directly add them to your package setup.\n\n```python\nsetup(\n    ... #previously written stuff\n    extras_require={\n        \"dev\": [\n            \"pytest\u003e=3.7\",\n        ],\n    },\n)\n```\nNow we want to tell people how to use it, again we update the `readme.md`.\n\n```markdown\n# Developing Hello World \nTo install helloworld, along with the tools you need to develop and run tests, run the following in your virtualenv:\n\n$ pip install -e .[dev]\n\n# for mac use\n$ pip install -e .'[dev]'\n```\nThis is how you install the development dependencies so that you can run the tests. The `.[dev]` says \"we are installing the current module with the dev extras\".\n\n\u003cp style=\"text-align: center;\"\u003e ---------- A small detour ---------- \u003c/p\u003e\n\u003cb\u003e Question 1: \u003c/b\u003e What is the difference between install_requires and extras_requires?\n\n\u003cb\u003einstall requires\u003c/b\u003e\n- is for production dependencies (Flask, Click, Numpy, Pandas)\n- versions should be as relaxed as possible ( \u003e3.0, \u003c4.0 ) to not lock your users.\n\n\u003cb\u003eextras_require\u003c/b\u003e\n- is for optional requirements: (Pytest, Mock, Coverage.y)\n- versions should be as specific as possible\n\n\u003cbr\u003e\n\n\u003cb\u003eQuestion 2: \u003c/b\u003e What about `requirements.txt`? \u003cbr\u003e\nIt still has a place but it:\n\n- is for Apps being deployed on machines you control.\n- Uses fixed version numbers, eg: requests==2.22.0\n- Is generated with pip freeze \u003e requirements.txt\n\n\u003cp style=\"text-align: center;\"\u003e ---------- A small detour that ended ---------- \u003c/p\u003e\n\nNow we can write tests. Here we use `test_helloworld.py`\n\n```python\n#test_helloworld.py\nfrom helloworld import say_hello\ndef test_helloworld_no_params ():\n    assert say_hello () == \"Hello, World!\"\n\ndef test_helloworld_with_param ():\n    assert say_hello (\"Everyone\") == \"Hello, Everyone!\"\n```\n\nTo run the test just write `pytest` in console:\n\n```bash\n$ pytest \n============== test session starts ===========: \nplatform darwin -- Python 3.6.3, pytest-3.7.2, \npy-1.5.4, pluggy-0.7.1\nrootdir: /path/to/helloworld, inifile:\ncollected 2 items\ntest_helloworld.py ..                    [100%]\n========= 2 passed in 0.02 seconds ===========\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frssr25%2Fperfect-python-packaging","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frssr25%2Fperfect-python-packaging","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frssr25%2Fperfect-python-packaging/lists"}