Commit a5d6333f by Sébastien Eustace

Merge branch 'master' into merge-master-into-develop

# Conflicts:
#	.github/workflows/main.yml
#	.github/workflows/release.yml
#	.pre-commit-config.yaml
#	CHANGELOG.md
#	CONTRIBUTING.md
#	docs/docs/cli.md
#	get-poetry.py
#	make-linux-release.sh
#	poetry.lock
#	poetry/__version__.py
#	poetry/console/commands/export.py
#	poetry/console/commands/self/update.py
#	poetry/installation/pip_installer.py
#	poetry/masonry/api.py
#	poetry/masonry/builders/builder.py
#	poetry/masonry/builders/sdist.py
#	poetry/masonry/utils/package_include.py
#	poetry/masonry/utils/tags.py
#	poetry/packages/__init__.py
#	poetry/packages/directory_dependency.py
#	poetry/packages/file_dependency.py
#	poetry/packages/package.py
#	poetry/packages/url_dependency.py
#	poetry/packages/utils/utils.py
#	poetry/packages/vcs_dependency.py
#	poetry/puzzle/provider.py
#	poetry/repositories/installed_repository.py
#	poetry/repositories/legacy_repository.py
#	poetry/repositories/pypi_repository.py
#	poetry/semver/__init__.py
#	poetry/semver/patterns.py
#	poetry/utils/env.py
#	poetry/utils/helpers.py
#	poetry/utils/inspector.py
#	poetry/vcs/__init__.py
#	poetry/vcs/git.py
#	pyproject.toml
#	tests/conftest.py
#	tests/installation/fixtures/with-directory-dependency-poetry-transitive.test
#	tests/json/test_poetry_schema.py
#	tests/masonry/builders/test_sdist.py
#	tests/masonry/builders/test_wheel.py
#	tests/masonry/test_api.py
#	tests/masonry/utils/test_package_include.py
#	tests/packages/test_main.py
#	tests/packages/test_package.py
#	tests/puzzle/test_solver.py
#	tests/repositories/fixtures/installed/vendor/py3.7/attrs-19.3.0.dist-info/METADATA
#	tests/repositories/test_installed_repository.py
#	tests/repositories/test_legacy_repository.py
#	tests/vcs/test_git.py
parents 8d8822ed 6ea3849b
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
name: "\U0001F41E Bug Report" name: "\U0001F41E Bug Report"
about: Did you find a bug? about: Did you find a bug?
title: '' title: ''
labels: 'Bug' labels: Bug, Triage
assignees: '' assignees: ''
--- ---
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
name: "\U0001F4DA Documentation" name: "\U0001F4DA Documentation"
about: Did you find errors, problems, or anything unintelligible in the docs (https://python-poetry.org/docs)? about: Did you find errors, problems, or anything unintelligible in the docs (https://python-poetry.org/docs)?
title: '' title: ''
labels: 'Documentation' labels: Documentation, Triage
assignees: '' assignees: ''
--- ---
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
name: "\U0001F381 Feature Request" name: "\U0001F381 Feature Request"
about: Do you have ideas for new features and improvements? about: Do you have ideas for new features and improvements?
title: '' title: ''
labels: 'Feature' labels: Feature, Triage
assignees: '' assignees: ''
--- ---
......
# Ref: https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser
blank_issues_enabled: true
contact_links:
- name: '💬 Discord Server'
url: https://discordapp.com/invite/awxPgve
about: |
Chat with the community, ask questions and learn about best practices.
# Pull Request Check List # Pull Request Check List
This is just a reminder about the most common mistakes. Please make sure that you tick all *appropriate* boxes. But please read our [contribution guide](https://python-poetry.org/docs/contributing/) at least once, it will save you unnecessary review cycles! Resolves: #issue-number-here
<!-- This is just a reminder about the most common mistakes. Please make sure that you tick all *appropriate* boxes. But please read our [contribution guide](https://python-poetry.org/docs/contributing/) at least once, it will save you unnecessary review cycles! -->
- [ ] Added **tests** for changed code. - [ ] Added **tests** for changed code.
- [ ] Updated **documentation** for changed code. - [ ] Updated **documentation** for changed code.
**Note**: If your Pull Request introduces a new feature or changes the current behavior, it should be based <!-- **Note**: If your Pull Request introduces a new feature or changes the current behavior, it should be based
on the `develop` branch. If it's a bug fix or only a documentation update, it should be based on the `master` branch. on the `develop` branch. If it's a bug fix or only a documentation update, it should be based on the `master` branch. -->
If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! <!-- If you have *any* questions to *any* of the points above, just **submit and ask**! This checklist is here to *help* you, not to deter you from contributing! -->
...@@ -33,7 +33,7 @@ jobs: ...@@ -33,7 +33,7 @@ jobs:
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Get full python version - name: Get full Python version
id: full-python-version id: full-python-version
shell: bash shell: bash
run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")
...@@ -50,7 +50,7 @@ jobs: ...@@ -50,7 +50,7 @@ jobs:
run: poetry config virtualenvs.in-project true run: poetry config virtualenvs.in-project true
- name: Set up cache - name: Set up cache
uses: actions/cache@v1 uses: actions/cache@v2
id: cache id: cache
with: with:
path: .venv path: .venv
......
...@@ -148,32 +148,32 @@ jobs: ...@@ -148,32 +148,32 @@ jobs:
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz name: poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz
path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz path: releases/
- name: Download Linux checksum file - name: Download Linux checksum file
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum name: poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum
path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum path: releases/
- name: Download MacOS release file - name: Download MacOS release file
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz name: poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz
path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz path: releases/
- name: Download MacOS checksum file - name: Download MacOS checksum file
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum name: poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum
path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum path: releases/
- name: Download Windows release file - name: Download Windows release file
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz name: poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz
path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz path: releases/
- name: Download Windows checksum file - name: Download Windows checksum file
uses: actions/download-artifact@master uses: actions/download-artifact@master
with: with:
name: poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum name: poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum
path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum path: releases/
- name: Create Release - name: Create Release
id: create_release id: create_release
uses: actions/create-release@v1 uses: actions/create-release@v1
...@@ -190,7 +190,7 @@ jobs: ...@@ -190,7 +190,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz/poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz
asset_name: poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz asset_name: poetry-${{ steps.tag.outputs.tag }}-linux.tar.gz
asset_content_type: application/gzip asset_content_type: application/gzip
- name: Upload Linux checksum file asset - name: Upload Linux checksum file asset
...@@ -199,16 +199,16 @@ jobs: ...@@ -199,16 +199,16 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum/poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum
asset_name: poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum asset_name: poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum
asset_content_type: text/pain asset_content_type: text/plain
- name: Upload MacOS release file asset - name: Upload MacOS release file asset
uses: actions/upload-release-asset@v1.0.1 uses: actions/upload-release-asset@v1.0.1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz/poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz
asset_name: poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz asset_name: poetry-${{ steps.tag.outputs.tag }}-darwin.tar.gz
asset_content_type: application/gzip asset_content_type: application/gzip
- name: Upload MacOS checksum file asset - name: Upload MacOS checksum file asset
...@@ -217,16 +217,16 @@ jobs: ...@@ -217,16 +217,16 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum/poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum
asset_name: poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum asset_name: poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum
asset_content_type: text/pain asset_content_type: text/plain
- name: Upload Windows release file asset - name: Upload Windows release file asset
uses: actions/upload-release-asset@v1.0.1 uses: actions/upload-release-asset@v1.0.1
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz/poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz
asset_name: poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz asset_name: poetry-${{ steps.tag.outputs.tag }}-win32.tar.gz
asset_content_type: application/gzip asset_content_type: application/gzip
- name: Upload Windows checksum file asset - name: Upload Windows checksum file asset
...@@ -235,9 +235,9 @@ jobs: ...@@ -235,9 +235,9 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:
upload_url: ${{ steps.create_release.outputs.upload_url }} upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum/poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum asset_path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum
asset_name: poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum asset_name: poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum
asset_content_type: text/pain asset_content_type: text/plain
- name: Install Poetry - name: Install Poetry
run: | run: |
python get-poetry.py --preview -y python get-poetry.py --preview -y
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
*.egg *.egg
!/tests/**/*.egg !/tests/**/*.egg
/*.egg-info /*.egg-info
/tests/fixtures/**/*.egg-info
/dist/* /dist/*
build build
_build _build
......
...@@ -10,7 +10,7 @@ repos: ...@@ -10,7 +10,7 @@ repos:
- id: flake8 - id: flake8
- repo: https://github.com/timothycrosley/isort - repo: https://github.com/timothycrosley/isort
rev: 4.3.21 rev: 4.3.21-2
hooks: hooks:
- id: isort - id: isort
additional_dependencies: [toml] additional_dependencies: [toml]
......
...@@ -15,6 +15,34 @@ This release **must** be downloaded via the `get-poetry.py` script and not via t ...@@ -15,6 +15,34 @@ This release **must** be downloaded via the `get-poetry.py` script and not via t
- The exceptions are now beautifully displayed in the terminal with various level of details depending on the verbosity ([2230](https://github.com/python-poetry/poetry/pull/2230)). - The exceptions are now beautifully displayed in the terminal with various level of details depending on the verbosity ([2230](https://github.com/python-poetry/poetry/pull/2230)).
## [1.0.7] - 2020-06-05
### Fixed
- Fixed an error when trying to execute some packages `setup.py` file ([#2349](https://github.com/python-poetry/poetry/pull/2349)).
## [1.0.6] - 2020-06-05
### Changed
- The `self update` command has been updated in order to handle future releases of Poetry ([#2429](https://github.com/python-poetry/poetry/pull/2429)).
### Fixed
- Fixed an error were a new line was not written when displaying the virtual environment's path with `env info` ([#2196](https://github.com/python-poetry/poetry/pull/2196)).
- Fixed a misleading error message when the `packages` property was empty ([#2265](https://github.com/python-poetry/poetry/pull/2265)).
- Fixed shell detection by using environment variables ([#2147](https://github.com/python-poetry/poetry/pull/2147)).
- Fixed the removal of VCS dependencies ([#2239](https://github.com/python-poetry/poetry/pull/2239)).
- Fixed generated wheel ABI tags for Python 3.8 ([#2121](https://github.com/python-poetry/poetry/pull/2121)).
- Fixed a regression when building stub-only packages ([#2000](https://github.com/python-poetry/poetry/pull/2000)).
- Fixed errors when parsing PEP-440 constraints with whitespace ([#2347](https://github.com/python-poetry/poetry/pull/2347)).
- Fixed PEP 508 representation of VCS dependencies ([#2349](https://github.com/python-poetry/poetry/pull/2349)).
- Fixed errors when source distributions were read-only ([#1140](https://github.com/python-poetry/poetry/pull/1140)).
- Fixed dependency resolution errors and inconsistencies with directory, file and VCS dependencies ([#2398](https://github.com/python-poetry/poetry/pull/2398)).
- Fixed custom repositories information not being properly locked ([#2484](https://github.com/python-poetry/poetry/pull/2484)).
## [1.0.5] - 2020-02-29 ## [1.0.5] - 2020-02-29
### Fixed ### Fixed
...@@ -840,6 +868,8 @@ Initial release ...@@ -840,6 +868,8 @@ Initial release
[Unreleased]: https://github.com/python-poetry/poetry/compare/1.1.0a1...develop [Unreleased]: https://github.com/python-poetry/poetry/compare/1.1.0a1...develop
[1.1.0a1]: https://github.com/python-poetry/poetry/releases/tag/1.1.0a1 [1.1.0a1]: https://github.com/python-poetry/poetry/releases/tag/1.1.0a1
[1.0.7]: https://github.com/python-poetry/poetry/releases/tag/1.0.7
[1.0.6]: https://github.com/python-poetry/poetry/releases/tag/1.0.6
[1.0.5]: https://github.com/python-poetry/poetry/releases/tag/1.0.5 [1.0.5]: https://github.com/python-poetry/poetry/releases/tag/1.0.5
[1.0.4]: https://github.com/python-poetry/poetry/releases/tag/1.0.4 [1.0.4]: https://github.com/python-poetry/poetry/releases/tag/1.0.4
[1.0.3]: https://github.com/python-poetry/poetry/releases/tag/1.0.3 [1.0.3]: https://github.com/python-poetry/poetry/releases/tag/1.0.3
......
...@@ -20,7 +20,7 @@ The following is a set of guidelines for contributing to Poetry on GitHub. These ...@@ -20,7 +20,7 @@ The following is a set of guidelines for contributing to Poetry on GitHub. These
This section guides you through submitting a bug report for Poetry. This section guides you through submitting a bug report for Poetry.
Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports. Following these guidelines helps maintainers and the community understand your report, reproduce the behavior, and find related reports.
Before creating bug reports, please check [this list](#before-submitting-a-bug-report) to be sure that you need to create one. When you are creating a bug report, please include as many details as possible. Fill out the [required template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/1_Bug_report.md), the information it asks helps the maintainers resolve the issue faster. Before creating bug reports, please check [this list](#before-submitting-a-bug-report) to be sure that you need to create one. When you are creating a bug report, please include as many details as possible. Fill out the [required template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/---bug-report.md), the information it asks helps the maintainers resolve the issue faster.
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. > **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
...@@ -31,7 +31,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r ...@@ -31,7 +31,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r
#### How do I submit a bug report? #### How do I submit a bug report?
Bugs are tracked on the [official issue tracker](https://github.com/python-poetry/poetry/issues) where you can create a new one and provide the following information by filling in [the template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/1_Bug_report.md). Bugs are tracked on the [official issue tracker](https://github.com/python-poetry/poetry/issues) where you can create a new one and provide the following information by filling in [the template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/---bug-report.md).
Explain the problem and include additional details to help maintainers reproduce the problem: Explain the problem and include additional details to help maintainers reproduce the problem:
...@@ -60,14 +60,13 @@ Include details about your configuration and environment: ...@@ -60,14 +60,13 @@ Include details about your configuration and environment:
This section guides you through submitting an enhancement suggestion for Poetry, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions. This section guides you through submitting an enhancement suggestion for Poetry, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-an-enhancement-suggestion). Fill in [the template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/2_Feature_request.md), including the steps that you imagine you would take if the feature you're requesting existed. Before creating enhancement suggestions, please check [this list](#before-submitting-an-enhancement-suggestion) as you might find out that you don't need to create one. When you are creating an enhancement suggestion, please [include as many details as possible](#how-do-i-submit-an-enhancement-suggestion). Fill in [the template](https://github.com/python-poetry/poetry/blob/master/.github/ISSUE_TEMPLATE/---feature-request.md), including the steps that you imagine you would take if the feature you're requesting existed.
#### Before submitting an enhancement suggestion #### Before submitting an enhancement suggestion
* **Check the [FAQs on the official website](https://python-poetry.org/docs/faq)** for a list of common questions and problems. * **Check the [FAQs on the official website](https://python-poetry.org/docs/faq)** for a list of common questions and problems.
* **Check that your issue does not already exist in the [issue tracker](https://github.com/python-poetry/poetry/issues)**. * **Check that your issue does not already exist in the [issue tracker](https://github.com/python-poetry/poetry/issues)**.
#### How do I submit an Enhancement suggestion? #### How do I submit an Enhancement suggestion?
Enhancement suggestions are tracked on the [official issue tracker](https://github.com/python-poetry/poetry/issues) where you can create a new one and provide the following information: Enhancement suggestions are tracked on the [official issue tracker](https://github.com/python-poetry/poetry/issues) where you can create a new one and provide the following information:
......
...@@ -86,17 +86,27 @@ See `poetry help completions` for full details, but the gist is as simple as usi ...@@ -86,17 +86,27 @@ See `poetry help completions` for full details, but the gist is as simple as usi
# Bash # Bash
poetry completions bash > /etc/bash_completion.d/poetry.bash-completion poetry completions bash > /etc/bash_completion.d/poetry.bash-completion
# Bash (macOS/Homebrew) # Bash (Homebrew)
poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion
# Fish # Fish
poetry completions fish > ~/.config/fish/completions/poetry.fish poetry completions fish > ~/.config/fish/completions/poetry.fish
# Fish (Homebrew)
poetry completions fish > (brew --prefix)/share/fish/vendor_completions.d/poetry.fish
# Zsh # Zsh
poetry completions zsh > ~/.zfunc/_poetry poetry completions zsh > ~/.zfunc/_poetry
# Zsh (macOS/Homebrew) # Zsh (Homebrew)
poetry completions zsh > $(brew --prefix)/share/zsh/site-functions/_poetry poetry completions zsh > $(brew --prefix)/share/zsh/site-functions/_poetry
# Zsh (Oh-My-Zsh)
mkdir $ZSH/plugins/poetry
poetry completions zsh > $ZSH/plugins/poetry/_poetry
# Zsh (prezto)
poetry completions zsh > ~/.zprezto/modules/completion/external/src/_poetry
``` ```
*Note:* you may need to restart your shell in order for the changes to take *Note:* you may need to restart your shell in order for the changes to take
......
...@@ -77,7 +77,7 @@ how versions relate to each other, and on the different ways you can specify dep ...@@ -77,7 +77,7 @@ how versions relate to each other, and on the different ways you can specify dep
**How does Poetry download the right files?** **How does Poetry download the right files?**
When you specify a dependency in `pyproject.toml`, Poetry first take the name of the package When you specify a dependency in `pyproject.toml`, Poetry first takes the name of the package
that you have requested and searches for it in any repository you have registered using the `repositories` key. that you have requested and searches for it in any repository you have registered using the `repositories` key.
If you have not registered any extra repositories, or it does not find a package with that name in the If you have not registered any extra repositories, or it does not find a package with that name in the
repositories you have specified, it falls back on PyPI. repositories you have specified, it falls back on PyPI.
...@@ -134,6 +134,15 @@ the dependencies installed are still working even if your dependencies released ...@@ -134,6 +134,15 @@ the dependencies installed are still working even if your dependencies released
For libraries it is not necessary to commit the lock file. For libraries it is not necessary to commit the lock file.
### Installing dependencies only
The current project is installed in [editable](https://pip.pypa.io/en/stable/reference/pip_install/#editable-installs) mode by default.
If you want to install the dependencies only, run the `install` command with the `--no-root` flag:
```bash
poetry install --no-root
```
## Updating dependencies to their latest versions ## Updating dependencies to their latest versions
......
...@@ -6,15 +6,6 @@ This chapter documents all the available commands. ...@@ -6,15 +6,6 @@ This chapter documents all the available commands.
To get help from the command-line, simply call `poetry` to see the complete list of commands, To get help from the command-line, simply call `poetry` to see the complete list of commands,
then `--help` combined with any of those can give you more information. then `--help` combined with any of those can give you more information.
As `Poetry` uses [cleo](https://github.com/sdispater/cleo) you can call commands by short name if it's not ambiguous.
```bash
poetry up
```
calls `poetry update`.
## Global options ## Global options
* `--verbose (-v|vv|vvv)`: Increase the verbosity of messages: "-v" for normal output, "-vv" for more verbose output and "-vvv" for debug. * `--verbose (-v|vv|vvv)`: Increase the verbosity of messages: "-v" for normal output, "-vv" for more verbose output and "-vvv" for debug.
...@@ -172,6 +163,11 @@ If you just want to update a few packages and not all, you can list them as such ...@@ -172,6 +163,11 @@ If you just want to update a few packages and not all, you can list them as such
poetry update requests toml poetry update requests toml
``` ```
Note that this will not update versions for dependencies outside their version constraints specified
in the `pyproject.toml` file. In other terms, `poetry update foo` will be a no-op if the version constraint
specified for `foo` is `~2.3` or `2.3` and `2.4` is available. In order for `foo` to be updated, you must
update the constraint, for example `^2.3`. You can do this using the `add` command.
### Options ### Options
* `--dry-run` : Outputs the operations but will not execute anything (implicitly enables --verbose). * `--dry-run` : Outputs the operations but will not execute anything (implicitly enables --verbose).
...@@ -428,9 +424,23 @@ This command shows the current version of the project or bumps the version of ...@@ -428,9 +424,23 @@ This command shows the current version of the project or bumps the version of
the project and writes the new version back to `pyproject.toml` if a valid the project and writes the new version back to `pyproject.toml` if a valid
bump rule is provided. bump rule is provided.
The new version should ideally be a valid semver string or a valid bump rule: The new version should ideally be a valid [semver](https://semver.org/) string or a valid bump rule:
`patch`, `minor`, `major`, `prepatch`, `preminor`, `premajor`, `prerelease`. `patch`, `minor`, `major`, `prepatch`, `preminor`, `premajor`, `prerelease`.
The table below illustrates the effect of these rules with concrete examples.
| rule | before | after |
|------------|---------------|---------------|
| major | 1.3.0 | 2.0.0 |
| minor | 2.1.4 | 2.2.0 |
| patch | 4.1.1 | 4.1.2 |
| premajor | 1.0.2 | 2.0.0-alpha.0 |
| preminor | 1.0.2 | 1.1.0-alpha.0 |
| prepatch | 1.0.2 | 1.0.3-alpha.0 |
| prerelease | 1.0.2 | 1.0.3-alpha.0 |
| prerelease | 1.0.3-alpha.0 | 1.0.3-alpha.1 |
| prerelease | 1.0.3-beta.0 | 1.0.3-beta.1 |
## Options ## Options
* `--short (-s)`: Output the version number only. * `--short (-s)`: Output the version number only.
...@@ -463,7 +473,7 @@ poetry export -f requirements.txt > requirements.txt ...@@ -463,7 +473,7 @@ poetry export -f requirements.txt > requirements.txt
The `env` command regroups sub commands to interact with the virtualenvs The `env` command regroups sub commands to interact with the virtualenvs
associated with a specific project. associated with a specific project.
See [Managing environments](./managing-environments.md) for more information about these commands. See [Managing environments](/docs/managing-environments.md) for more information about these commands.
## cache ## cache
......
...@@ -42,7 +42,7 @@ If you only specify a major version, then minor- and patch-level changes are all ...@@ -42,7 +42,7 @@ If you only specify a major version, then minor- and patch-level changes are all
### Wildcard requirements ### Wildcard requirements
**Wildcard requirements** allow for any version where the wildcard is positioned. **Wildcard requirements** allow for the latest (dependency dependent) version where the wildcard is positioned.
`*`, `1.*` and `1.2.*` are examples of wildcard requirements. `*`, `1.*` and `1.2.*` are examples of wildcard requirements.
...@@ -179,6 +179,34 @@ foo = [ ...@@ -179,6 +179,34 @@ foo = [
] ]
``` ```
## Expanded dependency specification syntax
In the case of more complex dependency specifications, you may find that you
end up with lines which are very long and difficult to read. In these cases,
you can shift from using "inline table" syntax, to the "standard table" syntax.
An example where this might be useful is the following:
```toml
[tool.poetry.dev-dependencies]
black = {version = "19.10b0", allow-prereleases = true, python = "^3.6", markers = "platform_python_implementation == 'CPython'}
```
As a single line, this is a lot to digest. To make this a little bit easier to
work with, you can do the following:
```toml
[tool.poetry.dev-dependencies.black]
version = "19.10b0"
allow-prereleases = true
python = "^3.6"
markers = "platform_python_implementation == 'CPython'"
```
All of the same information is still present, and ends up providing the exact
same specification. It's simply split into multiple, slightly more readable,
lines.
!!!note !!!note
The constraints **must** have different requirements (like `python`) The constraints **must** have different requirements (like `python`)
......
...@@ -28,7 +28,7 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet ...@@ -28,7 +28,7 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet
!!! note !!! note
You only need to install Poetry once. It will automatically pick up the current You only need to install Poetry once. It will automatically pick up the current
Python version and use it to [create virtualenvs](/docs/basic-usage/#poetry-and-virtualenvs) accordingly. Python version and use it to [create virtualenvs](/docs/managing-environments.md) accordingly.
The installer installs the `poetry` tool to Poetry's `bin` directory. The installer installs the `poetry` tool to Poetry's `bin` directory.
On Unix it is located at `$HOME/.poetry/bin` and on Windows at `%USERPROFILE%\.poetry\bin`. On Unix it is located at `$HOME/.poetry/bin` and on Windows at `%USERPROFILE%\.poetry\bin`.
...@@ -161,12 +161,15 @@ See `poetry help completions` for full details, but the gist is as simple as usi ...@@ -161,12 +161,15 @@ See `poetry help completions` for full details, but the gist is as simple as usi
# Bash # Bash
poetry completions bash > /etc/bash_completion.d/poetry.bash-completion poetry completions bash > /etc/bash_completion.d/poetry.bash-completion
# Bash (macOS/Homebrew) # Bash (Homebrew)
poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion poetry completions bash > $(brew --prefix)/etc/bash_completion.d/poetry.bash-completion
# Fish # Fish
poetry completions fish > ~/.config/fish/completions/poetry.fish poetry completions fish > ~/.config/fish/completions/poetry.fish
# Fish (Homebrew)
poetry completions fish > (brew --prefix)/share/fish/vendor_completions.d/poetry.fish
# Zsh # Zsh
poetry completions zsh > ~/.zfunc/_poetry poetry completions zsh > ~/.zfunc/_poetry
...@@ -174,6 +177,9 @@ poetry completions zsh > ~/.zfunc/_poetry ...@@ -174,6 +177,9 @@ poetry completions zsh > ~/.zfunc/_poetry
mkdir $ZSH/plugins/poetry mkdir $ZSH/plugins/poetry
poetry completions zsh > $ZSH/plugins/poetry/_poetry poetry completions zsh > $ZSH/plugins/poetry/_poetry
# prezto
poetry completions zsh > ~/.zprezto/modules/completion/external/src/_poetry
``` ```
!!! note !!! note
......
...@@ -118,4 +118,4 @@ poetry env remove 3.7 ...@@ -118,4 +118,4 @@ poetry env remove 3.7
poetry env remove test-O3eWbxRl-py3.7 poetry env remove test-O3eWbxRl-py3.7
``` ```
If your remove the currently activated virtual environment, it will be automatically deactivated. If you remove the currently activated virtual environment, it will be automatically deactivated.
...@@ -40,6 +40,10 @@ The recommended notation for the most common licenses is (alphabetical): ...@@ -40,6 +40,10 @@ The recommended notation for the most common licenses is (alphabetical):
Optional, but it is highly recommended to supply this. Optional, but it is highly recommended to supply this.
More identifiers are listed at the [SPDX Open Source License Registry](https://www.spdx.org/licenses/). More identifiers are listed at the [SPDX Open Source License Registry](https://www.spdx.org/licenses/).
!!!note
If your project is proprietary and does not use a specific licence, you can set this value as `Proprietary`.
## authors ## authors
The authors of the package. **Required** The authors of the package. **Required**
...@@ -127,11 +131,11 @@ it by using `format`: ...@@ -127,11 +131,11 @@ it by using `format`:
# ... # ...
packages = [ packages = [
{ include = "my_package" }, { include = "my_package" },
{ include = "tests", format = "sdist" }, { include = "my_other_package", format = "sdist" },
] ]
``` ```
From now on, only the `sdist` build archive will include the `tests` package. From now on, only the `sdist` build archive will include the `my_other_package` package.
!!!note !!!note
......
...@@ -19,7 +19,7 @@ class EnvInfoCommand(Command): ...@@ -19,7 +19,7 @@ class EnvInfoCommand(Command):
if not env.is_venv(): if not env.is_venv():
return 1 return 1
self.write(str(env.path)) self.line(str(env.path))
return return
......
...@@ -14,7 +14,7 @@ class ExportCommand(Command): ...@@ -14,7 +14,7 @@ class ExportCommand(Command):
option( option(
"format", "format",
"f", "f",
"Format to export to.", "Format to export to. Currently, only requirements.txt is supported.",
flag=False, flag=False,
default=Exporter.FORMAT_REQUIREMENTS_TXT, default=Exporter.FORMAT_REQUIREMENTS_TXT,
), ),
......
...@@ -151,7 +151,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the ...@@ -151,7 +151,7 @@ The <c1>init</c1> command creates a basic <comment>pyproject.toml</> file in the
" - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n" " - A git url with a revision (<b>git+https://github.com/python-poetry/poetry.git#develop</b>)\n"
" - A file path (<b>../my-package/my-package.whl</b>)\n" " - A file path (<b>../my-package/my-package.whl</b>)\n"
" - A directory (<b>../my-package/</b>)\n" " - A directory (<b>../my-package/</b>)\n"
" - An url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>)\n" " - A url (<b>https://example.com/packages/my-package-0.1.0.tar.gz</b>)\n"
) )
help_displayed = False help_displayed = False
if self.confirm(question, True): if self.confirm(question, True):
......
...@@ -37,6 +37,12 @@ libraries and dependencies outlined in that file. If the file does not ...@@ -37,6 +37,12 @@ libraries and dependencies outlined in that file. If the file does not
exist it will look for <comment>pyproject.toml</> and do the same. exist it will look for <comment>pyproject.toml</> and do the same.
<info>poetry install</info> <info>poetry install</info>
By default, the above command will also install the current project. To install only the
dependencies and not including the current project, run the command with the
<info>--no-root</info> option like below:
<info> poetry install --no-root</info>
""" """
_loggers = ["poetry.repositories.pypi_repository"] _loggers = ["poetry.repositories.pypi_repository"]
......
from __future__ import unicode_literals
import hashlib import hashlib
import os import os
import re
import shutil import shutil
import stat
import subprocess import subprocess
import sys import sys
import tarfile import tarfile
...@@ -22,6 +26,27 @@ except ImportError: ...@@ -22,6 +26,27 @@ except ImportError:
from urllib2 import urlopen from urllib2 import urlopen
BIN = """# -*- coding: utf-8 -*-
import glob
import sys
import os
lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "../..", "lib"))
vendors = os.path.join(lib, "poetry", "_vendor")
current_vendors = os.path.join(
vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2]))
)
sys.path.insert(0, lib)
sys.path.insert(0, current_vendors)
if __name__ == "__main__":
from poetry.console import main
main()
"""
BAT = '@echo off\r\n{python_executable} "{poetry_bin}" %*\r\n'
class SelfUpdateCommand(Command): class SelfUpdateCommand(Command):
name = "update" name = "update"
...@@ -32,7 +57,6 @@ class SelfUpdateCommand(Command): ...@@ -32,7 +57,6 @@ class SelfUpdateCommand(Command):
REPOSITORY_URL = "https://github.com/python-poetry/poetry" REPOSITORY_URL = "https://github.com/python-poetry/poetry"
BASE_URL = REPOSITORY_URL + "/releases/download" BASE_URL = REPOSITORY_URL + "/releases/download"
FALLBACK_BASE_URL = "https://github.com/sdispater/poetry/releases/download"
@property @property
def home(self): def home(self):
...@@ -41,6 +65,10 @@ class SelfUpdateCommand(Command): ...@@ -41,6 +65,10 @@ class SelfUpdateCommand(Command):
return Path(os.environ.get("POETRY_HOME", "~/.poetry")).expanduser() return Path(os.environ.get("POETRY_HOME", "~/.poetry")).expanduser()
@property @property
def bin(self):
return self.home / "bin"
@property
def lib(self): def lib(self):
return self.home / "lib" return self.home / "lib"
...@@ -52,16 +80,8 @@ class SelfUpdateCommand(Command): ...@@ -52,16 +80,8 @@ class SelfUpdateCommand(Command):
from poetry.__version__ import __version__ from poetry.__version__ import __version__
from poetry.repositories.pypi_repository import PyPiRepository from poetry.repositories.pypi_repository import PyPiRepository
from poetry.core.semver import Version from poetry.core.semver import Version
from poetry.utils._compat import Path
current = Path(__file__) self._check_recommended_installation()
try:
current.relative_to(self.home)
except ValueError:
raise RuntimeError(
"Poetry was not installed with the recommended installer. "
"Cannot update automatically."
)
version = self.argument("version") version = self.argument("version")
if not version: if not version:
...@@ -133,6 +153,8 @@ class SelfUpdateCommand(Command): ...@@ -133,6 +153,8 @@ class SelfUpdateCommand(Command):
if self.lib_backup.exists(): if self.lib_backup.exists():
shutil.rmtree(str(self.lib_backup)) shutil.rmtree(str(self.lib_backup))
self.make_bin()
self.line("") self.line("")
self.line("") self.line("")
self.line( self.line(
...@@ -144,20 +166,11 @@ class SelfUpdateCommand(Command): ...@@ -144,20 +166,11 @@ class SelfUpdateCommand(Command):
def _update(self, version): def _update(self, version):
from poetry.utils.helpers import temporary_directory from poetry.utils.helpers import temporary_directory
platform = sys.platform release_name = self._get_release_name(version)
if platform == "linux2":
platform = "linux"
checksum = "poetry-{}-{}.sha256sum".format(version, platform) checksum = "{}.sha256sum".format(release_name)
base_url = self.BASE_URL base_url = self.BASE_URL
try:
urlopen(self.REPOSITORY_URL)
except HTTPError as e:
if e.code == 404:
base_url = self.FALLBACK_BASE_URL
else:
raise
try: try:
r = urlopen(base_url + "/{}/{}".format(version, checksum)) r = urlopen(base_url + "/{}/{}".format(version, checksum))
...@@ -167,10 +180,10 @@ class SelfUpdateCommand(Command): ...@@ -167,10 +180,10 @@ class SelfUpdateCommand(Command):
raise raise
checksum = r.read().decode() checksum = r.read().decode().strip()
# We get the payload from the remote host # We get the payload from the remote host
name = "poetry-{}-{}.tar.gz".format(version, platform) name = "{}.tar.gz".format(release_name)
try: try:
r = urlopen(base_url + "/{}/{}".format(version, name)) r = urlopen(base_url + "/{}/{}".format(version, name))
except HTTPError as e: except HTTPError as e:
...@@ -223,8 +236,94 @@ class SelfUpdateCommand(Command): ...@@ -223,8 +236,94 @@ class SelfUpdateCommand(Command):
def process(self, *args): def process(self, *args):
return subprocess.check_output(list(args), stderr=subprocess.STDOUT) return subprocess.check_output(list(args), stderr=subprocess.STDOUT)
def _check_recommended_installation(self):
from poetry.utils._compat import Path
current = Path(__file__)
try:
current.relative_to(self.home)
except ValueError:
raise RuntimeError(
"Poetry was not installed with the recommended installer. "
"Cannot update automatically."
)
def _get_release_name(self, version):
platform = sys.platform
if platform == "linux2":
platform = "linux"
return "poetry-{}-{}".format(version, platform)
def _bin_path(self, base_path, bin): def _bin_path(self, base_path, bin):
if sys.platform == "win32": from poetry.utils._compat import WINDOWS
if WINDOWS:
return (base_path / "Scripts" / bin).with_suffix(".exe") return (base_path / "Scripts" / bin).with_suffix(".exe")
return base_path / "bin" / bin return base_path / "bin" / bin
def make_bin(self):
from poetry.utils._compat import WINDOWS
self.bin.mkdir(0o755, parents=True, exist_ok=True)
python_executable = self._which_python()
if WINDOWS:
with self.bin.joinpath("poetry.bat").open("w", newline="") as f:
f.write(
BAT.format(
python_executable=python_executable,
poetry_bin=str(self.bin / "poetry").replace(
os.environ["USERPROFILE"], "%USERPROFILE%"
),
)
)
bin_content = BIN
if not WINDOWS:
bin_content = "#!/usr/bin/env {}\n".format(python_executable) + bin_content
self.bin.joinpath("poetry").write_text(bin_content, encoding="utf-8")
if not WINDOWS:
# Making the file executable
st = os.stat(str(self.bin.joinpath("poetry")))
os.chmod(str(self.bin.joinpath("poetry")), st.st_mode | stat.S_IEXEC)
def _which_python(self):
"""
Decides which python executable we'll embed in the launcher script.
"""
from poetry.utils._compat import WINDOWS
allowed_executables = ["python", "python3"]
if WINDOWS:
allowed_executables += ["py.exe -3", "py.exe -2"]
# \d in regex ensures we can convert to int later
version_matcher = re.compile(r"^Python (?P<major>\d+)\.(?P<minor>\d+)\..+$")
fallback = None
for executable in allowed_executables:
try:
raw_version = subprocess.check_output(
executable + " --version", stderr=subprocess.STDOUT, shell=True
).decode("utf-8")
except subprocess.CalledProcessError:
continue
match = version_matcher.match(raw_version.strip())
if match and tuple(map(int, match.groups())) >= (3, 0):
# favor the first py3 executable we can find.
return executable
if fallback is None:
# keep this one as the fallback; it was the first valid executable we found.
fallback = executable
if fallback is None:
# Avoid breaking existing scripts
fallback = "python"
return fallback
...@@ -422,10 +422,7 @@ class PackageInfo: ...@@ -422,10 +422,7 @@ class PackageInfo:
os.chdir(str(path)) os.chdir(str(path))
# Execute egg_info # Execute egg_info
with temporary_directory() as tmp_dir: cls._execute_setup()
EnvManager.build_venv(tmp_dir)
venv = VirtualEnv(Path(tmp_dir), Path(tmp_dir))
venv.run("python", "setup.py", "egg_info")
except EnvCommandError: except EnvCommandError:
cls._log( cls._log(
"Falling back to parsing setup.py file for {}".format(path), "debug" "Falling back to parsing setup.py file for {}".format(path), "debug"
...@@ -497,3 +494,10 @@ class PackageInfo: ...@@ -497,3 +494,10 @@ class PackageInfo:
return cls.from_bdist(path=path) return cls.from_bdist(path=path)
except PackageInfoError: except PackageInfoError:
return cls.from_sdist(path=path) return cls.from_sdist(path=path)
@classmethod
def _execute_setup(cls):
with temporary_directory() as tmp_dir:
EnvManager.build_venv(tmp_dir)
venv = VirtualEnv(Path(tmp_dir), Path(tmp_dir))
venv.run("python", "setup.py", "egg_info")
...@@ -103,12 +103,6 @@ class PipInstaller(BaseInstaller): ...@@ -103,12 +103,6 @@ class PipInstaller(BaseInstaller):
self.install(target, update=True) self.install(target, update=True)
def remove(self, package): def remove(self, package):
# If we have a VCS package, remove its source directory
if package.source_type == "git":
src_dir = self._env.path / "src" / package.name
if src_dir.exists():
safe_rmtree(str(src_dir))
try: try:
self.run("uninstall", package.name, "-y") self.run("uninstall", package.name, "-y")
except CalledProcessError as e: except CalledProcessError as e:
...@@ -117,6 +111,17 @@ class PipInstaller(BaseInstaller): ...@@ -117,6 +111,17 @@ class PipInstaller(BaseInstaller):
raise raise
# This is a workaround for https://github.com/pypa/pip/issues/4176
nspkg_pth_file = self._env.site_packages / "{}-nspkg.pth".format(package.name)
if nspkg_pth_file.exists():
nspkg_pth_file.unlink()
# If we have a VCS package, remove its source directory
if package.source_type == "git":
src_dir = self._env.path / "src" / package.name
if src_dir.exists():
safe_rmtree(str(src_dir))
def run(self, *args, **kwargs): # type: (...) -> str def run(self, *args, **kwargs): # type: (...) -> str
return self._env.run_pip(*args, **kwargs) return self._env.run_pip(*args, **kwargs)
......
...@@ -339,6 +339,16 @@ class VersionSolver: ...@@ -339,6 +339,16 @@ class VersionSolver:
if dependency.name in self._locked: if dependency.name in self._locked:
return 1 return 1
# VCS, URL, File or Directory dependencies
# represent a single version
if (
dependency.is_vcs()
or dependency.is_url()
or dependency.is_file()
or dependency.is_directory()
):
return 1
try: try:
return len(self._provider.search_for(dependency)) return len(self._provider.search_for(dependency))
except ValueError: except ValueError:
......
...@@ -65,6 +65,7 @@ class Provider: ...@@ -65,6 +65,7 @@ class Provider:
self._is_debugging = self._io.is_debug() or self._io.is_very_verbose() self._is_debugging = self._io.is_debug() or self._io.is_very_verbose()
self._in_progress = False self._in_progress = False
self._overrides = {} self._overrides = {}
self._deferred_cache = {}
@property @property
def pool(self): # type: () -> Pool def pool(self): # type: () -> Pool
...@@ -156,6 +157,9 @@ class Provider: ...@@ -156,6 +157,9 @@ class Provider:
Basically, we clone the repository in a temporary directory Basically, we clone the repository in a temporary directory
and get the information we need by checking out the specified reference. and get the information we need by checking out the specified reference.
""" """
if dependency in self._deferred_cache:
return [self._deferred_cache[dependency]]
package = self.get_package_from_vcs( package = self.get_package_from_vcs(
dependency.vcs, dependency.vcs,
dependency.source, dependency.source,
...@@ -170,6 +174,11 @@ class Provider: ...@@ -170,6 +174,11 @@ class Provider:
package.requires += package.extras[extra] package.requires += package.extras[extra]
dependency._constraint = package.version
dependency._pretty_constraint = package.version.text
self._deferred_cache[dependency] = package
return [package] return [package]
@classmethod @classmethod
...@@ -206,7 +215,17 @@ class Provider: ...@@ -206,7 +215,17 @@ class Provider:
return package return package
def search_for_file(self, dependency): # type: (FileDependency) -> List[Package] def search_for_file(self, dependency): # type: (FileDependency) -> List[Package]
package = self.get_package_from_file(dependency.full_path) if dependency in self._deferred_cache:
dependency, _package = self._deferred_cache[dependency]
package = _package.clone()
else:
package = self.get_package_from_file(dependency.full_path)
dependency._constraint = package.version
dependency._pretty_constraint = package.version.text
self._deferred_cache[dependency] = (dependency, package)
if dependency.name != package.name: if dependency.name != package.name:
# For now, the dependency's name must match the actual package's name # For now, the dependency's name must match the actual package's name
...@@ -216,6 +235,9 @@ class Provider: ...@@ -216,6 +235,9 @@ class Provider:
) )
) )
if dependency.base is not None:
package.root_dir = dependency.base
package.source_url = dependency.path.as_posix() package.source_url = dependency.path.as_posix()
package.files = [ package.files = [
{"file": dependency.path.name, "hash": "sha256:" + dependency.hash()} {"file": dependency.path.name, "hash": "sha256:" + dependency.hash()}
...@@ -249,15 +271,25 @@ class Provider: ...@@ -249,15 +271,25 @@ class Provider:
def search_for_directory( def search_for_directory(
self, dependency self, dependency
): # type: (DirectoryDependency) -> List[Package] ): # type: (DirectoryDependency) -> List[Package]
package = self.get_package_from_directory( if dependency in self._deferred_cache:
dependency.full_path, name=dependency.name dependency, _package = self._deferred_cache[dependency]
)
package = _package.clone()
else:
package = self.get_package_from_directory(
dependency.full_path, name=dependency.name
)
dependency._constraint = package.version
dependency._pretty_constraint = package.version.text
self._deferred_cache[dependency] = (dependency, package)
package.source_url = dependency.path.as_posix() package.source_url = dependency.path.as_posix()
package.develop = dependency.develop package.develop = dependency.develop
if dependency.base is not None: if dependency.base is not None:
package.root_dir = dependency.base.as_posix() package.root_dir = dependency.base
for extra in dependency.extras: for extra in dependency.extras:
if extra in package.extras: if extra in package.extras:
...@@ -275,6 +307,7 @@ class Provider: ...@@ -275,6 +307,7 @@ class Provider:
package = PackageInfo.from_directory( package = PackageInfo.from_directory(
path=directory, allow_build=True path=directory, allow_build=True
).to_package(root_dir=directory) ).to_package(root_dir=directory)
if name and name != package.name: if name and name != package.name:
# For now, the dependency's name must match the actual package's name # For now, the dependency's name must match the actual package's name
raise RuntimeError( raise RuntimeError(
...@@ -289,6 +322,9 @@ class Provider: ...@@ -289,6 +322,9 @@ class Provider:
return package return package
def search_for_url(self, dependency): # type: (URLDependency) -> List[Package] def search_for_url(self, dependency): # type: (URLDependency) -> List[Package]
if dependency in self._deferred_cache:
return [self._deferred_cache[dependency]]
package = self.get_package_from_url(dependency.url) package = self.get_package_from_url(dependency.url)
if dependency.name != package.name: if dependency.name != package.name:
...@@ -306,6 +342,11 @@ class Provider: ...@@ -306,6 +342,11 @@ class Provider:
package.requires += package.extras[extra] package.requires += package.extras[extra]
dependency._constraint = package.version
dependency._pretty_constraint = package.version.text
self._deferred_cache[dependency] = package
return [package] return [package]
@classmethod @classmethod
...@@ -422,6 +463,17 @@ class Provider: ...@@ -422,6 +463,17 @@ class Provider:
else: else:
requires = package.requires requires = package.requires
# Retrieving constraints for deferred dependencies
for r in requires:
if r.is_directory():
self.search_for_directory(r)
elif r.is_file():
self.search_for_file(r)
elif r.is_vcs():
self.search_for_vcs(r)
elif r.is_url():
self.search_for_url(r)
_dependencies = [ _dependencies = [
r r
for r in requires for r in requires
...@@ -628,15 +680,15 @@ class Provider: ...@@ -628,15 +680,15 @@ class Provider:
if (package.dependency.is_directory() or package.dependency.is_file()) and ( if (package.dependency.is_directory() or package.dependency.is_file()) and (
dep.is_directory() or dep.is_file() dep.is_directory() or dep.is_file()
): ):
if dep.path.as_posix().startswith(package.source_url): relative_path = Path(
relative = (Path(package.source_url) / dep.path).relative_to( os.path.relpath(
package.source_url dep.full_path.as_posix(), package.root_dir.as_posix()
) )
else: )
relative = Path(package.source_url) / dep.path
# TODO: Improve the way we set the correct relative path for dependencies # TODO: Improve the way we set the correct relative path for dependencies
dep._path = relative dep._path = relative_path
clean_dependencies.append(dep) clean_dependencies.append(dep)
package.requires = clean_dependencies package.requires = clean_dependencies
......
...@@ -264,6 +264,8 @@ class LegacyRepository(PyPiRepository): ...@@ -264,6 +264,8 @@ class LegacyRepository(PyPiRepository):
for version in versions: for version in versions:
package = Package(name, version) package = Package(name, version)
package.source_type = "legacy"
package.source_reference = self.name
package.source_url = self._url package.source_url = self._url
if extras is not None: if extras is not None:
...@@ -296,7 +298,10 @@ class LegacyRepository(PyPiRepository): ...@@ -296,7 +298,10 @@ class LegacyRepository(PyPiRepository):
return self._packages[index] return self._packages[index]
except ValueError: except ValueError:
package = super(LegacyRepository, self).package(name, version, extras) package = super(LegacyRepository, self).package(name, version, extras)
package.source_type = "legacy"
package.source_url = self._url package.source_url = self._url
package.source_reference = self.name
return package return package
def _get_release_info(self, name, version): # type: (str, str) -> dict def _get_release_info(self, name, version): # type: (str, str) -> dict
......
...@@ -1188,6 +1188,7 @@ class MockEnv(NullEnv): ...@@ -1188,6 +1188,7 @@ class MockEnv(NullEnv):
pip_version="19.1", pip_version="19.1",
sys_path=None, sys_path=None,
marker_env=None, marker_env=None,
config_vars=None,
**kwargs **kwargs
): ):
super(MockEnv, self).__init__(**kwargs) super(MockEnv, self).__init__(**kwargs)
...@@ -1200,6 +1201,15 @@ class MockEnv(NullEnv): ...@@ -1200,6 +1201,15 @@ class MockEnv(NullEnv):
self._pip_version = Version.parse(pip_version) self._pip_version = Version.parse(pip_version)
self._sys_path = sys_path self._sys_path = sys_path
self._mock_marker_env = marker_env self._mock_marker_env = marker_env
self._config_vars = config_vars
@property
def version_info(self): # type: () -> Tuple[int]
return self._version_info
@property
def python_implementation(self): # type: () -> str
return self._python_implementation
@property @property
def platform(self): # type: () -> str def platform(self): # type: () -> str
...@@ -1234,3 +1244,12 @@ class MockEnv(NullEnv): ...@@ -1234,3 +1244,12 @@ class MockEnv(NullEnv):
def is_venv(self): # type: () -> bool def is_venv(self): # type: () -> bool
return self._is_venv return self._is_venv
def config_var(self, var): # type: (str) -> Any
if self._config_vars is None:
return super().config_var(var)
else:
try:
return self._config_vars[var]
except KeyError:
return None
...@@ -35,19 +35,18 @@ def normalize_version(version): # type: (str) -> str ...@@ -35,19 +35,18 @@ def normalize_version(version): # type: (str) -> str
return str(Version(version)) return str(Version(version))
def _del_ro(action, name, exc):
os.chmod(name, stat.S_IWRITE)
os.remove(name)
@contextmanager @contextmanager
def temporary_directory(*args, **kwargs): def temporary_directory(*args, **kwargs):
try: name = tempfile.mkdtemp(*args, **kwargs)
from tempfile import TemporaryDirectory
with TemporaryDirectory(*args, **kwargs) as name:
yield name
except ImportError:
name = tempfile.mkdtemp(*args, **kwargs)
yield name yield name
shutil.rmtree(name) shutil.rmtree(name, onerror=_del_ro)
def get_cert(config, repository_name): # type: (Config, str) -> Optional[Path] def get_cert(config, repository_name): # type: (Config, str) -> Optional[Path]
......
...@@ -9,6 +9,7 @@ from shellingham import ShellDetectionFailure ...@@ -9,6 +9,7 @@ from shellingham import ShellDetectionFailure
from shellingham import detect_shell from shellingham import detect_shell
from ._compat import WINDOWS from ._compat import WINDOWS
from ._compat import Path
from .env import VirtualEnv from .env import VirtualEnv
...@@ -42,7 +43,17 @@ class Shell: ...@@ -42,7 +43,17 @@ class Shell:
try: try:
name, path = detect_shell(os.getpid()) name, path = detect_shell(os.getpid())
except (RuntimeError, ShellDetectionFailure): except (RuntimeError, ShellDetectionFailure):
raise RuntimeError("Unable to detect the current shell.") shell = None
if os.name == "posix":
shell = os.environ.get("SHELL")
elif os.name == "nt":
shell = os.environ.get("COMSPEC")
if not shell:
raise RuntimeError("Unable to detect the current shell.")
name, path = Path(shell).stem, shell
cls._shell = cls(name, path) cls._shell = cls(name, path)
......
...@@ -58,7 +58,10 @@ subprocess32 = { version = "^3.5", python = "~2.7" } ...@@ -58,7 +58,10 @@ subprocess32 = { version = "^3.5", python = "~2.7" }
importlib-metadata = {version = "^1.6.0", python = "<3.8"} importlib-metadata = {version = "^1.6.0", python = "<3.8"}
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^4.1" pytest = [
{version = "^4.1", python = "<3.5"},
{version = "^5.4.3", python = ">=3.5"}
]
pytest-cov = "^2.5" pytest-cov = "^2.5"
mkdocs = { version = "^1.0", python = "~2.7.9 || ^3.4" } mkdocs = { version = "^1.0", python = "~2.7.9 || ^3.4" }
pymdown-extensions = "^6.0" pymdown-extensions = "^6.0"
...@@ -114,3 +117,23 @@ known_third_party = [ ...@@ -114,3 +117,23 @@ known_third_party = [
"shellingham", "shellingham",
"tomlkit", "tomlkit",
] ]
[tool.black]
line-length = 88
include = '\.pyi?$'
exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| tests/.*/setup.py
)/
'''
...@@ -11,6 +11,8 @@ import pytest ...@@ -11,6 +11,8 @@ import pytest
from poetry.config.config import Config as BaseConfig from poetry.config.config import Config as BaseConfig
from poetry.config.dict_config_source import DictConfigSource from poetry.config.dict_config_source import DictConfigSource
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils.env import EnvManager
from poetry.utils.env import VirtualEnv
from tests.helpers import mock_clone from tests.helpers import mock_clone
from tests.helpers import mock_download from tests.helpers import mock_download
...@@ -76,6 +78,11 @@ def download_mock(mocker): ...@@ -76,6 +78,11 @@ def download_mock(mocker):
mocker.patch("poetry.repositories.pypi_repository.download_file", new=mock_download) mocker.patch("poetry.repositories.pypi_repository.download_file", new=mock_download)
@pytest.fixture(autouse=True)
def execute_setup_mock(mocker):
mocker.patch("poetry.inspection.info.PackageInfo._execute_setup")
@pytest.fixture @pytest.fixture
def environ(): def environ():
original_environ = dict(os.environ) original_environ = dict(os.environ)
...@@ -134,3 +141,15 @@ def mocked_open_files(mocker): ...@@ -134,3 +141,15 @@ def mocked_open_files(mocker):
mocker.patch("poetry.utils._compat.Path.open", mocked_open) mocker.patch("poetry.utils._compat.Path.open", mocked_open)
yield files yield files
@pytest.fixture
def tmp_venv(tmp_dir):
venv_path = Path(tmp_dir) / "venv"
EnvManager.build_venv(str(venv_path))
venv = VirtualEnv(venv_path)
yield venv
shutil.rmtree(str(venv.path))
...@@ -48,4 +48,4 @@ def test_env_info_displays_path_only(app): ...@@ -48,4 +48,4 @@ def test_env_info_displays_path_only(app):
expected = str(Path("/prefix")) expected = str(Path("/prefix"))
assert expected == tester.io.fetch_output() assert expected + "\n" == tester.io.fetch_output()
be3d3b916cb47038899d6ff37e875fd08ba3fed22bcdbf5a92f3f48fd2f15da8
import os
from cleo.testers import CommandTester
from poetry.__version__ import __version__
from poetry.core.packages.package import Package
from poetry.core.semver.version import Version
from poetry.utils._compat import WINDOWS
from poetry.utils._compat import Path
FIXTURES = Path(__file__).parent.joinpath("fixtures")
def test_self_update_should_install_all_necessary_elements(
app, http, mocker, environ, tmp_dir
):
os.environ["POETRY_HOME"] = tmp_dir
command = app.find("self update")
version = Version.parse(__version__).next_minor.text
mocker.patch(
"poetry.repositories.pypi_repository.PyPiRepository.find_packages",
return_value=[Package("poetry", version)],
)
mocker.patch.object(command, "_check_recommended_installation", return_value=None)
mocker.patch.object(
command, "_get_release_name", return_value="poetry-{}-darwin".format(version)
)
mocker.patch("subprocess.check_output", return_value=b"Python 3.8.2")
http.register_uri(
"GET",
command.BASE_URL + "/{}/poetry-{}-darwin.sha256sum".format(version, version),
body=FIXTURES.joinpath("poetry-1.0.5-darwin.sha256sum").read_bytes(),
)
http.register_uri(
"GET",
command.BASE_URL + "/{}/poetry-{}-darwin.tar.gz".format(version, version),
body=FIXTURES.joinpath("poetry-1.0.5-darwin.tar.gz").read_bytes(),
)
tester = CommandTester(command)
tester.execute()
bin_ = Path(tmp_dir).joinpath("bin")
lib = Path(tmp_dir).joinpath("lib")
assert bin_.exists()
script = bin_.joinpath("poetry")
assert script.exists()
expected_script = """\
# -*- coding: utf-8 -*-
import glob
import sys
import os
lib = os.path.normpath(os.path.join(os.path.realpath(__file__), "../..", "lib"))
vendors = os.path.join(lib, "poetry", "_vendor")
current_vendors = os.path.join(
vendors, "py{}".format(".".join(str(v) for v in sys.version_info[:2]))
)
sys.path.insert(0, lib)
sys.path.insert(0, current_vendors)
if __name__ == "__main__":
from poetry.console import main
main()
"""
if not WINDOWS:
expected_script = "#!/usr/bin/env python\n" + expected_script
assert expected_script == script.read_text()
if WINDOWS:
bat = bin_.joinpath("poetry.bat")
expected_bat = '@echo off\r\npython "{}" %*\r\n'.format(
str(script).replace(os.environ.get("USERPROFILE", ""), "%USERPROFILE%")
)
assert bat.exists()
with bat.open(newline="") as f:
assert expected_bat == f.read()
assert lib.exists()
assert lib.joinpath("poetry").exists()
...@@ -56,6 +56,9 @@ def setup(mocker, installer, installed, config, env): ...@@ -56,6 +56,9 @@ def setup(mocker, installer, installed, config, env):
# Patch the virtual environment creation do actually do nothing # Patch the virtual environment creation do actually do nothing
mocker.patch("poetry.utils.env.EnvManager.create_venv", return_value=env) mocker.patch("poetry.utils.env.EnvManager.create_venv", return_value=env)
# Patch the virtual environment creation do actually do nothing
mocker.patch("poetry.utils.env.EnvManager.create_venv", return_value=env)
# Setting terminal width # Setting terminal width
environ = dict(os.environ) environ = dict(os.environ)
os.environ["COLUMNS"] = "80" os.environ["COLUMNS"] = "80"
......
...@@ -8,5 +8,6 @@ license = "MIT" ...@@ -8,5 +8,6 @@ license = "MIT"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "*" python = "*"
project-with-extras = {path = "../../project_with_extras/"} project-with-extras = {path = "../../project_with_extras/"}
project-with-transitive-file-dependencies = {path = "../project_with_transitive_file_dependencies/"}
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
[tool.poetry]
name = "inner-directory-project"
version = "1.2.4"
description = "This is a description"
authors = ["Your Name <you@example.com>"]
license = "MIT"
[tool.poetry.dependencies]
python = "*"
[tool.poetry.dev-dependencies]
...@@ -8,5 +8,6 @@ license = "MIT" ...@@ -8,5 +8,6 @@ license = "MIT"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "*" python = "*"
demo = {path = "../../distributions/demo-0.1.0-py2.py3-none-any.whl"} demo = {path = "../../distributions/demo-0.1.0-py2.py3-none-any.whl"}
inner-directory-project = {path = "./inner-directory-project"}
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
Metadata-Version: 2.1
Name: demo
Version: 0.1.2
Summary: Demo project.
Home-page: https://github.com/demo/demo
Author: Sébastien Eustace
Author-email: sebastien@eustace.io
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
Provides-Extra: bar
Provides-Extra: foo
setup.py
demo/__init__.py
demo.egg-info/PKG-INFO
demo.egg-info/SOURCES.txt
demo.egg-info/dependency_links.txt
demo.egg-info/requires.txt
demo.egg-info/top_level.txt
from setuptools import setup, find_packages
setup(
name="namespace_package_one",
version="1.0.0",
description="",
long_description="",
author="Python Poetry",
author_email="noreply@python-poetry.org",
license="MIT",
packages=find_packages(),
namespace_packages=["namespace_package"],
zip_safe=False,
)
Metadata-Version: 1.0
Name: demo
Version: 0.1.2
Summary: Demo project.
Home-page: https://github.com/demo/demo
Author: Sébastien Eustace
Author-email: sebastien@eustace.io
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
setup.py
demo/__init__.py
demo.egg-info/PKG-INFO
demo.egg-info/SOURCES.txt
demo.egg-info/dependency_links.txt
demo.egg-info/top_level.txt
Metadata-Version: 2.1
Name: Demo
Version: 0.1.2
Summary: Demo project.
Home-page: https://github.com/demo/demo
Author: Sébastien Eustace
Author-email: sebastien@eustace.io
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
Provides-Extra: foo
Provides-Extra: bar
setup.py
Demo.egg-info/PKG-INFO
Demo.egg-info/SOURCES.txt
Demo.egg-info/dependency_links.txt
Demo.egg-info/requires.txt
Demo.egg-info/top_level.txt
demo/__init__.py
Metadata-Version: 1.0
Name: my-package
Version: 0.1.2
Summary: Demo project.
Home-page: https://github.com/demo/demo
Author: Sébastien Eustace
Author-email: sebastien@eustace.io
License: MIT
Description: UNKNOWN
Platform: UNKNOWN
setup.py
my_package/__init__.py
my_package.egg-info/PKG-INFO
my_package.egg-info/SOURCES.txt
my_package.egg-info/dependency_links.txt
my_package.egg-info/requires.txt
my_package.egg-info/top_level.txt
[[package]] [[package]]
category = "main" category = "main"
description = ""
name = "demo"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.1.0"
[package.dependencies]
pendulum = ">=1.4.4"
[package.extras]
bar = ["tomlkit"]
foo = ["cleo"]
[package.source]
reference = ""
type = "file"
url = "../../distributions/demo-0.1.0-py2.py3-none-any.whl"
[[package]]
category = "main"
description = "This is a description"
develop = true
name = "inner-directory-project"
optional = false
python-versions = "*"
version = "1.2.4"
[package.source]
reference = ""
type = "directory"
url = "../project_with_transitive_file_dependencies/inner-directory-project"
[[package]]
category = "main"
description = ""
name = "pendulum"
optional = false
python-versions = "*"
version = "1.4.4"
[[package]]
category = "main"
description = "This is a description" description = "This is a description"
develop = true develop = true
name = "project-with-extras" name = "project-with-extras"
...@@ -14,7 +56,7 @@ extras_b = ["cachy (>=0.2.0)"] ...@@ -14,7 +56,7 @@ extras_b = ["cachy (>=0.2.0)"]
[package.source] [package.source]
reference = "" reference = ""
type = "directory" type = "directory"
url = "tests/fixtures/directory/project_with_transitive_directory_dependencies/../../project_with_extras" url = "../project_with_extras"
[[package]] [[package]]
category = "main" category = "main"
...@@ -26,17 +68,42 @@ python-versions = "*" ...@@ -26,17 +68,42 @@ python-versions = "*"
version = "1.2.3" version = "1.2.3"
[package.dependencies] [package.dependencies]
project-with-extras = "*" project-with-extras = "1.2.3"
project-with-transitive-file-dependencies = "1.2.3"
[package.source]
reference = ""
type = "directory"
url = "project_with_transitive_directory_dependencies"
[[package]]
category = "main"
description = "This is a description"
develop = true
name = "project-with-transitive-file-dependencies"
optional = false
python-versions = "*"
version = "1.2.3"
[package.dependencies]
demo = "0.1.0"
inner-directory-project = "1.2.4"
[package.source] [package.source]
reference = "" reference = ""
type = "directory" type = "directory"
url = "tests/fixtures/directory/project_with_transitive_directory_dependencies" url = "project_with_transitive_file_dependencies"
[metadata] [metadata]
content-hash = "123456789" content-hash = "123456789"
python-versions = "*" python-versions = "*"
[metadata.files] [metadata.files]
demo = [
{file = "demo-0.1.0-py2.py3-none-any.whl", hash = "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"},
]
inner-directory-project = []
pendulum = []
project-with-extras = [] project-with-extras = []
project-with-transitive-directory-dependencies = [] project-with-transitive-directory-dependencies = []
project-with-transitive-file-dependencies = []
...@@ -16,7 +16,21 @@ foo = ["cleo"] ...@@ -16,7 +16,21 @@ foo = ["cleo"]
[package.source] [package.source]
reference = "" reference = ""
type = "file" type = "file"
url = "tests/fixtures/directory/project_with_transitive_file_dependencies/../../distributions/demo-0.1.0-py2.py3-none-any.whl" url = "../distributions/demo-0.1.0-py2.py3-none-any.whl"
[[package]]
category = "main"
description = "This is a description"
develop = true
name = "inner-directory-project"
optional = false
python-versions = "*"
version = "1.2.4"
[package.source]
reference = ""
type = "directory"
url = "project_with_transitive_file_dependencies/inner-directory-project"
[[package]] [[package]]
category = "main" category = "main"
...@@ -36,12 +50,13 @@ python-versions = "*" ...@@ -36,12 +50,13 @@ python-versions = "*"
version = "1.2.3" version = "1.2.3"
[package.dependencies] [package.dependencies]
demo = "*" demo = "0.1.0"
inner-directory-project = "1.2.4"
[package.source] [package.source]
reference = "" reference = ""
type = "directory" type = "directory"
url = "tests/fixtures/directory/project_with_transitive_file_dependencies" url = "project_with_transitive_file_dependencies"
[metadata] [metadata]
content-hash = "123456789" content-hash = "123456789"
...@@ -51,5 +66,6 @@ python-versions = "*" ...@@ -51,5 +66,6 @@ python-versions = "*"
demo = [ demo = [
{file = "demo-0.1.0-py2.py3-none-any.whl", hash = "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"}, {file = "demo-0.1.0-py2.py3-none-any.whl", hash = "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"},
] ]
inner-directory-project = []
pendulum = [] pendulum = []
project-with-transitive-file-dependencies = [] project-with-transitive-file-dependencies = []
...@@ -770,11 +770,13 @@ def test_run_installs_with_local_poetry_directory_and_extras( ...@@ -770,11 +770,13 @@ def test_run_installs_with_local_poetry_directory_and_extras(
def test_run_installs_with_local_poetry_directory_transitive( def test_run_installs_with_local_poetry_directory_transitive(
installer, locker, repo, package, tmpdir installer, locker, repo, package, tmpdir
): ):
file_path = ( package.root_dir = fixtures_dir.joinpath("directory")
fixtures_dir / "directory/project_with_transitive_directory_dependencies/" directory = fixtures_dir.joinpath("directory").joinpath(
"project_with_transitive_directory_dependencies"
) )
package.add_dependency( package.add_dependency(
"project-with-transitive-directory-dependencies", {"path": str(file_path)} "project-with-transitive-directory-dependencies",
{"path": str(directory.relative_to(fixtures_dir.joinpath("directory")))},
) )
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
...@@ -786,15 +788,19 @@ def test_run_installs_with_local_poetry_directory_transitive( ...@@ -786,15 +788,19 @@ def test_run_installs_with_local_poetry_directory_transitive(
assert locker.written_data == expected assert locker.written_data == expected
assert len(installer.installer.installs) == 2 assert len(installer.installer.installs) == 6
def test_run_installs_with_local_poetry_file_transitive( def test_run_installs_with_local_poetry_file_transitive(
installer, locker, repo, package, tmpdir installer, locker, repo, package, tmpdir
): ):
file_path = fixtures_dir / "directory/project_with_transitive_file_dependencies/" package.root_dir = fixtures_dir.joinpath("directory")
directory = fixtures_dir.joinpath("directory").joinpath(
"project_with_transitive_file_dependencies"
)
package.add_dependency( package.add_dependency(
"project-with-transitive-file-dependencies", {"path": str(file_path)} "project-with-transitive-file-dependencies",
{"path": str(directory.relative_to(fixtures_dir.joinpath("directory")))},
) )
repo.add_package(get_package("pendulum", "1.4.4")) repo.add_package(get_package("pendulum", "1.4.4"))
...@@ -806,7 +812,7 @@ def test_run_installs_with_local_poetry_file_transitive( ...@@ -806,7 +812,7 @@ def test_run_installs_with_local_poetry_file_transitive(
assert locker.written_data == expected assert locker.written_data == expected
assert len(installer.installer.installs) == 3 assert len(installer.installer.installs) == 4
def test_run_installs_with_local_setuptools_directory( def test_run_installs_with_local_setuptools_directory(
......
import shutil
import pytest import pytest
from poetry.core.packages.package import Package from poetry.core.packages.package import Package
...@@ -152,3 +154,42 @@ def test_requirement_git_develop_true(installer, package_git): ...@@ -152,3 +154,42 @@ def test_requirement_git_develop_true(installer, package_git):
expected = ["-e", "git+git@github.com:demo/demo.git@master#egg=demo"] expected = ["-e", "git+git@github.com:demo/demo.git@master#egg=demo"]
assert expected == result assert expected == result
def test_uninstall_git_package_nspkg_pth_cleanup(mocker, tmp_venv, pool):
# this test scenario requires a real installation using the pip installer
installer = PipInstaller(tmp_venv, NullIO(), pool)
# use a namepspace package
package = Package("namespace-package-one", "1.0.0")
package.source_type = "git"
package.source_url = "https://github.com/demo/namespace-package-one.git"
package.source_reference = "master"
package.develop = True
# we do this here because the virtual env might not be usable if failure case is triggered
pth_file_candidate = tmp_venv.site_packages / "{}-nspkg.pth".format(package.name)
# in order to reproduce the scenario where the git source is removed prior to proper
# clean up of nspkg.pth file, we need to make sure the fixture is copied and not
# symlinked into the git src directory
def copy_only(source, dest):
if dest.exists():
dest.unlink()
if source.is_dir():
shutil.copytree(str(source), str(dest))
else:
shutil.copyfile(str(source), str(dest))
mocker.patch("tests.helpers.copy_or_symlink", new=copy_only)
# install package and then remove it
installer.install(package)
installer.remove(package)
assert not Path(pth_file_candidate).exists()
# any command in the virtual environment should trigger the error message
output = tmp_venv.run("python", "-m", "site")
assert "Error processing line 1 of {}".format(pth_file_candidate) not in output
from .. import __version__
def test_version():
assert __version__ == "0.1.0"
[tool.poetry]
name = "example"
version = "0.1.0"
description = ""
authors = ["Sébastien Eustace <sebastien@eustace.io>"]
exclude = [
"**/test/**/*",
]
[tool.poetry.dependencies]
python = "^3.6"
[tool.poetry.dev-dependencies]
pytest = "^3.0"
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
"""Example module"""
from typing import Tuple
version_info = Tuple[int, int, int]
[tool.poetry]
name = "pep-561-stubs"
version = "0.1"
description = "PEP 561 stub package example"
authors = [
"Oleg Höfling <oleg.hoefling@gmail.com>"
]
license = "MIT"
packages = [
{include = "pkg-stubs"}
]
[tool.poetry.dependencies]
python = "^3.6"
"""Example module"""
from typing import Tuple
version_info = Tuple[int, int, int]
[tool.poetry]
name = "pep-561-stubs"
version = "0.1"
description = "PEP 561 stub package example with the py.typed marker file"
authors = [
"Oleg Höfling <oleg.hoefling@gmail.com>"
]
license = "MIT"
packages = [
{include = "pkg-stubs"}
]
[tool.poetry.dependencies]
python = "^3.6"
[tool.poetry]
name = "pep-561-stubs"
version = "0.1"
description = "PEP 561 stub package example with an src layout"
authors = [
"Oleg Höfling <oleg.hoefling@gmail.com>"
]
license = "MIT"
packages = [
{include = "pkg-stubs", from = "src"}
]
[tool.poetry.dependencies]
python = "^3.6"
"""Example module"""
from typing import Tuple
version_info = Tuple[int, int, int]
...@@ -118,7 +118,7 @@ def test_search_for_vcs_read_setup_with_extras(provider, mocker): ...@@ -118,7 +118,7 @@ def test_search_for_vcs_read_setup_with_extras(provider, mocker):
def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker): def test_search_for_vcs_read_setup_raises_error_if_no_version(provider, mocker):
mocker.patch( mocker.patch(
"poetry.utils.env.VirtualEnv.run", "poetry.inspection.info.PackageInfo._execute_setup",
side_effect=EnvCommandError(CalledProcessError(1, "python", output="")), side_effect=EnvCommandError(CalledProcessError(1, "python", output="")),
) )
...@@ -204,16 +204,13 @@ def test_search_for_directory_setup_with_base(provider, directory): ...@@ -204,16 +204,13 @@ def test_search_for_directory_setup_with_base(provider, directory):
"foo": [get_dependency("cleo")], "foo": [get_dependency("cleo")],
"bar": [get_dependency("tomlkit")], "bar": [get_dependency("tomlkit")],
} }
assert ( assert package.root_dir == (
package.root_dir Path(__file__).parent.parent
== ( / "fixtures"
Path(__file__).parent.parent / "git"
/ "fixtures" / "github.com"
/ "git" / "demo"
/ "github.com" / directory
/ "demo"
/ directory
).as_posix()
) )
......
...@@ -1873,3 +1873,114 @@ def test_solver_remove_untracked_keeps_critical_package( ...@@ -1873,3 +1873,114 @@ def test_solver_remove_untracked_keeps_critical_package(
ops = solver.solve() ops = solver.solve()
check_solver_result(ops, []) check_solver_result(ops, [])
def test_solver_cannot_choose_another_version_for_directory_dependencies(
solver, repo, package
):
pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.1.0")
foo = get_package("foo", "1.2.3")
foo.add_dependency("demo", "<0.1.2")
repo.add_package(foo)
repo.add_package(demo)
repo.add_package(pendulum)
path = (
Path(__file__).parent.parent
/ "fixtures"
/ "git"
/ "github.com"
/ "demo"
/ "demo"
).as_posix()
package.add_dependency("demo", {"path": path})
package.add_dependency("foo", "^1.2.3")
# This is not solvable since the demo version is pinned
# via the directory dependency
with pytest.raises(SolverProblemError):
solver.solve()
def test_solver_cannot_choose_another_version_for_file_dependencies(
solver, repo, package
):
pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.0.8")
foo = get_package("foo", "1.2.3")
foo.add_dependency("demo", "<0.1.0")
repo.add_package(foo)
repo.add_package(demo)
repo.add_package(pendulum)
path = (
Path(__file__).parent.parent
/ "fixtures"
/ "distributions"
/ "demo-0.1.0-py2.py3-none-any.whl"
).as_posix()
package.add_dependency("demo", {"path": path})
package.add_dependency("foo", "^1.2.3")
# This is not solvable since the demo version is pinned
# via the file dependency
with pytest.raises(SolverProblemError):
solver.solve()
def test_solver_cannot_choose_another_version_for_git_dependencies(
solver, repo, package
):
pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.0.8")
foo = get_package("foo", "1.2.3")
foo.add_dependency("demo", "<0.1.0")
repo.add_package(foo)
repo.add_package(demo)
repo.add_package(pendulum)
package.add_dependency("demo", {"git": "https://github.com/demo/demo.git"})
package.add_dependency("foo", "^1.2.3")
# This is not solvable since the demo version is pinned
# via the file dependency
with pytest.raises(SolverProblemError):
solver.solve()
def test_solver_cannot_choose_another_version_for_url_dependencies(
solver, repo, package, http
):
path = (
Path(__file__).parent.parent
/ "fixtures"
/ "distributions"
/ "demo-0.1.0-py2.py3-none-any.whl"
)
http.register_uri(
"GET",
"https://foo.bar/demo-0.1.0-py2.py3-none-any.whl",
body=path.read_bytes(),
streaming=True,
)
pendulum = get_package("pendulum", "2.0.3")
demo = get_package("demo", "0.0.8")
foo = get_package("foo", "1.2.3")
foo.add_dependency("demo", "<0.1.0")
repo.add_package(foo)
repo.add_package(demo)
repo.add_package(pendulum)
package.add_dependency(
"demo", {"url": "https://foo.bar/distributions/demo-0.1.0-py2.py3-none-any.whl"}
)
package.add_dependency("foo", "^1.2.3")
# This is not solvable since the demo version is pinned
# via the git dependency
with pytest.raises(SolverProblemError):
solver.solve()
...@@ -521,3 +521,5 @@ replacing ``[program]`` with the command you use to run your application: ...@@ -521,3 +521,5 @@ replacing ``[program]`` with the command you use to run your application:
# FISH # FISH
[program] completions fish > ~/.config/fish/completions/[program].fish [program] completions fish > ~/.config/fish/completions/[program].fish
# FISH - Mac OSX (with Homebrew "fish")
[program] completions fish > $(brew --prefix)/share/fish/vendor_completions.d/[program].fish
...@@ -225,5 +225,3 @@ A full list of contributors can be found in `GitHub's overview <https://github.c ...@@ -225,5 +225,3 @@ A full list of contributors can be found in `GitHub's overview <https://github.c
It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.io/>`_ and aspires to fix some of it clunkiness and unfortunate decisions. It’s the spiritual successor of `characteristic <https://characteristic.readthedocs.io/>`_ and aspires to fix some of it clunkiness and unfortunate decisions.
Both were inspired by Twisted’s `FancyEqMixin <https://twistedmatrix.com/documents/current/api/twisted.python.util.FancyEqMixin.html>`_ but both are implemented using class decorators because `subclassing is bad for you <https://www.youtube.com/watch?v=3MNVP9-hglc>`_, m’kay? Both were inspired by Twisted’s `FancyEqMixin <https://twistedmatrix.com/documents/current/api/twisted.python.util.FancyEqMixin.html>`_ but both are implemented using class decorators because `subclassing is bad for you <https://www.youtube.com/watch?v=3MNVP9-hglc>`_, m’kay?
...@@ -84,6 +84,9 @@ def test_get_package_information_fallback_read_setup(): ...@@ -84,6 +84,9 @@ def test_get_package_information_fallback_read_setup():
package = repo.package("jupyter", "1.0.0") package = repo.package("jupyter", "1.0.0")
assert package.source_type == "legacy"
assert package.source_reference == repo.name
assert package.source_url == repo.url
assert package.name == "jupyter" assert package.name == "jupyter"
assert package.version.text == "1.0.0" assert package.version.text == "1.0.0"
assert ( assert (
...@@ -142,6 +145,10 @@ def test_find_packages_no_prereleases(): ...@@ -142,6 +145,10 @@ def test_find_packages_no_prereleases():
assert len(packages) == 1 assert len(packages) == 1
assert packages[0].source_type == "legacy"
assert packages[0].source_reference == repo.name
assert packages[0].source_url == repo.url
def test_get_package_information_chooses_correct_distribution(): def test_get_package_information_chooses_correct_distribution():
repo = MockRepository() repo = MockRepository()
......
...@@ -127,7 +127,10 @@ def test_create_poetry_with_packages_and_includes(): ...@@ -127,7 +127,10 @@ def test_create_poetry_with_packages_and_includes():
{"include": "src_package", "from": "src"}, {"include": "src_package", "from": "src"},
] ]
assert package.include == ["extra_dir/vcs_excluded.txt", "notes.txt"] assert package.include == [
{"path": "extra_dir/vcs_excluded.txt", "format": []},
{"path": "notes.txt", "format": []},
]
def test_create_poetry_with_multi_constraints_dependency(): def test_create_poetry_with_multi_constraints_dependency():
......
...@@ -60,18 +60,6 @@ def manager(poetry): ...@@ -60,18 +60,6 @@ def manager(poetry):
return EnvManager(poetry) return EnvManager(poetry)
@pytest.fixture
def tmp_venv(tmp_dir, manager):
venv_path = Path(tmp_dir) / "venv"
manager.build_venv(str(venv_path))
venv = VirtualEnv(venv_path)
yield venv
shutil.rmtree(str(venv.path))
def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, manager): def test_virtualenvs_with_spaces_in_their_path_work_as_expected(tmp_dir, manager):
venv_path = Path(tmp_dir) / "Virtual Env" venv_path = Path(tmp_dir) / "Virtual Env"
......
...@@ -29,6 +29,9 @@ pathlib2>=2.3.0.0,<3.0.0.0 ...@@ -29,6 +29,9 @@ pathlib2>=2.3.0.0,<3.0.0.0
[:python_version >= "3.4.0.0" and python_version < "3.6.0.0"] [:python_version >= "3.4.0.0" and python_version < "3.6.0.0"]
zipfile36>=0.1.0.0,<0.2.0.0 zipfile36>=0.1.0.0,<0.2.0.0
[dev]
isort@ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort
""" """
result = parse_requires(requires) result = parse_requires(requires)
expected = [ expected = [
...@@ -45,10 +48,11 @@ zipfile36>=0.1.0.0,<0.2.0.0 ...@@ -45,10 +48,11 @@ zipfile36>=0.1.0.0,<0.2.0.0
"msgpack-python>=0.5.0.0,<0.6.0.0", "msgpack-python>=0.5.0.0,<0.6.0.0",
"pyparsing>=2.2.0.0,<3.0.0.0", "pyparsing>=2.2.0.0,<3.0.0.0",
"requests-toolbelt>=0.8.0.0,<0.9.0.0", "requests-toolbelt>=0.8.0.0,<0.9.0.0",
'typing>=3.6.0.0,<4.0.0.0; (python_version >= "2.7.0.0" and python_version < "2.8.0.0") or (python_version >= "3.4.0.0" and python_version < "3.5.0.0")', 'typing>=3.6.0.0,<4.0.0.0 ; (python_version >= "2.7.0.0" and python_version < "2.8.0.0") or (python_version >= "3.4.0.0" and python_version < "3.5.0.0")',
'virtualenv>=15.2.0.0,<16.0.0.0; python_version >= "2.7.0.0" and python_version < "2.8.0.0"', 'virtualenv>=15.2.0.0,<16.0.0.0 ; python_version >= "2.7.0.0" and python_version < "2.8.0.0"',
'pathlib2>=2.3.0.0,<3.0.0.0; python_version >= "2.7.0.0" and python_version < "2.8.0.0"', 'pathlib2>=2.3.0.0,<3.0.0.0 ; python_version >= "2.7.0.0" and python_version < "2.8.0.0"',
'zipfile36>=0.1.0.0,<0.2.0.0; python_version >= "3.4.0.0" and python_version < "3.6.0.0"', 'zipfile36>=0.1.0.0,<0.2.0.0 ; python_version >= "3.4.0.0" and python_version < "3.6.0.0"',
'isort@ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort ; extra == "dev"',
] ]
assert result == expected assert result == expected
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment