I tried poetry because pipenv installation is quite slow these days. I will summarize what I found after using it all over. Since I am using Pipenv, I can compare it with that. Please refer to Official Doc as it does not describe package-related commands (build, publish ...) or detailed functions.
Poetry is a Python package management tool. Like Pipenv, resolve the dependencies and install / uninstall packages, The poetry.lock file allows other users to install the package with the appropriate version and dependencies. A virtual environment is available and packaging is also possible.
Python uses the one installed by pyenv.
$ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
PATH is entered in ~ ./bash_profile
and poetry starts up.
$ poetry -V
Poetry version 1.0.2
In the case of pipenv, environment variables were used to set the .venv
folder in the project.
Pipenv
$ export PIPENV_VENV_IN_PROJECT=1
$ pipenv install...
In the case of poetry, set from poetry config
.
You can check the current settings with the --list
option. The default is virtualenvs.in-project = false
.
poetry
$ poetry config --list
cache-dir = "/home/user/.cache/pypoetry"
virtualenvs.create = true
virtualenvs.in-project = false
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/user/.cache/pypoetry/virtualenvs
Change the settings.
python
$ poetry config virtualenvs.in-project true
$ poetry config --list
cache-dir = "/home/user/.cache/pypoetry"
virtualenvs.create = true
virtualenvs.in-project = true
virtualenvs.path = "{cache-dir}/virtualenvs" # /home/user/.cache/pypoetry/virtualenvs
Start the project with poetry new
and a template will be generated.
The following is as per Official Doc.
$ poetry new my-package
Created package my_package in my-package
Generated stationery
my-package
├── pyproject.toml
├── README.rst
├── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
The generated pyproject.toml
is as follows. It seems that pytest is automatically included in dev-dependencies.
pyproject.toml
[tool.poetry]
name = "my-package"
version = "0.1.0"
description = ""
authors = ["Your Name <[email protected]>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
pytest = "^5.2"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
However, it is difficult to use the my_package directory inside my-package. You can change the directory name in the package with the --name
option.
---- name
option
$ poetry new my-package --name app
Created package app in my-package
Model
my-package
├── pyproject.toml
├── README.rst
├── app
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
----src
option
There seems to be a --src
option, but it's more complicated, so don't use it.
$ poetry new --src my-package
Model
├── pyproject.toml
├── README.rst
├── src
│ └── my_package
│ └── __init__.py
└── tests
├── __init__.py
└── test_my_package.py
pyproject.toml
If you don't need a template, you can only create pyproject.toml
with poetry init
.
Interactively determine the contents of pyproject.toml
like npm init
.
$ poetry init
Package name [{folder_name}]:
Version [0.1.0]:
Description []:
Author [None, n to skip]: n
License []:
Compatible Python versions [^3.7]:
Would you like to define your main dependencies interactively? (yes/no) [yes] no
Would you like to define your dev dependencies (require-dev) interactively (yes/no) [yes] no
Generated file
[tool.poetry]
name = "new_ais"
version = "0.1.0"
description = ""
authors = ["Your Name <[email protected]>"]
[tool.poetry.dependencies]
python = "^3.7"
[tool.poetry.dev-dependencies]
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
Do you confirm generation? (yes/no) [yes] yes
If you do not enter anything for package name, it will be the folder name there. Enter y / n for Author and dependencies. This will create pyproject.toml
in the current directory.
If you use it in the same way as Pipenv, it seems easier to start with init.
install
poetry install
, like pipenv install
, resolves dependencies and installs the required packages from the pyproject.toml
created above.
$ poetry new myapp
$ cd myapp
$ poetry install
reating virtualenv myapp in /home/user/workspace/poetry/myapp/.venv
Updating dependencies
Resolving dependencies... (0.5s)
Writing lock file
Package operations: 11 installs, 0 updates, 0 removals
- Installing more-itertools (8.1.0)
- Installing zipp (1.0.0)
- Installing importlib-metadata (1.4.0)
- Installing pyparsing (2.4.6)
- Installing six (1.14.0)
- Installing attrs (19.3.0)
- Installing packaging (20.0)
- Installing pluggy (0.13.1)
- Installing py (1.8.1)
- Installing wcwidth (0.1.8)
- Installing pytest (5.3.2)
- Installing myapp (0.1.0)
The install will create a poetry.lock
file where you can see the dependencies.
---- no-root
option
poetry installs myapp by default. To avoid this, install with the --no-root
option.
$ poetry install --no-root
---- no-dev
option
If you don't want to install dev-dependencies, the --no-dev
option is OK.
$ poetry install --no-dev
add
Install the package. Note that unlike Pipenv, it is an add. Locking is faster than pipenv.
$ poetry add django==2.2.8
For dev-dependencies, the --dev (-D)
option.
$ poetry add flake8 -D
If you use the --dry-run
option, you can see what is installed without installing.
$ poetry add django --dry-run
Using version ^3.0.2 for django
Updating dependencies
Resolving dependencies... (0.4s)
Package operations: 4 installs, 0 updates, 0 removals, 13 skipped
- Skipping more-itertools (8.1.0) Already installed
- Skipping zipp (1.0.0) Already installed
- Skipping importlib-metadata (1.4.0) Already installed
- Skipping pyparsing (2.4.6) Already installed
- ...
update
When updating the packages installed in the project
$ poetry update
Update individually
$ poetry update requests django
As with add, you can see the contents of the update with the --dry-run
option.
$ poetry update --dry-run
Updating dependencies
Resolving dependencies... (0.4s)
No dependencies to install or update
- Skipping more-itertools (8.1.0) Already installed
- Skipping zipp (1.0.0) Already installed
- Skipping importlib-metadata (1.4.0) Already installed
- Skipping pyparsing (2.4.6) Already installed
- Skipping six (1.14.0) Already installed
- Skipping atomicwrites (1.3.0) Not needed for the current environment
- ...
remove
Delete the installed package.
$ poetry remove flask
Note that packages installed in dev-dependencies require the --dev (-D)
option.
$ poetry add flake8 -D
$ poetry remove flake8 # failed
[ValueError]
Package flake8 not found
$ poetry remove flake8 -D # OK
You can also use the --dry-run
option with remove.
show
Display a list of available packages.
Features like an enhanced version of pip list
.
$ poetry show
asgiref 3.2.3 ASGI specs, helper code, and ada...
attrs 19.3.0 Classes Without Boilerplate
django 3.0.2 A high-level Python Web framewor...
entrypoints 0.3 Discover and load entry points f...
flake8 3.7.9 the modular source code checker:...
importlib-metadata 1.4.0 Read metadata from Python packages
mccabe 0.6.1 McCabe checker, plugin for flake8
more-itertools 8.1.0 More routines for operating on i...
packaging 20.0 Core utilities for Python packages
pluggy 0.13.1 plugin and hook calling mechanis...
...
Information about packages can also be displayed.
$ poetry show django
name : django
version : 3.0.2
description : A high-level Python Web framework that
encourages rapid development and clean, pragmatic
design.
dependencies
- asgiref >=3.2,<4.0
- pytz *
- sqlparse >=0.2.2
---- tree
option
Dependencies can be displayed in a tree structure. A function similar to pipenv graph
. Actually, it is easy to see because it is a colored output.
$ poetry show --tree
django 3.0.2 A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
├── asgiref >=3.2,<4.0
├── pytz *
└── sqlparse >=0.2.2
flake8 3.7.9 the modular source code checker: pep8, pyflakes and co
├── entrypoints >=0.3.0,<0.4.0
├── mccabe >=0.6.0,<0.7.0
├── pycodestyle >=2.5.0,<2.6.0
└── pyflakes >=2.1.0,<2.2.0
...
---- latest (-l)
option
View the latest version.
$ poetry show --latest
asgiref 3.2.3 3.2.3 ASGI specs, helper code, a...
attrs 19.3.0 19.3.0 Classes Without Boilerplate
django 3.0.2 3.0.2 A high-level Python Web fr...
entrypoints 0.3 0.3 Discover and load entry po...
flake8 3.7.9 3.7.9 the modular source code ch...
importlib-metadata 1.4.0 1.4.0 Read metadata from Python ...
----outdated (-o)
option
View of older packages.
$ poetry show -o
django 2.2.4 3.0.2 A high-level Python Web framework that e...
lock
Lock the dependency specified in pyproject.toml
. (Do not install)
poetry.lock
is generated.
$ poetry lock
env
Virtual environment related commands. For the [python] part, specify 3.7.4 etc.
$ poetry env info #Information on the current virtual environment
$ poetry env list #Virtual environment list
$ poetry env remove <python> #Delete virtual environment
$ poetry env use <python> #Activate or create a virtual environment
In my environment, when virtualenvs.in-project = true
, it was not displayed in list and remove did not work.
It's a good idea to delete .venv /.
shell
Launch the shell in the virtual environment. Equivalent to pipenv shell
.
$ poetry shell
scripts
You can execute the script by entering the following in pyproject.toml
.
pyproject.toml
[tool.poetry.scripts]
start = "script:main"
script.py
def main():
print("Run script with poetry!")
$ poetry run start
Run script with poetry!
Even if you do not enter the virtual environment, if you execute it from a script, it will be executed in the virtual environment.
Looking at poetry's scripts executable code, it seems that you can't pass any arguments.
poetry/console/commands/run.py
#poetry script executable code
def run_script(self, script, args):
if isinstance(script, dict):
script = script["callable"]
module, callable_ = script.split(":")
src_in_sys_path = "sys.path.append('src'); " if self._module.is_in_src() else ""
cmd = ["python", "-c"]
cmd += [
"import sys; "
"from importlib import import_module; "
"sys.argv = {!r}; {}"
"import_module('{}').{}()".format(args, src_in_sys_path, module, callable_) #Run
]
return self.env.execute(*cmd)
With the above script settings, ʻimport_module ('script'). main ()is executed, so there is no part to pass arguments in the first place. I often registered
start =" python manage.py runserver 0.0.0.0:8000 "` in Pipenv, so I was in trouble.
pyproject.toml
[tool.poetry.scripts]
start = "manage:main"
Then, if you set poetry run start runserver 0.0.0.0:8000
, it will work for the time being. .. ..
-Good (compared to pipenv)
Install, add, remove and lock are faster (important) than Pipenv, and the display on the console is easy to see.
Functions equivalent to pip list
and pipenv graph
are also fairly easy to see.
-Perfect (compared to pipenv) Cooperation with venv. It can be used with the same usability as Pipenv. (I'm worried about the behavior at the time of venv in project) There doesn't seem to be a feature that pyenv install can be done from pipenv, but it's okay because it's not something I use often.
-Bad (compared to pipenv) After all the script part. There were many issues, so I'm waiting for improvement. I feel that there are many options. Just remember.
Based on the above points, it seems that poetry will be used.
Speaking of luxury, I should have known if it was dev at the poetry show
.