1
0
Fork 0
mirror of https://github.com/python-poetry/install.python-poetry.org.git synced 2024-11-23 14:30:57 -05:00

Compare commits

..

43 commits

Author SHA1 Message Date
Tatsunori Uchino
2b71f2bd03
Correcting verbs to the present tense
Co-authored-by: Arun Babu Neelicattu <arun.neelicattu@gmail.com>
2024-11-21 00:00:09 +09:00
Tatsunori Uchino
29ac4557b7 Add PowerShell snippets for postinstall 2024-11-20 15:40:39 +01:00
dependabot[bot]
d3ff39aaef
chore(deps): bump actions/checkout from 3 to 4 (#149) 2024-11-20 14:34:33 +00:00
dependabot[bot]
c762e1bc54
chore(deps): bump actions/setup-python from 3 to 5 (#148) 2024-11-20 14:27:45 +00:00
David Hotham
89e0b6f7b9 ci: update matrix versions 2024-11-20 15:08:34 +01:00
David Hotham
f9ec0dc5c2 dependabot for github actions 2024-11-20 15:08:34 +01:00
David Hotham
76183eebc8 bump actions/upload-artifact 2024-11-20 15:08:34 +01:00
pre-commit-ci[bot]
d62875fc05
[pre-commit.ci] pre-commit autoupdate (#132)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Randy Döring <30527984+radoering@users.noreply.github.com>
2023-09-19 16:36:15 +02:00
pre-commit-ci[bot]
e518c55933
[pre-commit.ci] pre-commit autoupdate (#131)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-22 17:25:22 +02:00
pre-commit-ci[bot]
348d37f67f
[pre-commit.ci] pre-commit autoupdate (#130)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-15 22:14:46 +02:00
pre-commit-ci[bot]
04dd4769d5
[pre-commit.ci] pre-commit autoupdate (#126)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-08-08 15:42:55 +02:00
pre-commit-ci[bot]
34305a09a1
[pre-commit.ci] pre-commit autoupdate (#124)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-25 09:10:01 +02:00
pre-commit-ci[bot]
aebbeda95f
[pre-commit.ci] pre-commit autoupdate (#123)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-18 09:57:28 +02:00
johnthagen
ac8231e7e0
Add Official Poetry Badge to README (#120) 2023-07-15 15:04:33 -07:00
pre-commit-ci[bot]
b9cf4334bc
[pre-commit.ci] pre-commit autoupdate (#119)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-07-15 15:02:50 -07:00
pre-commit-ci[bot]
385616cd90
[pre-commit.ci] pre-commit autoupdate (#116)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-06-13 09:55:53 +02:00
pre-commit-ci[bot]
07ccfe459b
[pre-commit.ci] pre-commit autoupdate (#115)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-23 09:37:27 +02:00
Bisola Olasehinde
e69417b029
Update github workflows (#90) 2023-05-16 08:19:18 -07:00
Branch Vincent
fcd759d6fe
chore: migrate to ruff (#113) 2023-05-14 20:47:14 +02:00
pre-commit-ci[bot]
649e855f81
[pre-commit.ci] pre-commit autoupdate (#111)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-05-13 17:07:05 -07:00
pre-commit-ci[bot]
64b3848647
[pre-commit.ci] pre-commit autoupdate (#88)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-04-25 01:25:13 +02:00
pre-commit-ci[bot]
42a10434ed [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)
- [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0)
2022-11-28 19:58:07 -07:00
pre-commit-ci[bot]
fb4d36d19d [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.2.0 → v3.2.2](https://github.com/asottile/pyupgrade/compare/v3.2.0...v3.2.2)
2022-11-14 17:23:25 -07:00
pre-commit-ci[bot]
89f4049e20 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.1.0 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v3.1.0...v3.2.0)
2022-10-31 19:27:53 -06:00
Bartosz Sokorski
c776287cbd
Change -dev to full Python 3.11 version (#77)
As in the title, this PR removes the -dev part from Python 3.11 version
in CI.
2022-10-31 01:05:34 +01:00
pre-commit-ci[bot]
6362d37d57 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)
- [github.com/asottile/pyupgrade: v2.38.2 → v3.1.0](https://github.com/asottile/pyupgrade/compare/v2.38.2...v3.1.0)
2022-10-10 19:23:17 -06:00
pre-commit-ci[bot]
6161821b1d [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.38.0 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.38.0...v2.38.2)
2022-09-26 18:19:13 -06:00
pre-commit-ci[bot]
c8c3ce44ff [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.3 → v2.38.0](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.0)
2022-09-19 19:23:24 -06:00
Mathieu Kniewallner
6fd4578c5f chore(ci): don't fail fast on matrix 2022-09-17 19:13:16 -06:00
Mathieu Kniewallner
fb3ae6a4ee docs(README): consistently use install.python-poetry.org 2022-09-17 19:13:16 -06:00
Bjorn Neergaard
e8d8f76750 fix: check that sys.executable is valid before env creation 2022-09-17 15:49:17 -06:00
pre-commit-ci[bot]
206447fcd4
[pre-commit.ci] pre-commit autoupdate (#41)
updates:
- [github.com/asottile/pyupgrade: v2.34.0 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.34.0...v2.37.3)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-09-13 01:17:36 +02:00
Bartosz Sokorski
9b64f71d73
Added pyupgrade check and upgraded script code (#16) 2022-09-07 00:56:46 -06:00
Mathieu Kniewallner
ae8a9ad9a8
ci: explicitly test for 1.2.0 2022-09-06 02:01:00 -06:00
Bjorn Neergaard
c71c7d6c22 ci: only test Ubuntu LTS versions 2022-09-06 01:59:59 -06:00
Bjorn Neergaard
edbdec9887 ci: update matrix versions 2022-09-06 01:59:59 -06:00
Bjorn Neergaard
ac6fb50a38 refactor: update path handling and comments
This is part of a major overhaul of the installer I hope to complete in
a relatively short time. This first pass makes sure we use consistent
directories on all platforms by preferring the documented paths to a
possibly unexpected `site.getuserbase()` (which results in a Library
path on macOS Framework builds, like Homebrew and OS-provided Pythons).

Path handling as a whole is updated to take advantage of `pathlib` and
DRY up some tedious code. It also starts the first stage of increasing
use of classes and careful thought as to the visibility of class-level
attributes in this script -- I hope to end up with a DSL-like end result
that is as informative as possible to the reader of this script.
2022-09-06 01:59:59 -06:00
pre-commit-ci[bot]
07dd8a55c5
[pre-commit.ci] pre-commit autoupdate (#35)
updates:
- [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-09-05 21:33:07 -04:00
Mathieu Kniewallner
e837f27653
Bump flake8 and additional dependencies (#27)
* chore: run `pre-commit autoupdate`

* build(deps): bump `flake8-bugbear` to `22.7.1`
2022-08-11 12:10:07 -04:00
Arun Babu Neelicattu
5ad0932c19 ci: add debian integration tests 2022-07-25 01:54:18 -06:00
Arun Babu Neelicattu
d2a07fc9f1 readme: document known issue with debian 2022-07-25 01:54:18 -06:00
Arun Babu Neelicattu
be23be56c5 installer: use virtualenv.pyz when ensurepip absent 2022-07-25 01:54:18 -06:00
StarHeart
303392379b fix: delete leftover poetry script on windows 2022-07-25 01:52:47 -06:00
7 changed files with 320 additions and 157 deletions

View file

@ -1,3 +0,0 @@
[flake8]
max-line-length = 88
ignore = E501, E203, W503

6
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly

View file

@ -15,7 +15,7 @@ on:
- '**' - '**'
concurrency: concurrency:
group: installer-${{ github.head_ref || github.ref }} group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }} cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs: jobs:
@ -25,27 +25,32 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [Ubuntu, macOS, Windows] os: [Ubuntu, macOS, Windows]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11-dev"] python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
args: args:
- "" - ""
- "--preview" - "--preview"
- "--git https://github.com/python-poetry/poetry.git" - "--git https://github.com/python-poetry/poetry.git"
- "--version 1.1.14"
include: include:
- os: Ubuntu - os: Ubuntu
image: ubuntu-latest image: ubuntu-22.04
- os: Windows - os: Windows
image: windows-2022 image: windows-2022
- os: macOS - os: macOS
image: macos-11 image: macos-12
fail-fast: false
defaults: defaults:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3 uses: actions/setup-python@v5
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
@ -58,10 +63,10 @@ jobs:
run: echo "$APPDATA\Python\Scripts" >> $GITHUB_PATH run: echo "$APPDATA\Python\Scripts" >> $GITHUB_PATH
- name: Install Poetry - name: Install Poetry
run: python install-poetry.py -y run: python install-poetry.py -y ${{ matrix.args }}
- name: Upload Failure Log - name: Upload Failure Log
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v4
if: failure() if: failure()
with: with:
name: poetry-installer-error.log name: poetry-installer-error.log
@ -81,3 +86,56 @@ jobs:
run: | run: |
python install-poetry.py -y --uninstall python install-poetry.py -y --uninstall
{ type poetry 2>/dev/null >&2 && exit 1; } || exit 0 { type poetry 2>/dev/null >&2 && exit 1; } || exit 0
# debian/ubuntu needs special testing due to various issues around python packaging
# and configuration
integration-ubuntu:
name: Integration Test / Ubuntu / ${{ matrix.tag }}
runs-on: ubuntu-latest
container: docker.io/ubuntu:${{ matrix.tag }}
strategy:
matrix:
tag:
- focal
- jammy
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v4
- name: Install Packages
run: |
apt-get -y update
apt-get -y install python3 ca-certificates
apt-get -y install --reinstall python3-distutils
- name: Update PATH
run: echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Install Poetry
env:
DEB_PYTHON_INSTALL_LAYOUT: "deb"
run: python3 install-poetry.py -y
- name: Upload Failure Log
uses: actions/upload-artifact@v4
if: failure()
with:
name: poetry-installer-error.log
path: poetry-installer-error-*.log
- name: Verify Installation
run: |
set -e
poetry new foobar
cd foobar
poetry config virtualenvs.in-project true
poetry env use python3
[ "$(poetry run python --version)" == "$(python3 --version)" ] \
|| { echo >&2 "ERROR: Virtual environment Python version do not match system version." && exit 1; }
- name: Uninstall Poetry
run: |
python3 install-poetry.py -y --uninstall
{ type poetry 2>/dev/null >&2 && exit 1; } || exit 0

View file

@ -1,28 +1,20 @@
repos: repos:
- repo: https://github.com/psf/black - repo: https://github.com/psf/black-pre-commit-mirror
rev: 22.6.0 rev: 23.9.1
hooks: hooks:
- id: black - id: black
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear==22.4.25
- repo: https://github.com/PyCQA/isort
rev: 5.10.1
hooks:
- id: isort
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0 rev: v4.4.0
hooks: hooks:
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer
- id: debug-statements - id: debug-statements
- id: pretty-format-json - id: pretty-format-json
args: args: [--autofix]
- --autofix
- id: check-json - id: check-json
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.290
hooks:
- id: ruff

View file

@ -1,4 +1,7 @@
# Python Poetry Installer # Python Poetry Installer
[![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
This repository contains Poetry's official installation script, installer source and This repository contains Poetry's official installation script, installer source and
related hosting configuration. related hosting configuration.
@ -11,16 +14,21 @@ Poetry provides a custom installer that will install `poetry` isolated
from the rest of your system. from the rest of your system.
### osx / linux / bashonwindows / Windows+MinGW install instructions ### osx / linux / bashonwindows / Windows+MinGW install instructions
```bash ```bash
curl -sSL https://install.python-poetry.org | python - curl -sSL https://install.python-poetry.org | python3 -
```
### windows powershell install instructions
```powershell
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python -
``` ```
### windows powershell install instructions
```powershell
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -
```
> If you have installed Python through the Microsoft Store, replace `py` with `python` in the command above.
**Warning**: The previous `get-poetry.py` installer is now deprecated, if you are currently using it **Warning**: The previous `get-poetry.py` installer is now deprecated, if you are currently using it
you should migrate to the new, supported, `install-poetry.py` installer. you should migrate to the new, supported, `install.python-poetry.org` installer.
The installer installs the `poetry` tool to Poetry's `bin` directory. This location depends on your system: The installer installs the `poetry` tool to Poetry's `bin` directory. This location depends on your system:
@ -41,40 +49,88 @@ poetry --version
If you see something like `Poetry (version 1.2.0)` then you are ready to use Poetry. If you see something like `Poetry (version 1.2.0)` then you are ready to use Poetry.
If you decide Poetry isn't your thing, you can completely remove it from your system If you decide Poetry isn't your thing, you can completely remove it from your system
by running the installer again with the `--uninstall` option or by setting by running the installer again with the `--uninstall` option or by setting
the `POETRY_UNINSTALL` environment variable before executing the installer. the `POETRY_UNINSTALL` environment variable before executing the installer:
```bash ```bash
python install-poetry.py --uninstall curl -sSL https://install.python-poetry.org | python3 - --uninstall
POETRY_UNINSTALL=1 python install-poetry.py curl -sSL https://install.python-poetry.org | POETRY_UNINSTALL=1 python3 -
``` ```
By default, Poetry is installed into the user's platform-specific home directory. By default, Poetry is installed into the user's platform-specific home directory.
If you wish to change this, you may define the `POETRY_HOME` environment variable: If you wish to change this, you may define the `POETRY_HOME` environment variable:
```bash ```bash
POETRY_HOME=/etc/poetry python install-poetry.py curl -sSL https://install.python-poetry.org | POETRY_HOME=/etc/poetry python3 -
``` ```
If you want to install prerelease versions, you can do so by passing `--preview` option to `install-poetry.py` If you want to install prerelease versions, you can do so by passing `--preview` option or by using the `POETRY_PREVIEW`
or by using the `POETRY_PREVIEW` environment variable: environment variable:
```bash ```bash
python install-poetry.py --preview curl -sSL https://install.python-poetry.org | python3 - --preview
POETRY_PREVIEW=1 python install-poetry.py curl -sSL https://install.python-poetry.org | POETRY_PREVIEW=1 python3 -
``` ```
Similarly, if you want to install a specific version, you can use `--version` option or the `POETRY_VERSION` Similarly, if you want to install a specific version, you can use `--version` option or the `POETRY_VERSION`
environment variable: environment variable:
```bash ```bash
python install-poetry.py --version 1.2.0 curl -sSL https://install.python-poetry.org | python3 - --version 1.2.0
POETRY_VERSION=1.2.0 python install-poetry.py curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.2.0 python3 -
``` ```
You can also install Poetry for a `git` repository by using the `--git` option: You can also install Poetry for a `git` repository by using the `--git` option:
```bash ```bash
python install-poetry.py --git https://github.com/python-poetry/poetry.git@master curl -sSL https://install.python-poetry.org | python3 - --git https://github.com/python-poetry/poetry.git@master
```` ````
**Note**: Note that the installer does not support Python < 3.6. > **Note**: The installer does not support Python < 3.6.
## Known Issues
### Debian/Ubuntu
On Debian and Ubuntu systems, there are various issues that maybe caused due to how
various Python standard library components are packaged and configured. The following
details issues we are presently aware of, and potential workarounds.
> **Note:** This can also affect WSL users on Windows.
#### Installation Layout
If you encounter an error similar to the following, this might be due to
[pypa/virtualenv#2350](https://github.com/pypa/virtualenv/issues/2350).
```console
FileNotFoundError: [Errno 2] No such file or directory: '/root/.local/share/pypoetry/venv/bin/python'
```
You can work around this issue by setting the `DEB_PYTHON_INSTALL_LAYOUT` environment
variable to `deb` in order to emulate previously working behaviour.
```bash
export DEB_PYTHON_INSTALL_LAYOUT=deb
```
#### Missing `distutils` Module
In certain Debian/Ubuntu environments, you might encounter the following error message
in error logs (`poetry-installer-error-*.log`) provided when the installer fails.
```console
ModuleNotFoundError: No module named 'distutils.cmd'
```
This is probably due to [this bug](https://bugs.launchpad.net/ubuntu/+source/python3.10/+bug/1940705).
See also [pypa/get-pip#124](https://github.com/pypa/get-pip/issues/124).
The known workaround for this issue is to reinstall the `distutils` package provided by
the distribution.
```bash
apt-get install --reinstall python3-distutils
```
If you have installed a specific python version, eg: `3.10`, you might have to use the
package name `python3.10-distutils`.

View file

@ -1,27 +1,43 @@
""" #!/usr/bin/env python3
This script will install Poetry and its dependencies. r"""
This script will install Poetry and its dependencies in an isolated fashion.
It does, in order: It will perform the following steps:
* Create a new virtual environment using the built-in venv module, or the virtualenv zipapp if venv is unavailable.
This will be created at a platform-specific path (or `$POETRY_HOME` if `$POETRY_HOME` is set:
- `~/Library/Application Support/pypoetry` on macOS
- `$XDG_DATA_HOME/pypoetry` on Linux/Unix (`$XDG_DATA_HOME` is `~/.local/share` if unset)
- `%APPDATA%\pypoetry` on Windows
* Update pip inside the virtual environment to avoid bugs in older versions.
* Install the latest (or a given) version of Poetry inside this virtual environment using pip.
* Install a `poetry` script into a platform-specific path (or `$POETRY_HOME/bin` if `$POETRY_HOME` is set):
- `~/.local/bin` on Unix
- `%APPDATA%\Python\Scripts` on Windows
* Attempt to inform the user if they need to add this bin directory to their `$PATH`, as well as how to do so.
* Upon failure, write an error log to `poetry-installer-error-<hash>.log and restore any previous environment.
This script performs minimal magic, and should be relatively stable. However, it is optimized for interactive developer
use and trivial pipelines. If you are considering using this script in production, you should consider manually-managed
installs, or use of pipx as alternatives to executing arbitrary, unversioned code from the internet. If you prefer this
script to alternatives, consider maintaining a local copy as part of your infrastructure.
For full documentation, visit https://python-poetry.org/docs/#installation.
""" # noqa: E501
import sys
# Eager version check so we fail nicely before possible syntax errors
if sys.version_info < (3, 6): # noqa: UP036
sys.stdout.write("Poetry installer requires Python 3.6 or newer to run!\n")
sys.exit(1)
- Creates a virtual environment using venv (or virtualenv zipapp) in the correct OS data dir which will be
- `%APPDATA%\\pypoetry` on Windows
- ~/Library/Application Support/pypoetry on MacOS
- `${XDG_DATA_HOME}/pypoetry` (or `~/.local/share/pypoetry` if it's not set) on UNIX systems
- In `${POETRY_HOME}` if it's set.
- Installs the latest or given version of Poetry inside this virtual environment.
- Installs a `poetry` script in the Python user directory (or `${POETRY_HOME/bin}` if `POETRY_HOME` is set).
- On failure, the error log is written to poetry-installer-error-*.log and any previously existing environment
is restored.
"""
import argparse import argparse
import json import json
import os import os
import re import re
import shutil import shutil
import site
import subprocess import subprocess
import sys
import sysconfig import sysconfig
import tempfile import tempfile
@ -98,8 +114,8 @@ def is_decorated():
if WINDOWS: if WINDOWS:
return ( return (
os.getenv("ANSICON") is not None os.getenv("ANSICON") is not None
or "ON" == os.getenv("ConEmuANSI") or os.getenv("ConEmuANSI") == "ON" # noqa: SIM112
or "xterm" == os.getenv("Term") or os.getenv("Term") == "xterm" # noqa: SIM112
) )
if not hasattr(sys.stdout, "fileno"): if not hasattr(sys.stdout, "fileno"):
@ -125,7 +141,7 @@ def colorize(style, text):
if not is_decorated(): if not is_decorated():
return text return text
return "{}{}\033[0m".format(STYLES[style], text) return f"{STYLES[style]}{text}\033[0m"
def string_to_bool(value): def string_to_bool(value):
@ -134,38 +150,29 @@ def string_to_bool(value):
return value in {"true", "1", "y", "yes"} return value in {"true", "1", "y", "yes"}
def data_dir(version: Optional[str] = None) -> Path: def data_dir() -> Path:
if os.getenv("POETRY_HOME"): if os.getenv("POETRY_HOME"):
return Path(os.getenv("POETRY_HOME")).expanduser() return Path(os.getenv("POETRY_HOME")).expanduser()
if WINDOWS: if WINDOWS:
const = "CSIDL_APPDATA" base_dir = Path(_get_win_folder("CSIDL_APPDATA"))
path = os.path.normpath(_get_win_folder(const))
path = os.path.join(path, "pypoetry")
elif MACOS: elif MACOS:
path = os.path.expanduser("~/Library/Application Support/pypoetry") base_dir = Path("~/Library/Application Support").expanduser()
else: else:
path = os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share")) base_dir = Path(os.getenv("XDG_DATA_HOME", "~/.local/share")).expanduser()
path = os.path.join(path, "pypoetry")
if version: base_dir = base_dir.resolve()
path = os.path.join(path, version) return base_dir / "pypoetry"
return Path(path)
def bin_dir(version: Optional[str] = None) -> Path: def bin_dir() -> Path:
if os.getenv("POETRY_HOME"): if os.getenv("POETRY_HOME"):
return Path(os.getenv("POETRY_HOME"), "bin").expanduser() return Path(os.getenv("POETRY_HOME")).expanduser() / "bin"
user_base = site.getuserbase()
if WINDOWS and not MINGW: if WINDOWS and not MINGW:
bin_dir = os.path.join(user_base, "Scripts") return Path(_get_win_folder("CSIDL_APPDATA")) / "Python/Scripts"
else: else:
bin_dir = os.path.join(user_base, "bin") return Path("~/.local/bin").expanduser()
return Path(bin_dir)
def _get_win_folder_from_registry(csidl_name): def _get_win_folder_from_registry(csidl_name):
@ -181,9 +188,9 @@ def _get_win_folder_from_registry(csidl_name):
_winreg.HKEY_CURRENT_USER, _winreg.HKEY_CURRENT_USER,
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders", r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders",
) )
dir, type = _winreg.QueryValueEx(key, shell_folder_name) path, _ = _winreg.QueryValueEx(key, shell_folder_name)
return dir return path
def _get_win_folder_with_ctypes(csidl_name): def _get_win_folder_with_ctypes(csidl_name):
@ -265,7 +272,7 @@ You can execute `set -U fish_user_paths {poetry_home_bin} $fish_user_paths`
POST_MESSAGE_CONFIGURE_WINDOWS = """ POST_MESSAGE_CONFIGURE_WINDOWS = """
You can choose and execute one of the following commands in PowerShell: You can choose and execute one of the following commands in PowerShell:
A. Appends the bin directory to your user environment variable `PATH`: A. Append the bin directory to your user environment variable `PATH`:
``` ```
[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";{poetry_home_bin}", "User") [Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";{poetry_home_bin}", "User")
@ -281,7 +288,7 @@ echo 'if (-not (Get-Command poetry -ErrorAction Ignore)) {{ $env:Path += ";{poet
class PoetryInstallationError(RuntimeError): class PoetryInstallationError(RuntimeError):
def __init__(self, return_code: int = 0, log: Optional[str] = None): def __init__(self, return_code: int = 0, log: Optional[str] = None):
super(PoetryInstallationError, self).__init__() super().__init__()
self.return_code = return_code self.return_code = return_code
self.log = log self.log = log
@ -292,7 +299,7 @@ class VirtualEnvironment:
self._bin_path = self._path.joinpath( self._bin_path = self._path.joinpath(
"Scripts" if WINDOWS and not MINGW else "bin" "Scripts" if WINDOWS and not MINGW else "bin"
) )
# str is required for compatibility with subprocess run on CPython <= 3.7 on Windows # str is for compatibility with subprocess.run on CPython <= 3.7 on Windows
self._python = str( self._python = str(
self._path.joinpath(self._bin_path, "python.exe" if WINDOWS else "python") self._path.joinpath(self._bin_path, "python.exe" if WINDOWS else "python")
) )
@ -307,7 +314,18 @@ class VirtualEnvironment:
@classmethod @classmethod
def make(cls, target: Path) -> "VirtualEnvironment": def make(cls, target: Path) -> "VirtualEnvironment":
if not sys.executable:
raise ValueError(
"Unable to determine sys.executable. Set PATH to a sane value or set it"
" explicitly with PYTHONEXECUTABLE."
)
try: try:
# on some linux distributions (eg: debian), the distribution provided python
# installation might not include ensurepip, causing the venv module to
# fail when attempting to create a virtual environment
# we import ensurepip but do not use it explicitly here
import ensurepip # noqa: F401
import venv import venv
builder = venv.EnvBuilder(clear=True, with_pip=True, symlinks=False) builder = venv.EnvBuilder(clear=True, with_pip=True, symlinks=False)
@ -344,7 +362,7 @@ class VirtualEnvironment:
env = cls(target) env = cls(target)
# we do this here to ensure that outdated system default pip does not trigger older bugs # this ensures that outdated system default pip does not trigger older bugs
env.pip("install", "--disable-pip-version-check", "--upgrade", "pip") env.pip("install", "--disable-pip-version-check", "--upgrade", "pip")
return env return env
@ -376,32 +394,32 @@ class Cursor:
self._output = sys.stdout self._output = sys.stdout
def move_up(self, lines: int = 1) -> "Cursor": def move_up(self, lines: int = 1) -> "Cursor":
self._output.write("\x1b[{}A".format(lines)) self._output.write(f"\x1b[{lines}A")
return self return self
def move_down(self, lines: int = 1) -> "Cursor": def move_down(self, lines: int = 1) -> "Cursor":
self._output.write("\x1b[{}B".format(lines)) self._output.write(f"\x1b[{lines}B")
return self return self
def move_right(self, columns: int = 1) -> "Cursor": def move_right(self, columns: int = 1) -> "Cursor":
self._output.write("\x1b[{}C".format(columns)) self._output.write(f"\x1b[{columns}C")
return self return self
def move_left(self, columns: int = 1) -> "Cursor": def move_left(self, columns: int = 1) -> "Cursor":
self._output.write("\x1b[{}D".format(columns)) self._output.write(f"\x1b[{columns}D")
return self return self
def move_to_column(self, column: int) -> "Cursor": def move_to_column(self, column: int) -> "Cursor":
self._output.write("\x1b[{}G".format(column)) self._output.write(f"\x1b[{column}G")
return self return self
def move_to_position(self, column: int, row: int) -> "Cursor": def move_to_position(self, column: int, row: int) -> "Cursor":
self._output.write("\x1b[{};{}H".format(row + 1, column)) self._output.write(f"\x1b[{row + 1};{column}H")
return self return self
@ -486,9 +504,26 @@ class Installer:
self._accept_all = accept_all self._accept_all = accept_all
self._git = git self._git = git
self._path = path self._path = path
self._data_dir = data_dir()
self._bin_dir = bin_dir()
self._cursor = Cursor() self._cursor = Cursor()
self._bin_dir = None
self._data_dir = None
@property
def bin_dir(self) -> Path:
if not self._bin_dir:
self._bin_dir = bin_dir()
return self._bin_dir
@property
def data_dir(self) -> Path:
if not self._data_dir:
self._data_dir = data_dir()
return self._data_dir
@property
def version_file(self) -> Path:
return self.data_dir.joinpath("VERSION")
def allows_prereleases(self) -> bool: def allows_prereleases(self) -> bool:
return self._preview return self._preview
@ -514,18 +549,20 @@ class Installer:
mx = self.VERSION_REGEX.match(x) mx = self.VERSION_REGEX.match(x)
if mx is None: if mx is None:
# the version is not semver, perhaps scm or file, we assume upgrade is supported # the version is not semver, perhaps scm or file
# we assume upgrade is supported
return True return True
vx = tuple(int(p) for p in mx.groups()[:3]) + (mx.group(5),) vx = (*tuple(int(p) for p in mx.groups()[:3]), mx.group(5))
return vx >= (1, 1, 7) return vx >= (1, 1, 7)
if version and not _is_self_upgrade_supported(version): if version and not _is_self_upgrade_supported(version):
self._write( self._write(
colorize( colorize(
"warning", "warning",
f"You are installing {version}. When using the current installer, this version does not support " f"You are installing {version}. When using the current installer, "
f"updating using the 'self update' command. Please use 1.1.7 or later.", "this version does not support updating using the 'self update' "
"command. Please use 1.1.7 or later.",
) )
) )
if not self._accept_all: if not self._accept_all:
@ -538,14 +575,14 @@ class Installer:
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
raise PoetryInstallationError( raise PoetryInstallationError(
return_code=e.returncode, log=e.output.decode() return_code=e.returncode, log=e.output.decode()
) ) from e
self._write("") self._write("")
self.display_post_message(version) self.display_post_message(version)
return 0 return 0
def install(self, version, upgrade=False): def install(self, version):
""" """
Installs Poetry in $POETRY_HOME. Installs Poetry in $POETRY_HOME.
""" """
@ -558,13 +595,13 @@ class Installer:
with self.make_env(version) as env: with self.make_env(version) as env:
self.install_poetry(version, env) self.install_poetry(version, env)
self.make_bin(version, env) self.make_bin(version, env)
self._data_dir.joinpath("VERSION").write_text(version) self.version_file.write_text(version)
self._install_comment(version, "Done") self._install_comment(version, "Done")
return 0 return 0
def uninstall(self) -> int: def uninstall(self) -> int:
if not self._data_dir.exists(): if not self.data_dir.exists():
self._write( self._write(
"{} is not currently installed.".format(colorize("info", "Poetry")) "{} is not currently installed.".format(colorize("info", "Poetry"))
) )
@ -572,8 +609,8 @@ class Installer:
return 1 return 1
version = None version = None
if self._data_dir.joinpath("VERSION").exists(): if self.version_file.exists():
version = self._data_dir.joinpath("VERSION").read_text().strip() version = self.version_file.read_text().strip()
if version: if version:
self._write( self._write(
@ -584,10 +621,10 @@ class Installer:
else: else:
self._write("Removing {}".format(colorize("info", "Poetry"))) self._write("Removing {}".format(colorize("info", "Poetry")))
shutil.rmtree(str(self._data_dir)) shutil.rmtree(str(self.data_dir))
for script in ["poetry", "poetry.bat"]: for script in ["poetry", "poetry.bat", "poetry.exe"]:
if self._bin_dir.joinpath(script).exists(): if self.bin_dir.joinpath(script).exists():
self._bin_dir.joinpath(script).unlink() self.bin_dir.joinpath(script).unlink()
return 0 return 0
@ -602,7 +639,7 @@ class Installer:
@contextmanager @contextmanager
def make_env(self, version: str) -> VirtualEnvironment: def make_env(self, version: str) -> VirtualEnvironment:
env_path = self._data_dir.joinpath("venv") env_path = self.data_dir.joinpath("venv")
env_path_saved = env_path.with_suffix(".save") env_path_saved = env_path.with_suffix(".save")
if env_path.exists(): if env_path.exists():
@ -634,20 +671,20 @@ class Installer:
def make_bin(self, version: str, env: VirtualEnvironment) -> None: def make_bin(self, version: str, env: VirtualEnvironment) -> None:
self._install_comment(version, "Creating script") self._install_comment(version, "Creating script")
self._bin_dir.mkdir(parents=True, exist_ok=True) self.bin_dir.mkdir(parents=True, exist_ok=True)
script = "poetry.exe" if WINDOWS else "poetry" script = "poetry.exe" if WINDOWS else "poetry"
target_script = env.bin_path.joinpath(script) target_script = env.bin_path.joinpath(script)
if self._bin_dir.joinpath(script).exists(): if self.bin_dir.joinpath(script).exists():
self._bin_dir.joinpath(script).unlink() self.bin_dir.joinpath(script).unlink()
try: try:
self._bin_dir.joinpath(script).symlink_to(target_script) self.bin_dir.joinpath(script).symlink_to(target_script)
except OSError: except OSError:
# This can happen if the user # This can happen if the user
# does not have the correct permission on Windows # does not have the correct permission on Windows
shutil.copy(target_script, self._bin_dir.joinpath(script)) shutil.copy(target_script, self.bin_dir.joinpath(script))
def install_poetry(self, version: str, env: VirtualEnvironment) -> None: def install_poetry(self, version: str, env: VirtualEnvironment) -> None:
self._install_comment(version, "Installing Poetry") self._install_comment(version, "Installing Poetry")
@ -664,7 +701,7 @@ class Installer:
def display_pre_message(self) -> None: def display_pre_message(self) -> None:
kwargs = { kwargs = {
"poetry": colorize("info", "Poetry"), "poetry": colorize("info", "Poetry"),
"poetry_home_bin": colorize("comment", self._bin_dir), "poetry_home_bin": colorize("comment", self.bin_dir),
} }
self._write(PRE_MESSAGE.format(**kwargs)) self._write(PRE_MESSAGE.format(**kwargs))
@ -681,17 +718,17 @@ class Installer:
path = self.get_windows_path_var() path = self.get_windows_path_var()
message = POST_MESSAGE_NOT_IN_PATH message = POST_MESSAGE_NOT_IN_PATH
if path and str(self._bin_dir) in path: if path and str(self.bin_dir) in path:
message = POST_MESSAGE message = POST_MESSAGE
self._write( self._write(
message.format( message.format(
poetry=colorize("info", "Poetry"), poetry=colorize("info", "Poetry"),
version=colorize("b", version), version=colorize("b", version),
poetry_home_bin=colorize("comment", self._bin_dir), poetry_home_bin=colorize("comment", self.bin_dir),
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")), poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
configure_message=POST_MESSAGE_CONFIGURE_WINDOWS.format( configure_message=POST_MESSAGE_CONFIGURE_WINDOWS.format(
poetry_home_bin=colorize("comment", self._bin_dir) poetry_home_bin=colorize("comment", self.bin_dir)
), ),
test_command=colorize("b", "poetry --version"), test_command=colorize("b", "poetry --version"),
) )
@ -700,11 +737,12 @@ class Installer:
def get_windows_path_var(self) -> Optional[str]: def get_windows_path_var(self) -> Optional[str]:
import winreg import winreg
with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as root: with winreg.ConnectRegistry(
with winreg.OpenKey(root, "Environment", 0, winreg.KEY_ALL_ACCESS) as key: None, winreg.HKEY_CURRENT_USER
path, _ = winreg.QueryValueEx(key, "PATH") ) as root, winreg.OpenKey(root, "Environment", 0, winreg.KEY_ALL_ACCESS) as key:
path, _ = winreg.QueryValueEx(key, "PATH")
return path return path
def display_post_message_fish(self, version: str) -> None: def display_post_message_fish(self, version: str) -> None:
fish_user_paths = subprocess.check_output( fish_user_paths = subprocess.check_output(
@ -712,17 +750,17 @@ class Installer:
).decode("utf-8") ).decode("utf-8")
message = POST_MESSAGE_NOT_IN_PATH message = POST_MESSAGE_NOT_IN_PATH
if fish_user_paths and str(self._bin_dir) in fish_user_paths: if fish_user_paths and str(self.bin_dir) in fish_user_paths:
message = POST_MESSAGE message = POST_MESSAGE
self._write( self._write(
message.format( message.format(
poetry=colorize("info", "Poetry"), poetry=colorize("info", "Poetry"),
version=colorize("b", version), version=colorize("b", version),
poetry_home_bin=colorize("comment", self._bin_dir), poetry_home_bin=colorize("comment", self.bin_dir),
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")), poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
configure_message=POST_MESSAGE_CONFIGURE_FISH.format( configure_message=POST_MESSAGE_CONFIGURE_FISH.format(
poetry_home_bin=colorize("comment", self._bin_dir) poetry_home_bin=colorize("comment", self.bin_dir)
), ),
test_command=colorize("b", "poetry --version"), test_command=colorize("b", "poetry --version"),
) )
@ -732,30 +770,30 @@ class Installer:
paths = os.getenv("PATH", "").split(":") paths = os.getenv("PATH", "").split(":")
message = POST_MESSAGE_NOT_IN_PATH message = POST_MESSAGE_NOT_IN_PATH
if paths and str(self._bin_dir) in paths: if paths and str(self.bin_dir) in paths:
message = POST_MESSAGE message = POST_MESSAGE
self._write( self._write(
message.format( message.format(
poetry=colorize("info", "Poetry"), poetry=colorize("info", "Poetry"),
version=colorize("b", version), version=colorize("b", version),
poetry_home_bin=colorize("comment", self._bin_dir), poetry_home_bin=colorize("comment", self.bin_dir),
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")), poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
configure_message=POST_MESSAGE_CONFIGURE_UNIX.format( configure_message=POST_MESSAGE_CONFIGURE_UNIX.format(
poetry_home_bin=colorize("comment", self._bin_dir) poetry_home_bin=colorize("comment", self.bin_dir)
), ),
test_command=colorize("b", "poetry --version"), test_command=colorize("b", "poetry --version"),
) )
) )
def ensure_directories(self) -> None: def ensure_directories(self) -> None:
self._data_dir.mkdir(parents=True, exist_ok=True) self.data_dir.mkdir(parents=True, exist_ok=True)
self._bin_dir.mkdir(parents=True, exist_ok=True) self.bin_dir.mkdir(parents=True, exist_ok=True)
def get_version(self): def get_version(self):
current_version = None current_version = None
if self._data_dir.joinpath("VERSION").exists(): if self.version_file.exists():
current_version = self._data_dir.joinpath("VERSION").read_text().strip() current_version = self.version_file.read_text().strip()
self._write(colorize("info", "Retrieving Poetry metadata")) self._write(colorize("info", "Retrieving Poetry metadata"))
@ -765,8 +803,8 @@ class Installer:
mx = self.VERSION_REGEX.match(x) mx = self.VERSION_REGEX.match(x)
my = self.VERSION_REGEX.match(y) my = self.VERSION_REGEX.match(y)
vx = tuple(int(p) for p in mx.groups()[:3]) + (mx.group(5),) vx = (*tuple(int(p) for p in mx.groups()[:3]), mx.group(5))
vy = tuple(int(p) for p in my.groups()[:3]) + (my.group(5),) vy = (*tuple(int(p) for p in my.groups()[:3]), my.group(5))
if vx < vy: if vx < vy:
return -1 return -1
@ -781,7 +819,7 @@ class Installer:
) )
if self._version and self._version not in releases: if self._version and self._version not in releases:
msg = "Version {} does not exist.".format(self._version) msg = f"Version {self._version} does not exist."
self._write(colorize("error", msg)) self._write(colorize("error", msg))
raise ValueError(msg) raise ValueError(msg)
@ -799,9 +837,7 @@ class Installer:
if current_version == version and not self._force: if current_version == version and not self._force:
self._write( self._write(
"The latest version ({}) is already installed.".format( f'The latest version ({colorize("b", version)}) is already installed.'
colorize("b", version)
)
) )
return None, current_version return None, current_version
@ -912,7 +948,8 @@ def main():
text=True, text=True,
) )
installer._write(colorize("error", f"See {path} for error logs.")) installer._write(colorize("error", f"See {path} for error logs."))
text = f"{e.log}\nTraceback:\n\n{''.join(traceback.format_tb(e.__traceback__))}" tb = "".join(traceback.format_tb(e.__traceback__))
text = f"{e.log}\nTraceback:\n\n{tb}"
Path(path).write_text(text) Path(path).write_text(text)
return e.return_code return e.return_code

View file

@ -1,12 +1,29 @@
[tool.isort] [tool.ruff]
profile = "black" fix = true
force_single_line = true unfixable = [
atomic = true "ERA", # do not autoremove commented out code
lines_after_imports = 2 ]
lines_between_types = 1 target-version = "py37"
filter_files = true
[tool.black]
line-length = 88 line-length = 88
include = '\.pyi?$' extend-select = [
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"ERA", # flake8-eradicate/eradicate
"I", # isort
"N", # pep8-naming
"PIE", # flake8-pie
"PGH", # pygrep
"RUF", # ruff checks
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
"UP", # pyupgrade
]
[tool.ruff.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.isort]
force-single-line = true
lines-between-types = 1
lines-after-imports = 2