You often see these instructions to install a package:
pip install [package] # Use only in virtual environment!
pip install --user [package] # Almost never use
🚨 Don't do this unless you know what you are doing!
pipx
(applications)(and use system package managers like brew
when possible)
Use standard library venv
module or virtualenv
module:
python3 -m venv .venv
Source with:
. .venv/bin/activate
Now pip
install away!
# turn off the default environment
conda config --set auto_activate_base false
conda env create -n some_name # or use paths with `-p`
conda activate some_name
conda deactivate
Use pipx
, which creates new virtual environment for package
pipx install [package]
pipx inject ipython matplotlib
module: Python file (.py
) that contains definitions and statements.
package: a collection of modules in the same directory
Package directory must contain __init__.py
for Python to "see" it*
* ... Not true with namespace packages
rescale
function from Software Carpentry:
import numpy as np
def rescale(input_array):
"""Rescales an array from 0 to 1.
Takes an array as input, and returns a corresponding array scaled
so that 0 corresponds to the minimum and 1 to the maximum value
of the input array.
"""
L = np.min(input_array)
H = np.max(input_array)
output_array = (input_array - L) / (H - L)
return output_array
Call it:
rescale(np.linspace(0, 100, 5))
array([ 0. , 0.25, 0.5 , 0.75, 1. ])
mkdir package
cd package
git init
mkdir -p src/rescale tests docs
touch src/rescale/__init__.py src/rescale/rescale.py
touch pyproject.toml
pyproject.toml
# contents of pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "package"
version = "0.1.0"
.
├── docs/
├── pyproject.toml
├── src/
│ └── package/
│ │ ├── __init__.py
│ │ └── rescale.py
└── tests/
Install in editable mode:
$ pip install -e .
Import and call:
import numpy as np
from package.rescale import rescale
rescale(np.linspace(0, 100, 5))
Output:
array([0. , 0.25, 0.5 , 0.75, 1. ])
compphys
package structure:
src/
|-- compphys/
| |-- __init__.py
| |-- constants.py
| |-- physics.py
| |-- more/
| | |-- __init__.py
| | |-- morephysics.py
| | |-- evenmorephysics.py
|-- assets/
| |-- data.txt
| |-- orphan.py
tests/
|-- test_physics.py
|-- test_morephysics.py
docs/
...
compphys
contents:__init__.py
:
tells Python this is a package; typically empty. Executed before any other modules imported.
constants.py
and physics.py
more
is a submodule
assets
is a subdirectory;
not a submodule since it doesn't have __init__.py
(orphan.py
is unreachable!)
tests
: subdirectory with tests
Use attribute access operator: .
import compphys.constants
import compphys.more.morephysics
two_pi = 2 * compphys.constants.pi
These are absolute imports
From physics.py
:
from . import constants
from .constants import pi, h
from .more import morephysics
From evenmorephysics.py
:
from . import morephysics
from .. import constants
from ..constants import pi, h
Rely on the Python standard library, NumPy, SciPy, etc. as much as you need.
from time import sleep
print("This is my file to demonstrate best practices.")
def process_data(data):
print("Beginning data processing...")
modified_data = data + " that has been modified"
sleep(3)
print("Data processing finished.")
return modified_data
def read_data_from_web():
print("Reading data from the Web")
data = "Data from the web"
return data
def write_data_to_database(data):
print("Writing data to a database")
print(data)
def main():
data = read_data_from_web()
modified_data = process_data(data)
write_data_to_database(modified_data)
if __name__ == "__main__":
main()
touch README.md
A README is a form of software documentation, and should contain at minimum:
In addition, a README may also contain:
# Package
`package` is a simple Python library that contains a single function
for rescaling arrays.
## Installation
Download the source code and use the package manager
[pip](https://pip.pypa.io/en/stable/) to install `package`:
```bash
pip install .
```
## Usage
```python
import numpy as np
from package.rescale import rescale
# rescales over 0 to 1
rescale(np.linspace(0, 100, 5))
```
## Contributing
Pull requests are welcome. For major changes, please open an issue
first to discuss what you would like to change.
Please make sure to update tests as appropriate.
## License
TBD
More on this later... for now:
touch LICENSE
Copy-paste the BSD 3-clause license:
BSD 3-Clause License
Copyright (c) [year], [fullname]
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Over time, your package will change as you fix bugs, add features, and make improvements.
Technically, your Git history should contain all the records of changes, but in practice this isn't very helpful for functionality changes.
Instead,
CHANGELOG.md
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.1.0] - 2015-10-06
### Added
- Answer "Should you ever rewrite a change log?".
### Changed
- Improve argument against commit logs.
- Start following [SemVer](http://semver.org) properly.
## [0.0.8] - 2015-02-17
### Changed
- Update year to match in every README example.
- Reluctantly stop making fun of Brits only, since most of the world
writes dates in a strange way.
### Fixed
- Fix typos in recent README changes.
- Update outdated unreleased diff link.
## [0.0.7] - 2015-02-16
### Added
- Link, and make it obvious that date format is ISO 8601.
### Changed
- Clarified the section on "Is there a standard change log format?".
### Fixed
- Fix Markdown links to tag comparison URL with footnote-style links.
## [0.0.6] - 2014-12-12
### Added
- README section on "yanked" releases.
## [0.0.5] - 2014-08-09
### Added
- Markdown links to version tags on release headings.
- Unreleased section to gather unreleased changes and encourage note
keeping prior to releases.
## [0.0.4] - 2014-08-09
### Added
- Better explanation of the difference between the file ("CHANGELOG")
and its function "the change log".
### Changed
- Refer to a "change log" instead of a "CHANGELOG" throughout the site
to differentiate between the file and the purpose of the file — the
logging of changes.
### Removed
- Remove empty sections from CHANGELOG, they occupy too much space and
create too much noise in the file. People will have to assume that the
missing sections were intentionally left out because they contained no
notable changes.
## [0.0.3] - 2014-08-09
### Added
- "Why should I care?" section mentioning The Changelog podcast.
## [0.0.2] - 2014-07-10
### Added
- Explanation of the recommended reverse chronological release ordering.
## 0.0.1 - 2014-05-31
### Added
- This CHANGELOG file to hopefully serve as an evolving example of a
standardized open source project CHANGELOG.
- CNAME file to enable GitHub Pages custom domain
- README now contains answers to common questions about CHANGELOGs
- Good examples and basic guidelines, including proper date formatting.
- Counter-examples: "What makes unicorns cry?"
[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD
[0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0
[0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8
[0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7
[0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6
[0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5
[0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4
[0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3
[0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2
pyproject.toml
src/
|-- compphys/
| |-- __init__.py
| |-- _version.py
| |-- constants.py
| |-- physics.py
| |-- more/
| | |-- __init__.py
| | |-- morephysics.py
| | |-- evenmorephysics.py
assets/
|-- data.txt
|-- orphan.py
tests/
|-- test_physics.py
|-- test_morephysics.py
docs/
LICENSE
README.md
CHANGELOG.md
CONTRIBUTING.md
CODE_OF_CONDUCT.md
pyproject.toml
name = "some_project"
version = "1.2.3"
version = "0.2.1b1"
Can also have specified elsewhere with dynamic = ["version"]
description = "This is a very short summary of a very cool project."
readme = "README.md"
keywords = ["example", "tutorial"]
authors = [
{name="Me Myself", email="email@mail.com"},
{name="You Yourself", email="email2@mail.com"},
]
maintainers = [
{name="It Itself", email="email3@mail.com"},
]
# Inline form
urls.Homepage = "https://pypi.org"
urls."Source Code" = "https://pypi.org"
# Sectional form
[project.urls]
Homepage = "https://pypi.org"
"Source Code" = "https://pypi.org"
Others: Documentation, Bug Tracker, Changelog, Discussions, and Chat
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Information Analysis",
"Topic :: Scientific/Engineering :: Mathematics",
"Topic :: Scientific/Engineering :: Physics",
"Typing :: Typed",
]
requires-python = ">=3.8"
dependencies = [
"numpy>=1.18",
]
[project.optional-dependenices]
test = ["pytest>=6"]
check = ["flake8"]
plot = ["matplotlib"]
[project.scripts]
project-cli = "project.__main__:main"
pyproject.toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "package"
version = "0.0.1"
authors = [
{ name="Example Author", email="author@example.com" },
]
description = "A small example package"
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
"Homepage" = "https://github.com/pypa/sampleproject"
"Bug Tracker" = "https://github.com/pypa/sampleproject/issues"