diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md index caf8db9a353..05288e74fef 100644 --- a/.github/ISSUE_TEMPLATE/---bug-report.md +++ b/.github/ISSUE_TEMPLATE/---bug-report.md @@ -2,7 +2,7 @@ name: "\U0001F41E Bug Report" about: Did you find a bug? title: '' -labels: 'Bug' +labels: Bug, Triage assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/---documentation.md b/.github/ISSUE_TEMPLATE/---documentation.md index 1e6737d6067..4ded4f67949 100644 --- a/.github/ISSUE_TEMPLATE/---documentation.md +++ b/.github/ISSUE_TEMPLATE/---documentation.md @@ -2,7 +2,7 @@ name: "\U0001F4DA Documentation" about: Did you find errors, problems, or anything unintelligible in the docs (https://python-poetry.org/docs)? title: '' -labels: 'Documentation' +labels: Documentation, Triage assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/---feature-request.md b/.github/ISSUE_TEMPLATE/---feature-request.md index f486d4abbdf..6a984e925c5 100644 --- a/.github/ISSUE_TEMPLATE/---feature-request.md +++ b/.github/ISSUE_TEMPLATE/---feature-request.md @@ -2,7 +2,7 @@ name: "\U0001F381 Feature Request" about: Do you have ideas for new features and improvements? title: '' -labels: 'Feature' +labels: Feature, Triage assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..82577fb2a8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,7 @@ +# 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. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3b8acacb709..bdba9f27880 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,11 +1,13 @@ # 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 + + - [ ] Added **tests** 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 -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! + diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ec42d4c608..3a343b6001d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,120 +8,62 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up Python 3.7 + - name: Set up Python 3.8 uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.8 - name: Linting run: | pip install pre-commit pre-commit run --all-files - Linux: + Tests: needs: Linting - runs-on: ubuntu-latest + name: ${{ matrix.os }} / ${{ matrix.python-version }} + runs-on: ${{ matrix.os }}-latest strategy: matrix: + os: [Ubuntu, MacOS, Windows] python-version: [2.7, 3.5, 3.6, 3.7, 3.8] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Get full python version - id: full-python-version - run: | - echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - - name: Install and set up Poetry - run: | - python get-poetry.py --preview -y - source $HOME/.poetry/env - poetry config virtualenvs.in-project true - - name: Set up cache - uses: actions/cache@v1 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} - - name: Install dependencies - run: | - source $HOME/.poetry/env - poetry install - - name: Test - run: | - source $HOME/.poetry/env - poetry run pytest -q tests + - uses: actions/checkout@v2 - MacOS: - needs: Linting - runs-on: macos-latest - strategy: - matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Get full python version - id: full-python-version - run: | - echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - - name: Install and set up Poetry - run: | - python get-poetry.py --preview -y - source $HOME/.poetry/env - poetry config virtualenvs.in-project true - - name: Set up cache - uses: actions/cache@v1 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} - - name: Install dependencies - run: | - source $HOME/.poetry/env - poetry install - - name: Test - run: | - source $HOME/.poetry/env - .venv/bin/pytest -q tests + - name: Get full Python version + id: full-python-version + shell: bash + run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - Windows: - needs: Linting - runs-on: windows-latest - strategy: - matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + - name: Install poetry + shell: bash + run: | + python get-poetry.py -y + echo "::set-env name=PATH::$HOME/.poetry/bin:$PATH" - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v1 - with: - python-version: ${{ matrix.python-version }} - - name: Get full python version - id: full-python-version - shell: bash - run: | - echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - - name: Install and setup Poetry - run: | - python get-poetry.py --preview -y - $env:Path += ";$env:Userprofile\.poetry\bin" - poetry config virtualenvs.in-project true - - name: Set up cache - uses: actions/cache@v1 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} - - name: Install dependencies - run: | - $env:Path += ";$env:Userprofile\.poetry\bin" - poetry install - - name: Test - run: | - $env:Path += ";$env:Userprofile\.poetry\bin" - poetry run pytest -q tests + - name: Configure poetry + shell: bash + run: poetry config virtualenvs.in-project true + + - name: Set up cache + uses: actions/cache@v2 + id: cache + with: + path: .venv + key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }}-${{ hashFiles('**/poetry.lock') }} + + - name: Ensure cache is healthy + if: steps.cache.outputs.cache-hit == 'true' + shell: bash + run: poetry run pip --version >/dev/null 2>&1 || rm -rf .venv + + - name: Install dependencies + shell: bash + run: poetry install + + - name: Run pytest + shell: bash + run: poetry run pytest -q tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0b3b27925f..b422419bb98 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,32 +152,32 @@ jobs: uses: actions/download-artifact@master with: 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 uses: actions/download-artifact@master with: name: poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum - path: releases/poetry-${{ steps.tag.outputs.tag }}-linux.sha256sum + path: releases/ - name: Download MacOS release file uses: actions/download-artifact@master with: 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 uses: actions/download-artifact@master with: name: poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum - path: releases/poetry-${{ steps.tag.outputs.tag }}-darwin.sha256sum + path: releases/ - name: Download Windows release file uses: actions/download-artifact@master with: 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 uses: actions/download-artifact@master with: name: poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum - path: releases/poetry-${{ steps.tag.outputs.tag }}-win32.sha256sum + path: releases/ - name: Create Release id: create_release uses: actions/create-release@v1 @@ -194,7 +194,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: application/gzip - name: Upload Linux checksum file asset @@ -203,16 +203,16 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: text/pain + asset_content_type: text/plain - name: Upload MacOS release file asset uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: application/gzip - name: Upload MacOS checksum file asset @@ -221,16 +221,16 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: text/pain + asset_content_type: text/plain - name: Upload Windows release file asset uses: actions/upload-release-asset@v1.0.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: application/gzip - name: Upload Windows checksum file asset @@ -239,9 +239,9 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: 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_content_type: text/pain + asset_content_type: text/plain - name: Install Poetry run: | python get-poetry.py --preview -y diff --git a/.gitignore b/.gitignore index c2d2a72090e..fcbd92e97a3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ *.egg !/tests/**/*.egg /*.egg-info -/tests/fixtures/**/*.egg-info /dist/* build _build diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b296497d29f..79b09408ed4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,8 +9,8 @@ repos: hooks: - id: flake8 - - repo: https://github.com/pre-commit/mirrors-isort - rev: v4.3.21 + - repo: https://github.com/timothycrosley/isort + rev: 4.3.21-2 hooks: - id: isort additional_dependencies: [toml] diff --git a/CHANGELOG.md b/CHANGELOG.md index d196bd38d52..a00edcf837a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Change Log +## [1.0.9] - 2020-06-09 + +### Fixed + +- Fixed an issue where packages from custom indices where continuously updated ([#2525](https://github.com/python-poetry/poetry/pull/2525)). +- Fixed errors in the way Python environment markers were parsed and generated ([#2526](https://github.com/python-poetry/poetry/pull/2526)). + + +## [1.0.8] - 2020-06-05 + +### Fixed + +- Fixed a possible error when installing the root package ([#2505](https://github.com/python-poetry/poetry/pull/2505)). +- Fixed an error where directory and VCS dependencies were not installed ([#2505](https://github.com/python-poetry/poetry/pull/2505)). + + +## [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 ### Fixed @@ -824,7 +868,11 @@ Initial release -[Unreleased]: https://github.com/python-poetry/poetry/compare/1.0.5...master +[Unreleased]: https://github.com/python-poetry/poetry/compare/1.0.9...master +[1.0.9]: https://github.com/python-poetry/poetry/releases/tag/1.0.9 +[1.0.8]: https://github.com/python-poetry/poetry/releases/tag/1.0.8 +[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.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 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d03da34c186..0b184a286ee 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. 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. @@ -31,7 +31,7 @@ Before creating bug reports, please check [this list](#before-submitting-a-bug-r #### 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: @@ -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. -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 * **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)**. - #### 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: diff --git a/README.md b/README.md index ea0df8ded25..44145cba57c 100644 --- a/README.md +++ b/README.md @@ -79,17 +79,27 @@ See `poetry help completions` for full details, but the gist is as simple as usi # Bash 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 # Fish poetry completions fish > ~/.config/fish/completions/poetry.fish +# Fish (Homebrew) +poetry completions fish > (brew --prefix)/share/fish/vendor_completions.d/poetry.fish + # Zsh poetry completions zsh > ~/.zfunc/_poetry -# Zsh (macOS/Homebrew) +# Zsh (Homebrew) 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 diff --git a/docs/docs/basic-usage.md b/docs/docs/basic-usage.md index dad1ef9b9b4..48fc8f480e7 100644 --- a/docs/docs/basic-usage.md +++ b/docs/docs/basic-usage.md @@ -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?** - 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. 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. @@ -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. +### 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 diff --git a/docs/docs/cli.md b/docs/docs/cli.md index 89d19a8cc18..f6f13694c18 100644 --- a/docs/docs/cli.md +++ b/docs/docs/cli.md @@ -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, 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 * `--verbose (-v|vv|vvv)`: Increase the verbosity of messages: "-v" for normal output, "-vv" for more verbose output and "-vvv" for debug. @@ -165,6 +156,11 @@ If you just want to update a few packages and not all, you can list them as such 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 * `--dry-run` : Outputs the operations but will not execute anything (implicitly enables --verbose). @@ -204,6 +200,12 @@ You can also add `git` dependencies: poetry add git+https://github.com/sdispater/pendulum.git ``` +or use ssh instead of https: + +```bash +poetry add git+ssh://git@github.com/sdispater/pendulum.git +``` + If you need to checkout a specific branch, tag or revision, you can specify it when using `add`: @@ -419,9 +421,24 @@ 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 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`. +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 | + + ## export @@ -451,4 +468,4 @@ poetry export -f requirements.txt > requirements.txt The `env` command regroups sub commands to interact with the virtualenvs associated with a specific project. -See [Managing environments](./managing-environments.md) for more information about these commands. +See [Managing environments](/docs/managing-environments/) for more information about these commands. diff --git a/docs/docs/dependency-specification.md b/docs/docs/dependency-specification.md index 8ae0044f8b6..257b585b5a3 100644 --- a/docs/docs/dependency-specification.md +++ b/docs/docs/dependency-specification.md @@ -42,7 +42,7 @@ If you only specify a major version, then minor- and patch-level changes are all ### 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. @@ -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 The constraints **must** have different requirements (like `python`) diff --git a/docs/docs/index.md b/docs/docs/index.md index e768cc19124..d61f444f8d4 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -28,7 +28,7 @@ curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poet !!! note 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) accordingly. 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`. @@ -77,6 +77,15 @@ POETRY_VERSION=0.12.0 python get-poetry.py Note that the installer does not support Poetry releases < 0.12.0. +!!!note + + The setup script must be able to find one of following executables in your shell's path environment: + + - `python` (which can be a py3 or py2 interpreter) + - `python3` + - `py.exe -3` (Windows) + - `py.exe -2` (Windows) + ### Alternative installation methods (not recommended) !!!note @@ -161,12 +170,15 @@ See `poetry help completions` for full details, but the gist is as simple as usi # Bash 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 # Fish poetry completions fish > ~/.config/fish/completions/poetry.fish +# Fish (Homebrew) +poetry completions fish > (brew --prefix)/share/fish/vendor_completions.d/poetry.fish + # Zsh poetry completions zsh > ~/.zfunc/_poetry @@ -174,6 +186,9 @@ poetry completions zsh > ~/.zfunc/_poetry mkdir $ZSH/plugins/poetry poetry completions zsh > $ZSH/plugins/poetry/_poetry +# prezto +poetry completions zsh > ~/.zprezto/modules/completion/external/src/_poetry + ``` !!! note diff --git a/docs/docs/managing-environments.md b/docs/docs/managing-environments.md index 51e2a68e7a0..8b626cd813a 100644 --- a/docs/docs/managing-environments.md +++ b/docs/docs/managing-environments.md @@ -1,6 +1,6 @@ # Managing environments -Poetry makes project environment isolation one of its core feature. +Poetry makes project environment isolation one of its core features. What this means is that it will always work isolated from your global Python installation. To achieve this, it will first check if it's currently running inside a virtual environment. @@ -92,7 +92,7 @@ poetry env info --path ## Listing the environments associated with the project -You can also list all the virtual environments associated with the current virtual environment +You can also list all the virtual environments associated with the current project with the `env list` command: ```bash @@ -118,4 +118,4 @@ poetry env remove 3.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. diff --git a/docs/docs/pyproject.md b/docs/docs/pyproject.md index b6bcbe318f1..c402f3498de 100644 --- a/docs/docs/pyproject.md +++ b/docs/docs/pyproject.md @@ -38,7 +38,11 @@ The recommended notation for the most common licenses is (alphabetical): * MIT 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://spdx.org/licenses/). + +!!!note + + If your project is proprietary and does not use a specific licence, you can set this value as `Proprietary`. ## authors @@ -127,11 +131,11 @@ it by using `format`: # ... packages = [ { 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 diff --git a/get-poetry.py b/get-poetry.py index 7a2b18d3997..fcac28c86f5 100644 --- a/get-poetry.py +++ b/get-poetry.py @@ -197,15 +197,18 @@ def expanduser(path): POETRY_LIB_BACKUP = os.path.join(POETRY_HOME, "lib-backup") -BIN = """#!/usr/bin/env python -# -*- coding: utf-8 -*- +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 @@ -213,7 +216,7 @@ def expanduser(path): main() """ -BAT = u('@echo off\r\npython "{poetry_bin}" %*\r\n') +BAT = u('@echo off\r\n{python_executable} "{poetry_bin}" %*\r\n') PRE_MESSAGE = """# Welcome to {poetry}! @@ -585,23 +588,63 @@ def _make_lib(self, version): finally: gz.close() + def _which_python(self): + """Decides which python executable we'll embed in the launcher script.""" + 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\d+)\.(?P\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: + 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: + raise RuntimeError( + "No python executable found in shell environment. Tried: " + + str(allowed_executables) + ) + + return fallback + def make_bin(self): if not os.path.exists(POETRY_BIN): os.mkdir(POETRY_BIN, 0o755) + python_executable = self._which_python() + if WINDOWS: with open(os.path.join(POETRY_BIN, "poetry.bat"), "w") as f: f.write( u( BAT.format( + python_executable=python_executable, poetry_bin=os.path.join(POETRY_BIN, "poetry").replace( os.environ["USERPROFILE"], "%USERPROFILE%" - ) + ), ) ) ) with open(os.path.join(POETRY_BIN, "poetry"), "w", encoding="utf-8") as f: + if WINDOWS: + python_executable = "python" + + f.write(u("#!/usr/bin/env {}\n".format(python_executable))) f.write(u(BIN)) if not WINDOWS: diff --git a/poetry.lock b/poetry.lock index 68b195a47b1..8d423ed68f9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -4,7 +4,7 @@ description = "A small Python module for determining appropriate platform-specif name = "appdirs" optional = false python-versions = "*" -version = "1.4.3" +version = "1.4.4" [[package]] category = "dev" @@ -20,10 +20,11 @@ pyyaml = "*" [[package]] category = "dev" description = "Atomic file writes." +marker = "python_version >= \"3.5\" and sys_platform == \"win32\" or python_version < \"3.5\"" name = "atomicwrites" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" +version = "1.4.0" [[package]] category = "main" @@ -39,6 +40,19 @@ dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.int docs = ["sphinx", "zope.interface"] tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] +[[package]] +category = "dev" +description = "Backport of functools.lru_cache" +marker = "python_version < \"3.2\"" +name = "backports.functools-lru-cache" +optional = false +python-versions = ">=2.6" +version = "1.6.1" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-black-multipy", "pytest-cov"] + [[package]] category = "dev" description = "The uncompromising code formatter." @@ -99,7 +113,7 @@ description = "Python package for providing Mozilla's CA Bundle." name = "certifi" optional = false python-versions = "*" -version = "2019.11.28" +version = "2020.4.5.1" [[package]] category = "main" @@ -149,6 +163,15 @@ description = "Composable command line interface toolkit" marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"4.0\" or python_version >= \"3.6\" and python_version < \"4.0\"" name = "click" optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" + +[[package]] +category = "dev" +description = "Composable command line interface toolkit" +marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"4.0\"" +name = "click" +optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "7.0" @@ -158,7 +181,7 @@ description = "CliKit is a group of utilities to build beautiful and testable co name = "clikit" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.2" +version = "0.4.3" [package.dependencies] pastel = ">=0.2.0,<0.3.0" @@ -188,7 +211,7 @@ version = "0.4.1" [[package]] category = "dev" description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\" and python_version != \"3.4\" or platform_system == \"Windows\"" +marker = "sys_platform == \"win32\" and python_version != \"3.4\" and python_version < \"3.5\" or platform_system == \"Windows\" or python_version >= \"3.5\" and sys_platform == \"win32\"" name = "colorama" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -230,7 +253,7 @@ description = "Code coverage measurement for Python" name = "coverage" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.0.3" +version = "5.1" [package.extras] toml = ["toml"] @@ -238,7 +261,7 @@ toml = ["toml"] [[package]] category = "main" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -marker = "python_version >= \"2.7\" and python_version < \"2.8\" and (sys_platform == \"linux2\" or sys_platform == \"linux\") or python_version >= \"3.4\" and python_version < \"3.5\" and (sys_platform == \"linux2\" or sys_platform == \"linux\") or python_version >= \"3.5\" and python_version < \"4.0\" and sys_platform == \"linux\"" +marker = "python_version >= \"2.7\" and python_version < \"2.8\" and (sys_platform == \"linux2\" or sys_platform == \"linux\") or python_version >= \"3.4\" and python_version < \"3.5\" and (sys_platform == \"linux2\" or sys_platform == \"linux\")" name = "cryptography" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" @@ -248,6 +271,26 @@ version = "2.8" cffi = ">=1.8,<1.11.3 || >1.11.3" six = ">=1.4.1" +[package.extras] +docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"] +docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] +idna = ["idna (>=2.1)"] +pep8test = ["flake8", "flake8-import-order", "pep8-naming"] +test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"] + +[[package]] +category = "main" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +marker = "python_version >= \"2.7\" and python_version < \"2.8\" and (sys_platform == \"linux2\" or sys_platform == \"linux\") or python_version >= \"3.4\" and python_version < \"3.5\" and (sys_platform == \"linux2\" or sys_platform == \"linux\") or python_version >= \"3.5\" and python_version < \"4.0\" and sys_platform == \"linux\"" +name = "cryptography" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +version = "2.9.2" + +[package.dependencies] +cffi = ">=1.8,<1.11.3 || >1.11.3" +six = ">=1.4.1" + [package.dependencies.enum34] python = "<3" version = "*" @@ -292,7 +335,7 @@ marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_versi name = "enum34" optional = false python-versions = "*" -version = "1.1.9" +version = "1.1.10" [[package]] category = "dev" @@ -383,7 +426,7 @@ description = "File identification library for Python" name = "identify" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "1.4.11" +version = "1.4.19" [package.extras] license = ["editdistance"] @@ -437,14 +480,47 @@ python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" version = "1.0.2" [package.dependencies] +[package.dependencies.typing] +python = "<3.5" +version = "*" + +[[package]] +category = "dev" +description = "Read resources from Python packages" +marker = "python_version < \"3.7\"" +name = "importlib-resources" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +version = "1.5.0" + +[package.dependencies] +[package.dependencies.contextlib2] +python = "<3" +version = "*" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" + [package.dependencies.pathlib2] python = "<3" version = "*" +[package.dependencies.singledispatch] +python = "<3.4" +version = "*" + [package.dependencies.typing] python = "<3.5" version = "*" +[package.dependencies.zipp] +python = "<3.8" +version = ">=0.4" + +[package.extras] +docs = ["sphinx", "rst.linker", "jaraco.packaging"] + [[package]] category = "main" description = "IPv4/IPv6 manipulation library" @@ -461,7 +537,7 @@ marker = "python_version >= \"3.5\" and python_version < \"4.0\" and sys_platfor name = "jeepney" optional = false python-versions = ">=3.5" -version = "0.4.2" +version = "0.4.3" [package.extras] dev = ["testpath"] @@ -488,7 +564,7 @@ marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_v name = "jinja2" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.1" +version = "2.11.2" [package.dependencies] MarkupSafe = ">=0.23" @@ -496,6 +572,15 @@ MarkupSafe = ">=0.23" [package.extras] i18n = ["Babel (>=0.8)"] +[[package]] +category = "dev" +description = "Lightweight pipelining: using Python functions as pipeline jobs." +marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"4.0\"" +name = "joblib" +optional = false +python-versions = "*" +version = "0.14.1" + [[package]] category = "main" description = "An implementation of JSON Schema validation for Python" @@ -592,7 +677,7 @@ marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_v name = "lunr" optional = false python-versions = "*" -version = "0.5.6" +version = "0.5.8" [package.dependencies] future = ">=0.16.0" @@ -600,10 +685,11 @@ six = ">=1.11.0" [package.dependencies.nltk] optional = true +python = ">=2.8" version = ">=3.2.5" [package.extras] -languages = ["nltk (>=3.2.5)"] +languages = ["nltk (>=3.2.5,<3.5)", "nltk (>=3.2.5)"] [[package]] category = "dev" @@ -633,10 +719,12 @@ description = "Python implementation of Markdown." name = "markdown" optional = false python-versions = ">=3.5" -version = "3.2.1" +version = "3.2.2" [package.dependencies] -setuptools = ">=36" +[package.dependencies.importlib-metadata] +python = "<3.8" +version = "*" [package.extras] testing = ["coverage", "pyyaml"] @@ -685,7 +773,7 @@ marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_v name = "mkdocs" optional = false python-versions = ">=3.5" -version = "1.1" +version = "1.1.2" [package.dependencies] Jinja2 = ">=2.10.1" @@ -697,7 +785,7 @@ tornado = ">=5.0" [package.dependencies.lunr] extras = ["languages"] -version = "0.5.6" +version = "0.5.8" [[package]] category = "dev" @@ -735,7 +823,7 @@ six = ">=1.0.0,<2.0.0" [[package]] category = "dev" description = "More routines for operating on iterables, beyond itertools" -marker = "python_version > \"2.7\"" +marker = "python_version < \"3.5\" and python_version > \"2.7\"" name = "more-itertools" optional = false python-versions = ">=3.4" @@ -744,11 +832,11 @@ version = "7.2.0" [[package]] category = "dev" description = "More routines for operating on iterables, beyond itertools" -marker = "python_version > \"2.7\"" +marker = "python_version >= \"3.5\"" name = "more-itertools" optional = false python-versions = ">=3.5" -version = "8.2.0" +version = "8.3.0" [[package]] category = "main" @@ -765,13 +853,16 @@ marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_v name = "nltk" optional = false python-versions = "*" -version = "3.4.5" +version = "3.5" [package.dependencies] -six = "*" +click = "*" +joblib = "*" +regex = "*" +tqdm = "*" [package.extras] -all = ["pyparsing", "scikit-learn", "python-crfsuite", "matplotlib", "scipy", "gensim", "requests", "twython", "numpy"] +all = ["requests", "numpy", "python-crfsuite", "scikit-learn", "twython", "pyparsing", "scipy", "matplotlib", "gensim"] corenlp = ["requests"] machine_learning = ["gensim", "numpy", "python-crfsuite", "scikit-learn", "scipy"] plot = ["matplotlib"] @@ -784,7 +875,7 @@ description = "Node.js virtual environment builder" name = "nodeenv" optional = false python-versions = "*" -version = "1.3.5" +version = "1.4.0" [[package]] category = "dev" @@ -792,7 +883,7 @@ description = "Core utilities for Python packages" name = "packaging" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.1" +version = "20.4" [package.dependencies] pyparsing = ">=2.0.2" @@ -809,7 +900,7 @@ version = "0.2.0" [[package]] category = "main" description = "Object-oriented filesystem paths" -marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\" or python_version < \"3.6\"" +marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\" or python_version < \"3.5\" or python_version >= \"3.5\" and python_version < \"3.6\"" name = "pathlib2" optional = false python-versions = "*" @@ -829,7 +920,7 @@ marker = "python_version >= \"3.6\" and python_version < \"4.0\"" name = "pathspec" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "0.7.0" +version = "0.8.0" [[package]] category = "dev" @@ -953,7 +1044,7 @@ marker = "python_version >= \"2.7\" and python_version < \"2.8\" and (sys_platfo name = "pycparser" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.19" +version = "2.20" [[package]] category = "dev" @@ -971,6 +1062,14 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "2.5.2" +[[package]] +category = "dev" +description = "Pygments is a syntax highlighting package written in Python." +name = "pygments" +optional = false +python-versions = ">=3.5" +version = "2.6.1" + [[package]] category = "dev" description = "Pygments Github custom lexers." @@ -1030,7 +1129,7 @@ description = "Python parsing module" name = "pyparsing" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.6" +version = "2.4.7" [[package]] category = "main" @@ -1049,7 +1148,7 @@ description = "pytest: simple powerful testing with Python" name = "pytest" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "4.6.9" +version = "4.6.11" [package.dependencies] atomicwrites = ">=1.0" @@ -1091,6 +1190,36 @@ version = ">=2.2.0" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "nose", "requests", "mock"] +[[package]] +category = "dev" +description = "pytest: simple powerful testing with Python" +name = "pytest" +optional = false +python-versions = ">=3.5" +version = "5.4.3" + +[package.dependencies] +atomicwrites = ">=1.0" +attrs = ">=17.4.0" +colorama = "*" +more-itertools = ">=4.0.0" +packaging = "*" +pluggy = ">=0.12,<1.0" +py = ">=1.5.0" +wcwidth = "*" + +[package.dependencies.importlib-metadata] +python = "<3.8" +version = ">=0.12" + +[package.dependencies.pathlib2] +python = "<3.6" +version = ">=2.2.0" + +[package.extras] +checkqa-mypy = ["mypy (v0.761)"] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + [[package]] category = "dev" description = "Pytest plugin for measuring coverage." @@ -1106,6 +1235,21 @@ pytest = ">=3.6" [package.extras] testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "virtualenv"] +[[package]] +category = "dev" +description = "Pytest plugin for measuring coverage." +name = "pytest-cov" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "2.9.0" + +[package.dependencies] +coverage = ">=4.4" +pytest = ">=3.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "pytest-xdist", "virtualenv"] + [[package]] category = "dev" description = "Thin-wrapper around the mock package for easier use with py.test" @@ -1130,7 +1274,7 @@ description = "pytest-sugar is a plugin for pytest that changes the default look name = "pytest-sugar" optional = false python-versions = "*" -version = "0.9.2" +version = "0.9.3" [package.dependencies] packaging = ">=14.1" @@ -1160,16 +1304,16 @@ description = "YAML parser and emitter for Python" name = "pyyaml" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "5.3" +version = "5.3.1" [[package]] category = "dev" description = "Alternative regular expression module, to replace re." -marker = "python_version >= \"3.6\" and python_version < \"4.0\"" +marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"4.0\" or python_version >= \"3.6\" and python_version < \"4.0\"" name = "regex" optional = false python-versions = "*" -version = "2020.2.20" +version = "2020.5.14" [[package]] category = "main" @@ -1221,7 +1365,7 @@ requests = ">=2.0.1,<3.0.0" [[package]] category = "main" description = "scandir, a better directory iterator and faster os.walk()" -marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\" or python_version < \"3.5\"" +marker = "python_version >= \"2.7\" and python_version < \"2.8\" or python_version >= \"3.4\" and python_version < \"3.5\"" name = "scandir" optional = false python-versions = "*" @@ -1263,13 +1407,25 @@ optional = false python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" version = "1.3.2" +[[package]] +category = "dev" +description = "This library brings functools.singledispatch from Python 3.4 to Python 2.6-3.3." +marker = "python_version < \"3.4\"" +name = "singledispatch" +optional = false +python-versions = "*" +version = "3.4.0.3" + +[package.dependencies] +six = "*" + [[package]] category = "main" description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.14.0" +version = "1.15.0" [[package]] category = "main" @@ -1294,7 +1450,7 @@ description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false python-versions = "*" -version = "0.10.0" +version = "0.10.1" [[package]] category = "main" @@ -1333,7 +1489,7 @@ marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_v name = "tornado" optional = false python-versions = ">= 3.5" -version = "6.0.3" +version = "6.0.4" [[package]] category = "dev" @@ -1362,25 +1518,37 @@ description = "tox is a generic virtualenv management and test command line tool name = "tox" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "3.14.5" +version = "3.15.1" [package.dependencies] colorama = ">=0.4.1" -filelock = ">=3.0.0,<4" +filelock = ">=3.0.0" packaging = ">=14" -pluggy = ">=0.12.0,<1" -py = ">=1.4.17,<2" -six = ">=1.14.0,<2" +pluggy = ">=0.12.0" +py = ">=1.4.17" +six = ">=1.14.0" toml = ">=0.9.4" -virtualenv = ">=16.0.0" +virtualenv = ">=16.0.0,<20.0.0 || >20.0.0,<20.0.1 || >20.0.1,<20.0.2 || >20.0.2,<20.0.3 || >20.0.3,<20.0.4 || >20.0.4,<20.0.5 || >20.0.5,<20.0.6 || >20.0.6,<20.0.7 || >20.0.7" [package.dependencies.importlib-metadata] python = "<3.8" version = ">=0.12,<2" [package.extras] -docs = ["sphinx (>=2.0.0,<3)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] -testing = ["freezegun (>=0.3.11,<1)", "pathlib2 (>=2.3.3,<3)", "pytest (>=4.0.0,<6)", "pytest-cov (>=2.5.1,<3)", "pytest-mock (>=1.10.0,<2)", "pytest-xdist (>=1.22.2,<2)", "pytest-randomly (>=1.0.0,<4)", "flaky (>=3.4.0,<4)", "psutil (>=5.6.1,<6)"] +docs = ["sphinx (>=2.0.0)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] +testing = ["freezegun (>=0.3.11)", "pathlib2 (>=2.3.3)", "pytest (>=4.0.0)", "pytest-cov (>=2.5.1)", "pytest-mock (>=1.10.0)", "pytest-xdist (>=1.22.2)", "pytest-randomly (>=1.0.0)", "flaky (>=3.4.0)", "psutil (>=5.6.1)"] + +[[package]] +category = "dev" +description = "Fast, Extensible Progress Meter" +marker = "python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"4.0\"" +name = "tqdm" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" +version = "4.46.1" + +[package.extras] +dev = ["py-make (>=0.1.0)", "twine", "argopt", "pydoc-markdown"] [[package]] category = "dev" @@ -1407,7 +1575,7 @@ marker = "python_version >= \"3.5.0\" and python_version < \"3.5.4\"" name = "typing-extensions" optional = false python-versions = "*" -version = "3.7.4.1" +version = "3.7.4.2" [[package]] category = "main" @@ -1427,11 +1595,11 @@ description = "HTTP library with thread-safe connection pooling, file post, and name = "urllib3" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "1.25.8" +version = "1.25.9" [package.extras] brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"] socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"] [[package]] @@ -1452,7 +1620,7 @@ description = "Virtual Python Environment builder" name = "virtualenv" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "20.0.7" +version = "20.0.21" [package.dependencies] appdirs = ">=1.4.3,<2" @@ -1469,16 +1637,22 @@ python = "<3.7" version = ">=1.0,<2" [package.extras] -docs = ["sphinx (>=2.0.0,<3)", "sphinx-argparse (>=0.2.5,<1)", "sphinx-rtd-theme (>=0.4.3,<1)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2,<1)"] -testing = ["pytest (>=4.0.0,<6)", "coverage (>=4.5.1,<6)", "pytest-mock (>=2.0.0,<3)", "pytest-env (>=0.6.2,<1)", "packaging (>=20.0)", "xonsh (>=0.9.13,<1)"] +docs = ["sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=19.9.0rc1)", "proselint (>=0.10.2)"] +testing = ["pytest (>=4)", "coverage (>=5)", "coverage-enable-subprocess (>=1)", "pytest-xdist (>=1.31.0)", "pytest-mock (>=2)", "pytest-env (>=0.6.2)", "pytest-randomly (>=1)", "pytest-timeout", "packaging (>=20.0)", "xonsh (>=0.9.16)"] [[package]] category = "dev" -description = "Measures number of Terminal column cells of wide-character codes" +description = "Measures the displayed width of unicode strings in a terminal" +marker = "python_version < \"3.5\" or python_version >= \"3.5\"" name = "wcwidth" optional = false python-versions = "*" -version = "0.1.8" +version = "0.2.3" + +[package.dependencies] +[package.dependencies."backports.functools-lru-cache"] +python = "<3.2" +version = ">=1.2.1" [[package]] category = "main" @@ -1491,6 +1665,7 @@ version = "0.5.1" [[package]] category = "main" description = "Backport of pathlib-compatible object wrapper for zip files" +marker = "python_version < \"3.8\" or python_version >= \"3.5\" and python_version < \"3.8\" or python_version >= \"2.7.9\" and python_version < \"2.8.0\" or python_version >= \"3.4\" and python_version < \"3.8\"" name = "zipp" optional = false python-versions = ">=2.7" @@ -1506,26 +1681,30 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pathlib2", "unittest2", "jaraco.itertools", "func-timeout"] [metadata] -content-hash = "70609fddc0d3768b1003fc24207951ab7ad8bfad4c6cb326d6217c52f5a92e3d" +content-hash = "f585f9479c9551e48768249cc80ec8f217539b42fcc3822543fdd0789f9f9d87" python-versions = "~2.7 || ^3.4" [metadata.files] appdirs = [ - {file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"}, - {file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"}, + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] "aspy.yaml" = [ {file = "aspy.yaml-1.3.0-py2.py3-none-any.whl", hash = "sha256:463372c043f70160a9ec950c3f1e4c3a82db5fca01d334b6bc89c7164d744bdc"}, {file = "aspy.yaml-1.3.0.tar.gz", hash = "sha256:e7c742382eff2caed61f87a39d13f99109088e5e93f04d76eb8d4b28aa143f45"}, ] atomicwrites = [ - {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"}, - {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"}, + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, ] +"backports.functools-lru-cache" = [ + {file = "backports.functools_lru_cache-1.6.1-py2.py3-none-any.whl", hash = "sha256:0bada4c2f8a43d533e4ecb7a12214d9420e66eb206d54bf2d682581ca4b80848"}, + {file = "backports.functools_lru_cache-1.6.1.tar.gz", hash = "sha256:8fde5f188da2d593bd5bc0be98d9abc46c95bb8a9dde93429570192ee6cc2d4a"}, +] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, @@ -1539,8 +1718,8 @@ cachy = [ {file = "cachy-0.3.0.tar.gz", hash = "sha256:186581f4ceb42a0bbe040c407da73c14092379b1e4c0e327fdb72ae4a9b269b1"}, ] certifi = [ - {file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"}, - {file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"}, + {file = "certifi-2020.4.5.1-py2.py3-none-any.whl", hash = "sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304"}, + {file = "certifi-2020.4.5.1.tar.gz", hash = "sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519"}, ] cffi = [ {file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"}, @@ -1585,12 +1764,14 @@ cleo = [ {file = "cleo-0.7.6.tar.gz", hash = "sha256:99cf342406f3499cec43270fcfaf93c126c5164092eca201dfef0f623360b409"}, ] click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, {file = "Click-7.0-py2.py3-none-any.whl", hash = "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13"}, {file = "Click-7.0.tar.gz", hash = "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"}, ] clikit = [ - {file = "clikit-0.4.2-py2.py3-none-any.whl", hash = "sha256:95394982cfa460a77ded2f173380a958e5f90c16972307c19d79b96f6e335326"}, - {file = "clikit-0.4.2.tar.gz", hash = "sha256:f67336462800078e0896cf6ecfa3b460dfea4dfa01de659388a4ff0d83c8d6ca"}, + {file = "clikit-0.4.3-py2.py3-none-any.whl", hash = "sha256:71e321b7795a2a6c4888629f43365d52db071737e668ab16861121d7dd3ada09"}, + {file = "clikit-0.4.3.tar.gz", hash = "sha256:6e2d7e115e7c7b35bceb0209109935ab2f9ab50910e9ff2293f7fa0b7abf973e"}, ] colorama = [ {file = "colorama-0.4.1-py2.py3-none-any.whl", hash = "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"}, @@ -1639,37 +1820,37 @@ coverage = [ {file = "coverage-4.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351"}, {file = "coverage-4.5.4-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5"}, {file = "coverage-4.5.4.tar.gz", hash = "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c"}, - {file = "coverage-5.0.3-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:cc1109f54a14d940b8512ee9f1c3975c181bbb200306c6d8b87d93376538782f"}, - {file = "coverage-5.0.3-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:be18f4ae5a9e46edae3f329de2191747966a34a3d93046dbdf897319923923bc"}, - {file = "coverage-5.0.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3230d1003eec018ad4a472d254991e34241e0bbd513e97a29727c7c2f637bd2a"}, - {file = "coverage-5.0.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:e69215621707119c6baf99bda014a45b999d37602cb7043d943c76a59b05bf52"}, - {file = "coverage-5.0.3-cp27-cp27m-win32.whl", hash = "sha256:1daa3eceed220f9fdb80d5ff950dd95112cd27f70d004c7918ca6dfc6c47054c"}, - {file = "coverage-5.0.3-cp27-cp27m-win_amd64.whl", hash = "sha256:51bc7710b13a2ae0c726f69756cf7ffd4362f4ac36546e243136187cfcc8aa73"}, - {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:9bea19ac2f08672636350f203db89382121c9c2ade85d945953ef3c8cf9d2a68"}, - {file = "coverage-5.0.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5012d3b8d5a500834783689a5d2292fe06ec75dc86ee1ccdad04b6f5bf231691"}, - {file = "coverage-5.0.3-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:d513cc3db248e566e07a0da99c230aca3556d9b09ed02f420664e2da97eac301"}, - {file = "coverage-5.0.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3dbb72eaeea5763676a1a1efd9b427a048c97c39ed92e13336e726117d0b72bf"}, - {file = "coverage-5.0.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:15cf13a6896048d6d947bf7d222f36e4809ab926894beb748fc9caa14605d9c3"}, - {file = "coverage-5.0.3-cp35-cp35m-win32.whl", hash = "sha256:fca1669d464f0c9831fd10be2eef6b86f5ebd76c724d1e0706ebdff86bb4adf0"}, - {file = "coverage-5.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:1e44a022500d944d42f94df76727ba3fc0a5c0b672c358b61067abb88caee7a0"}, - {file = "coverage-5.0.3-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:b26aaf69713e5674efbde4d728fb7124e429c9466aeaf5f4a7e9e699b12c9fe2"}, - {file = "coverage-5.0.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:722e4557c8039aad9592c6a4213db75da08c2cd9945320220634f637251c3894"}, - {file = "coverage-5.0.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:7afad9835e7a651d3551eab18cbc0fdb888f0a6136169fbef0662d9cdc9987cf"}, - {file = "coverage-5.0.3-cp36-cp36m-win32.whl", hash = "sha256:25dbf1110d70bab68a74b4b9d74f30e99b177cde3388e07cc7272f2168bd1477"}, - {file = "coverage-5.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:c312e57847db2526bc92b9bfa78266bfbaabac3fdcd751df4d062cd4c23e46dc"}, - {file = "coverage-5.0.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:a8b8ac7876bc3598e43e2603f772d2353d9931709345ad6c1149009fd1bc81b8"}, - {file = "coverage-5.0.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:527b4f316e6bf7755082a783726da20671a0cc388b786a64417780b90565b987"}, - {file = "coverage-5.0.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d649dc0bcace6fcdb446ae02b98798a856593b19b637c1b9af8edadf2b150bea"}, - {file = "coverage-5.0.3-cp37-cp37m-win32.whl", hash = "sha256:cd60f507c125ac0ad83f05803063bed27e50fa903b9c2cfee3f8a6867ca600fc"}, - {file = "coverage-5.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c60097190fe9dc2b329a0eb03393e2e0829156a589bd732e70794c0dd804258e"}, - {file = "coverage-5.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:d7008a6796095a79544f4da1ee49418901961c97ca9e9d44904205ff7d6aa8cb"}, - {file = "coverage-5.0.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ea9525e0fef2de9208250d6c5aeeee0138921057cd67fcef90fbed49c4d62d37"}, - {file = "coverage-5.0.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:c62a2143e1313944bf4a5ab34fd3b4be15367a02e9478b0ce800cb510e3bbb9d"}, - {file = "coverage-5.0.3-cp38-cp38m-win32.whl", hash = "sha256:b0840b45187699affd4c6588286d429cd79a99d509fe3de0f209594669bb0954"}, - {file = "coverage-5.0.3-cp38-cp38m-win_amd64.whl", hash = "sha256:76e2057e8ffba5472fd28a3a010431fd9e928885ff480cb278877c6e9943cc2e"}, - {file = "coverage-5.0.3-cp39-cp39m-win32.whl", hash = "sha256:b63dd43f455ba878e5e9f80ba4f748c0a2156dde6e0e6e690310e24d6e8caf40"}, - {file = "coverage-5.0.3-cp39-cp39m-win_amd64.whl", hash = "sha256:da93027835164b8223e8e5af2cf902a4c80ed93cb0909417234f4a9df3bcd9af"}, - {file = "coverage-5.0.3.tar.gz", hash = "sha256:77afca04240c40450c331fa796b3eab6f1e15c5ecf8bf2b8bee9706cd5452fef"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:0cb4be7e784dcdc050fc58ef05b71aa8e89b7e6636b99967fadbdba694cf2b65"}, + {file = "coverage-5.1-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:c317eaf5ff46a34305b202e73404f55f7389ef834b8dbf4da09b9b9b37f76dd2"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:b83835506dfc185a319031cf853fa4bb1b3974b1f913f5bb1a0f3d98bdcded04"}, + {file = "coverage-5.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5f2294dbf7875b991c381e3d5af2bcc3494d836affa52b809c91697449d0eda6"}, + {file = "coverage-5.1-cp27-cp27m-win32.whl", hash = "sha256:de807ae933cfb7f0c7d9d981a053772452217df2bf38e7e6267c9cbf9545a796"}, + {file = "coverage-5.1-cp27-cp27m-win_amd64.whl", hash = "sha256:bf9cb9a9fd8891e7efd2d44deb24b86d647394b9705b744ff6f8261e6f29a730"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:acf3763ed01af8410fc36afea23707d4ea58ba7e86a8ee915dfb9ceff9ef69d0"}, + {file = "coverage-5.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:dec5202bfe6f672d4511086e125db035a52b00f1648d6407cc8e526912c0353a"}, + {file = "coverage-5.1-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:7a5bdad4edec57b5fb8dae7d3ee58622d626fd3a0be0dfceda162a7035885ecf"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1601e480b9b99697a570cea7ef749e88123c04b92d84cedaa01e117436b4a0a9"}, + {file = "coverage-5.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:dbe8c6ae7534b5b024296464f387d57c13caa942f6d8e6e0346f27e509f0f768"}, + {file = "coverage-5.1-cp35-cp35m-win32.whl", hash = "sha256:a027ef0492ede1e03a8054e3c37b8def89a1e3c471482e9f046906ba4f2aafd2"}, + {file = "coverage-5.1-cp35-cp35m-win_amd64.whl", hash = "sha256:0e61d9803d5851849c24f78227939c701ced6704f337cad0a91e0972c51c1ee7"}, + {file = "coverage-5.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:2d27a3f742c98e5c6b461ee6ef7287400a1956c11421eb574d843d9ec1f772f0"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66460ab1599d3cf894bb6baee8c684788819b71a5dc1e8fa2ecc152e5d752019"}, + {file = "coverage-5.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5c542d1e62eece33c306d66fe0a5c4f7f7b3c08fecc46ead86d7916684b36d6c"}, + {file = "coverage-5.1-cp36-cp36m-win32.whl", hash = "sha256:2742c7515b9eb368718cd091bad1a1b44135cc72468c731302b3d641895b83d1"}, + {file = "coverage-5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:dead2ddede4c7ba6cb3a721870f5141c97dc7d85a079edb4bd8d88c3ad5b20c7"}, + {file = "coverage-5.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:01333e1bd22c59713ba8a79f088b3955946e293114479bbfc2e37d522be03355"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e1ea316102ea1e1770724db01998d1603ed921c54a86a2efcb03428d5417e489"}, + {file = "coverage-5.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:adeb4c5b608574a3d647011af36f7586811a2c1197c861aedb548dd2453b41cd"}, + {file = "coverage-5.1-cp37-cp37m-win32.whl", hash = "sha256:782caea581a6e9ff75eccda79287daefd1d2631cc09d642b6ee2d6da21fc0a4e"}, + {file = "coverage-5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:00f1d23f4336efc3b311ed0d807feb45098fc86dee1ca13b3d6768cdab187c8a"}, + {file = "coverage-5.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:402e1744733df483b93abbf209283898e9f0d67470707e3c7516d84f48524f55"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a3f3654d5734a3ece152636aad89f58afc9213c6520062db3978239db122f03c"}, + {file = "coverage-5.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6402bd2fdedabbdb63a316308142597534ea8e1895f4e7d8bf7476c5e8751fef"}, + {file = "coverage-5.1-cp38-cp38-win32.whl", hash = "sha256:8fa0cbc7ecad630e5b0f4f35b0f6ad419246b02bc750de7ac66db92667996d24"}, + {file = "coverage-5.1-cp38-cp38-win_amd64.whl", hash = "sha256:79a3cfd6346ce6c13145731d39db47b7a7b859c0272f02cdb89a3bdcbae233a0"}, + {file = "coverage-5.1-cp39-cp39-win32.whl", hash = "sha256:a82b92b04a23d3c8a581fc049228bafde988abacba397d57ce95fe95e0338ab4"}, + {file = "coverage-5.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb28a7245de68bf29f6fb199545d072d1036a1917dca17a1e75bbb919e14ee8e"}, + {file = "coverage-5.1.tar.gz", hash = "sha256:f90bfc4ad18450c80b024036eaf91e4a246ae287701aaa88eaebebf150868052"}, ] cryptography = [ {file = "cryptography-2.8-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"}, @@ -1693,6 +1874,25 @@ cryptography = [ {file = "cryptography-2.8-cp38-cp38-win32.whl", hash = "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e"}, {file = "cryptography-2.8-cp38-cp38-win_amd64.whl", hash = "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13"}, {file = "cryptography-2.8.tar.gz", hash = "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651"}, + {file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"}, + {file = "cryptography-2.9.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:3b3eba865ea2754738616f87292b7f29448aec342a7c720956f8083d252bf28b"}, + {file = "cryptography-2.9.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:c447cf087cf2dbddc1add6987bbe2f767ed5317adb2d08af940db517dd704365"}, + {file = "cryptography-2.9.2-cp27-cp27m-win32.whl", hash = "sha256:f118a95c7480f5be0df8afeb9a11bd199aa20afab7a96bcf20409b411a3a85f0"}, + {file = "cryptography-2.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:c4fd17d92e9d55b84707f4fd09992081ba872d1a0c610c109c18e062e06a2e55"}, + {file = "cryptography-2.9.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d0d5aeaedd29be304848f1c5059074a740fa9f6f26b84c5b63e8b29e73dfc270"}, + {file = "cryptography-2.9.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:1e4014639d3d73fbc5ceff206049c5a9a849cefd106a49fa7aaaa25cc0ce35cf"}, + {file = "cryptography-2.9.2-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:96c080ae7118c10fcbe6229ab43eb8b090fccd31a09ef55f83f690d1ef619a1d"}, + {file = "cryptography-2.9.2-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:e993468c859d084d5579e2ebee101de8f5a27ce8e2159959b6673b418fd8c785"}, + {file = "cryptography-2.9.2-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:88c881dd5a147e08d1bdcf2315c04972381d026cdb803325c03fe2b4a8ed858b"}, + {file = "cryptography-2.9.2-cp35-cp35m-win32.whl", hash = "sha256:651448cd2e3a6bc2bb76c3663785133c40d5e1a8c1a9c5429e4354201c6024ae"}, + {file = "cryptography-2.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:726086c17f94747cedbee6efa77e99ae170caebeb1116353c6cf0ab67ea6829b"}, + {file = "cryptography-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:091d31c42f444c6f519485ed528d8b451d1a0c7bf30e8ca583a0cac44b8a0df6"}, + {file = "cryptography-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:bb1f0281887d89617b4c68e8db9a2c42b9efebf2702a3c5bf70599421a8623e3"}, + {file = "cryptography-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:18452582a3c85b96014b45686af264563e3e5d99d226589f057ace56196ec78b"}, + {file = "cryptography-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:22e91636a51170df0ae4dcbd250d318fd28c9f491c4e50b625a49964b24fe46e"}, + {file = "cryptography-2.9.2-cp38-cp38-win32.whl", hash = "sha256:844a76bc04472e5135b909da6aed84360f522ff5dfa47f93e3dd2a0b84a89fa0"}, + {file = "cryptography-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:1dfa985f62b137909496e7fc182dac687206d8d089dd03eaeb28ae16eec8e7d5"}, + {file = "cryptography-2.9.2.tar.gz", hash = "sha256:a0c30272fb4ddda5f5ffc1089d7405b7a71b0b0f51993cb4e5dbb4590b2fc229"}, ] distlib = [ {file = "distlib-0.3.0.zip", hash = "sha256:2e166e231a26b36d6dfe35a48c4464346620f8645ed0ace01ee31822b288de21"}, @@ -1702,9 +1902,9 @@ entrypoints = [ {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, ] enum34 = [ - {file = "enum34-1.1.9-py2-none-any.whl", hash = "sha256:98df1f1937840b7d8012fea7f0b36392a3e6fd8a2f429c48a3ff4b1aad907f3f"}, - {file = "enum34-1.1.9-py3-none-any.whl", hash = "sha256:708aabfb3d5898f99674c390d360d59efdd08547019763622365f19e84a7fef4"}, - {file = "enum34-1.1.9.tar.gz", hash = "sha256:13ef9a1c478203252107f66c25b99b45b1865693ca1284aab40dafa7e1e7ac17"}, + {file = "enum34-1.1.10-py2-none-any.whl", hash = "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53"}, + {file = "enum34-1.1.10-py3-none-any.whl", hash = "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328"}, + {file = "enum34-1.1.10.tar.gz", hash = "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248"}, ] filelock = [ {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, @@ -1736,8 +1936,8 @@ httpretty = [ {file = "httpretty-0.9.7.tar.gz", hash = "sha256:66216f26b9d2c52e81808f3e674a6fb65d4bf719721394a1a9be926177e55fbe"}, ] identify = [ - {file = "identify-1.4.11-py2.py3-none-any.whl", hash = "sha256:1222b648251bdcb8deb240b294f450fbf704c7984e08baa92507e4ea10b436d5"}, - {file = "identify-1.4.11.tar.gz", hash = "sha256:d824ebe21f38325c771c41b08a95a761db1982f1fc0eee37c6c97df3f1636b96"}, + {file = "identify-1.4.19-py2.py3-none-any.whl", hash = "sha256:781fd3401f5d2b17b22a8b18b493a48d5d948e3330634e82742e23f9c20234ef"}, + {file = "identify-1.4.19.tar.gz", hash = "sha256:249ebc7e2066d6393d27c1b1be3b70433f824a120b1d8274d362f1eb419e3b52"}, ] idna = [ {file = "idna-2.8-py2.py3-none-any.whl", hash = "sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"}, @@ -1752,20 +1952,26 @@ importlib-metadata = [ importlib-resources = [ {file = "importlib_resources-1.0.2-py2.py3-none-any.whl", hash = "sha256:6e2783b2538bd5a14678284a3962b0660c715e5a0f10243fd5e00a4b5974f50b"}, {file = "importlib_resources-1.0.2.tar.gz", hash = "sha256:d3279fd0f6f847cced9f7acc19bd3e5df54d34f93a2e7bb5f238f81545787078"}, + {file = "importlib_resources-1.5.0-py2.py3-none-any.whl", hash = "sha256:85dc0b9b325ff78c8bef2e4ff42616094e16b98ebd5e3b50fe7e2f0bbcdcde49"}, + {file = "importlib_resources-1.5.0.tar.gz", hash = "sha256:6f87df66833e1942667108628ec48900e02a4ab4ad850e25fbf07cb17cf734ca"}, ] ipaddress = [ {file = "ipaddress-1.0.23-py2.py3-none-any.whl", hash = "sha256:6e0f4a39e66cb5bb9a137b00276a2eff74f93b71dcbdad6f10ff7df9d3557fcc"}, {file = "ipaddress-1.0.23.tar.gz", hash = "sha256:b7f8e0369580bb4a24d5ba1d7cc29660a4a6987763faf1d8a8046830e020e7e2"}, ] jeepney = [ - {file = "jeepney-0.4.2-py3-none-any.whl", hash = "sha256:6f45dce1125cf6c58a1c88123d3831f36a789f9204fbad3172eac15f8ccd08d0"}, - {file = "jeepney-0.4.2.tar.gz", hash = "sha256:0ba6d8c597e9bef1ebd18aaec595f942a264e25c1a48f164d46120eacaa2e9bb"}, + {file = "jeepney-0.4.3-py3-none-any.whl", hash = "sha256:d6c6b49683446d2407d2fe3acb7a368a77ff063f9182fe427da15d622adc24cf"}, + {file = "jeepney-0.4.3.tar.gz", hash = "sha256:3479b861cc2b6407de5188695fa1a8d57e5072d7059322469b62628869b8e36e"}, ] jinja2 = [ {file = "Jinja2-2.10.3-py2.py3-none-any.whl", hash = "sha256:74320bb91f31270f9551d46522e33af46a80c3d619f4a4bf42b3164d30b5911f"}, {file = "Jinja2-2.10.3.tar.gz", hash = "sha256:9fe95f19286cfefaa917656583d020be14e7859c6b0252588391e47db34527de"}, - {file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"}, - {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, + {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, + {file = "Jinja2-2.11.2.tar.gz", hash = "sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0"}, +] +joblib = [ + {file = "joblib-0.14.1-py2.py3-none-any.whl", hash = "sha256:bdb4fd9b72915ffb49fde2229ce482dd7ae79d842ed8c2b4c932441495af1403"}, + {file = "joblib-0.14.1.tar.gz", hash = "sha256:0630eea4f5664c463f23fbf5dcfc54a2bc6168902719fa8e19daf033022786c8"}, ] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, @@ -1786,16 +1992,16 @@ lockfile = [ {file = "lockfile-0.12.2.tar.gz", hash = "sha256:6aed02de03cba24efabcd600b30540140634fc06cfa603822d508d5361e9f799"}, ] lunr = [ - {file = "lunr-0.5.6-py2.py3-none-any.whl", hash = "sha256:1208622930c915a07e6f8e8640474357826bad48534c0f57969b6fca9bffc88e"}, - {file = "lunr-0.5.6.tar.gz", hash = "sha256:7be69d7186f65784a4f2adf81e5c58efd6a9921aa95966babcb1f2f2ada75c20"}, + {file = "lunr-0.5.8-py2.py3-none-any.whl", hash = "sha256:aab3f489c4d4fab4c1294a257a30fec397db56f0a50273218ccc3efdbf01d6ca"}, + {file = "lunr-0.5.8.tar.gz", hash = "sha256:c4fb063b98eff775dd638b3df380008ae85e6cb1d1a24d1cd81a10ef6391c26e"}, ] markdown = [ {file = "Markdown-3.0.1-py2.py3-none-any.whl", hash = "sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa"}, {file = "Markdown-3.0.1.tar.gz", hash = "sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"}, {file = "Markdown-3.1.1-py2.py3-none-any.whl", hash = "sha256:56a46ac655704b91e5b7e6326ce43d5ef72411376588afa1dd90e881b83c7e8c"}, {file = "Markdown-3.1.1.tar.gz", hash = "sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a"}, - {file = "Markdown-3.2.1-py2.py3-none-any.whl", hash = "sha256:e4795399163109457d4c5af2183fbe6b60326c17cfdf25ce6e7474c6624f725d"}, - {file = "Markdown-3.2.1.tar.gz", hash = "sha256:90fee683eeabe1a92e149f7ba74e5ccdc81cd397bd6c516d93a8da0ef90b6902"}, + {file = "Markdown-3.2.2-py3-none-any.whl", hash = "sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59"}, + {file = "Markdown-3.2.2.tar.gz", hash = "sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17"}, ] markdown-include = [ {file = "markdown-include-0.5.1.tar.gz", hash = "sha256:72a45461b589489a088753893bc95c5fa5909936186485f4ed55caa57d10250f"}, @@ -1828,18 +2034,13 @@ markupsafe = [ {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] mkdocs = [ {file = "mkdocs-1.0.4-py2.py3-none-any.whl", hash = "sha256:8cc8b38325456b9e942c981a209eaeb1e9f3f77b493ad755bfef889b9c8d356a"}, {file = "mkdocs-1.0.4.tar.gz", hash = "sha256:17d34329aad75d5de604b9ed4e31df3a4d235afefdc46ce7b1964fddb2e1e939"}, - {file = "mkdocs-1.1-py2.py3-none-any.whl", hash = "sha256:1e385a70aea8a9dedb731aea4fd5f3704b2074801c4f96f06b2920999babda8a"}, - {file = "mkdocs-1.1.tar.gz", hash = "sha256:9243291392f59e20b655e4e46210233453faf97787c2cf72176510e868143174"}, + {file = "mkdocs-1.1.2-py3-none-any.whl", hash = "sha256:096f52ff52c02c7e90332d2e53da862fde5c062086e1b5356a6e392d5d60f5e9"}, + {file = "mkdocs-1.1.2.tar.gz", hash = "sha256:f0b61e5402b99d7789efa032c7a74c90a20220a9c81749da06dbfbcbd52ffb39"}, ] mock = [ {file = "mock-3.0.5-py2.py3-none-any.whl", hash = "sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8"}, @@ -1851,8 +2052,8 @@ more-itertools = [ {file = "more_itertools-5.0.0-py3-none-any.whl", hash = "sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"}, {file = "more-itertools-7.2.0.tar.gz", hash = "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832"}, {file = "more_itertools-7.2.0-py3-none-any.whl", hash = "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"}, - {file = "more-itertools-8.2.0.tar.gz", hash = "sha256:b1ddb932186d8a6ac451e1d95844b382f55e12686d51ca0c68b6f61f2ab7a507"}, - {file = "more_itertools-8.2.0-py3-none-any.whl", hash = "sha256:5dd8bcf33e5f9513ffa06d5ad33d78f31e1931ac9a18f33d37e77a180d393a7c"}, + {file = "more-itertools-8.3.0.tar.gz", hash = "sha256:558bb897a2232f5e4f8e2399089e35aecb746e1f9191b6584a151647e89267be"}, + {file = "more_itertools-8.3.0-py3-none-any.whl", hash = "sha256:7818f596b1e87be009031c7653d01acc46ed422e6656b394b0f765ce66ed4982"}, ] msgpack = [ {file = "msgpack-1.0.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:cec8bf10981ed70998d98431cd814db0ecf3384e6b113366e7f36af71a0fca08"}, @@ -1875,15 +2076,14 @@ msgpack = [ {file = "msgpack-1.0.0.tar.gz", hash = "sha256:9534d5cc480d4aff720233411a1f765be90885750b07df772380b34c10ecb5c0"}, ] nltk = [ - {file = "nltk-3.4.5.win32.exe", hash = "sha256:a08bdb4b8a1c13de16743068d9eb61c8c71c2e5d642e8e08205c528035843f82"}, - {file = "nltk-3.4.5.zip", hash = "sha256:bed45551259aa2101381bbdd5df37d44ca2669c5c3dad72439fa459b29137d94"}, + {file = "nltk-3.5.zip", hash = "sha256:845365449cd8c5f9731f7cb9f8bd6fd0767553b9d53af9eb1b3abf7700936b35"}, ] nodeenv = [ - {file = "nodeenv-1.3.5-py2.py3-none-any.whl", hash = "sha256:5b2438f2e42af54ca968dd1b374d14a1194848955187b0e5e4be1f73813a5212"}, + {file = "nodeenv-1.4.0-py2.py3-none-any.whl", hash = "sha256:4b0b77afa3ba9b54f4b6396e60b0c83f59eaeb2d63dc3cc7a70f7f4af96c82bc"}, ] packaging = [ - {file = "packaging-20.1-py2.py3-none-any.whl", hash = "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73"}, - {file = "packaging-20.1.tar.gz", hash = "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"}, + {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, + {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] pastel = [ {file = "pastel-0.2.0-py2.py3-none-any.whl", hash = "sha256:18b559dc3ad4ba9b8bd5baebe6503f25f36d21460f021cf27a8d889cb5d17840"}, @@ -1894,8 +2094,8 @@ pathlib2 = [ {file = "pathlib2-2.3.5.tar.gz", hash = "sha256:6cd9a47b597b37cc57de1c05e56fb1a1c9cc9fab04fe78c29acd090418529868"}, ] pathspec = [ - {file = "pathspec-0.7.0-py2.py3-none-any.whl", hash = "sha256:163b0632d4e31cef212976cf57b43d9fd6b0bac6e67c26015d611a647d5e7424"}, - {file = "pathspec-0.7.0.tar.gz", hash = "sha256:562aa70af2e0d434367d9790ad37aed893de47f1693e4201fd1d3dca15d19b96"}, + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, ] pep562 = [ {file = "pep562-1.0-py2.py3-none-any.whl", hash = "sha256:d2a48b178ebf5f8dd31709cc26a19808ef794561fa2fe50ea01ea2bad4d667ef"}, @@ -1928,13 +2128,16 @@ py = [ {file = "py-1.8.1.tar.gz", hash = "sha256:5e27081401262157467ad6e7f851b7aa402c5852dbcb3dae06768434de5752aa"}, ] pycparser = [ - {file = "pycparser-2.19.tar.gz", hash = "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"}, + {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, + {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, ] pygments = [ {file = "Pygments-2.3.1-py2.py3-none-any.whl", hash = "sha256:e8218dd399a61674745138520d0d4cf2621d7e032439341bc3f647bff125818d"}, {file = "Pygments-2.3.1.tar.gz", hash = "sha256:5ffada19f6203563680669ee7f53b64dabbeb100eb51b61996085e99c03b284a"}, {file = "Pygments-2.5.2-py2.py3-none-any.whl", hash = "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b"}, {file = "Pygments-2.5.2.tar.gz", hash = "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe"}, + {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, + {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, ] pygments-github-lexers = [ {file = "pygments-github-lexers-0.0.5.tar.gz", hash = "sha256:aaca57e77cd6fcfce8d6ee97a998962eebf7fbb810519a8ebde427c62823e133"}, @@ -1953,27 +2156,30 @@ pymdown-extensions = [ {file = "pymdown_extensions-6.3-py2.py3-none-any.whl", hash = "sha256:66fae2683c7a1dac53184f7de57f51f8dad73f9ead2f453e94e85096cb811335"}, ] pyparsing = [ - {file = "pyparsing-2.4.6-py2.py3-none-any.whl", hash = "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec"}, - {file = "pyparsing-2.4.6.tar.gz", hash = "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f"}, + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyrsistent = [ {file = "pyrsistent-0.14.11.tar.gz", hash = "sha256:3ca82748918eb65e2d89f222b702277099aca77e34843c5eb9d52451173970e2"}, ] pytest = [ - {file = "pytest-4.6.9-py2.py3-none-any.whl", hash = "sha256:c77a5f30a90e0ce24db9eaa14ddfd38d4afb5ea159309bdd2dae55b931bc9324"}, - {file = "pytest-4.6.9.tar.gz", hash = "sha256:19e8f75eac01dd3f211edd465b39efbcbdc8fc5f7866d7dd49fedb30d8adf339"}, + {file = "pytest-4.6.11-py2.py3-none-any.whl", hash = "sha256:a00a7d79cbbdfa9d21e7d0298392a8dd4123316bfac545075e6f8f24c94d8c97"}, + {file = "pytest-4.6.11.tar.gz", hash = "sha256:50fa82392f2120cc3ec2ca0a75ee615be4c479e66669789771f1758332be4353"}, + {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, + {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, ] pytest-cov = [ {file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"}, {file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"}, + {file = "pytest-cov-2.9.0.tar.gz", hash = "sha256:b6a814b8ed6247bd81ff47f038511b57fe1ce7f4cc25b9106f1a4b106f1d9322"}, + {file = "pytest_cov-2.9.0-py2.py3-none-any.whl", hash = "sha256:c87dfd8465d865655a8213859f1b4749b43448b5fae465cb981e16d52a811424"}, ] pytest-mock = [ {file = "pytest-mock-1.13.0.tar.gz", hash = "sha256:e24a911ec96773022ebcc7030059b57cd3480b56d4f5d19b7c370ec635e6aed5"}, {file = "pytest_mock-1.13.0-py2.py3-none-any.whl", hash = "sha256:67e414b3caef7bff6fc6bd83b22b5bc39147e4493f483c2679bc9d4dc485a94d"}, ] pytest-sugar = [ - {file = "pytest-sugar-0.9.2.tar.gz", hash = "sha256:fcd87a74b2bce5386d244b49ad60549bfbc4602527797fac167da147983f58ab"}, - {file = "pytest_sugar-0.9.2-py2.py3-none-any.whl", hash = "sha256:26cf8289fe10880cbbc130bd77398c4e6a8b936d8393b116a5c16121d95ab283"}, + {file = "pytest-sugar-0.9.3.tar.gz", hash = "sha256:1630b5b7ea3624919b73fde37cffb87965c5087a4afab8a43074ff44e0d810c4"}, ] pywin32-ctypes = [ {file = "pywin32-ctypes-0.2.0.tar.gz", hash = "sha256:24ffc3b341d457d48e8922352130cf2644024a4ff09762a2261fd34c36ee5942"}, @@ -1991,40 +2197,40 @@ pyyaml = [ {file = "PyYAML-5.2-cp38-cp38-win32.whl", hash = "sha256:8100c896ecb361794d8bfdb9c11fce618c7cf83d624d73d5ab38aef3bc82d43f"}, {file = "PyYAML-5.2-cp38-cp38-win_amd64.whl", hash = "sha256:2e9f0b7c5914367b0916c3c104a024bb68f269a486b9d04a2e8ac6f6597b7803"}, {file = "PyYAML-5.2.tar.gz", hash = "sha256:c0ee8eca2c582d29c3c2ec6e2c4f703d1b7f1fb10bc72317355a746057e7346c"}, - {file = "PyYAML-5.3-cp27-cp27m-win32.whl", hash = "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d"}, - {file = "PyYAML-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6"}, - {file = "PyYAML-5.3-cp35-cp35m-win32.whl", hash = "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e"}, - {file = "PyYAML-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689"}, - {file = "PyYAML-5.3-cp36-cp36m-win32.whl", hash = "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994"}, - {file = "PyYAML-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e"}, - {file = "PyYAML-5.3-cp37-cp37m-win32.whl", hash = "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5"}, - {file = "PyYAML-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf"}, - {file = "PyYAML-5.3-cp38-cp38-win32.whl", hash = "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811"}, - {file = "PyYAML-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20"}, - {file = "PyYAML-5.3.tar.gz", hash = "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, + {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, + {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, + {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, + {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, + {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, + {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, + {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, ] regex = [ - {file = "regex-2020.2.20-cp27-cp27m-win32.whl", hash = "sha256:99272d6b6a68c7ae4391908fc15f6b8c9a6c345a46b632d7fdb7ef6c883a2bbb"}, - {file = "regex-2020.2.20-cp27-cp27m-win_amd64.whl", hash = "sha256:974535648f31c2b712a6b2595969f8ab370834080e00ab24e5dbb9d19b8bfb74"}, - {file = "regex-2020.2.20-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5de40649d4f88a15c9489ed37f88f053c15400257eeb18425ac7ed0a4e119400"}, - {file = "regex-2020.2.20-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:82469a0c1330a4beb3d42568f82dffa32226ced006e0b063719468dcd40ffdf0"}, - {file = "regex-2020.2.20-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d58a4fa7910102500722defbde6e2816b0372a4fcc85c7e239323767c74f5cbc"}, - {file = "regex-2020.2.20-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f1ac2dc65105a53c1c2d72b1d3e98c2464a133b4067a51a3d2477b28449709a0"}, - {file = "regex-2020.2.20-cp36-cp36m-win32.whl", hash = "sha256:8c2b7fa4d72781577ac45ab658da44c7518e6d96e2a50d04ecb0fd8f28b21d69"}, - {file = "regex-2020.2.20-cp36-cp36m-win_amd64.whl", hash = "sha256:269f0c5ff23639316b29f31df199f401e4cb87529eafff0c76828071635d417b"}, - {file = "regex-2020.2.20-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:bed7986547ce54d230fd8721aba6fd19459cdc6d315497b98686d0416efaff4e"}, - {file = "regex-2020.2.20-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:046e83a8b160aff37e7034139a336b660b01dbfe58706f9d73f5cdc6b3460242"}, - {file = "regex-2020.2.20-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:b33ebcd0222c1d77e61dbcd04a9fd139359bded86803063d3d2d197b796c63ce"}, - {file = "regex-2020.2.20-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bba52d72e16a554d1894a0cc74041da50eea99a8483e591a9edf1025a66843ab"}, - {file = "regex-2020.2.20-cp37-cp37m-win32.whl", hash = "sha256:01b2d70cbaed11f72e57c1cfbaca71b02e3b98f739ce33f5f26f71859ad90431"}, - {file = "regex-2020.2.20-cp37-cp37m-win_amd64.whl", hash = "sha256:113309e819634f499d0006f6200700c8209a2a8bf6bd1bdc863a4d9d6776a5d1"}, - {file = "regex-2020.2.20-cp38-cp38-manylinux1_i686.whl", hash = "sha256:25f4ce26b68425b80a233ce7b6218743c71cf7297dbe02feab1d711a2bf90045"}, - {file = "regex-2020.2.20-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9b64a4cc825ec4df262050c17e18f60252cdd94742b4ba1286bcfe481f1c0f26"}, - {file = "regex-2020.2.20-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:9ff16d994309b26a1cdf666a6309c1ef51ad4f72f99d3392bcd7b7139577a1f2"}, - {file = "regex-2020.2.20-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c7f58a0e0e13fb44623b65b01052dae8e820ed9b8b654bb6296bc9c41f571b70"}, - {file = "regex-2020.2.20-cp38-cp38-win32.whl", hash = "sha256:200539b5124bc4721247a823a47d116a7a23e62cc6695744e3eb5454a8888e6d"}, - {file = "regex-2020.2.20-cp38-cp38-win_amd64.whl", hash = "sha256:7f78f963e62a61e294adb6ff5db901b629ef78cb2a1cfce3cf4eeba80c1c67aa"}, - {file = "regex-2020.2.20.tar.gz", hash = "sha256:9e9624440d754733eddbcd4614378c18713d2d9d0dc647cf9c72f64e39671be5"}, + {file = "regex-2020.5.14-cp27-cp27m-win32.whl", hash = "sha256:e565569fc28e3ba3e475ec344d87ed3cd8ba2d575335359749298a0899fe122e"}, + {file = "regex-2020.5.14-cp27-cp27m-win_amd64.whl", hash = "sha256:d466967ac8e45244b9dfe302bbe5e3337f8dc4dec8d7d10f5e950d83b140d33a"}, + {file = "regex-2020.5.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:27ff7325b297fb6e5ebb70d10437592433601c423f5acf86e5bc1ee2919b9561"}, + {file = "regex-2020.5.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ea55b80eb0d1c3f1d8d784264a6764f931e172480a2f1868f2536444c5f01e01"}, + {file = "regex-2020.5.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:c9bce6e006fbe771a02bda468ec40ffccbf954803b470a0345ad39c603402577"}, + {file = "regex-2020.5.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:d881c2e657c51d89f02ae4c21d9adbef76b8325fe4d5cf0e9ad62f850f3a98fd"}, + {file = "regex-2020.5.14-cp36-cp36m-win32.whl", hash = "sha256:99568f00f7bf820c620f01721485cad230f3fb28f57d8fbf4a7967ec2e446994"}, + {file = "regex-2020.5.14-cp36-cp36m-win_amd64.whl", hash = "sha256:70c14743320a68c5dac7fc5a0f685be63bc2024b062fe2aaccc4acc3d01b14a1"}, + {file = "regex-2020.5.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a7c37f048ec3920783abab99f8f4036561a174f1314302ccfa4e9ad31cb00eb4"}, + {file = "regex-2020.5.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:89d76ce33d3266173f5be80bd4efcbd5196cafc34100fdab814f9b228dee0fa4"}, + {file = "regex-2020.5.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:51f17abbe973c7673a61863516bdc9c0ef467407a940f39501e786a07406699c"}, + {file = "regex-2020.5.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:ce5cc53aa9fbbf6712e92c7cf268274eaff30f6bd12a0754e8133d85a8fb0f5f"}, + {file = "regex-2020.5.14-cp37-cp37m-win32.whl", hash = "sha256:8044d1c085d49673aadb3d7dc20ef5cb5b030c7a4fa253a593dda2eab3059929"}, + {file = "regex-2020.5.14-cp37-cp37m-win_amd64.whl", hash = "sha256:c2062c7d470751b648f1cacc3f54460aebfc261285f14bc6da49c6943bd48bdd"}, + {file = "regex-2020.5.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:329ba35d711e3428db6b45a53b1b13a0a8ba07cbbcf10bbed291a7da45f106c3"}, + {file = "regex-2020.5.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:579ea215c81d18da550b62ff97ee187b99f1b135fd894a13451e00986a080cad"}, + {file = "regex-2020.5.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:3a9394197664e35566242686d84dfd264c07b20f93514e2e09d3c2b3ffdf78fe"}, + {file = "regex-2020.5.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ce367d21f33e23a84fb83a641b3834dd7dd8e9318ad8ff677fbfae5915a239f7"}, + {file = "regex-2020.5.14-cp38-cp38-win32.whl", hash = "sha256:1386e75c9d1574f6aa2e4eb5355374c8e55f9aac97e224a8a5a6abded0f9c927"}, + {file = "regex-2020.5.14-cp38-cp38-win_amd64.whl", hash = "sha256:7e61be8a2900897803c293247ef87366d5df86bf701083b6c43119c7c6c99108"}, + {file = "regex-2020.5.14.tar.gz", hash = "sha256:ce450ffbfec93821ab1fea94779a8440e10cf63819be6e176eb1973a6017aff5"}, ] requests = [ {file = "requests-2.21.0-py2.py3-none-any.whl", hash = "sha256:7bf2a778576d825600030a110f3c0e3e8edc51dfaafe1c146e39a2027784957b"}, @@ -2058,9 +2264,13 @@ shellingham = [ {file = "shellingham-1.3.2-py2.py3-none-any.whl", hash = "sha256:7f6206ae169dc1a03af8a138681b3f962ae61cc93ade84d0585cca3aaf770044"}, {file = "shellingham-1.3.2.tar.gz", hash = "sha256:576c1982bea0ba82fb46c36feb951319d7f42214a82634233f58b40d858a751e"}, ] +singledispatch = [ + {file = "singledispatch-3.4.0.3-py2.py3-none-any.whl", hash = "sha256:833b46966687b3de7f438c761ac475213e53b306740f1abfaa86e1d1aae56aa8"}, + {file = "singledispatch-3.4.0.3.tar.gz", hash = "sha256:5b06af87df13818d14f08a028e42f566640aef80805c3b50c5056b086e3c2b9c"}, +] six = [ - {file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"}, - {file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"}, + {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, + {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, ] subprocess32 = [ {file = "subprocess32-3.5.4-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:88e37c1aac5388df41cc8a8456bb49ebffd321a3ad4d70358e3518176de3a56b"}, @@ -2070,9 +2280,8 @@ termcolor = [ {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, ] toml = [ - {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, - {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, - {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, + {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, + {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, ] tomlkit = [ {file = "tomlkit-0.5.11-py2.py3-none-any.whl", hash = "sha256:4e1bd6c9197d984528f9ff0cc9db667c317d8881288db50db20eeeb0f6b0380b"}, @@ -2086,19 +2295,25 @@ tornado = [ {file = "tornado-5.1.1-cp37-cp37m-win32.whl", hash = "sha256:e5f2585afccbff22390cddac29849df463b252b711aa2ce7c5f3f342a5b3b444"}, {file = "tornado-5.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:8e9d728c4579682e837c92fdd98036bd5cdefa1da2aaf6acf26947e6dd0c01c5"}, {file = "tornado-5.1.1.tar.gz", hash = "sha256:4e5158d97583502a7e2739951553cbd88a72076f152b4b11b64b9a10c4c49409"}, - {file = "tornado-6.0.3-cp35-cp35m-win32.whl", hash = "sha256:c9399267c926a4e7c418baa5cbe91c7d1cf362d505a1ef898fde44a07c9dd8a5"}, - {file = "tornado-6.0.3-cp35-cp35m-win_amd64.whl", hash = "sha256:398e0d35e086ba38a0427c3b37f4337327231942e731edaa6e9fd1865bbd6f60"}, - {file = "tornado-6.0.3-cp36-cp36m-win32.whl", hash = "sha256:4e73ef678b1a859f0cb29e1d895526a20ea64b5ffd510a2307b5998c7df24281"}, - {file = "tornado-6.0.3-cp36-cp36m-win_amd64.whl", hash = "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c"}, - {file = "tornado-6.0.3-cp37-cp37m-win32.whl", hash = "sha256:559bce3d31484b665259f50cd94c5c28b961b09315ccd838f284687245f416e5"}, - {file = "tornado-6.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:abbe53a39734ef4aba061fca54e30c6b4639d3e1f59653f0da37a0003de148c7"}, - {file = "tornado-6.0.3.tar.gz", hash = "sha256:c845db36ba616912074c5b1ee897f8e0124df269468f25e4fe21fe72f6edd7a9"}, + {file = "tornado-6.0.4-cp35-cp35m-win32.whl", hash = "sha256:5217e601700f24e966ddab689f90b7ea4bd91ff3357c3600fa1045e26d68e55d"}, + {file = "tornado-6.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:c98232a3ac391f5faea6821b53db8db461157baa788f5d6222a193e9456e1740"}, + {file = "tornado-6.0.4-cp36-cp36m-win32.whl", hash = "sha256:5f6a07e62e799be5d2330e68d808c8ac41d4a259b9cea61da4101b83cb5dc673"}, + {file = "tornado-6.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c952975c8ba74f546ae6de2e226ab3cc3cc11ae47baf607459a6728585bb542a"}, + {file = "tornado-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:2c027eb2a393d964b22b5c154d1a23a5f8727db6fda837118a776b29e2b8ebc6"}, + {file = "tornado-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:5618f72e947533832cbc3dec54e1dffc1747a5cb17d1fd91577ed14fa0dc081b"}, + {file = "tornado-6.0.4-cp38-cp38-win32.whl", hash = "sha256:22aed82c2ea340c3771e3babc5ef220272f6fd06b5108a53b4976d0d722bcd52"}, + {file = "tornado-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9"}, + {file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"}, ] tox = [ {file = "tox-3.12.1-py2.py3-none-any.whl", hash = "sha256:f5c8e446b51edd2ea97df31d4ded8c8b72e7d6c619519da6bb6084b9dd5770f9"}, {file = "tox-3.12.1.tar.gz", hash = "sha256:f87fd33892a2df0950e5e034def9468988b8d008c7e9416be665fcc0dd45b14f"}, - {file = "tox-3.14.5-py2.py3-none-any.whl", hash = "sha256:0cbe98369081fa16bd6f1163d3d0b2a62afa29d402ccfad2bd09fb2668be0956"}, - {file = "tox-3.14.5.tar.gz", hash = "sha256:676f1e3e7de245ad870f956436b84ea226210587d1f72c8dfb8cd5ac7b6f0e70"}, + {file = "tox-3.15.1-py2.py3-none-any.whl", hash = "sha256:322dfdf007d7d53323f767badcb068a5cfa7c44d8aabb698d131b28cf44e62c4"}, + {file = "tox-3.15.1.tar.gz", hash = "sha256:8c9ad9b48659d291c5bc78bcabaa4d680d627687154b812fa52baedaa94f9f83"}, +] +tqdm = [ + {file = "tqdm-4.46.1-py2.py3-none-any.whl", hash = "sha256:07c06493f1403c1380b630ae3dcbe5ae62abcf369a93bbc052502279f189ab8c"}, + {file = "tqdm-4.46.1.tar.gz", hash = "sha256:cd140979c2bebd2311dfb14781d8f19bd5a9debb92dcab9f6ef899c987fcf71f"}, ] typed-ast = [ {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, @@ -2129,25 +2344,25 @@ typing = [ {file = "typing-3.7.4.1.tar.gz", hash = "sha256:91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.1-py2-none-any.whl", hash = "sha256:910f4656f54de5993ad9304959ce9bb903f90aadc7c67a0bef07e678014e892d"}, - {file = "typing_extensions-3.7.4.1-py3-none-any.whl", hash = "sha256:cf8b63fedea4d89bab840ecbb93e75578af28f76f66c35889bd7065f5af88575"}, - {file = "typing_extensions-3.7.4.1.tar.gz", hash = "sha256:091ecc894d5e908ac75209f10d5b4f118fbdb2eb1ede6a63544054bb1edb41f2"}, + {file = "typing_extensions-3.7.4.2-py2-none-any.whl", hash = "sha256:f8d2bd89d25bc39dabe7d23df520442fa1d8969b82544370e03d88b5a591c392"}, + {file = "typing_extensions-3.7.4.2-py3-none-any.whl", hash = "sha256:6e95524d8a547a91e08f404ae485bbb71962de46967e1b71a0cb89af24e761c5"}, + {file = "typing_extensions-3.7.4.2.tar.gz", hash = "sha256:79ee589a3caca649a9bfd2a8de4709837400dfa00b6cc81962a1e6a1815969ae"}, ] urllib3 = [ {file = "urllib3-1.24.3-py2.py3-none-any.whl", hash = "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb"}, {file = "urllib3-1.24.3.tar.gz", hash = "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4"}, - {file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"}, - {file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"}, + {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, + {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, ] virtualenv = [ {file = "virtualenv-16.7.10-py2.py3-none-any.whl", hash = "sha256:105893c8dc66b7817691c7371439ec18e3b6c5e323a304b5ed96cdd2e75cc1ec"}, {file = "virtualenv-16.7.10.tar.gz", hash = "sha256:e88fdcb08b0ecb11da97868f463dd06275923f50d87f4b9c8b2fc0994eec40f4"}, - {file = "virtualenv-20.0.7-py2.py3-none-any.whl", hash = "sha256:30ea90b21dabd11da5f509710ad3be2ae47d40ccbc717dfdd2efe4367c10f598"}, - {file = "virtualenv-20.0.7.tar.gz", hash = "sha256:4a36a96d785428278edd389d9c36d763c5755844beb7509279194647b1ef47f1"}, + {file = "virtualenv-20.0.21-py2.py3-none-any.whl", hash = "sha256:a730548b27366c5e6cbdf6f97406d861cccece2e22275e8e1a757aeff5e00c70"}, + {file = "virtualenv-20.0.21.tar.gz", hash = "sha256:a116629d4e7f4d03433b8afa27f43deba09d48bc48f5ecefa4f015a178efb6cf"}, ] wcwidth = [ - {file = "wcwidth-0.1.8-py2.py3-none-any.whl", hash = "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603"}, - {file = "wcwidth-0.1.8.tar.gz", hash = "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8"}, + {file = "wcwidth-0.2.3-py2.py3-none-any.whl", hash = "sha256:980fbf4f3c196c0f329cdcd1e84c554d6a211f18e252e525a0cf4223154a41d6"}, + {file = "wcwidth-0.2.3.tar.gz", hash = "sha256:edbc2b718b4db6cdf393eefe3a420183947d6aa312505ce6754516f458ff8830"}, ] webencodings = [ {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, diff --git a/poetry/__version__.py b/poetry/__version__.py index 68cdeee4b21..39e0411d5cd 100644 --- a/poetry/__version__.py +++ b/poetry/__version__.py @@ -1 +1 @@ -__version__ = "1.0.5" +__version__ = "1.0.9" diff --git a/poetry/console/commands/add.py b/poetry/console/commands/add.py index 275fc44f5f1..378d7a2f871 100644 --- a/poetry/console/commands/add.py +++ b/poetry/console/commands/add.py @@ -40,11 +40,18 @@ class AddCommand(EnvCommand, InitCommand): "Output the operations but do not execute anything (implicitly enables --verbose).", ), ] - - help = """The add command adds required packages to your pyproject.toml and installs them. - -If you do not specify a version constraint, poetry will choose a suitable one based on the available package versions. -""" + help = ( + "The add command adds required packages to your pyproject.toml and installs them.\n\n" + "If you do not specify a version constraint, poetry will choose a suitable one based on the available package versions.\n\n" + "You can specify a package in the following forms:\n" + " - A single name (requests)\n" + " - A name and a constraint (requests@^2.23.0)\n" + " - A git url (git+https://github.com/python-poetry/poetry.git)\n" + " - A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)\n" + " - A file path (../my-package/my-package.whl)\n" + " - A directory (../my-package/)\n" + " - A url (https://example.com/packages/my-package-0.1.0.tar.gz)\n" + ) loggers = ["poetry.repositories.pypi_repository"] diff --git a/poetry/console/commands/env/info.py b/poetry/console/commands/env/info.py index d66baa56408..301d88f9520 100644 --- a/poetry/console/commands/env/info.py +++ b/poetry/console/commands/env/info.py @@ -19,7 +19,7 @@ def handle(self): if not env.is_venv(): return 1 - self.write(str(env.path)) + self.line(str(env.path)) return diff --git a/poetry/console/commands/export.py b/poetry/console/commands/export.py index 37cfc1394e8..5e2d450e011 100644 --- a/poetry/console/commands/export.py +++ b/poetry/console/commands/export.py @@ -11,7 +11,12 @@ class ExportCommand(Command): description = "Exports the lock file to alternative formats." options = [ - option("format", "f", "Format to export to.", flag=False), + option( + "format", + "f", + "Format to export to. Currently, only requirements.txt is supported.", + flag=False, + ), option("output", "o", "The name of the output file.", flag=False), option("without-hashes", None, "Exclude hashes from the exported file."), option("dev", None, "Include development dependencies."), diff --git a/poetry/console/commands/init.py b/poetry/console/commands/init.py index 825f8c68e2a..c85f441b8aa 100644 --- a/poetry/console/commands/init.py +++ b/poetry/console/commands/init.py @@ -146,12 +146,12 @@ def handle(self): help_message = ( "You can specify a package in the following forms:\n" " - A single name (requests)\n" - " - A name and a constraint (requests ^2.23.0)\n" + " - A name and a constraint (requests@^2.23.0)\n" " - A git url (git+https://github.com/python-poetry/poetry.git)\n" " - A git url with a revision (git+https://github.com/python-poetry/poetry.git#develop)\n" " - A file path (../my-package/my-package.whl)\n" " - A directory (../my-package/)\n" - " - An url (https://example.com/packages/my-package-0.1.0.tar.gz)\n" + " - A url (https://example.com/packages/my-package-0.1.0.tar.gz)\n" ) help_displayed = False if self.confirm(question, True): diff --git a/poetry/console/commands/install.py b/poetry/console/commands/install.py index fabffec4a24..f69e4e5873c 100644 --- a/poetry/console/commands/install.py +++ b/poetry/console/commands/install.py @@ -34,6 +34,12 @@ class InstallCommand(EnvCommand): exist it will look for pyproject.toml and do the same. poetry install + +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 +--no-root option like below: + + poetry install --no-root """ _loggers = ["poetry.repositories.pypi_repository"] diff --git a/poetry/console/commands/self/update.py b/poetry/console/commands/self/update.py index 032213ae0ce..5e0433e368c 100644 --- a/poetry/console/commands/self/update.py +++ b/poetry/console/commands/self/update.py @@ -1,6 +1,10 @@ +from __future__ import unicode_literals + import hashlib import os +import re import shutil +import stat import subprocess import sys import tarfile @@ -22,6 +26,27 @@ 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): name = "update" @@ -32,17 +57,23 @@ class SelfUpdateCommand(Command): REPOSITORY_URL = "https://github.com/python-poetry/poetry" BASE_URL = REPOSITORY_URL + "/releases/download" - FALLBACK_BASE_URL = "https://github.com/sdispater/poetry/releases/download" @property def home(self): from poetry.utils._compat import Path from poetry.utils.appdirs import expanduser + if os.environ.get("POETRY_HOME"): + return Path(expanduser(os.environ["POETRY_HOME"])) + home = Path(expanduser("~")) return home / ".poetry" + @property + def bin(self): + return self.home / "bin" + @property def lib(self): return self.home / "lib" @@ -55,16 +86,8 @@ def handle(self): from poetry.__version__ import __version__ from poetry.repositories.pypi_repository import PyPiRepository from poetry.semver import Version - 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." - ) + self._check_recommended_installation() version = self.argument("version") if not version: @@ -136,6 +159,8 @@ def update(self, release): if self.lib_backup.exists(): shutil.rmtree(str(self.lib_backup)) + self.make_bin() + self.line("") self.line("") self.line( @@ -147,20 +172,11 @@ def update(self, release): def _update(self, version): from poetry.utils.helpers import temporary_directory - platform = sys.platform - if platform == "linux2": - platform = "linux" + release_name = self._get_release_name(version) - checksum = "poetry-{}-{}.sha256sum".format(version, platform) + checksum = "{}.sha256sum".format(release_name) 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: r = urlopen(base_url + "/{}/{}".format(version, checksum)) @@ -170,10 +186,10 @@ def _update(self, version): raise - checksum = r.read().decode() + checksum = r.read().decode().strip() # We get the payload from the remote host - name = "poetry-{}-{}.tar.gz".format(version, platform) + name = "{}.tar.gz".format(release_name) try: r = urlopen(base_url + "/{}/{}".format(version, name)) except HTTPError as e: @@ -226,8 +242,94 @@ def _update(self, version): def process(self, *args): 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): - if sys.platform == "win32": + from poetry.utils._compat import WINDOWS + + if WINDOWS: return (base_path / "Scripts" / bin).with_suffix(".exe") 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\d+)\.(?P\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 diff --git a/poetry/installation/pip_installer.py b/poetry/installation/pip_installer.py index aada0cd0190..3129e0b69f5 100644 --- a/poetry/installation/pip_installer.py +++ b/poetry/installation/pip_installer.py @@ -1,7 +1,6 @@ import os import tempfile -from io import open from subprocess import CalledProcessError from clikit.api.io import IO @@ -105,12 +104,6 @@ def update(self, package, target): self.install(target, update=True) 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: self.run("uninstall", package.name, "-y") except CalledProcessError as e: @@ -119,6 +112,17 @@ def remove(self, package): 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 return self._env.run_pip(*args, **kwargs) @@ -139,7 +143,7 @@ def requirement(self, package, formatted=False): if package.source_type in ["file", "directory"]: if package.root_dir: - req = os.path.join(package.root_dir, package.source_url) + req = (package.root_dir / package.source_url).as_posix() else: req = os.path.realpath(package.source_url) @@ -176,14 +180,11 @@ def create_temporary_requirement(self, package): return name def install_directory(self, package): - from poetry.masonry.builder import SdistBuilder from poetry.factory import Factory - from poetry.utils._compat import decode - from poetry.utils.env import NullEnv from poetry.utils.toml_file import TomlFile if package.root_dir: - req = os.path.join(package.root_dir, package.source_url) + req = (package.root_dir / package.source_url).as_posix() else: req = os.path.realpath(package.source_url) @@ -205,17 +206,20 @@ def install_directory(self, package): setup = os.path.join(req, "setup.py") has_setup = os.path.exists(setup) - if not has_setup and has_poetry and (package.develop or not has_build_system): + if has_poetry and (package.develop or not has_build_system): # We actually need to rely on creating a temporary setup.py # file since pip, as of this comment, does not support # build-system for editable packages # We also need it for non-PEP-517 packages - builder = SdistBuilder( - Factory().create_poetry(pyproject.parent), NullEnv(), NullIO() + from poetry.masonry.builders.editable import EditableBuilder + + builder = EditableBuilder( + Factory().create_poetry(pyproject.parent), self._env, NullIO() ) - with open(setup, "w", encoding="utf-8") as f: - f.write(decode(builder.build_setup())) + builder.build() + + return if package.develop: args.append("-e") diff --git a/poetry/masonry/builders/editable.py b/poetry/masonry/builders/editable.py index 1757bd4ff3d..15cfe53676a 100644 --- a/poetry/masonry/builders/editable.py +++ b/poetry/masonry/builders/editable.py @@ -38,7 +38,7 @@ def _setup_build(self): str(self._poetry.file), str(self._poetry.file.with_suffix(".tmp")) ) try: - self._env.run_pip("install", "-e", str(self._path)) + self._env.run_pip("install", "--no-deps", "-e", str(self._path)) finally: shutil.move( str(self._poetry.file.with_suffix(".tmp")), diff --git a/poetry/masonry/utils/package_include.py b/poetry/masonry/utils/package_include.py index 42ecbbc1fd0..47345765f07 100644 --- a/poetry/masonry/utils/package_include.py +++ b/poetry/masonry/utils/package_include.py @@ -33,31 +33,43 @@ def refresh(self): # type: () -> PackageInclude return self.check_elements() - def check_elements(self): # type: () -> PackageInclude - root = self._elements[0] + def is_stub_only(self): # type: () -> bool + # returns `True` if this a PEP 561 stub-only package, + # see [PEP 561](https://www.python.org/dev/peps/pep-0561/#stub-only-packages) + return self.package.endswith("-stubs") and all( + el.suffix == ".pyi" + or (el.parent.name == self.package and el.name == "py.typed") + for el in self.elements + if el.is_file() + ) + + def has_modules(self): # type: () -> bool + # Packages no longer need an __init__.py in python3, but there must + # at least be one .py file for it to be considered a package + return any(element.suffix == ".py" for element in self.elements) + def check_elements(self): # type: () -> PackageInclude if not self._elements: raise ValueError( "{} does not contain any element".format(self._base / self._include) ) + root = self._elements[0] if len(self._elements) > 1: # Probably glob self._is_package = True + self._package = root.parent.name - # Packages no longer need an __init__.py in python3, but there must - # at least be one .py file for it to be considered a package - if not any([element.suffix == ".py" for element in self._elements]): + if not self.is_stub_only() and not self.has_modules(): raise ValueError("{} is not a package.".format(root.name)) - self._package = root.parent.name else: if root.is_dir(): # If it's a directory, we include everything inside it self._package = root.name self._elements = sorted(list(root.glob("**/*"))) - if not any([element.suffix == ".py" for element in self._elements]): + if not self.is_stub_only() and not self.has_modules(): raise ValueError("{} is not a package.".format(root.name)) self._is_package = True diff --git a/poetry/masonry/utils/tags.py b/poetry/masonry/utils/tags.py index 175cdd8b73b..88dc33f5b53 100644 --- a/poetry/masonry/utils/tags.py +++ b/poetry/masonry/utils/tags.py @@ -76,19 +76,22 @@ def get_abi_tag(env): env, "Py_DEBUG", lambda: hasattr(sys, "gettotalrefcount"), - warn=(impl == "cp"), + warn=(impl == "cp" and env.version_info < (3, 8)), ): d = "d" - if get_flag(env, "WITH_PYMALLOC", lambda: impl == "cp", warn=(impl == "cp")): - m = "m" - if get_flag( - env, - "Py_UNICODE_SIZE", - lambda: sys.maxunicode == 0x10FFFF, - expected=4, - warn=(impl == "cp" and env.version_info < (3, 3)), - ) and env.version_info < (3, 3): - u = "u" + if env.version_info < (3, 8): + if get_flag( + env, "WITH_PYMALLOC", lambda: impl == "cp", warn=(impl == "cp") + ): + m = "m" + if get_flag( + env, + "Py_UNICODE_SIZE", + lambda: sys.maxunicode == 0x10FFFF, + expected=4, + warn=(impl == "cp" and env.version_info < (3, 3)), + ) and env.version_info < (3, 3): + u = "u" abi = "%s%s%s%s%s" % (impl, get_impl_ver(env), d, m, u) elif soabi and soabi.startswith("cpython-"): abi = "cp" + soabi.split("-")[1] diff --git a/poetry/mixology/incompatibility.py b/poetry/mixology/incompatibility.py index 2af54b6c877..e731b743cb4 100644 --- a/poetry/mixology/incompatibility.py +++ b/poetry/mixology/incompatibility.py @@ -61,18 +61,18 @@ def __init__( else: by_ref[ref] = term - new_terms = [] - for by_ref in by_name.values(): - positive_terms = [ - term for term in by_ref.values() if term.is_positive() - ] - if positive_terms: - new_terms += positive_terms - continue - - new_terms += list(by_ref.values()) - - terms = new_terms + new_terms = [] + for by_ref in by_name.values(): + positive_terms = [ + term for term in by_ref.values() if term.is_positive() + ] + if positive_terms: + new_terms += positive_terms + continue + + new_terms += list(by_ref.values()) + + terms = new_terms self._terms = terms self._cause = cause diff --git a/poetry/mixology/version_solver.py b/poetry/mixology/version_solver.py index d1c78ba7661..02b9a74a1d8 100644 --- a/poetry/mixology/version_solver.py +++ b/poetry/mixology/version_solver.py @@ -339,6 +339,16 @@ def _get_min(dependency): if dependency.name in self._locked: 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: return len(self._provider.search_for(dependency)) except ValueError: diff --git a/poetry/packages/__init__.py b/poetry/packages/__init__.py index e0a2203c9d3..a829858deb2 100644 --- a/poetry/packages/__init__.py +++ b/poetry/packages/__init__.py @@ -33,8 +33,8 @@ def dependency_from_pep_508(name): name = parts[0].strip() if len(parts) > 1: rest = parts[1] - if ";" in rest: - name += ";" + rest.split(";", 1)[1] + if " ;" in rest: + name += " ;" + rest.split(" ;", 1)[1] req = Requirement(name) diff --git a/poetry/packages/dependency.py b/poetry/packages/dependency.py index 83ad36a129c..5b688a3b2bb 100644 --- a/poetry/packages/dependency.py +++ b/poetry/packages/dependency.py @@ -271,16 +271,30 @@ def _create_nested_marker(self, name, constraint): marker = glue.join(parts) elif isinstance(constraint, Version): + if constraint.precision >= 3 and name == "python_version": + name = "python_full_version" + marker = '{} == "{}"'.format(name, constraint.text) else: if constraint.min is not None: + min_name = name + if constraint.min.precision >= 3 and name == "python_version": + min_name = "python_full_version" + + if constraint.max is None: + name = min_name + op = ">=" if not constraint.include_min: op = ">" version = constraint.min.text if constraint.max is not None: - text = '{} {} "{}"'.format(name, op, version) + max_name = name + if constraint.max.precision >= 3 and name == "python_version": + max_name = "python_full_version" + + text = '{} {} "{}"'.format(min_name, op, version) op = "<=" if not constraint.include_max: @@ -288,10 +302,13 @@ def _create_nested_marker(self, name, constraint): version = constraint.max - text += ' and {} {} "{}"'.format(name, op, version) + text += ' and {} {} "{}"'.format(max_name, op, version) return text elif constraint.max is not None: + if constraint.max.precision >= 3 and name == "python_version": + name = "python_full_version" + op = "<=" if not constraint.include_max: op = "<" diff --git a/poetry/packages/dependency_package.py b/poetry/packages/dependency_package.py index f38892488d9..6285cf29ae4 100644 --- a/poetry/packages/dependency_package.py +++ b/poetry/packages/dependency_package.py @@ -3,6 +3,26 @@ def __init__(self, dependency, package): self._dependency = dependency self._package = package + @property + def name(self): + return self._package.name + + @property + def version(self): + return self._package.version + + @property + def constraint(self): + return self._package.constraint + + @property + def all_requires(self): + return self._package.all_requires + + @property + def marker(self): + return self._package.marker + @property def dependency(self): return self._dependency diff --git a/poetry/packages/directory_dependency.py b/poetry/packages/directory_dependency.py index ac4bca8ea82..978300ca689 100644 --- a/poetry/packages/directory_dependency.py +++ b/poetry/packages/directory_dependency.py @@ -79,3 +79,14 @@ def supports_poetry(self): def is_directory(self): return True + + def __str__(self): + if self.is_root: + return self._pretty_name + + return "{} ({} {})".format( + self._pretty_name, self._pretty_constraint, self._path + ) + + def __hash__(self): + return hash((self._name, self._full_path)) diff --git a/poetry/packages/file_dependency.py b/poetry/packages/file_dependency.py index b91d296a512..751e61997f8 100644 --- a/poetry/packages/file_dependency.py +++ b/poetry/packages/file_dependency.py @@ -41,6 +41,10 @@ def __init__( name, "*", category=category, optional=optional, allows_prereleases=True ) + @property + def base(self): + return self._base + @property def path(self): return self._path @@ -59,3 +63,14 @@ def hash(self): h.update(content) return h.hexdigest() + + def __str__(self): + if self.is_root: + return self._pretty_name + + return "{} ({} {})".format( + self._pretty_name, self._pretty_constraint, self._path + ) + + def __hash__(self): + return hash((self._name, self._full_path)) diff --git a/poetry/packages/package.py b/poetry/packages/package.py index cb28ef70c7f..03300e29d3d 100644 --- a/poetry/packages/package.py +++ b/poetry/packages/package.py @@ -40,7 +40,7 @@ def __init__(self, name, version, pretty_version=None): Creates a new in memory package. """ self._pretty_name = name - self._name = canonicalize_name(name) + self.name = canonicalize_name(name) if not isinstance(version, Version): self._version = Version.parse(version) @@ -88,10 +88,6 @@ def __init__(self, name, version, pretty_version=None): self.develop = True - @property - def name(self): - return self._name - @property def pretty_name(self): return self._pretty_name @@ -107,7 +103,7 @@ def pretty_version(self): @property def unique_name(self): if self.is_root(): - return self._name + return self.name return self.name + "-" + self._version.text @@ -163,6 +159,12 @@ def _get_author(self): # type: () -> dict m = AUTHOR_REGEX.match(normalize("NFC", self._authors[0])) + if m is None: + raise ValueError( + "Invalid author string. Must be in the format: " + "John Smith " + ) + name = m.group("name") email = m.group("email") @@ -174,6 +176,12 @@ def _get_maintainer(self): # type: () -> dict m = AUTHOR_REGEX.match(normalize("NFC", self._maintainers[0])) + if m is None: + raise ValueError( + "Invalid maintainer string. Must be in the format: " + "John Smith " + ) + name = m.group("name") email = m.group("email") @@ -333,7 +341,9 @@ def add_dependency( develop=constraint.get("develop", True), ) elif "url" in constraint: - dependency = URLDependency(name, constraint["url"], category=category) + dependency = URLDependency( + name, constraint["url"], category=category, optional=optional + ) else: version = constraint["version"] @@ -388,7 +398,7 @@ def add_dependency( def to_dependency(self): from . import dependency_from_pep_508 - name = "{} (=={})".format(self._name, self._version) + name = "{} (=={})".format(self.name, self._version) if not self.marker.is_any(): name += " ; {}".format(str(self.marker)) @@ -407,6 +417,7 @@ def with_python_versions(self, python_versions): def clone(self): # type: () -> Package clone = self.__class__(self.pretty_name, self.version) + clone.description = self.description clone.category = self.category clone.optional = self.optional clone.python_versions = self.python_versions @@ -425,13 +436,13 @@ def clone(self): # type: () -> Package return clone def __hash__(self): - return hash((self._name, self._version)) + return hash((self.name, self._version)) def __eq__(self, other): if not isinstance(other, Package): return NotImplemented - return self._name == other.name and self._version == other.version + return self.name == other.name and self._version == other.version def __str__(self): return self.unique_name diff --git a/poetry/packages/url_dependency.py b/poetry/packages/url_dependency.py index f128dc49366..295fea60e6e 100644 --- a/poetry/packages/url_dependency.py +++ b/poetry/packages/url_dependency.py @@ -38,3 +38,9 @@ def base_pep_508_name(self): # type: () -> str def is_url(self): # type: () -> bool return True + + def __str__(self): + return "{} ({} url)".format(self._pretty_name, self._pretty_constraint) + + def __hash__(self): + return hash((self._name, self._url)) diff --git a/poetry/packages/utils/utils.py b/poetry/packages/utils/utils.py index 03dfb84fda6..a219c36c416 100644 --- a/poetry/packages/utils/utils.py +++ b/poetry/packages/utils/utils.py @@ -22,13 +22,11 @@ except ImportError: import urlparse - try: import urllib.request as urllib2 except ImportError: import urllib2 - BZ2_EXTENSIONS = (".tar.bz2", ".tbz") XZ_EXTENSIONS = (".tar.xz", ".txz", ".tlz", ".tar.lz", ".tar.lzma") ZIP_EXTENSIONS = (".zip", ".whl") @@ -77,7 +75,8 @@ def is_url(name): "hg", "bzr", "sftp", - "svn" "ssh", + "svn", + "ssh", ] diff --git a/poetry/packages/vcs_dependency.py b/poetry/packages/vcs_dependency.py index 7574b8dbac3..b8f2992b92e 100644 --- a/poetry/packages/vcs_dependency.py +++ b/poetry/packages/vcs_dependency.py @@ -94,3 +94,11 @@ def is_vcs(self): # type: () -> bool def accepts_prereleases(self): # type: () -> bool return True + + def __str__(self): + return "{} ({} {})".format( + self._pretty_name, self._pretty_constraint, self._vcs + ) + + def __hash__(self): + return hash((self._name, self._vcs, self._branch, self._tag, self._rev)) diff --git a/poetry/puzzle/provider.py b/poetry/puzzle/provider.py index 989a592912b..40537260815 100644 --- a/poetry/puzzle/provider.py +++ b/poetry/puzzle/provider.py @@ -72,6 +72,7 @@ def __init__(self, package, pool, io): # type: (Package, Pool, Any) -> None self._search_for = {} self._is_debugging = self._io.is_debug() or self._io.is_very_verbose() self._in_progress = False + self._deferred_cache = {} @property def pool(self): # type: () -> Pool @@ -164,6 +165,9 @@ def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package] Basically, we clone the repository in a temporary directory 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( dependency.vcs, dependency.source, @@ -178,6 +182,11 @@ def search_for_vcs(self, dependency): # type: (VCSDependency) -> List[Package] package.requires += package.extras[extra] + dependency._constraint = package.version + dependency._pretty_constraint = package.version.text + + self._deferred_cache[dependency] = package + return [package] @classmethod @@ -214,7 +223,17 @@ def get_package_from_vcs( return 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: # For now, the dependency's name must match the actual package's name @@ -224,6 +243,9 @@ def search_for_file(self, dependency): # type: (FileDependency) -> List[Package ) ) + if dependency.base is not None: + package.root_dir = dependency.base + package.source_url = dependency.path.as_posix() package.files = [ {"file": dependency.path.name, "hash": "sha256:" + dependency.hash()} @@ -270,15 +292,25 @@ def get_package_from_file(cls, file_path): # type: (Path) -> Package def search_for_directory( self, dependency ): # type: (DirectoryDependency) -> List[Package] - package = self.get_package_from_directory( - dependency.full_path, name=dependency.name - ) + if dependency in self._deferred_cache: + 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.develop = dependency.develop if dependency.base is not None: - package.root_dir = dependency.base.as_posix() + package.root_dir = dependency.base for extra in dependency.extras: if extra in package.extras: @@ -326,10 +358,7 @@ def get_package_from_directory( os.chdir(str(directory)) try: - 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") + cls._execute_setup() except EnvCommandError: result = SetupReader.read_from_directory(directory) if not result["name"]: @@ -437,6 +466,9 @@ def get_package_from_directory( return 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) if dependency.name != package.name: @@ -454,6 +486,11 @@ def search_for_url(self, dependency): # type: (URLDependency) -> List[Package] package.requires += package.extras[extra] + dependency._constraint = package.version + dependency._pretty_constraint = package.version.text + + self._deferred_cache[dependency] = package + return [package] @classmethod @@ -554,6 +591,17 @@ def complete_package( else: 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 = [ r for r in requires @@ -699,15 +747,15 @@ def complete_package( if (package.dependency.is_directory() or package.dependency.is_file()) and ( dep.is_directory() or dep.is_file() ): - if dep.path.as_posix().startswith(package.source_url): - relative = (Path(package.source_url) / dep.path).relative_to( - package.source_url + relative_path = Path( + os.path.relpath( + 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 - dep._path = relative + dep._path = relative_path + clean_dependencies.append(dep) package.requires = clean_dependencies @@ -817,3 +865,10 @@ def progress(self): yield self._in_progress = False + + @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") diff --git a/poetry/puzzle/solver.py b/poetry/puzzle/solver.py index aff19ca6813..e9ea1e80658 100644 --- a/poetry/puzzle/solver.py +++ b/poetry/puzzle/solver.py @@ -92,7 +92,7 @@ def solve(self, use_latest=None): # type: (...) -> List[Operation] elif package.version != pkg.version: # Checking version operations.append(Update(pkg, package)) - elif package.source_type != pkg.source_type: + elif pkg.source_type and package.source_type != pkg.source_type: operations.append(Update(pkg, package)) else: operations.append(Install(package).skip("Already installed")) diff --git a/poetry/repositories/legacy_repository.py b/poetry/repositories/legacy_repository.py index 4bb0496eb29..f850c29c85a 100644 --- a/poetry/repositories/legacy_repository.py +++ b/poetry/repositories/legacy_repository.py @@ -269,6 +269,8 @@ def find_packages( for version in versions: package = Package(name, version) + package.source_type = "legacy" + package.source_reference = self.name package.source_url = self._url if extras is not None: @@ -313,6 +315,7 @@ def package( if release_info["requires_python"]: package.python_versions = release_info["requires_python"] + package.source_type = "legacy" package.source_url = self._url package.source_reference = self.name diff --git a/poetry/semver/__init__.py b/poetry/semver/__init__.py index 725b7d43f58..39ab433d670 100644 --- a/poetry/semver/__init__.py +++ b/poetry/semver/__init__.py @@ -20,7 +20,7 @@ def parse_constraint(constraints): # type: (str) -> VersionConstraint or_groups = [] for constraints in or_constraints: and_constraints = re.split( - "(?< ,]) *(?< ,]) *(?|!=|>=?|<=?|==?)?\s*({}|dev)".format(_COMPLETE_VERSION) diff --git a/poetry/spdx/__init__.py b/poetry/spdx/__init__.py index 80a2a67d736..41d1da5bd6a 100644 --- a/poetry/spdx/__init__.py +++ b/poetry/spdx/__init__.py @@ -17,7 +17,36 @@ def license_by_id(identifier): id = identifier.lower() if id not in _licenses: - raise ValueError("Invalid license id: {}".format(identifier)) + err = "Invalid license id: {}\nPoetry uses SPDX license identifiers: https://spdx.org/licenses/".format( + identifier + ) + + # Covers the licenses listed as common for python packages in https://snyk.io/blog/over-10-of-python-packages-on-pypi-are-distributed-without-any-license/ + # MIT/WTFPL/Unlicense are excluded as their ids are simply their name - if someone types "mit", they've already found the license they were looking for + + common_strings = ["agpl", "lgpl", "gpl", "bsd", "apache", "mpl", "cc0"] + for string in common_strings: + if string in id: + + err += "\n" + err += "Did you mean one of the following?" + + matches = sorted( + { + license.id + for license in _licenses.values() + if license.id.lower().startswith(string) + and not license.is_deprecated + } + ) + + for license in matches: + err += "\n * {}".format(license) + + # Don't match agpl for "gpl" + break + + raise ValueError(err) return _licenses[id] diff --git a/poetry/utils/env.py b/poetry/utils/env.py index 0c326880ba1..94193e50628 100644 --- a/poetry/utils/env.py +++ b/poetry/utils/env.py @@ -15,6 +15,7 @@ from typing import List from typing import Optional from typing import Tuple +from typing import Union import tomlkit @@ -403,7 +404,7 @@ def remove(self, python): # type: (str) -> Env if venv.path.name == python: # Exact virtualenv name if not envs_file.exists(): - self.remove_venv(str(venv.path)) + self.remove_venv(venv.path) return venv @@ -413,7 +414,7 @@ def remove(self, python): # type: (str) -> Env current_env = envs.get(base_env_name) if not current_env: - self.remove_venv(str(venv.path)) + self.remove_venv(venv.path) return venv @@ -421,7 +422,7 @@ def remove(self, python): # type: (str) -> Env del envs[base_env_name] envs_file.write(envs) - self.remove_venv(str(venv.path)) + self.remove_venv(venv.path) return venv @@ -475,7 +476,7 @@ def remove(self, python): # type: (str) -> Env del envs[base_env_name] envs_file.write(envs) - self.remove_venv(str(venv)) + self.remove_venv(venv) return VirtualEnv(venv) @@ -621,7 +622,7 @@ def create_venv( "Creating virtualenv {} in {}".format(name, str(venv_path)) ) - self.build_venv(str(venv), executable=executable) + self.build_venv(venv, executable=executable) else: if force: if not env.is_sane(): @@ -633,8 +634,8 @@ def create_venv( io.write_line( "Recreating virtualenv {} in {}".format(name, str(venv)) ) - self.remove_venv(str(venv)) - self.build_venv(str(venv), executable=executable) + self.remove_venv(venv) + self.build_venv(venv, executable=executable) elif io.is_very_verbose(): io.write_line("Virtualenv {} already exists.".format(name)) @@ -657,7 +658,9 @@ def create_venv( return VirtualEnv(venv) @classmethod - def build_venv(cls, path, executable=None): + def build_venv( + cls, path, executable=None + ): # type: (Union[Path,str], Optional[str]) -> () if executable is not None: # Create virtualenv by using an external executable try: @@ -682,21 +685,41 @@ def build_venv(cls, path, executable=None): use_symlinks = True builder = EnvBuilder(with_pip=True, symlinks=use_symlinks) - builder.create(path) + builder.create(str(path)) except ImportError: try: # We fallback on virtualenv for Python 2.7 from virtualenv import create_environment - create_environment(path) + create_environment(str(path)) except ImportError: # since virtualenv>20 we have to use cli_run from virtualenv import cli_run - cli_run([path]) + cli_run([str(path)]) - def remove_venv(self, path): # type: (str) -> None - shutil.rmtree(path) + @classmethod + def remove_venv(cls, path): # type: (Union[Path,str]) -> None + if isinstance(path, str): + path = Path(path) + assert path.is_dir() + try: + shutil.rmtree(str(path)) + return + except OSError as e: + # Continue only if e.errno == 16 + if e.errno != 16: # ERRNO 16: Device or resource busy + raise e + + # Delete all files and folders but the toplevel one. This is because sometimes + # the venv folder is mounted by the OS, such as in a docker volume. In such + # cases, an attempt to delete the folder itself will result in an `OSError`. + # See https://github.com/python-poetry/poetry/pull/2064 + for file_path in path.iterdir(): + if file_path.is_file() or file_path.is_symlink(): + file_path.unlink() + elif file_path.is_dir(): + shutil.rmtree(str(file_path)) def get_base_prefix(self): # type: () -> Path if hasattr(sys, "real_prefix"): @@ -1151,6 +1174,7 @@ def __init__( is_venv=False, pip_version="19.1", sys_path=None, + config_vars=None, **kwargs ): super(MockEnv, self).__init__(**kwargs) @@ -1162,6 +1186,7 @@ def __init__( self._is_venv = is_venv self._pip_version = Version.parse(pip_version) self._sys_path = sys_path + self._config_vars = config_vars @property def version_info(self): # type: () -> Tuple[int] @@ -1192,3 +1217,12 @@ def sys_path(self): def is_venv(self): # type: () -> bool 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 diff --git a/poetry/utils/helpers.py b/poetry/utils/helpers.py index 3ecef0c391e..af68a6d0105 100644 --- a/poetry/utils/helpers.py +++ b/poetry/utils/helpers.py @@ -34,19 +34,18 @@ def normalize_version(version): # type: (str) -> str return str(Version(version)) +def _del_ro(action, name, exc): + os.chmod(name, stat.S_IWRITE) + os.remove(name) + + @contextmanager def temporary_directory(*args, **kwargs): - try: - from tempfile import TemporaryDirectory - - with TemporaryDirectory(*args, **kwargs) as name: - yield name - except ImportError: - name = tempfile.mkdtemp(*args, **kwargs) + name = tempfile.mkdtemp(*args, **kwargs) - yield name + yield name - shutil.rmtree(name) + shutil.rmtree(name, onerror=_del_ro) def parse_requires(requires): # type: (str) -> List[str] @@ -83,7 +82,7 @@ def parse_requires(requires): # type: (str) -> List[str] continue if current_marker: - line = "{}; {}".format(line, current_marker) + line = "{} ; {}".format(line, current_marker) requires_dist.append(line) diff --git a/poetry/utils/shell.py b/poetry/utils/shell.py index e883c80fc6e..2b2fe91f946 100644 --- a/poetry/utils/shell.py +++ b/poetry/utils/shell.py @@ -9,6 +9,7 @@ from shellingham import detect_shell from ._compat import WINDOWS +from ._compat import Path from .env import VirtualEnv @@ -42,7 +43,17 @@ def get(cls): # type: () -> Shell try: name, path = detect_shell(os.getpid()) 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) @@ -83,6 +94,8 @@ def _get_activate_script(self): suffix = ".fish" elif "csh" == self._name: suffix = ".csh" + elif "tcsh" == self._name: + suffix = ".csh" else: suffix = "" @@ -93,6 +106,8 @@ def _get_source_command(self): return "source" elif "csh" == self._name: return "source" + elif "tcsh" == self._name: + return "source" return "." diff --git a/poetry/vcs/git.py b/poetry/vcs/git.py index 28b8de74c2b..8992c410b76 100644 --- a/poetry/vcs/git.py +++ b/poetry/vcs/git.py @@ -197,7 +197,7 @@ def config(self): # type: () -> GitConfig return self._config def clone(self, repository, dest): # type: (...) -> str - return self.run("clone", repository, str(dest)) + return self.run("clone", "--recurse-submodules", repository, str(dest)) def checkout(self, rev, folder=None): # type: (...) -> str args = [] diff --git a/poetry/version/markers.py b/poetry/version/markers.py index bc4219a33d6..052c4662064 100644 --- a/poetry/version/markers.py +++ b/poetry/version/markers.py @@ -270,7 +270,11 @@ def __eq__(self, other): class SingleMarker(BaseMarker): _CONSTRAINT_RE = re.compile(r"(?i)^(~=|!=|>=?|<=?|==?|in|not in)?\s*(.+)$") - _VERSION_LIKE_MARKER_NAME = {"python_version", "platform_release"} + _VERSION_LIKE_MARKER_NAME = { + "python_version", + "python_full_version", + "platform_release", + } def __init__(self, name, constraint): from poetry.packages.constraints import ( diff --git a/pyproject.toml b/pyproject.toml index 938b89fe422..7a384698f2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "poetry" -version = "1.0.5" +version = "1.0.9" description = "Python dependency management and packaging made easy." authors = [ "Sébastien Eustace " @@ -58,7 +58,10 @@ subprocess32 = { version = "^3.5", python = "~2.7 || ~3.4" } importlib-metadata = {version = "~1.1.3", python = "<3.8"} [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" mkdocs = { version = "^1.0", python = "~2.7.9 || ^3.4" } pymdown-extensions = "^6.0" @@ -116,3 +119,23 @@ known_third_party = [ "shellingham", "tomlkit", ] + + +[tool.black] +line-length = 88 +include = '\.pyi?$' +exclude = ''' +/( + \.eggs + | \.git + | \.hg + | \.mypy_cache + | \.tox + | \.venv + | _build + | buck-out + | build + | dist + | tests/.*/setup.py +)/ +''' diff --git a/tests/conftest.py b/tests/conftest.py index d5ff7f488c9..7cda645c303 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,6 +11,8 @@ from poetry.config.config import Config as BaseConfig from poetry.config.dict_config_source import DictConfigSource 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_download @@ -74,6 +76,11 @@ def download_mock(mocker): mocker.patch("poetry.utils.inspector.Inspector.download", new=mock_download) +@pytest.fixture(autouse=True) +def execute_setup_mock(mocker): + mocker.patch("poetry.puzzle.provider.Provider._execute_setup") + + @pytest.fixture def environ(): original_environ = dict(os.environ) @@ -117,3 +124,15 @@ def tmp_dir(): yield dir_ shutil.rmtree(dir_) + + +@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)) diff --git a/tests/console/commands/env/test_info.py b/tests/console/commands/env/test_info.py index 77001ead3c3..775680f13dc 100644 --- a/tests/console/commands/env/test_info.py +++ b/tests/console/commands/env/test_info.py @@ -48,4 +48,4 @@ def test_env_info_displays_path_only(app): expected = str(Path("/prefix")) - assert expected == tester.io.fetch_output() + assert expected + "\n" == tester.io.fetch_output() diff --git a/tests/console/commands/env/test_use.py b/tests/console/commands/env/test_use.py index 2b1967bf3b1..0029ee00854 100644 --- a/tests/console/commands/env/test_use.py +++ b/tests/console/commands/env/test_use.py @@ -1,7 +1,9 @@ import os -import shutil import sys +from typing import Optional +from typing import Union + import tomlkit from cleo.testers import CommandTester @@ -16,12 +18,8 @@ CWD = Path(__file__).parent.parent / "fixtures" / "simple_project" -def build_venv(path, executable=None): - os.mkdir(path) - - -def remove_venv(path): - shutil.rmtree(path) +def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> () + os.mkdir(str(path)) def check_output_wrapper(version=Version.parse("3.7.1")): @@ -62,7 +60,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(app, tmp_dir, m ) m.assert_called_with( - os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" + Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7" ) envs_file = TomlFile(Path(tmp_dir) / "envs.toml") diff --git a/tests/console/commands/self/__init__.py b/tests/console/commands/self/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.sha256sum b/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.sha256sum new file mode 100644 index 00000000000..3229630afad --- /dev/null +++ b/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.sha256sum @@ -0,0 +1 @@ +be3d3b916cb47038899d6ff37e875fd08ba3fed22bcdbf5a92f3f48fd2f15da8 diff --git a/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.tar.gz b/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.tar.gz new file mode 100644 index 00000000000..09bb17bdeb9 Binary files /dev/null and b/tests/console/commands/self/fixtures/poetry-1.0.5-darwin.tar.gz differ diff --git a/tests/console/commands/self/test_update.py b/tests/console/commands/self/test_update.py new file mode 100644 index 00000000000..7d6914cfd7d --- /dev/null +++ b/tests/console/commands/self/test_update.py @@ -0,0 +1,87 @@ +import os + +from cleo.testers import CommandTester + +from poetry.__version__ import __version__ +from poetry.packages.package import Package +from poetry.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() diff --git a/tests/fixtures/directory/project_with_transitive_directory_dependencies/pyproject.toml b/tests/fixtures/directory/project_with_transitive_directory_dependencies/pyproject.toml index 0a97ea02c5f..28678e0d0ae 100644 --- a/tests/fixtures/directory/project_with_transitive_directory_dependencies/pyproject.toml +++ b/tests/fixtures/directory/project_with_transitive_directory_dependencies/pyproject.toml @@ -8,5 +8,6 @@ license = "MIT" [tool.poetry.dependencies] python = "*" project-with-extras = {path = "../../project_with_extras/"} +project-with-transitive-file-dependencies = {path = "../project_with_transitive_file_dependencies/"} [tool.poetry.dev-dependencies] diff --git a/tests/fixtures/directory/project_with_transitive_file_dependencies/inner-directory-project/pyproject.toml b/tests/fixtures/directory/project_with_transitive_file_dependencies/inner-directory-project/pyproject.toml new file mode 100644 index 00000000000..a80113675e6 --- /dev/null +++ b/tests/fixtures/directory/project_with_transitive_file_dependencies/inner-directory-project/pyproject.toml @@ -0,0 +1,11 @@ +[tool.poetry] +name = "inner-directory-project" +version = "1.2.4" +description = "This is a description" +authors = ["Your Name "] +license = "MIT" + +[tool.poetry.dependencies] +python = "*" + +[tool.poetry.dev-dependencies] diff --git a/tests/fixtures/directory/project_with_transitive_file_dependencies/pyproject.toml b/tests/fixtures/directory/project_with_transitive_file_dependencies/pyproject.toml index 14512e2746e..678e42f2fa5 100644 --- a/tests/fixtures/directory/project_with_transitive_file_dependencies/pyproject.toml +++ b/tests/fixtures/directory/project_with_transitive_file_dependencies/pyproject.toml @@ -8,5 +8,6 @@ license = "MIT" [tool.poetry.dependencies] python = "*" demo = {path = "../../distributions/demo-0.1.0-py2.py3-none-any.whl"} +inner-directory-project = {path = "./inner-directory-project"} [tool.poetry.dev-dependencies] diff --git a/tests/fixtures/git/github.com/demo/demo/demo.egg-info/PKG-INFO b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/PKG-INFO new file mode 100755 index 00000000000..7f543c49cb3 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/demo/demo.egg-info/SOURCES.txt b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/SOURCES.txt new file mode 100755 index 00000000000..6eb8a3ef3e3 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/SOURCES.txt @@ -0,0 +1,7 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/demo/demo.egg-info/dependency_links.txt b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/dependency_links.txt new file mode 100755 index 00000000000..e69de29bb2d diff --git a/tests/fixtures/git/github.com/demo/demo/demo.egg-info/requires.txt b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/requires.txt new file mode 100755 index 00000000000..e05a65d3c93 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/requires.txt @@ -0,0 +1,7 @@ +pendulum>=1.4.4 + +[bar] +tomlkit + +[foo] +cleo diff --git a/tests/fixtures/git/github.com/demo/demo/demo.egg-info/top_level.txt b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/top_level.txt new file mode 100755 index 00000000000..1549b67ca59 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/demo/demo.egg-info/top_level.txt @@ -0,0 +1 @@ +demo diff --git a/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/__init__.py b/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/__init__.py new file mode 100644 index 00000000000..5284146ebf2 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/__init__.py @@ -0,0 +1 @@ +__import__("pkg_resources").declare_namespace(__name__) diff --git a/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/one/__init__.py b/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/one/__init__.py new file mode 100644 index 00000000000..1ac9243c76f --- /dev/null +++ b/tests/fixtures/git/github.com/demo/namespace-package-one/namespace_package/one/__init__.py @@ -0,0 +1 @@ +name = "one" diff --git a/tests/fixtures/git/github.com/demo/namespace-package-one/setup.py b/tests/fixtures/git/github.com/demo/namespace-package-one/setup.py new file mode 100644 index 00000000000..871fae6cf69 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/namespace-package-one/setup.py @@ -0,0 +1,15 @@ +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, +) diff --git a/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/PKG-INFO b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/PKG-INFO new file mode 100644 index 00000000000..7ba97897a10 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/SOURCES.txt b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/SOURCES.txt new file mode 100644 index 00000000000..e19f4a4eb57 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/SOURCES.txt @@ -0,0 +1,6 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/dependency_links.txt b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/dependency_links.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/top_level.txt b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/top_level.txt new file mode 100644 index 00000000000..1549b67ca59 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/no-dependencies/demo.egg-info/top_level.txt @@ -0,0 +1 @@ +demo diff --git a/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/PKG-INFO b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/PKG-INFO new file mode 100644 index 00000000000..996589ec257 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/SOURCES.txt b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/SOURCES.txt new file mode 100644 index 00000000000..8134b008da5 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/SOURCES.txt @@ -0,0 +1,7 @@ +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 diff --git a/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/dependency_links.txt b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/dependency_links.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/requires.txt b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/requires.txt new file mode 100644 index 00000000000..e05a65d3c93 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/requires.txt @@ -0,0 +1,7 @@ +pendulum>=1.4.4 + +[bar] +tomlkit + +[foo] +cleo diff --git a/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/top_level.txt b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/top_level.txt new file mode 100644 index 00000000000..1549b67ca59 --- /dev/null +++ b/tests/fixtures/git/github.com/demo/non-canonical-name/Demo.egg-info/top_level.txt @@ -0,0 +1 @@ +demo diff --git a/tests/fixtures/project_with_setup/my_package.egg-info/PKG-INFO b/tests/fixtures/project_with_setup/my_package.egg-info/PKG-INFO new file mode 100644 index 00000000000..71ba645751f --- /dev/null +++ b/tests/fixtures/project_with_setup/my_package.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +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 diff --git a/tests/fixtures/project_with_setup/my_package.egg-info/SOURCES.txt b/tests/fixtures/project_with_setup/my_package.egg-info/SOURCES.txt new file mode 100644 index 00000000000..f5255dc9dad --- /dev/null +++ b/tests/fixtures/project_with_setup/my_package.egg-info/SOURCES.txt @@ -0,0 +1,7 @@ +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 diff --git a/tests/fixtures/project_with_setup/my_package.egg-info/dependency_links.txt b/tests/fixtures/project_with_setup/my_package.egg-info/dependency_links.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/fixtures/project_with_setup/my_package.egg-info/requires.txt b/tests/fixtures/project_with_setup/my_package.egg-info/requires.txt new file mode 100644 index 00000000000..eeb0a4815ce --- /dev/null +++ b/tests/fixtures/project_with_setup/my_package.egg-info/requires.txt @@ -0,0 +1,2 @@ +pendulum>=1.4.4 +cachy[msgpack]>=0.2.0 diff --git a/tests/fixtures/project_with_setup/my_package.egg-info/top_level.txt b/tests/fixtures/project_with_setup/my_package.egg-info/top_level.txt new file mode 100644 index 00000000000..5d04b540bc9 --- /dev/null +++ b/tests/fixtures/project_with_setup/my_package.egg-info/top_level.txt @@ -0,0 +1 @@ +my_package diff --git a/tests/installation/fixtures/with-directory-dependency-poetry-transitive.test b/tests/installation/fixtures/with-directory-dependency-poetry-transitive.test index 06f262f74e6..ad29dd7abe6 100644 --- a/tests/installation/fixtures/with-directory-dependency-poetry-transitive.test +++ b/tests/installation/fixtures/with-directory-dependency-poetry-transitive.test @@ -1,3 +1,45 @@ +[[package]] +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 = "" +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 = "" @@ -14,7 +56,7 @@ extras_b = ["cachy (>=0.2.0)"] [package.source] reference = "" type = "directory" -url = "tests/fixtures/directory/project_with_transitive_directory_dependencies/../../project_with_extras" +url = "../project_with_extras" [[package]] category = "main" @@ -26,17 +68,42 @@ python-versions = "*" version = "1.2.3" [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 = "" +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] reference = "" type = "directory" -url = "tests/fixtures/directory/project_with_transitive_directory_dependencies" +url = "project_with_transitive_file_dependencies" [metadata] content-hash = "123456789" python-versions = "*" [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-transitive-directory-dependencies = [] +project-with-transitive-file-dependencies = [] diff --git a/tests/installation/fixtures/with-file-dependency-transitive.test b/tests/installation/fixtures/with-file-dependency-transitive.test index db3b632694a..2cbd16e1a53 100644 --- a/tests/installation/fixtures/with-file-dependency-transitive.test +++ b/tests/installation/fixtures/with-file-dependency-transitive.test @@ -16,7 +16,21 @@ foo = ["cleo"] [package.source] reference = "" 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 = "" +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" @@ -36,12 +50,13 @@ python-versions = "*" version = "1.2.3" [package.dependencies] -demo = "*" +demo = "0.1.0" +inner-directory-project = "1.2.4" [package.source] reference = "" type = "directory" -url = "tests/fixtures/directory/project_with_transitive_file_dependencies" +url = "project_with_transitive_file_dependencies" [metadata] content-hash = "123456789" @@ -51,5 +66,6 @@ python-versions = "*" demo = [ {file = "demo-0.1.0-py2.py3-none-any.whl", hash = "sha256:70e704135718fffbcbf61ed1fc45933cfd86951a744b681000eaaa75da31f17a"}, ] +inner-directory-project = [] pendulum = [] project-with-transitive-file-dependencies = [] diff --git a/tests/installation/test_installer.py b/tests/installation/test_installer.py index c236141be44..ee5318a5a23 100644 --- a/tests/installation/test_installer.py +++ b/tests/installation/test_installer.py @@ -716,11 +716,13 @@ def test_run_installs_with_local_poetry_directory_and_extras( def test_run_installs_with_local_poetry_directory_transitive( installer, locker, repo, package, tmpdir ): - file_path = ( - fixtures_dir / "directory/project_with_transitive_directory_dependencies/" + package.root_dir = fixtures_dir.joinpath("directory") + directory = fixtures_dir.joinpath("directory").joinpath( + "project_with_transitive_directory_dependencies" ) 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")) @@ -732,15 +734,19 @@ def test_run_installs_with_local_poetry_directory_transitive( 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( 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( - "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")) @@ -752,7 +758,7 @@ def test_run_installs_with_local_poetry_file_transitive( 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( diff --git a/tests/installation/test_pip_installer.py b/tests/installation/test_pip_installer.py index fe40328aa1a..702dfe9c0e6 100644 --- a/tests/installation/test_pip_installer.py +++ b/tests/installation/test_pip_installer.py @@ -1,3 +1,5 @@ +import shutil + import pytest from poetry.installation.pip_installer import PipInstaller @@ -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"] 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 diff --git a/tests/masonry/builders/fixtures/excluded_subpackage/README.rst b/tests/masonry/builders/fixtures/excluded_subpackage/README.rst index b00640203c5..f7fe15470f9 100644 --- a/tests/masonry/builders/fixtures/excluded_subpackage/README.rst +++ b/tests/masonry/builders/fixtures/excluded_subpackage/README.rst @@ -1,2 +1,2 @@ My Package -========== \ No newline at end of file +========== diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/module.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/module.pyi new file mode 100644 index 00000000000..d79e6e39ee0 --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/module.pyi @@ -0,0 +1,4 @@ +"""Example module""" +from typing import Tuple + +version_info = Tuple[int, int, int] diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/subpkg/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only/pkg-stubs/subpkg/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only/pyproject.toml b/tests/masonry/builders/fixtures/pep_561_stub_only/pyproject.toml new file mode 100644 index 00000000000..36a077afd95 --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only/pyproject.toml @@ -0,0 +1,14 @@ +[tool.poetry] +name = "pep-561-stubs" +version = "0.1" +description = "PEP 561 stub package example" +authors = [ + "Oleg Höfling " +] +license = "MIT" +packages = [ + {include = "pkg-stubs"} +] + +[tool.poetry.dependencies] +python = "^3.6" diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/module.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/module.pyi new file mode 100644 index 00000000000..d79e6e39ee0 --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/module.pyi @@ -0,0 +1,4 @@ +"""Example module""" +from typing import Tuple + +version_info = Tuple[int, int, int] diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/py.typed b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/py.typed new file mode 100644 index 00000000000..b648ac92333 --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/py.typed @@ -0,0 +1 @@ +partial diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/subpkg/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pkg-stubs/subpkg/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pyproject.toml b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pyproject.toml new file mode 100644 index 00000000000..db202c04a1c --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only_partial/pyproject.toml @@ -0,0 +1,14 @@ +[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 " +] +license = "MIT" +packages = [ + {include = "pkg-stubs"} +] + +[tool.poetry.dependencies] +python = "^3.6" diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_src/pyproject.toml b/tests/masonry/builders/fixtures/pep_561_stub_only_src/pyproject.toml new file mode 100644 index 00000000000..666b2b24f6d --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only_src/pyproject.toml @@ -0,0 +1,14 @@ +[tool.poetry] +name = "pep-561-stubs" +version = "0.1" +description = "PEP 561 stub package example with an src layout" +authors = [ + "Oleg Höfling " +] +license = "MIT" +packages = [ + {include = "pkg-stubs", from = "src"} +] + +[tool.poetry.dependencies] +python = "^3.6" diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/module.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/module.pyi new file mode 100644 index 00000000000..d79e6e39ee0 --- /dev/null +++ b/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/module.pyi @@ -0,0 +1,4 @@ +"""Example module""" +from typing import Tuple + +version_info = Tuple[int, int, int] diff --git a/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/subpkg/__init__.pyi b/tests/masonry/builders/fixtures/pep_561_stub_only_src/src/pkg-stubs/subpkg/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/builders/test_editable.py b/tests/masonry/builders/test_editable.py index d1121243ca4..a067db46ea2 100644 --- a/tests/masonry/builders/test_editable.py +++ b/tests/masonry/builders/test_editable.py @@ -38,7 +38,9 @@ def test_build_should_temporarily_remove_the_pyproject_file(tmp_dir, mocker): builder = EditableBuilder(Factory().create_poetry(module_path), env, NullIO()) builder.build() - expected = [[sys.executable, "-m", "pip", "install", "-e", str(module_path)]] + expected = [ + [sys.executable, "-m", "pip", "install", "--no-deps", "-e", str(module_path)] + ] assert expected == env.executed assert 2 == move.call_count diff --git a/tests/masonry/builders/test_sdist.py b/tests/masonry/builders/test_sdist.py index ed2ded503df..7b55e2acbb2 100644 --- a/tests/masonry/builders/test_sdist.py +++ b/tests/masonry/builders/test_sdist.py @@ -488,3 +488,21 @@ def test_excluded_subpackage(): exec(compile(setup_ast, filename="setup.py", mode="exec"), ns) assert ns["packages"] == ["example"] + + +def test_sdist_package_pep_561_stub_only(): + root = fixtures_dir / "pep_561_stub_only" + poetry = Factory().create_poetry(root) + + builder = SdistBuilder(poetry, NullEnv(), NullIO()) + builder.build() + + sdist = root / "dist" / "pep-561-stubs-0.1.tar.gz" + + assert sdist.exists() + + with tarfile.open(str(sdist), "r") as tar: + names = tar.getnames() + assert "pep-561-stubs-0.1/pkg-stubs/__init__.pyi" in names + assert "pep-561-stubs-0.1/pkg-stubs/module.pyi" in names + assert "pep-561-stubs-0.1/pkg-stubs/subpkg/__init__.pyi" in names diff --git a/tests/masonry/builders/test_wheel.py b/tests/masonry/builders/test_wheel.py index ec3de8f7a60..36f8c27170b 100644 --- a/tests/masonry/builders/test_wheel.py +++ b/tests/masonry/builders/test_wheel.py @@ -162,3 +162,33 @@ def test_dist_info_file_permissions(): z.getinfo("my_package-1.2.3.dist-info/entry_points.txt").external_attr == 0o644 << 16 ) + + +@pytest.mark.parametrize( + "package", + ["pep_561_stub_only", "pep_561_stub_only_partial", "pep_561_stub_only_src"], +) +def test_wheel_package_pep_561_stub_only(package): + root = fixtures_dir / package + WheelBuilder.make(Factory().create_poetry(root), NullEnv(), NullIO()) + + whl = root / "dist" / "pep_561_stubs-0.1-py3-none-any.whl" + + assert whl.exists() + + with zipfile.ZipFile(str(whl)) as z: + assert "pkg-stubs/__init__.pyi" in z.namelist() + assert "pkg-stubs/module.pyi" in z.namelist() + assert "pkg-stubs/subpkg/__init__.pyi" in z.namelist() + + +def test_wheel_package_pep_561_stub_only_includes_typed_marker(): + root = fixtures_dir / "pep_561_stub_only_partial" + WheelBuilder.make(Factory().create_poetry(root), NullEnv(), NullIO()) + + whl = root / "dist" / "pep_561_stubs-0.1-py3-none-any.whl" + + assert whl.exists() + + with zipfile.ZipFile(str(whl)) as z: + assert "pkg-stubs/py.typed" in z.namelist() diff --git a/tests/masonry/utils/fixtures/pep_561_stub_only/bad/__init__.pyi b/tests/masonry/utils/fixtures/pep_561_stub_only/bad/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/utils/fixtures/pep_561_stub_only/bad/module.pyi b/tests/masonry/utils/fixtures/pep_561_stub_only/bad/module.pyi new file mode 100644 index 00000000000..f85a07d465a --- /dev/null +++ b/tests/masonry/utils/fixtures/pep_561_stub_only/bad/module.pyi @@ -0,0 +1,5 @@ +"""Example module""" +from typing import Tuple + + +version_info = Tuple[int, int, int] diff --git a/tests/masonry/utils/fixtures/pep_561_stub_only/good-stubs/__init__.pyi b/tests/masonry/utils/fixtures/pep_561_stub_only/good-stubs/__init__.pyi new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/masonry/utils/fixtures/pep_561_stub_only/good-stubs/module.pyi b/tests/masonry/utils/fixtures/pep_561_stub_only/good-stubs/module.pyi new file mode 100644 index 00000000000..f85a07d465a --- /dev/null +++ b/tests/masonry/utils/fixtures/pep_561_stub_only/good-stubs/module.pyi @@ -0,0 +1,5 @@ +"""Example module""" +from typing import Tuple + + +version_info = Tuple[int, int, int] diff --git a/tests/masonry/utils/test_package_include.py b/tests/masonry/utils/test_package_include.py index a79ff96f03c..88ce75101d9 100644 --- a/tests/masonry/utils/test_package_include.py +++ b/tests/masonry/utils/test_package_include.py @@ -41,3 +41,29 @@ def test_package_include_with_no_python_files_in_dir(): PackageInclude(base=with_includes, include="not_a_python_pkg") assert str(e.value) == "not_a_python_pkg is not a package." + + +def test_package_include_with_non_existent_directory(): + with pytest.raises(ValueError) as e: + PackageInclude(base=with_includes, include="not_a_dir") + + err_str = str(with_includes / "not_a_dir") + " does not contain any element" + + assert str(e.value) == err_str + + +def test_pep_561_stub_only_package_good_name_suffix(): + pkg_include = PackageInclude( + base=fixtures_dir / "pep_561_stub_only", include="good-stubs" + ) + assert pkg_include.elements == [ + fixtures_dir / "pep_561_stub_only/good-stubs/__init__.pyi", + fixtures_dir / "pep_561_stub_only/good-stubs/module.pyi", + ] + + +def test_pep_561_stub_only_package_bad_name_suffix(): + with pytest.raises(ValueError) as e: + PackageInclude(base=fixtures_dir / "pep_561_stub_only", include="bad") + + assert str(e.value) == "bad is not a package." diff --git a/tests/masonry/utils/test_tags.py b/tests/masonry/utils/test_tags.py new file mode 100644 index 00000000000..50193f509a2 --- /dev/null +++ b/tests/masonry/utils/test_tags.py @@ -0,0 +1,79 @@ +import pytest + +from poetry.masonry.utils.tags import get_abi_tag +from poetry.utils.env import MockEnv + + +def test_tags_cpython38(): + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 8, 0), + python_implementation="CPython", + config_vars={"Py_DEBUG": True}, + ) + ) + == "cp38d" + ) + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 8, 0), python_implementation="CPython", config_vars={}, + ) + ) + == "cp38" + ) + + +def test_tags_cpython37(): + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 7, 3), + python_implementation="CPython", + config_vars={"Py_DEBUG": True, "WITH_PYMALLOC": True}, + ) + ) + == "cp37dm" + ) + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 7, 3), + python_implementation="CPython", + config_vars={"Py_DEBUG": True, "WITH_PYMALLOC": False}, + ) + ) + == "cp37d" + ) + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 7, 3), + python_implementation="CPython", + config_vars={"Py_DEBUG": False, "WITH_PYMALLOC": True}, + ) + ) + == "cp37m" + ) + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 7, 3), + python_implementation="CPython", + config_vars={"Py_DEBUG": False, "WITH_PYMALLOC": False}, + ) + ) + == "cp37" + ) + with pytest.warns(RuntimeWarning): + assert ( + get_abi_tag( + MockEnv( + version_info=(3, 7, 3), + python_implementation="CPython", + config_vars={"Py_DEBUG": False}, + ) + ) + == "cp37m" + ) diff --git a/tests/packages/test_dependency.py b/tests/packages/test_dependency.py index 91654f4b874..2a08b2c6ff0 100644 --- a/tests/packages/test_dependency.py +++ b/tests/packages/test_dependency.py @@ -1,3 +1,5 @@ +import pytest + from poetry.packages import Dependency from poetry.packages import Package @@ -108,3 +110,23 @@ def test_to_pep_508_with_single_version_excluded(): dependency = Dependency("foo", "!=1.2.3") assert "foo (!=1.2.3)" == dependency.to_pep_508() + + +@pytest.mark.parametrize( + "python_versions, marker", + [ + (">=3.5,<3.5.4", 'python_version >= "3.5" and python_full_version < "3.5.4"'), + (">=3.5.4,<3.6", 'python_full_version >= "3.5.4" and python_version < "3.6"'), + ("<3.5.4", 'python_full_version < "3.5.4"'), + (">=3.5.4", 'python_full_version >= "3.5.4"'), + ("== 3.5.4", 'python_full_version == "3.5.4"'), + ], +) +def test_to_pep_508_with_patch_python_version(python_versions, marker): + dependency = Dependency("Django", "^1.23") + dependency.python_versions = python_versions + + expected = "Django (>=1.23,<2.0); {}".format(marker) + + assert expected == dependency.to_pep_508() + assert marker == str(dependency.marker) diff --git a/tests/packages/test_main.py b/tests/packages/test_main.py index 586be5a31b8..508e080b8aa 100644 --- a/tests/packages/test_main.py +++ b/tests/packages/test_main.py @@ -183,6 +183,22 @@ def test_dependency_from_pep_508_with_git_url(): assert "1.2" == dep.reference +def test_dependency_from_pep_508_with_git_url_and_comment_and_extra(): + name = ( + "poetry @ git+https://github.com/python-poetry/poetry.git@b;ar;#egg=poetry" + ' ; extra == "foo;"' + ) + + dep = dependency_from_pep_508(name) + + assert "poetry" == dep.name + assert dep.is_vcs() + assert "git" == dep.vcs + assert "https://github.com/python-poetry/poetry.git" == dep.source + assert "b;ar;" == dep.reference + assert dep.in_extras == ["foo;"] + + def test_dependency_from_pep_508_with_url(): name = "django-utils @ https://example.com/django-utils-1.0.0.tar.gz" @@ -202,3 +218,21 @@ def test_dependency_from_pep_508_with_wheel_url(): assert "example-wheel" == dep.name assert str(dep.constraint) == "14.0.2" + + +def test_dependency_from_pep_508_with_python_full_version(): + name = ( + "requests (==2.18.0); " + '(python_version >= "2.7" and python_version < "2.8") ' + 'or (python_full_version >= "3.4" and python_full_version < "3.5.4")' + ) + dep = dependency_from_pep_508(name) + + assert dep.name == "requests" + assert str(dep.constraint) == "2.18.0" + assert dep.extras == [] + assert dep.python_versions == ">=2.7 <2.8 || >=3.4 <3.5.4" + assert str(dep.marker) == ( + 'python_version >= "2.7" and python_version < "2.8" ' + 'or python_full_version >= "3.4" and python_full_version < "3.5.4"' + ) diff --git a/tests/packages/test_package.py b/tests/packages/test_package.py index 510f542f222..19226f81c3d 100644 --- a/tests/packages/test_package.py +++ b/tests/packages/test_package.py @@ -30,6 +30,19 @@ def test_package_authors(): assert package.author_email is None +def test_package_authors_invalid(): + package = Package("foo", "0.1.0") + + package.authors.insert(0, "" + ) + + @pytest.mark.parametrize("category", ["main", "dev"]) def test_package_add_dependency_vcs_category(category): package = Package("foo", "0.1.0") @@ -49,3 +62,20 @@ def test_package_add_dependency_vcs_category_default_main(): "poetry", constraint={"git": "https://github.com/python-poetry/poetry.git"} ) assert dependency.category == "main" + + +@pytest.mark.parametrize("category", ["main", "dev"]) +@pytest.mark.parametrize("optional", [True, False]) +def test_package_url_category_optional(category, optional): + package = Package("foo", "0.1.0") + + dependency = package.add_dependency( + "poetry", + constraint={ + "url": "https://github.com/python-poetry/poetry/releases/download/1.0.5/poetry-1.0.5-linux.tar.gz", + "optional": optional, + }, + category=category, + ) + assert dependency.category == category + assert dependency.is_optional() == optional diff --git a/tests/puzzle/test_provider.py b/tests/puzzle/test_provider.py index d3bcba65688..3431911866a 100644 --- a/tests/puzzle/test_provider.py +++ b/tests/puzzle/test_provider.py @@ -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): mocker.patch( - "poetry.utils.env.VirtualEnv.run", + "poetry.puzzle.provider.Provider._execute_setup", side_effect=EnvCommandError(CalledProcessError(1, "python", output="")), ) @@ -204,16 +204,13 @@ def test_search_for_directory_setup_with_base(provider, directory): "foo": [get_dependency("cleo")], "bar": [get_dependency("tomlkit")], } - assert ( - package.root_dir - == ( - Path(__file__).parent.parent - / "fixtures" - / "git" - / "github.com" - / "demo" - / directory - ).as_posix() + assert package.root_dir == ( + Path(__file__).parent.parent + / "fixtures" + / "git" + / "github.com" + / "demo" + / directory ) diff --git a/tests/puzzle/test_solver.py b/tests/puzzle/test_solver.py index 415f6bcea09..6ee6fea911f 100644 --- a/tests/puzzle/test_solver.py +++ b/tests/puzzle/test_solver.py @@ -1928,3 +1928,133 @@ def test_solver_properly_propagates_markers(solver, repo, package): str(ops[0].package.marker) == 'python_version >= "3.6" and implementation_name != "pypy"' ) + + +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() + + +def test_solver_should_not_update_same_version_packages_if_installed_has_no_source_type( + solver, repo, package, installed +): + package.add_dependency("foo", "1.0.0") + + foo = get_package("foo", "1.0.0") + foo.source_type = "legacy" + foo.source_reference = "custom" + foo.source_url = "https://foo.bar" + repo.add_package(foo) + installed.add_package(get_package("foo", "1.0.0")) + + ops = solver.solve() + + check_solver_result( + ops, [{"job": "install", "package": foo, "skipped": True}], + ) diff --git a/tests/repositories/fixtures/installed/lib/python3.7/site-packages/cleo-0.7.6.dist-info/METADATA b/tests/repositories/fixtures/installed/lib/python3.7/site-packages/cleo-0.7.6.dist-info/METADATA index 2a4c1439cf2..261c036ecda 100644 --- a/tests/repositories/fixtures/installed/lib/python3.7/site-packages/cleo-0.7.6.dist-info/METADATA +++ b/tests/repositories/fixtures/installed/lib/python3.7/site-packages/cleo-0.7.6.dist-info/METADATA @@ -521,3 +521,5 @@ replacing ``[program]`` with the command you use to run your application: # 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 diff --git a/tests/repositories/fixtures/installed/vendor/py3.7/attrs-19.3.0.dist-info/METADATA b/tests/repositories/fixtures/installed/vendor/py3.7/attrs-19.3.0.dist-info/METADATA index a1064151030..6c8d9f7d6eb 100644 --- a/tests/repositories/fixtures/installed/vendor/py3.7/attrs-19.3.0.dist-info/METADATA +++ b/tests/repositories/fixtures/installed/vendor/py3.7/attrs-19.3.0.dist-info/METADATA @@ -225,5 +225,3 @@ A full list of contributors can be found in `GitHub's overview `_ and aspires to fix some of it clunkiness and unfortunate decisions. Both were inspired by Twisted’s `FancyEqMixin `_ but both are implemented using class decorators because `subclassing is bad for you `_, m’kay? - - diff --git a/tests/repositories/test_legacy_repository.py b/tests/repositories/test_legacy_repository.py index 3803da552ce..43aa8aae028 100644 --- a/tests/repositories/test_legacy_repository.py +++ b/tests/repositories/test_legacy_repository.py @@ -84,6 +84,9 @@ def test_get_package_information_fallback_read_setup(): 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.version.text == "1.0.0" assert ( @@ -142,6 +145,10 @@ def test_find_packages_no_prereleases(): 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(): repo = MockRepository() diff --git a/tests/semver/test_parse_constraint.py b/tests/semver/test_parse_constraint.py new file mode 100644 index 00000000000..e950168f17a --- /dev/null +++ b/tests/semver/test_parse_constraint.py @@ -0,0 +1,86 @@ +import pytest + +from poetry.semver import Version +from poetry.semver import VersionRange +from poetry.semver import VersionUnion +from poetry.semver import parse_constraint + + +@pytest.mark.parametrize( + "constraint,version", + [ + ("~=3.8", VersionRange(min=Version(3, 8), max=Version(4, 0), include_min=True)), + ( + "~= 3.8", + VersionRange(min=Version(3, 8), max=Version(4, 0), include_min=True), + ), + ("~3.8", VersionRange(min=Version(3, 8), max=Version(3, 9), include_min=True)), + ("~ 3.8", VersionRange(min=Version(3, 8), max=Version(3, 9), include_min=True)), + (">3.8", VersionRange(min=Version(3, 8))), + (">=3.8", VersionRange(min=Version(3, 8), include_min=True)), + (">= 3.8", VersionRange(min=Version(3, 8), include_min=True)), + ( + ">3.8,<=6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + ">3.8,<= 6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + "> 3.8,<= 6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + "> 3.8,<=6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + ">3.8 ,<=6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + ">3.8, <=6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + ">3.8 , <=6.5", + VersionRange(min=Version(3, 8), max=Version(6, 5), include_max=True), + ), + ( + "==3.8", + VersionRange( + min=Version(3, 8), max=Version(3, 8), include_min=True, include_max=True + ), + ), + ( + "== 3.8", + VersionRange( + min=Version(3, 8), max=Version(3, 8), include_min=True, include_max=True + ), + ), + ( + "~2.7 || ~3.8", + VersionUnion( + VersionRange(min=Version(2, 7), max=Version(2, 8), include_min=True), + VersionRange(min=Version(3, 8), max=Version(3, 9), include_min=True), + ), + ), + ( + "~2.7||~3.8", + VersionUnion( + VersionRange(min=Version(2, 7), max=Version(2, 8), include_min=True), + VersionRange(min=Version(3, 8), max=Version(3, 9), include_min=True), + ), + ), + ( + "~ 2.7||~ 3.8", + VersionUnion( + VersionRange(min=Version(2, 7), max=Version(2, 8), include_min=True), + VersionRange(min=Version(3, 8), max=Version(3, 9), include_min=True), + ), + ), + ], +) +def test_parse_constraint(constraint, version): + assert parse_constraint(constraint) == version diff --git a/tests/spdx/test_main.py b/tests/spdx/test_main.py index 00e0910044d..ef941458c89 100644 --- a/tests/spdx/test_main.py +++ b/tests/spdx/test_main.py @@ -41,3 +41,38 @@ def test_license_by_id_with_full_name(): def test_license_by_id_invalid(): with pytest.raises(ValueError): license_by_id("invalid") + + +def test_license_by_id_invalid_gpl(): + with pytest.raises(ValueError) as exc_info: + license_by_id("gpl") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" in str(exc_info.value) + assert " AGPL-3.0-only" not in str(exc_info.value) + + +def test_license_by_id_invalid_agpl(): + with pytest.raises(ValueError) as exc_info: + license_by_id("agpl") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" not in str(exc_info.value) + assert " AGPL-3.0-only" in str(exc_info.value) + + +def test_license_by_id_invalid_agpl_versioned(): + with pytest.raises(ValueError) as exc_info: + license_by_id("gnu agpl v3+") + + assert "Did you mean" in str(exc_info.value) + assert " GPL-3.0-only" not in str(exc_info.value) + assert " AGPL-3.0-only" in str(exc_info.value) + + +def test_license_by_id_invalid_unpopular(): + with pytest.raises(ValueError) as exc_info: + license_by_id("not-a-well-known-license") + + assert "spdx.org" in str(exc_info.value) + assert "Did you mean" not in str(exc_info.value) diff --git a/tests/utils/test_env.py b/tests/utils/test_env.py index e5926e68862..04bb4f8808e 100644 --- a/tests/utils/test_env.py +++ b/tests/utils/test_env.py @@ -2,6 +2,9 @@ import shutil import sys +from typing import Optional +from typing import Union + import pytest import tomlkit @@ -60,18 +63,6 @@ def manager(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): venv_path = Path(tmp_dir) / "Virtual Env" @@ -95,12 +86,8 @@ def test_env_get_in_project_venv(manager, poetry): shutil.rmtree(str(venv.path)) -def build_venv(path, executable=None): - os.mkdir(path) - - -def remove_venv(path): - shutil.rmtree(path) +def build_venv(path, executable=None): # type: (Union[Path,str], Optional[str]) -> () + os.mkdir(str(path)) def check_output_wrapper(version=Version.parse("3.7.1")): @@ -137,7 +124,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file( venv_name = EnvManager.generate_env_name("simple-project", str(poetry.file.parent)) m.assert_called_with( - os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" + Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7" ) envs_file = TomlFile(Path(tmp_dir) / "envs.toml") @@ -255,7 +242,7 @@ def test_activate_activates_different_virtualenv_with_envs_file( env = manager.activate("python3.6", NullIO()) m.assert_called_with( - os.path.join(tmp_dir, "{}-py3.6".format(venv_name)), executable="python3.6" + Path(tmp_dir) / "{}-py3.6".format(venv_name), executable="python3.6" ) assert envs_file.exists() @@ -301,17 +288,15 @@ def test_activate_activates_recreates_for_different_patch( "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv ) remove_venv_m = mocker.patch( - "poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv + "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv ) env = manager.activate("python3.7", NullIO()) build_venv_m.assert_called_with( - os.path.join(tmp_dir, "{}-py3.7".format(venv_name)), executable="python3.7" - ) - remove_venv_m.assert_called_with( - os.path.join(tmp_dir, "{}-py3.7".format(venv_name)) + Path(tmp_dir) / "{}-py3.7".format(venv_name), executable="python3.7" ) + remove_venv_m.assert_called_with(Path(tmp_dir) / "{}-py3.7".format(venv_name)) assert envs_file.exists() envs = envs_file.read() @@ -352,7 +337,7 @@ def test_activate_does_not_recreate_when_switching_minor( "poetry.utils.env.EnvManager.build_venv", side_effect=build_venv ) remove_venv_m = mocker.patch( - "poetry.utils.env.EnvManager.remove_venv", side_effect=remove_venv + "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv ) env = manager.activate("python3.6", NullIO()) @@ -547,6 +532,54 @@ def test_remove_also_deactivates(tmp_dir, manager, poetry, config, mocker): assert venv_name not in envs +def test_remove_keeps_dir_if_not_deleteable(tmp_dir, manager, poetry, config, mocker): + # Ensure we empty rather than delete folder if its is an active mount point. + # See https://github.com/python-poetry/poetry/pull/2064 + config.merge({"virtualenvs": {"path": str(tmp_dir)}}) + + venv_name = manager.generate_env_name("simple-project", str(poetry.file.parent)) + venv_path = Path(tmp_dir) / "{}-py3.6".format(venv_name) + venv_path.mkdir() + + folder1_path = venv_path / "folder1" + folder1_path.mkdir() + + file1_path = folder1_path / "file1" + file1_path.touch(exist_ok=False) + + file2_path = venv_path / "file2" + file2_path.touch(exist_ok=False) + + mocker.patch( + "poetry.utils._compat.subprocess.check_output", + side_effect=check_output_wrapper(Version.parse("3.6.6")), + ) + + original_rmtree = shutil.rmtree + + def err_on_rm_venv_only(path, *args, **kwargs): + print(path) + if path == str(venv_path): + raise OSError(16, "Test error") # ERRNO 16: Device or resource busy + else: + original_rmtree(path) + + m = mocker.patch("shutil.rmtree", side_effect=err_on_rm_venv_only) + + venv = manager.remove("{}-py3.6".format(venv_name)) + + m.assert_any_call(str(venv_path)) + + assert venv_path == venv.path + assert venv_path.exists() + + assert not folder1_path.exists() + assert not file1_path.exists() + assert not file2_path.exists() + + m.side_effect = original_rmtree # Avoid teardown using `err_on_rm_venv_only` + + def test_env_has_symlinks_on_nix(tmp_dir, tmp_venv): venv_available = False try: @@ -596,7 +629,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ manager.create_venv(NullIO()) m.assert_called_with( - str(Path("/foo/virtualenvs/{}-py3.7".format(venv_name))), executable="python3" + Path("/foo/virtualenvs/{}-py3.7".format(venv_name)), executable="python3" ) @@ -620,7 +653,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific manager.create_venv(NullIO()) m.assert_called_with( - str(Path("/foo/virtualenvs/{}-py3.8".format(venv_name))), executable="python3.8" + Path("/foo/virtualenvs/{}-py3.8".format(venv_name)), executable="python3.8" ) @@ -703,11 +736,9 @@ def test_create_venv_uses_patch_version_to_detect_compatibility( assert not check_output.called m.assert_called_with( - str( - Path( - "/foo/virtualenvs/{}-py{}.{}".format( - venv_name, version.major, version.minor - ) + Path( + "/foo/virtualenvs/{}-py{}.{}".format( + venv_name, version.major, version.minor ) ), executable=None, @@ -742,11 +773,9 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( assert check_output.called m.assert_called_with( - str( - Path( - "/foo/virtualenvs/{}-py{}.{}".format( - venv_name, version.major, version.minor - 1 - ) + Path( + "/foo/virtualenvs/{}-py{}.{}".format( + venv_name, version.major, version.minor - 1 ) ), executable="python{}.{}".format(version.major, version.minor - 1), @@ -780,9 +809,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( manager.activate("python3.7", NullIO()) - m.assert_called_with( - os.path.join(str(poetry.file.parent), ".venv"), executable="python3.7" - ) + m.assert_called_with(poetry.file.parent / ".venv", executable="python3.7") envs_file = TomlFile(Path(tmp_dir) / "virtualenvs" / "envs.toml") assert not envs_file.exists() diff --git a/tests/utils/test_helpers.py b/tests/utils/test_helpers.py index d34061c88d6..eb7ce191f18 100644 --- a/tests/utils/test_helpers.py +++ b/tests/utils/test_helpers.py @@ -29,6 +29,9 @@ def test_parse_requires(): [:python_version >= "3.4.0.0" and python_version < "3.6.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) expected = [ @@ -45,10 +48,11 @@ def test_parse_requires(): "msgpack-python>=0.5.0.0,<0.6.0.0", "pyparsing>=2.2.0.0,<3.0.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")', - '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"', - 'zipfile36>=0.1.0.0,<0.2.0.0; python_version >= "3.4.0.0" and python_version < "3.6.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"', + '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"', + 'isort@ git+git://github.com/timothycrosley/isort.git@e63ae06ec7d70b06df9e528357650281a3d3ec22#egg=isort ; extra == "dev"', ] assert result == expected