mirror of
https://github.com/python-poetry/install.python-poetry.org.git
synced 2024-11-27 00:10:54 -05:00
Compare commits
43 commits
07185e6663
...
2b71f2bd03
Author | SHA1 | Date | |
---|---|---|---|
|
2b71f2bd03 | ||
|
29ac4557b7 | ||
|
d3ff39aaef | ||
|
c762e1bc54 | ||
|
89e0b6f7b9 | ||
|
f9ec0dc5c2 | ||
|
76183eebc8 | ||
|
d62875fc05 | ||
|
e518c55933 | ||
|
348d37f67f | ||
|
04dd4769d5 | ||
|
34305a09a1 | ||
|
aebbeda95f | ||
|
ac8231e7e0 | ||
|
b9cf4334bc | ||
|
385616cd90 | ||
|
07ccfe459b | ||
|
e69417b029 | ||
|
fcd759d6fe | ||
|
649e855f81 | ||
|
64b3848647 | ||
|
42a10434ed | ||
|
fb4d36d19d | ||
|
89f4049e20 | ||
|
c776287cbd | ||
|
6362d37d57 | ||
|
6161821b1d | ||
|
c8c3ce44ff | ||
|
6fd4578c5f | ||
|
fb3ae6a4ee | ||
|
e8d8f76750 | ||
|
206447fcd4 | ||
|
9b64f71d73 | ||
|
ae8a9ad9a8 | ||
|
c71c7d6c22 | ||
|
edbdec9887 | ||
|
ac6fb50a38 | ||
|
07dd8a55c5 | ||
|
e837f27653 | ||
|
5ad0932c19 | ||
|
d2a07fc9f1 | ||
|
be23be56c5 | ||
|
303392379b |
7 changed files with 334 additions and 157 deletions
3
.flake8
3
.flake8
|
@ -1,3 +0,0 @@
|
|||
[flake8]
|
||||
max-line-length = 88
|
||||
ignore = E501, E203, W503
|
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: monthly
|
76
.github/workflows/installer.yml
vendored
76
.github/workflows/installer.yml
vendored
|
@ -15,7 +15,7 @@ on:
|
|||
- '**'
|
||||
|
||||
concurrency:
|
||||
group: installer-${{ github.head_ref || github.ref }}
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
jobs:
|
||||
|
@ -25,27 +25,32 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
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:
|
||||
- ""
|
||||
- "--preview"
|
||||
- "--git https://github.com/python-poetry/poetry.git"
|
||||
- "--version 1.1.14"
|
||||
include:
|
||||
- os: Ubuntu
|
||||
image: ubuntu-latest
|
||||
image: ubuntu-22.04
|
||||
- os: Windows
|
||||
image: windows-2022
|
||||
- os: macOS
|
||||
image: macos-11
|
||||
image: macos-12
|
||||
fail-fast: false
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v3
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
|
@ -58,10 +63,10 @@ jobs:
|
|||
run: echo "$APPDATA\Python\Scripts" >> $GITHUB_PATH
|
||||
|
||||
- name: Install Poetry
|
||||
run: python install-poetry.py -y
|
||||
run: python install-poetry.py -y ${{ matrix.args }}
|
||||
|
||||
- name: Upload Failure Log
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: poetry-installer-error.log
|
||||
|
@ -81,3 +86,56 @@ jobs:
|
|||
run: |
|
||||
python install-poetry.py -y --uninstall
|
||||
{ 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
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.6.0
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.9.1
|
||||
hooks:
|
||||
- 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
|
||||
rev: v4.3.0
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: debug-statements
|
||||
- id: pretty-format-json
|
||||
args:
|
||||
- --autofix
|
||||
args: [--autofix]
|
||||
- id: check-json
|
||||
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.0.290
|
||||
hooks:
|
||||
- id: ruff
|
||||
|
|
92
README.md
92
README.md
|
@ -1,4 +1,7 @@
|
|||
# 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
|
||||
related hosting configuration.
|
||||
|
||||
|
@ -11,16 +14,21 @@ Poetry provides a custom installer that will install `poetry` isolated
|
|||
from the rest of your system.
|
||||
|
||||
### osx / linux / bashonwindows / Windows+MinGW install instructions
|
||||
|
||||
```bash
|
||||
curl -sSL https://install.python-poetry.org | python -
|
||||
```
|
||||
### windows powershell install instructions
|
||||
```powershell
|
||||
(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | python -
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
```
|
||||
|
||||
### 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
|
||||
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:
|
||||
|
||||
|
@ -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 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
|
||||
the `POETRY_UNINSTALL` environment variable before executing the installer.
|
||||
the `POETRY_UNINSTALL` environment variable before executing the installer:
|
||||
|
||||
```bash
|
||||
python install-poetry.py --uninstall
|
||||
POETRY_UNINSTALL=1 python install-poetry.py
|
||||
curl -sSL https://install.python-poetry.org | python3 - --uninstall
|
||||
curl -sSL https://install.python-poetry.org | POETRY_UNINSTALL=1 python3 -
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```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`
|
||||
or by using the `POETRY_PREVIEW` environment variable:
|
||||
If you want to install prerelease versions, you can do so by passing `--preview` option or by using the `POETRY_PREVIEW`
|
||||
environment variable:
|
||||
|
||||
```bash
|
||||
python install-poetry.py --preview
|
||||
POETRY_PREVIEW=1 python install-poetry.py
|
||||
curl -sSL https://install.python-poetry.org | python3 - --preview
|
||||
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`
|
||||
environment variable:
|
||||
|
||||
```bash
|
||||
python install-poetry.py --version 1.2.0
|
||||
POETRY_VERSION=1.2.0 python install-poetry.py
|
||||
curl -sSL https://install.python-poetry.org | python3 - --version 1.2.0
|
||||
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:
|
||||
|
||||
```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`.
|
||||
|
|
|
@ -1,27 +1,43 @@
|
|||
"""
|
||||
This script will install Poetry and its dependencies.
|
||||
#!/usr/bin/env python3
|
||||
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 json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import site
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import tempfile
|
||||
|
||||
|
@ -98,8 +114,8 @@ def is_decorated():
|
|||
if WINDOWS:
|
||||
return (
|
||||
os.getenv("ANSICON") is not None
|
||||
or "ON" == os.getenv("ConEmuANSI")
|
||||
or "xterm" == os.getenv("Term")
|
||||
or os.getenv("ConEmuANSI") == "ON" # noqa: SIM112
|
||||
or os.getenv("Term") == "xterm" # noqa: SIM112
|
||||
)
|
||||
|
||||
if not hasattr(sys.stdout, "fileno"):
|
||||
|
@ -125,7 +141,7 @@ def colorize(style, text):
|
|||
if not is_decorated():
|
||||
return text
|
||||
|
||||
return "{}{}\033[0m".format(STYLES[style], text)
|
||||
return f"{STYLES[style]}{text}\033[0m"
|
||||
|
||||
|
||||
def string_to_bool(value):
|
||||
|
@ -134,38 +150,29 @@ def string_to_bool(value):
|
|||
return value in {"true", "1", "y", "yes"}
|
||||
|
||||
|
||||
def data_dir(version: Optional[str] = None) -> Path:
|
||||
def data_dir() -> Path:
|
||||
if os.getenv("POETRY_HOME"):
|
||||
return Path(os.getenv("POETRY_HOME")).expanduser()
|
||||
|
||||
if WINDOWS:
|
||||
const = "CSIDL_APPDATA"
|
||||
path = os.path.normpath(_get_win_folder(const))
|
||||
path = os.path.join(path, "pypoetry")
|
||||
base_dir = Path(_get_win_folder("CSIDL_APPDATA"))
|
||||
elif MACOS:
|
||||
path = os.path.expanduser("~/Library/Application Support/pypoetry")
|
||||
base_dir = Path("~/Library/Application Support").expanduser()
|
||||
else:
|
||||
path = os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share"))
|
||||
path = os.path.join(path, "pypoetry")
|
||||
base_dir = Path(os.getenv("XDG_DATA_HOME", "~/.local/share")).expanduser()
|
||||
|
||||
if version:
|
||||
path = os.path.join(path, version)
|
||||
|
||||
return Path(path)
|
||||
base_dir = base_dir.resolve()
|
||||
return base_dir / "pypoetry"
|
||||
|
||||
|
||||
def bin_dir(version: Optional[str] = None) -> Path:
|
||||
def bin_dir() -> Path:
|
||||
if os.getenv("POETRY_HOME"):
|
||||
return Path(os.getenv("POETRY_HOME"), "bin").expanduser()
|
||||
|
||||
user_base = site.getuserbase()
|
||||
return Path(os.getenv("POETRY_HOME")).expanduser() / "bin"
|
||||
|
||||
if WINDOWS and not MINGW:
|
||||
bin_dir = os.path.join(user_base, "Scripts")
|
||||
return Path(_get_win_folder("CSIDL_APPDATA")) / "Python/Scripts"
|
||||
else:
|
||||
bin_dir = os.path.join(user_base, "bin")
|
||||
|
||||
return Path(bin_dir)
|
||||
return Path("~/.local/bin").expanduser()
|
||||
|
||||
|
||||
def _get_win_folder_from_registry(csidl_name):
|
||||
|
@ -181,9 +188,9 @@ def _get_win_folder_from_registry(csidl_name):
|
|||
_winreg.HKEY_CURRENT_USER,
|
||||
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):
|
||||
|
@ -262,12 +269,26 @@ POST_MESSAGE_CONFIGURE_FISH = """
|
|||
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:
|
||||
|
||||
A. Append the bin directory to your user environment variable `PATH`:
|
||||
|
||||
```
|
||||
[Environment]::SetEnvironmentVariable("Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";{poetry_home_bin}", "User")
|
||||
```
|
||||
|
||||
B. Tries to appends the bin directory to PATH every when you run PowerShell (>=6 recommended):
|
||||
|
||||
```
|
||||
echo 'if (-not (Get-Command poetry -ErrorAction Ignore)) {{ $env:Path += ";{poetry_home_bin}" }}' | Out-File -Append $PROFILE
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class PoetryInstallationError(RuntimeError):
|
||||
def __init__(self, return_code: int = 0, log: Optional[str] = None):
|
||||
super(PoetryInstallationError, self).__init__()
|
||||
super().__init__()
|
||||
self.return_code = return_code
|
||||
self.log = log
|
||||
|
||||
|
@ -278,7 +299,7 @@ class VirtualEnvironment:
|
|||
self._bin_path = self._path.joinpath(
|
||||
"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._path.joinpath(self._bin_path, "python.exe" if WINDOWS else "python")
|
||||
)
|
||||
|
@ -293,7 +314,18 @@ class VirtualEnvironment:
|
|||
|
||||
@classmethod
|
||||
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:
|
||||
# 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
|
||||
|
||||
builder = venv.EnvBuilder(clear=True, with_pip=True, symlinks=False)
|
||||
|
@ -330,7 +362,7 @@ class VirtualEnvironment:
|
|||
|
||||
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")
|
||||
|
||||
return env
|
||||
|
@ -362,32 +394,32 @@ class Cursor:
|
|||
self._output = sys.stdout
|
||||
|
||||
def move_up(self, lines: int = 1) -> "Cursor":
|
||||
self._output.write("\x1b[{}A".format(lines))
|
||||
self._output.write(f"\x1b[{lines}A")
|
||||
|
||||
return self
|
||||
|
||||
def move_down(self, lines: int = 1) -> "Cursor":
|
||||
self._output.write("\x1b[{}B".format(lines))
|
||||
self._output.write(f"\x1b[{lines}B")
|
||||
|
||||
return self
|
||||
|
||||
def move_right(self, columns: int = 1) -> "Cursor":
|
||||
self._output.write("\x1b[{}C".format(columns))
|
||||
self._output.write(f"\x1b[{columns}C")
|
||||
|
||||
return self
|
||||
|
||||
def move_left(self, columns: int = 1) -> "Cursor":
|
||||
self._output.write("\x1b[{}D".format(columns))
|
||||
self._output.write(f"\x1b[{columns}D")
|
||||
|
||||
return self
|
||||
|
||||
def move_to_column(self, column: int) -> "Cursor":
|
||||
self._output.write("\x1b[{}G".format(column))
|
||||
self._output.write(f"\x1b[{column}G")
|
||||
|
||||
return self
|
||||
|
||||
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
|
||||
|
||||
|
@ -472,9 +504,26 @@ class Installer:
|
|||
self._accept_all = accept_all
|
||||
self._git = git
|
||||
self._path = path
|
||||
self._data_dir = data_dir()
|
||||
self._bin_dir = bin_dir()
|
||||
|
||||
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:
|
||||
return self._preview
|
||||
|
@ -500,18 +549,20 @@ class Installer:
|
|||
mx = self.VERSION_REGEX.match(x)
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
if version and not _is_self_upgrade_supported(version):
|
||||
self._write(
|
||||
colorize(
|
||||
"warning",
|
||||
f"You are installing {version}. When using the current installer, this version does not support "
|
||||
f"updating using the 'self update' command. Please use 1.1.7 or later.",
|
||||
f"You are installing {version}. When using the current installer, "
|
||||
"this version does not support updating using the 'self update' "
|
||||
"command. Please use 1.1.7 or later.",
|
||||
)
|
||||
)
|
||||
if not self._accept_all:
|
||||
|
@ -524,14 +575,14 @@ class Installer:
|
|||
except subprocess.CalledProcessError as e:
|
||||
raise PoetryInstallationError(
|
||||
return_code=e.returncode, log=e.output.decode()
|
||||
)
|
||||
) from e
|
||||
|
||||
self._write("")
|
||||
self.display_post_message(version)
|
||||
|
||||
return 0
|
||||
|
||||
def install(self, version, upgrade=False):
|
||||
def install(self, version):
|
||||
"""
|
||||
Installs Poetry in $POETRY_HOME.
|
||||
"""
|
||||
|
@ -544,13 +595,13 @@ class Installer:
|
|||
with self.make_env(version) as env:
|
||||
self.install_poetry(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")
|
||||
|
||||
return 0
|
||||
|
||||
def uninstall(self) -> int:
|
||||
if not self._data_dir.exists():
|
||||
if not self.data_dir.exists():
|
||||
self._write(
|
||||
"{} is not currently installed.".format(colorize("info", "Poetry"))
|
||||
)
|
||||
|
@ -558,8 +609,8 @@ class Installer:
|
|||
return 1
|
||||
|
||||
version = None
|
||||
if self._data_dir.joinpath("VERSION").exists():
|
||||
version = self._data_dir.joinpath("VERSION").read_text().strip()
|
||||
if self.version_file.exists():
|
||||
version = self.version_file.read_text().strip()
|
||||
|
||||
if version:
|
||||
self._write(
|
||||
|
@ -570,10 +621,10 @@ class Installer:
|
|||
else:
|
||||
self._write("Removing {}".format(colorize("info", "Poetry")))
|
||||
|
||||
shutil.rmtree(str(self._data_dir))
|
||||
for script in ["poetry", "poetry.bat"]:
|
||||
if self._bin_dir.joinpath(script).exists():
|
||||
self._bin_dir.joinpath(script).unlink()
|
||||
shutil.rmtree(str(self.data_dir))
|
||||
for script in ["poetry", "poetry.bat", "poetry.exe"]:
|
||||
if self.bin_dir.joinpath(script).exists():
|
||||
self.bin_dir.joinpath(script).unlink()
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -588,7 +639,7 @@ class Installer:
|
|||
|
||||
@contextmanager
|
||||
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")
|
||||
|
||||
if env_path.exists():
|
||||
|
@ -620,20 +671,20 @@ class Installer:
|
|||
|
||||
def make_bin(self, version: str, env: VirtualEnvironment) -> None:
|
||||
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"
|
||||
target_script = env.bin_path.joinpath(script)
|
||||
|
||||
if self._bin_dir.joinpath(script).exists():
|
||||
self._bin_dir.joinpath(script).unlink()
|
||||
if self.bin_dir.joinpath(script).exists():
|
||||
self.bin_dir.joinpath(script).unlink()
|
||||
|
||||
try:
|
||||
self._bin_dir.joinpath(script).symlink_to(target_script)
|
||||
self.bin_dir.joinpath(script).symlink_to(target_script)
|
||||
except OSError:
|
||||
# This can happen if the user
|
||||
# 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:
|
||||
self._install_comment(version, "Installing Poetry")
|
||||
|
@ -650,7 +701,7 @@ class Installer:
|
|||
def display_pre_message(self) -> None:
|
||||
kwargs = {
|
||||
"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))
|
||||
|
||||
|
@ -667,17 +718,17 @@ class Installer:
|
|||
path = self.get_windows_path_var()
|
||||
|
||||
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
|
||||
|
||||
self._write(
|
||||
message.format(
|
||||
poetry=colorize("info", "Poetry"),
|
||||
version=colorize("b", version),
|
||||
poetry_home_bin=colorize("comment", self._bin_dir),
|
||||
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")),
|
||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
||||
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"),
|
||||
)
|
||||
|
@ -686,11 +737,12 @@ class Installer:
|
|||
def get_windows_path_var(self) -> Optional[str]:
|
||||
import winreg
|
||||
|
||||
with winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) as root:
|
||||
with winreg.OpenKey(root, "Environment", 0, winreg.KEY_ALL_ACCESS) as key:
|
||||
path, _ = winreg.QueryValueEx(key, "PATH")
|
||||
with winreg.ConnectRegistry(
|
||||
None, winreg.HKEY_CURRENT_USER
|
||||
) 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:
|
||||
fish_user_paths = subprocess.check_output(
|
||||
|
@ -698,17 +750,17 @@ class Installer:
|
|||
).decode("utf-8")
|
||||
|
||||
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
|
||||
|
||||
self._write(
|
||||
message.format(
|
||||
poetry=colorize("info", "Poetry"),
|
||||
version=colorize("b", version),
|
||||
poetry_home_bin=colorize("comment", self._bin_dir),
|
||||
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")),
|
||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
||||
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"),
|
||||
)
|
||||
|
@ -718,30 +770,30 @@ class Installer:
|
|||
paths = os.getenv("PATH", "").split(":")
|
||||
|
||||
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
|
||||
|
||||
self._write(
|
||||
message.format(
|
||||
poetry=colorize("info", "Poetry"),
|
||||
version=colorize("b", version),
|
||||
poetry_home_bin=colorize("comment", self._bin_dir),
|
||||
poetry_executable=colorize("b", self._bin_dir.joinpath("poetry")),
|
||||
poetry_home_bin=colorize("comment", self.bin_dir),
|
||||
poetry_executable=colorize("b", self.bin_dir.joinpath("poetry")),
|
||||
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"),
|
||||
)
|
||||
)
|
||||
|
||||
def ensure_directories(self) -> None:
|
||||
self._data_dir.mkdir(parents=True, exist_ok=True)
|
||||
self._bin_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)
|
||||
|
||||
def get_version(self):
|
||||
current_version = None
|
||||
if self._data_dir.joinpath("VERSION").exists():
|
||||
current_version = self._data_dir.joinpath("VERSION").read_text().strip()
|
||||
if self.version_file.exists():
|
||||
current_version = self.version_file.read_text().strip()
|
||||
|
||||
self._write(colorize("info", "Retrieving Poetry metadata"))
|
||||
|
||||
|
@ -751,8 +803,8 @@ class Installer:
|
|||
mx = self.VERSION_REGEX.match(x)
|
||||
my = self.VERSION_REGEX.match(y)
|
||||
|
||||
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),)
|
||||
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))
|
||||
|
||||
if vx < vy:
|
||||
return -1
|
||||
|
@ -767,7 +819,7 @@ class Installer:
|
|||
)
|
||||
|
||||
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))
|
||||
|
||||
raise ValueError(msg)
|
||||
|
@ -785,9 +837,7 @@ class Installer:
|
|||
|
||||
if current_version == version and not self._force:
|
||||
self._write(
|
||||
"The latest version ({}) is already installed.".format(
|
||||
colorize("b", version)
|
||||
)
|
||||
f'The latest version ({colorize("b", version)}) is already installed.'
|
||||
)
|
||||
|
||||
return None, current_version
|
||||
|
@ -898,7 +948,8 @@ def main():
|
|||
text=True,
|
||||
)
|
||||
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)
|
||||
|
||||
return e.return_code
|
||||
|
|
|
@ -1,12 +1,29 @@
|
|||
[tool.isort]
|
||||
profile = "black"
|
||||
force_single_line = true
|
||||
atomic = true
|
||||
lines_after_imports = 2
|
||||
lines_between_types = 1
|
||||
filter_files = true
|
||||
|
||||
|
||||
[tool.black]
|
||||
[tool.ruff]
|
||||
fix = true
|
||||
unfixable = [
|
||||
"ERA", # do not autoremove commented out code
|
||||
]
|
||||
target-version = "py37"
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue