mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 06:46:15 +00:00
Merge branch 'main' into pip-22.3
This commit is contained in:
@@ -47,7 +47,12 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
python-version: 3.x
|
||||
- name: Collect Workflow Telemetry
|
||||
uses: runforesight/foresight-workflow-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
- run: |
|
||||
python -m pip install pre-commit
|
||||
pre-commit run --all-files --verbose --show-diff-on-failure
|
||||
@@ -59,7 +64,13 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
python-version: 3.x
|
||||
- name: Collect Workflow Telemetry
|
||||
uses: runforesight/foresight-workflow-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
- run: |
|
||||
python -m pip install --upgrade wheel invoke parver bs4 vistir towncrier requests
|
||||
python -m invoke vendoring.update
|
||||
@@ -81,6 +92,12 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Collect Workflow Telemetry
|
||||
uses: runforesight/foresight-workflow-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
|
||||
- name: Get python path
|
||||
id: python-path
|
||||
run: |
|
||||
@@ -122,7 +139,15 @@ jobs:
|
||||
PYTHONIOENCODING: "utf-8"
|
||||
GIT_SSH_COMMAND: ssh -o StrictHostKeyChecking=accept-new -o CheckHostIP=no
|
||||
run: |
|
||||
pipenv run pytest -ra -n auto -v --fulltrace tests
|
||||
pipenv run pytest --junitxml=./reports/results.xml -ra -n auto -v --fulltrace tests
|
||||
- name: Analyze Test and/or Coverage Results
|
||||
uses: runforesight/foresight-test-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
test_format: JUNIT
|
||||
test_framework: PYTEST
|
||||
test_path: ./reports/**
|
||||
|
||||
build:
|
||||
name: Build Package
|
||||
@@ -133,6 +158,11 @@ jobs:
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Collect Workflow Telemetry
|
||||
uses: runforesight/foresight-workflow-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
- run: pip install -U build twine
|
||||
- run: |
|
||||
python -m build
|
||||
|
||||
@@ -21,6 +21,12 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Collect Workflow Telemetry
|
||||
uses: runforesight/foresight-workflow-kit-action@v1
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
api_key: ${{ secrets.FORESIGHT_API_KEY }}
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2020 Python Packaging Authority
|
||||
Copyright 2020-2022 Python Packaging Authority
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -5,6 +5,7 @@ Pipenv: Python Development Workflow for Humans
|
||||
[](https://python.org/pypi/pipenv)
|
||||
[](https://github.com/pypa/pipenv/actions/workflows/ci.yaml)
|
||||
[](https://python.org/pypi/pipenv)
|
||||
[](https://pypa.app.runforesight.com)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
@@ -36,6 +37,53 @@ You can quickly play with Pipenv right in your browser:
|
||||
|
||||
[](https://rootnroll.com/d/pipenv/)
|
||||
|
||||
Table Of Contents
|
||||
------------------
|
||||
|
||||
- [Pipenv](#pipenv-python-development-workflow-for-humans)
|
||||
|
||||
- [Installation](#installation)
|
||||
|
||||
- [User Testimonals](#☤-user-testimonials)
|
||||
|
||||
- [Features](#☤-features)
|
||||
|
||||
- [Basic Concepts](#basic-concepts)
|
||||
|
||||
- [Other Commands](#other-commands)
|
||||
|
||||
- [Shell Completion](#shell-completion)
|
||||
|
||||
- [Usage](#☤-usage)
|
||||
|
||||
- [Usage Examples](#usage-examples)
|
||||
|
||||
- [Commands](#commands)
|
||||
|
||||
- [Locate the Project](#locate-the-project)
|
||||
|
||||
- [Locate the virtualenv](#locate-the-virtualenv)
|
||||
|
||||
- [Locate the Python Interpreter](#locate-the-python-interpreter)
|
||||
|
||||
- [Install Packages](#install-packages)
|
||||
|
||||
- [Installing from git](#installing-from-git)
|
||||
|
||||
- [Install a dev dependency](#install-a-dev-dependency)
|
||||
|
||||
- [Show a dependency graph](#show-a-dependency-graph)
|
||||
|
||||
- [Generate a lockfile](#generate-a-lockfile)
|
||||
|
||||
- [Install all dev dependencies](#install-all-dev-dependencies)
|
||||
|
||||
- [Uninstall everything](#uninstall-everything)
|
||||
|
||||
- [Use the shell](#use-the-shell)
|
||||
|
||||
- [Documentation](#☤-documentation)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
@@ -178,7 +226,7 @@ Magic shell completions are now enabled!
|
||||
-h, --help Show this message and exit.
|
||||
|
||||
|
||||
Usage Examples:
|
||||
### Usage Examples:
|
||||
|
||||
Create a new project using Python 3.7, specifically:
|
||||
$ pipenv --python 3.7
|
||||
@@ -204,7 +252,7 @@ Magic shell completions are now enabled!
|
||||
Use a lower-level pip command:
|
||||
$ pipenv run pip freeze
|
||||
|
||||
Commands:
|
||||
### Commands:
|
||||
|
||||
check Checks for PyUp Safety security vulnerabilities and against
|
||||
PEP 508 markers provided in Pipfile.
|
||||
@@ -224,22 +272,22 @@ Magic shell completions are now enabled!
|
||||
verify Verify the hash in Pipfile.lock is up-to-date.
|
||||
|
||||
|
||||
Locate the project:
|
||||
### Locate the project:
|
||||
|
||||
$ pipenv --where
|
||||
/Users/kennethreitz/Library/Mobile Documents/com~apple~CloudDocs/repos/kr/pipenv/test
|
||||
|
||||
Locate the virtualenv:
|
||||
### Locate the virtualenv:
|
||||
|
||||
$ pipenv --venv
|
||||
/Users/kennethreitz/.local/share/virtualenvs/test-Skyy4vre
|
||||
|
||||
Locate the Python interpreter:
|
||||
### Locate the Python interpreter:
|
||||
|
||||
$ pipenv --py
|
||||
/Users/kennethreitz/.local/share/virtualenvs/test-Skyy4vre/bin/python
|
||||
|
||||
Install packages:
|
||||
### Install packages:
|
||||
|
||||
$ pipenv install
|
||||
Creating a virtualenv for this project...
|
||||
@@ -252,7 +300,7 @@ Install packages:
|
||||
To activate this project's virtualenv, run the following:
|
||||
$ pipenv shell
|
||||
|
||||
Installing from git:
|
||||
### Installing from git:
|
||||
|
||||
You can install packages with pipenv from git and other version control systems using URLs formatted according to the following rule:
|
||||
|
||||
@@ -275,14 +323,14 @@ Below is an example usage which installs the git repository located at `https://
|
||||
|
||||
You can read more about [pip's implementation of vcs support here](https://pip.pypa.io/en/stable/topics/vcs-support/).
|
||||
|
||||
Install a dev dependency:
|
||||
### Install a dev dependency:
|
||||
|
||||
$ pipenv install pytest --dev
|
||||
Installing pytest...
|
||||
...
|
||||
Adding pytest to Pipfile's [dev-packages]...
|
||||
|
||||
Show a dependency graph:
|
||||
### Show a dependency graph:
|
||||
|
||||
$ pipenv graph
|
||||
requests==2.18.4
|
||||
@@ -291,7 +339,7 @@ Show a dependency graph:
|
||||
- idna [required: >=2.5,<2.7, installed: 2.6]
|
||||
- urllib3 [required: <1.23,>=1.21.1, installed: 1.22]
|
||||
|
||||
Generate a lockfile:
|
||||
### Generate a lockfile:
|
||||
|
||||
$ pipenv lock
|
||||
Assuring all dependencies from Pipfile are installed...
|
||||
@@ -300,7 +348,7 @@ Generate a lockfile:
|
||||
Note: your project now has only default [packages] installed.
|
||||
To install [dev-packages], run: $ pipenv install --dev
|
||||
|
||||
Install all dev dependencies:
|
||||
### Install all dev dependencies:
|
||||
|
||||
$ pipenv install --dev
|
||||
Pipfile found at /Users/kennethreitz/repos/kr/pip2/test/Pipfile. Considering this to be the project home.
|
||||
@@ -309,7 +357,7 @@ Install all dev dependencies:
|
||||
Locking [dev-packages] dependencies...
|
||||
Locking [packages] dependencies...
|
||||
|
||||
Uninstall everything:
|
||||
### Uninstall everything:
|
||||
|
||||
$ pipenv uninstall --all
|
||||
No package provided, un-installing all dependencies.
|
||||
@@ -317,7 +365,7 @@ Uninstall everything:
|
||||
...
|
||||
Environment now purged and fresh!
|
||||
|
||||
Use the shell:
|
||||
### Use the shell:
|
||||
|
||||
$ pipenv shell
|
||||
Loading .env environment variables...
|
||||
|
||||
@@ -363,6 +363,27 @@ used to write them to a file::
|
||||
pytest==3.2.3
|
||||
setuptools==65.4.1 ; python_version >= '3.7'
|
||||
|
||||
If you have multiple categories in your Pipfile and wish to generate
|
||||
a requirements file for only some categories, you can do that too,
|
||||
using the ``--categories`` option::
|
||||
|
||||
$ pipenv requirements --categories="tests" > requirements-tests.txt
|
||||
$ pipenv requirements --categories="docs" > requirements-docs.txt
|
||||
$ cat requirements-tests.txt
|
||||
-i https://pypi.org/simple
|
||||
attrs==22.1.0 ; python_version >= '3.5'
|
||||
iniconfig==1.1.1
|
||||
packaging==21.3 ; python_version >= '3.6'
|
||||
pluggy==1.0.0 ; python_version >= '3.6'
|
||||
py==1.11.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||
pyparsing==3.0.9 ; python_full_version >= '3.6.8'
|
||||
pytest==7.1.3
|
||||
tomli==2.0.1 ; python_version >= '3.7'
|
||||
|
||||
It can be used to specify multiple categories also.
|
||||
|
||||
$ pipenv requirements --categories="tests,docs"
|
||||
|
||||
☤ Detection of Security Vulnerabilities
|
||||
---------------------------------------
|
||||
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ latex_documents = [
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [(master_doc, "pipenv", "pipenv Documentation", [author], 1)]
|
||||
man_pages = [("quickstart", "pipenv", "", [author], 1)]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
@@ -131,7 +131,7 @@ Tests are written in ``pytest`` style and can be run very simply:
|
||||
pytest
|
||||
|
||||
However many tests depend on running a private pypi server on localhost:8080.
|
||||
This can be accomplished by using either the ``run-tests.sh`` or ``run-tests.bat`
|
||||
This can be accomplished by using either the ``run-tests.sh`` or ``run-tests.bat``
|
||||
which will start the ``pypiserver`` process ahead of invoking pytest.
|
||||
|
||||
You may also manually perform this step and then invoke pytest as you would normally. Example::
|
||||
|
||||
+3
-23
@@ -65,10 +65,6 @@ More detailed installation instructions can be found in the :ref:`installing-pip
|
||||
✨🍰✨
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
install
|
||||
changelog
|
||||
|
||||
User Testimonials
|
||||
-----------------
|
||||
@@ -91,26 +87,8 @@ User Testimonials
|
||||
- Automatically adds/removes packages to a ``Pipfile`` when they are installed or uninstalled.
|
||||
- Automatically loads ``.env`` files, if they exist.
|
||||
|
||||
The main commands are ``install``, ``uninstall``, and ``lock``, which generates a ``Pipfile.lock``. These are intended to replace ``$ pip install`` usage, as well as manual virtualenv management (to activate a virtualenv, run ``$ pipenv shell``).
|
||||
|
||||
Basic Concepts
|
||||
//////////////
|
||||
|
||||
- A virtualenv will automatically be created, when one doesn't exist.
|
||||
- When no parameters are passed to ``install``, all packages ``[packages]`` specified will be installed.
|
||||
- To initialize a Python 3 virtual environment, run ``$ pipenv --three``.
|
||||
- Otherwise, whatever virtualenv defaults to will be the default.
|
||||
|
||||
|
||||
|
||||
Other Commands
|
||||
//////////////
|
||||
|
||||
- ``graph`` will show you a dependency graph of your installed dependencies.
|
||||
- ``shell`` will spawn a shell with the virtualenv activated. This shell can be deactivated by using ``exit``.
|
||||
- ``run`` will run a given command from the virtualenv, with any arguments forwarded (e.g. ``$ pipenv run python`` or ``$ pipenv run pip freeze``).
|
||||
- ``check`` checks for security vulnerabilities and asserts that `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_ requirements are being met by the current environment.
|
||||
|
||||
.. include:: quickstart.rst
|
||||
|
||||
Further Documentation Guides
|
||||
----------------------------
|
||||
@@ -118,10 +96,12 @@ Further Documentation Guides
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
install
|
||||
basics
|
||||
advanced
|
||||
cli
|
||||
diagnose
|
||||
changelog
|
||||
|
||||
Contribution Guides
|
||||
-------------------
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
Basic Commands and Concepts
|
||||
///////////////////////////
|
||||
|
||||
Pipenv uses a set of commands to manage your Project's dependencies and custom scripts.
|
||||
It replaces the use of ``Makefile``, direct calls to ``pip`` and ``python -m venv`` or ``virtualenv``.
|
||||
to create virtual environments and install packages in them.
|
||||
Pipenv uses two files to do this: ``Pipfile`` and ``Pipfile.lock`` (which will look familiar if you
|
||||
are used to packages manager like ``yarn`` or ``npm``).
|
||||
|
||||
The main commands are:
|
||||
|
||||
- ``install`` -
|
||||
|
||||
Will create a virtual env and install dependencies (if it does not exist already)
|
||||
The dependencies will be installed inside.
|
||||
|
||||
- ``install package==0.2`` -
|
||||
|
||||
Will add the package in version 0.2 to the virtual environment and
|
||||
to ``Pipfile`` and ``Pipfile.lock``
|
||||
|
||||
- ``uninstall`` - Will remove the dependency
|
||||
|
||||
- ``lock`` - Regenarate ``Pipfile.lock`` and updates the dependencies inside it.
|
||||
|
||||
These are intended to replace ``$ pip install`` usage, as well as manual virtualenv management.
|
||||
|
||||
Other Commands
|
||||
//////////////
|
||||
|
||||
- ``graph`` will show you a dependency graph of your installed dependencies.
|
||||
- ``shell`` will spawn a shell with the virtualenv activated. This shell can be deactivated by using ``exit``.
|
||||
- ``run`` will run a given command from the virtualenv, with any arguments forwarded (e.g. ``$ pipenv run python`` or ``$ pipenv run pip freeze``).
|
||||
- ``check`` checks for security vulnerabilities and asserts that `PEP 508 <https://www.python.org/dev/peps/pep-0508/>`_ requirements are being met by the current environment.
|
||||
@@ -0,0 +1 @@
|
||||
Remove usage of vistir.cmdparse in favor of pipenv.cmdparse
|
||||
@@ -0,0 +1 @@
|
||||
Remove appdirs.py in favor of platformdirs.
|
||||
@@ -0,0 +1 @@
|
||||
Add support to export requirements file for a specified set of categories.
|
||||
+19
-5
@@ -740,8 +740,16 @@ def verify(state):
|
||||
)
|
||||
@option("--hash", is_flag=True, default=False, help="Add package hashes.")
|
||||
@option("--exclude-markers", is_flag=True, default=False, help="Exclude markers.")
|
||||
@option(
|
||||
"--categories",
|
||||
is_flag=False,
|
||||
default="",
|
||||
help="Only add requirement of the specified categories.",
|
||||
)
|
||||
@pass_state
|
||||
def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=False):
|
||||
def requirements(
|
||||
state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories=""
|
||||
):
|
||||
|
||||
from pipenv.utils.dependencies import convert_deps_to_pip
|
||||
|
||||
@@ -752,11 +760,17 @@ def requirements(state, dev=False, dev_only=False, hash=False, exclude_markers=F
|
||||
echo(" ".join([prefix, package_index["url"]]))
|
||||
|
||||
deps = {}
|
||||
categories_list = categories.split(",") if categories else []
|
||||
|
||||
if dev or dev_only:
|
||||
deps.update(lockfile["develop"])
|
||||
if not dev_only:
|
||||
deps.update(lockfile["default"])
|
||||
if categories_list:
|
||||
for category in categories_list:
|
||||
category = category.strip()
|
||||
deps.update(lockfile.get(category, {}))
|
||||
else:
|
||||
if dev or dev_only:
|
||||
deps.update(lockfile["develop"])
|
||||
if not dev_only:
|
||||
deps.update(lockfile["default"])
|
||||
|
||||
pip_deps = convert_deps_to_pip(
|
||||
deps,
|
||||
|
||||
+8
-14
@@ -13,6 +13,7 @@ from pathlib import Path
|
||||
from sysconfig import get_paths, get_python_version, get_scheme_names
|
||||
|
||||
import pipenv
|
||||
from pipenv import cmdparse
|
||||
from pipenv.patched.pip._internal.commands.install import InstallCommand
|
||||
from pipenv.patched.pip._internal.index.package_finder import PackageFinder
|
||||
from pipenv.patched.pip._internal.req.req_uninstall import UninstallPathSet
|
||||
@@ -311,19 +312,12 @@ class Environment:
|
||||
return sys.path
|
||||
elif any([sys.prefix == self.prefix, not self.is_venv]):
|
||||
return sys.path
|
||||
cmd_args = [self.python, "-c", "import json, sys; print(json.dumps(sys.path))"]
|
||||
path, _ = vistir.misc.run(
|
||||
cmd_args,
|
||||
return_object=False,
|
||||
nospin=True,
|
||||
block=True,
|
||||
combine_stderr=False,
|
||||
write_to_stdout=False,
|
||||
)
|
||||
|
||||
try:
|
||||
path = json.loads(path.strip())
|
||||
except json.JSONDecodeError:
|
||||
path = pipenv.utils.shell.load_path(self.python)
|
||||
except json.decoder.JSONDecodeError:
|
||||
path = sys.path
|
||||
|
||||
return path
|
||||
|
||||
def build_command(
|
||||
@@ -815,7 +809,7 @@ class Environment:
|
||||
|
||||
c = None
|
||||
with self.activated():
|
||||
script = vistir.cmdparse.Script.parse(cmd)
|
||||
script = cmdparse.Script.parse(cmd)
|
||||
c = vistir.misc.run(
|
||||
script._parts,
|
||||
return_object=True,
|
||||
@@ -837,9 +831,9 @@ class Environment:
|
||||
|
||||
c = None
|
||||
if isinstance(cmd, str):
|
||||
script = vistir.cmdparse.Script.parse(f"{self.python} -c {cmd}")
|
||||
script = cmdparse.Script.parse(f"{self.python} -c {cmd}")
|
||||
else:
|
||||
script = vistir.cmdparse.Script.parse([self.python, "-c"] + list(cmd))
|
||||
script = cmdparse.Script.parse([self.python, "-c"] + list(cmd))
|
||||
with self.activated():
|
||||
c = vistir.misc.run(
|
||||
script._parts,
|
||||
|
||||
@@ -4,10 +4,10 @@ import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
from appdirs import user_cache_dir
|
||||
from vistir.path import normalize_drive
|
||||
|
||||
from pipenv._compat import fix_utf8
|
||||
from pipenv.patched.pip._vendor.platformdirs import user_cache_dir
|
||||
from pipenv.utils.constants import FALSE_VALUES, TRUE_VALUES
|
||||
from pipenv.utils.shell import env_to_bool
|
||||
from pipenv.vendor.vistir.misc import _isatty
|
||||
|
||||
+16
-5439
File diff suppressed because it is too large
Load Diff
+2
-3
@@ -50,7 +50,6 @@ except ImportError:
|
||||
# eventually distlib will remove cached property when they drop Python3.7
|
||||
from pipenv.patched.pip._vendor.distlib.util import cached_property
|
||||
|
||||
|
||||
if is_type_checking():
|
||||
from typing import Dict, List, Optional, Set, Text, Tuple, Union
|
||||
|
||||
@@ -421,7 +420,7 @@ class Project:
|
||||
loc = os.sep.join([self.virtualenv_location, "src"])
|
||||
else:
|
||||
loc = os.sep.join([self.project_directory, "src"])
|
||||
vistir.path.mkdir_p(loc)
|
||||
os.makedirs(loc, exist_ok=True)
|
||||
return loc
|
||||
|
||||
@property
|
||||
@@ -430,7 +429,7 @@ class Project:
|
||||
loc = os.sep.join([self.virtualenv_location, "downloads"])
|
||||
self._download_location = loc
|
||||
# Create the directory, if it doesn't exist.
|
||||
vistir.path.mkdir_p(self._download_location)
|
||||
os.makedirs(self._download_location, exist_ok=True)
|
||||
return self._download_location
|
||||
|
||||
@property
|
||||
|
||||
+3
-3
@@ -819,11 +819,11 @@ def main(argv=None):
|
||||
_ensure_modules()
|
||||
import warnings
|
||||
|
||||
from pipenv.vendor.vistir.misc import replace_with_text_stream
|
||||
from pipenv.vendor.click.utils import get_text_stream
|
||||
|
||||
warnings.simplefilter("ignore", category=ResourceWarning)
|
||||
replace_with_text_stream("stdout")
|
||||
replace_with_text_stream("stderr")
|
||||
sys.stdout = get_text_stream("stdout")
|
||||
sys.stderr = get_text_stream("stderr")
|
||||
os.environ["PIP_DISABLE_PIP_VERSION_CHECK"] = "1"
|
||||
os.environ["PYTHONIOENCODING"] = "utf-8"
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
|
||||
+2
-36
@@ -73,8 +73,7 @@ def load_path(python):
|
||||
from pathlib import Path
|
||||
|
||||
python = Path(python).as_posix()
|
||||
json_dump_commmand = '"import json, sys; print(json.dumps(sys.path));"'
|
||||
c = subprocess_run([python, "-c", json_dump_commmand])
|
||||
c = subprocess_run([python, "-c", "import json, sys; print(json.dumps(sys.path))"])
|
||||
if c.returncode == 0:
|
||||
return json.loads(c.stdout.strip())
|
||||
else:
|
||||
@@ -200,7 +199,7 @@ def get_workon_home():
|
||||
)
|
||||
# Create directory if it does not already exist
|
||||
expanded_path = Path(os.path.expandvars(workon_home)).expanduser()
|
||||
mkdir_p(str(expanded_path))
|
||||
os.makedirs(expanded_path, exist_ok=True)
|
||||
return expanded_path
|
||||
|
||||
|
||||
@@ -239,39 +238,6 @@ def is_virtual_environment(path):
|
||||
return False
|
||||
|
||||
|
||||
def mkdir_p(newdir):
|
||||
"""works the way a good mkdir should :)
|
||||
- already exists, silently complete
|
||||
- regular file in the way, raise an exception
|
||||
- parent directory(ies) does not exist, make them as well
|
||||
From: http://code.activestate.com/recipes/82465-a-friendly-mkdir/
|
||||
"""
|
||||
if os.path.isdir(newdir):
|
||||
pass
|
||||
elif os.path.isfile(newdir):
|
||||
raise OSError(
|
||||
"a file with the same name as the desired dir, '{}', already exists.".format(
|
||||
newdir
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
head, tail = os.path.split(newdir)
|
||||
if head and not os.path.isdir(head):
|
||||
mkdir_p(head)
|
||||
if tail:
|
||||
# Even though we've checked that the directory doesn't exist above, it might exist
|
||||
# now if some other process has created it between now and the time we checked it.
|
||||
try:
|
||||
os.mkdir(newdir)
|
||||
except OSError as exn:
|
||||
# If we failed because the directory does exist, that's not a problem -
|
||||
# that's what we were trying to do anyway. Only re-raise the exception
|
||||
# if we failed for some other reason.
|
||||
if exn.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
|
||||
def find_python(finder, line=None):
|
||||
"""
|
||||
Given a `pythonfinder.Finder` instance and an optional line, find a corresponding python
|
||||
|
||||
Vendored
-23
@@ -1,23 +0,0 @@
|
||||
# This is the MIT license
|
||||
|
||||
Copyright (c) 2010 ActiveState Software Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Vendored
-608
@@ -1,608 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2005-2010 ActiveState Software Inc.
|
||||
# Copyright (c) 2013 Eddy Petrișor
|
||||
|
||||
"""Utilities for determining application-specific dirs.
|
||||
|
||||
See <http://github.com/ActiveState/appdirs> for details and usage.
|
||||
"""
|
||||
# Dev Notes:
|
||||
# - MSDN on where to store app data files:
|
||||
# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120
|
||||
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
|
||||
# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
|
||||
__version__ = "1.4.4"
|
||||
__version_info__ = tuple(int(segment) for segment in __version__.split("."))
|
||||
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
if PY3:
|
||||
unicode = str
|
||||
|
||||
if sys.platform.startswith('java'):
|
||||
import platform
|
||||
os_name = platform.java_ver()[3][0]
|
||||
if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc.
|
||||
system = 'win32'
|
||||
elif os_name.startswith('Mac'): # "Mac OS X", etc.
|
||||
system = 'darwin'
|
||||
else: # "Linux", "SunOS", "FreeBSD", etc.
|
||||
# Setting this to "linux2" is not ideal, but only Windows or Mac
|
||||
# are actually checked for and the rest of the module expects
|
||||
# *sys.platform* style strings.
|
||||
system = 'linux2'
|
||||
else:
|
||||
system = sys.platform
|
||||
|
||||
|
||||
|
||||
def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user data directories are:
|
||||
Mac OS X: ~/Library/Application Support/<AppName>
|
||||
Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined
|
||||
Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName>
|
||||
Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>
|
||||
Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>
|
||||
Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName>
|
||||
|
||||
For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
|
||||
That means, by default "~/.local/share/<AppName>".
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
|
||||
path = os.path.normpath(_get_win_folder(const))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('~/Library/Application Support/')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||
r"""Return full path to the user-shared data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"multipath" is an optional parameter only applicable to *nix
|
||||
which indicates that the entire list of data dirs should be
|
||||
returned. By default, the first item from XDG_DATA_DIRS is
|
||||
returned, or '/usr/local/share/<AppName>',
|
||||
if XDG_DATA_DIRS is not set
|
||||
|
||||
Typical site data directories are:
|
||||
Mac OS X: /Library/Application Support/<AppName>
|
||||
Unix: /usr/local/share/<AppName> or /usr/share/<AppName>
|
||||
Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName>
|
||||
Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
|
||||
Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7.
|
||||
|
||||
For Unix, this is using the $XDG_DATA_DIRS[0] default.
|
||||
|
||||
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('/Library/Application Support')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
# XDG default for $XDG_DATA_DIRS
|
||||
# only first, if multipath is False
|
||||
path = os.getenv('XDG_DATA_DIRS',
|
||||
os.pathsep.join(['/usr/local/share', '/usr/share']))
|
||||
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
||||
if appname:
|
||||
if version:
|
||||
appname = os.path.join(appname, version)
|
||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||
|
||||
if multipath:
|
||||
path = os.pathsep.join(pathlist)
|
||||
else:
|
||||
path = pathlist[0]
|
||||
return path
|
||||
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific config dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user config directories are:
|
||||
Mac OS X: same as user_data_dir
|
||||
Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined
|
||||
Win *: same as user_data_dir
|
||||
|
||||
For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
|
||||
That means, by default "~/.config/<AppName>".
|
||||
"""
|
||||
if system in ["win32", "darwin"]:
|
||||
path = user_data_dir(appname, appauthor, None, roaming)
|
||||
else:
|
||||
path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
|
||||
r"""Return full path to the user-shared data dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"multipath" is an optional parameter only applicable to *nix
|
||||
which indicates that the entire list of config dirs should be
|
||||
returned. By default, the first item from XDG_CONFIG_DIRS is
|
||||
returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set
|
||||
|
||||
Typical site config directories are:
|
||||
Mac OS X: same as site_data_dir
|
||||
Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in
|
||||
$XDG_CONFIG_DIRS
|
||||
Win *: same as site_data_dir
|
||||
Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.)
|
||||
|
||||
For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False
|
||||
|
||||
WARNING: Do not use this on Windows. See the Vista-Fail note above for why.
|
||||
"""
|
||||
if system in ["win32", "darwin"]:
|
||||
path = site_data_dir(appname, appauthor)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
else:
|
||||
# XDG default for $XDG_CONFIG_DIRS
|
||||
# only first, if multipath is False
|
||||
path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
|
||||
pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
|
||||
if appname:
|
||||
if version:
|
||||
appname = os.path.join(appname, version)
|
||||
pathlist = [os.sep.join([x, appname]) for x in pathlist]
|
||||
|
||||
if multipath:
|
||||
path = os.pathsep.join(pathlist)
|
||||
else:
|
||||
path = pathlist[0]
|
||||
return path
|
||||
|
||||
|
||||
def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||
r"""Return full path to the user-specific cache dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"opinion" (boolean) can be False to disable the appending of
|
||||
"Cache" to the base app data dir for Windows. See
|
||||
discussion below.
|
||||
|
||||
Typical user cache directories are:
|
||||
Mac OS X: ~/Library/Caches/<AppName>
|
||||
Unix: ~/.cache/<AppName> (XDG default)
|
||||
Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache
|
||||
Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache
|
||||
|
||||
On Windows the only suggestion in the MSDN docs is that local settings go in
|
||||
the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming
|
||||
app data dir (the default returned by `user_data_dir` above). Apps typically
|
||||
put cache data somewhere *under* the given dir here. Some examples:
|
||||
...\Mozilla\Firefox\Profiles\<ProfileName>\Cache
|
||||
...\Acme\SuperApp\Cache\1.0
|
||||
OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
|
||||
This can be disabled with the `opinion=False` option.
|
||||
"""
|
||||
if system == "win32":
|
||||
if appauthor is None:
|
||||
appauthor = appname
|
||||
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
|
||||
if appname:
|
||||
if appauthor is not False:
|
||||
path = os.path.join(path, appauthor, appname)
|
||||
else:
|
||||
path = os.path.join(path, appname)
|
||||
if opinion:
|
||||
path = os.path.join(path, "Cache")
|
||||
elif system == 'darwin':
|
||||
path = os.path.expanduser('~/Library/Caches')
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
else:
|
||||
path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_state_dir(appname=None, appauthor=None, version=None, roaming=False):
|
||||
r"""Return full path to the user-specific state dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"roaming" (boolean, default False) can be set True to use the Windows
|
||||
roaming appdata directory. That means that for users on a Windows
|
||||
network setup for roaming profiles, this user data will be
|
||||
sync'd on login. See
|
||||
<http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx>
|
||||
for a discussion of issues.
|
||||
|
||||
Typical user state directories are:
|
||||
Mac OS X: same as user_data_dir
|
||||
Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined
|
||||
Win *: same as user_data_dir
|
||||
|
||||
For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state>
|
||||
to extend the XDG spec and support $XDG_STATE_HOME.
|
||||
|
||||
That means, by default "~/.local/state/<AppName>".
|
||||
"""
|
||||
if system in ["win32", "darwin"]:
|
||||
path = user_data_dir(appname, appauthor, None, roaming)
|
||||
else:
|
||||
path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state"))
|
||||
if appname:
|
||||
path = os.path.join(path, appname)
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
def user_log_dir(appname=None, appauthor=None, version=None, opinion=True):
|
||||
r"""Return full path to the user-specific log dir for this application.
|
||||
|
||||
"appname" is the name of application.
|
||||
If None, just the system directory is returned.
|
||||
"appauthor" (only used on Windows) is the name of the
|
||||
appauthor or distributing body for this application. Typically
|
||||
it is the owning company name. This falls back to appname. You may
|
||||
pass False to disable it.
|
||||
"version" is an optional version path element to append to the
|
||||
path. You might want to use this if you want multiple versions
|
||||
of your app to be able to run independently. If used, this
|
||||
would typically be "<major>.<minor>".
|
||||
Only applied when appname is present.
|
||||
"opinion" (boolean) can be False to disable the appending of
|
||||
"Logs" to the base app data dir for Windows, and "log" to the
|
||||
base cache dir for Unix. See discussion below.
|
||||
|
||||
Typical user log directories are:
|
||||
Mac OS X: ~/Library/Logs/<AppName>
|
||||
Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined
|
||||
Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs
|
||||
Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs
|
||||
|
||||
On Windows the only suggestion in the MSDN docs is that local settings
|
||||
go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in
|
||||
examples of what some windows apps use for a logs dir.)
|
||||
|
||||
OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA`
|
||||
value for Windows and appends "log" to the user cache dir for Unix.
|
||||
This can be disabled with the `opinion=False` option.
|
||||
"""
|
||||
if system == "darwin":
|
||||
path = os.path.join(
|
||||
os.path.expanduser('~/Library/Logs'),
|
||||
appname)
|
||||
elif system == "win32":
|
||||
path = user_data_dir(appname, appauthor, version)
|
||||
version = False
|
||||
if opinion:
|
||||
path = os.path.join(path, "Logs")
|
||||
else:
|
||||
path = user_cache_dir(appname, appauthor, version)
|
||||
version = False
|
||||
if opinion:
|
||||
path = os.path.join(path, "log")
|
||||
if appname and version:
|
||||
path = os.path.join(path, version)
|
||||
return path
|
||||
|
||||
|
||||
class AppDirs(object):
|
||||
"""Convenience wrapper for getting application dirs."""
|
||||
def __init__(self, appname=None, appauthor=None, version=None,
|
||||
roaming=False, multipath=False):
|
||||
self.appname = appname
|
||||
self.appauthor = appauthor
|
||||
self.version = version
|
||||
self.roaming = roaming
|
||||
self.multipath = multipath
|
||||
|
||||
@property
|
||||
def user_data_dir(self):
|
||||
return user_data_dir(self.appname, self.appauthor,
|
||||
version=self.version, roaming=self.roaming)
|
||||
|
||||
@property
|
||||
def site_data_dir(self):
|
||||
return site_data_dir(self.appname, self.appauthor,
|
||||
version=self.version, multipath=self.multipath)
|
||||
|
||||
@property
|
||||
def user_config_dir(self):
|
||||
return user_config_dir(self.appname, self.appauthor,
|
||||
version=self.version, roaming=self.roaming)
|
||||
|
||||
@property
|
||||
def site_config_dir(self):
|
||||
return site_config_dir(self.appname, self.appauthor,
|
||||
version=self.version, multipath=self.multipath)
|
||||
|
||||
@property
|
||||
def user_cache_dir(self):
|
||||
return user_cache_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
@property
|
||||
def user_state_dir(self):
|
||||
return user_state_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
@property
|
||||
def user_log_dir(self):
|
||||
return user_log_dir(self.appname, self.appauthor,
|
||||
version=self.version)
|
||||
|
||||
|
||||
#---- internal support stuff
|
||||
|
||||
def _get_win_folder_from_registry(csidl_name):
|
||||
"""This is a fallback technique at best. I'm not sure if using the
|
||||
registry for this guarantees us the correct answer for all CSIDL_*
|
||||
names.
|
||||
"""
|
||||
if PY3:
|
||||
import winreg as _winreg
|
||||
else:
|
||||
import _winreg
|
||||
|
||||
shell_folder_name = {
|
||||
"CSIDL_APPDATA": "AppData",
|
||||
"CSIDL_COMMON_APPDATA": "Common AppData",
|
||||
"CSIDL_LOCAL_APPDATA": "Local AppData",
|
||||
}[csidl_name]
|
||||
|
||||
key = _winreg.OpenKey(
|
||||
_winreg.HKEY_CURRENT_USER,
|
||||
r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
|
||||
)
|
||||
dir, type = _winreg.QueryValueEx(key, shell_folder_name)
|
||||
return dir
|
||||
|
||||
|
||||
def _get_win_folder_with_pywin32(csidl_name):
|
||||
from win32com.shell import shellcon, shell
|
||||
dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0)
|
||||
# Try to make this a unicode path because SHGetFolderPath does
|
||||
# not return unicode strings when there is unicode data in the
|
||||
# path.
|
||||
try:
|
||||
dir = unicode(dir)
|
||||
|
||||
# Downgrade to short path name if have highbit chars. See
|
||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
||||
has_high_char = False
|
||||
for c in dir:
|
||||
if ord(c) > 255:
|
||||
has_high_char = True
|
||||
break
|
||||
if has_high_char:
|
||||
try:
|
||||
import win32api
|
||||
dir = win32api.GetShortPathName(dir)
|
||||
except ImportError:
|
||||
pass
|
||||
except UnicodeError:
|
||||
pass
|
||||
return dir
|
||||
|
||||
|
||||
def _get_win_folder_with_ctypes(csidl_name):
|
||||
import ctypes
|
||||
|
||||
csidl_const = {
|
||||
"CSIDL_APPDATA": 26,
|
||||
"CSIDL_COMMON_APPDATA": 35,
|
||||
"CSIDL_LOCAL_APPDATA": 28,
|
||||
}[csidl_name]
|
||||
|
||||
buf = ctypes.create_unicode_buffer(1024)
|
||||
ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
|
||||
|
||||
# Downgrade to short path name if have highbit chars. See
|
||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
||||
has_high_char = False
|
||||
for c in buf:
|
||||
if ord(c) > 255:
|
||||
has_high_char = True
|
||||
break
|
||||
if has_high_char:
|
||||
buf2 = ctypes.create_unicode_buffer(1024)
|
||||
if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
|
||||
buf = buf2
|
||||
|
||||
return buf.value
|
||||
|
||||
def _get_win_folder_with_jna(csidl_name):
|
||||
import array
|
||||
from com.sun import jna
|
||||
from com.sun.jna.platform import win32
|
||||
|
||||
buf_size = win32.WinDef.MAX_PATH * 2
|
||||
buf = array.zeros('c', buf_size)
|
||||
shell = win32.Shell32.INSTANCE
|
||||
shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf)
|
||||
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
||||
|
||||
# Downgrade to short path name if have highbit chars. See
|
||||
# <http://bugs.activestate.com/show_bug.cgi?id=85099>.
|
||||
has_high_char = False
|
||||
for c in dir:
|
||||
if ord(c) > 255:
|
||||
has_high_char = True
|
||||
break
|
||||
if has_high_char:
|
||||
buf = array.zeros('c', buf_size)
|
||||
kernel = win32.Kernel32.INSTANCE
|
||||
if kernel.GetShortPathName(dir, buf, buf_size):
|
||||
dir = jna.Native.toString(buf.tostring()).rstrip("\0")
|
||||
|
||||
return dir
|
||||
|
||||
if system == "win32":
|
||||
try:
|
||||
import win32com.shell
|
||||
_get_win_folder = _get_win_folder_with_pywin32
|
||||
except ImportError:
|
||||
try:
|
||||
from ctypes import windll
|
||||
_get_win_folder = _get_win_folder_with_ctypes
|
||||
except ImportError:
|
||||
try:
|
||||
import com.sun.jna
|
||||
_get_win_folder = _get_win_folder_with_jna
|
||||
except ImportError:
|
||||
_get_win_folder = _get_win_folder_from_registry
|
||||
|
||||
|
||||
#---- self test code
|
||||
|
||||
if __name__ == "__main__":
|
||||
appname = "MyApp"
|
||||
appauthor = "MyCompany"
|
||||
|
||||
props = ("user_data_dir",
|
||||
"user_config_dir",
|
||||
"user_cache_dir",
|
||||
"user_state_dir",
|
||||
"user_log_dir",
|
||||
"site_data_dir",
|
||||
"site_config_dir")
|
||||
|
||||
print("-- app dirs %s --" % __version__)
|
||||
|
||||
print("-- app dirs (with optional 'version')")
|
||||
dirs = AppDirs(appname, appauthor, version="1.0")
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (without optional 'version')")
|
||||
dirs = AppDirs(appname, appauthor)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (without optional 'appauthor')")
|
||||
dirs = AppDirs(appname)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
|
||||
print("\n-- app dirs (with disabled 'appauthor')")
|
||||
dirs = AppDirs(appname, appauthor=False)
|
||||
for prop in props:
|
||||
print("%s: %s" % (prop, getattr(dirs, prop)))
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
appdirs==1.4.4
|
||||
attrs==21.2.0
|
||||
cerberus==1.3.4
|
||||
click-didyoumean==0.0.3
|
||||
|
||||
@@ -49,7 +49,6 @@ FILE_WHITE_LIST = (
|
||||
"__init__.py",
|
||||
"README.rst",
|
||||
"README.md",
|
||||
"appdirs.py",
|
||||
"safety.zip",
|
||||
"cacert.pem",
|
||||
"vendor_pip.txt",
|
||||
|
||||
@@ -23,7 +23,7 @@ from pipenv.vendor import toml, tomlkit
|
||||
from pipenv.vendor.vistir.contextmanagers import temp_environ
|
||||
from pipenv.vendor.vistir.misc import run
|
||||
from pipenv.vendor.vistir.path import (
|
||||
create_tracked_tempdir, handle_remove_readonly, mkdir_p
|
||||
create_tracked_tempdir, handle_remove_readonly
|
||||
)
|
||||
|
||||
from pytest_pypi.app import prepare_fixtures
|
||||
@@ -186,7 +186,7 @@ def isolate(create_tmpdir):
|
||||
# Create a directory to use as our home location.
|
||||
home_dir = os.path.join(str(create_tmpdir()), "home")
|
||||
os.makedirs(home_dir)
|
||||
mkdir_p(os.path.join(home_dir, ".config", "git"))
|
||||
os.makedirs(os.path.join(home_dir, ".config", "git"), exist_ok=True)
|
||||
git_config_file = os.path.join(home_dir, ".config", "git", "config")
|
||||
with open(git_config_file, "wb") as fp:
|
||||
fp.write(
|
||||
@@ -199,7 +199,7 @@ def isolate(create_tmpdir):
|
||||
workon_home = create_tmpdir()
|
||||
os.environ["WORKON_HOME"] = str(workon_home)
|
||||
os.environ["HOME"] = os.path.abspath(home_dir)
|
||||
mkdir_p(os.path.join(home_dir, "projects"))
|
||||
os.makedirs(os.path.join(home_dir, "projects"), exist_ok=True)
|
||||
# Ignore PIPENV_ACTIVE so that it works as under a bare environment.
|
||||
os.environ.pop("PIPENV_ACTIVE", None)
|
||||
os.environ.pop("VIRTUAL_ENV", None)
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from pipenv.utils.shell import mkdir_p, temp_environ
|
||||
from pipenv.utils.shell import temp_environ
|
||||
|
||||
|
||||
@pytest.mark.extras
|
||||
@@ -187,7 +186,7 @@ def test_install_local_uri_special_character(pipenv_instance_private_pypi, tests
|
||||
with pipenv_instance_private_pypi() as p:
|
||||
artifact_dir = "artifacts"
|
||||
artifact_path = os.path.join(p.path, artifact_dir)
|
||||
mkdir_p(artifact_path)
|
||||
os.makedirs(artifact_path, exist_ok=True)
|
||||
shutil.copy(source_path, os.path.join(artifact_path, file_name))
|
||||
with open(p.pipfile_path, "w") as f:
|
||||
contents = """
|
||||
|
||||
@@ -72,6 +72,47 @@ def test_requirements_generates_requirements_from_lockfile_multiple_sources(pipe
|
||||
assert '--extra-index-url https://some_other_source.org' in c.stdout
|
||||
|
||||
|
||||
@pytest.mark.requirements
|
||||
def test_requirements_generates_requirements_from_lockfile_from_categories(pipenv_instance_private_pypi):
|
||||
with pipenv_instance_private_pypi(chdir=True) as p:
|
||||
packages = ('six', '1.12.0')
|
||||
dev_packages = ('itsdangerous', '1.1.0')
|
||||
test_packages = ('pytest', '7.1.3')
|
||||
doc_packages = ('docutils', '0.19')
|
||||
|
||||
with open(p.pipfile_path, 'w') as f:
|
||||
contents = f"""
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
[packages]
|
||||
{packages[0]}= "=={packages[1]}"
|
||||
[dev-packages]
|
||||
{dev_packages[0]}= "=={dev_packages[1]}"
|
||||
[test]
|
||||
{test_packages[0]}= "=={test_packages[1]}"
|
||||
[doc]
|
||||
{doc_packages[0]}= "=={doc_packages[1]}"
|
||||
""".strip()
|
||||
f.write(contents)
|
||||
l = p.pipenv('lock')
|
||||
assert l.returncode == 0
|
||||
|
||||
c = p.pipenv('requirements --dev-only')
|
||||
assert c.returncode == 0
|
||||
assert f'{packages[0]}=={packages[1]}' not in c.stdout
|
||||
assert f'{test_packages[0]}=={test_packages[1]}' not in c.stdout
|
||||
assert f'{doc_packages[0]}=={doc_packages[1]}' not in c.stdout
|
||||
assert f'{dev_packages[0]}=={dev_packages[1]}' in c.stdout
|
||||
|
||||
d = p.pipenv('requirements --categories="test, doc"')
|
||||
assert d.returncode == 0
|
||||
assert f'{packages[0]}=={packages[1]}' not in d.stdout
|
||||
assert f'{dev_packages[0]}=={dev_packages[1]}' not in d.stdout
|
||||
assert f'{test_packages[0]}=={test_packages[1]}' in d.stdout
|
||||
assert f'{doc_packages[0]}=={doc_packages[1]}' in d.stdout
|
||||
|
||||
@pytest.mark.requirements
|
||||
def test_requirements_with_git_requirements(pipenv_instance_pypi):
|
||||
req_name, req_hash = 'example-repo', 'cc858e89f19bc0dbd70983f86b811ab625dc9292'
|
||||
|
||||
@@ -4,7 +4,6 @@ import pytest
|
||||
|
||||
from pipenv.project import Project
|
||||
from pipenv.utils.shell import subprocess_run, temp_environ
|
||||
from pipenv.utils.shell import mkdir_p
|
||||
|
||||
|
||||
@pytest.mark.run
|
||||
@@ -69,7 +68,7 @@ def test_scripts_with_package_functions(pipenv_instance_pypi):
|
||||
with pipenv_instance_pypi(chdir=True) as p:
|
||||
p.pipenv('install')
|
||||
pkg_path = os.path.join(p.path, "pkg")
|
||||
mkdir_p(pkg_path)
|
||||
os.makedirs(pkg_path, exist_ok=True)
|
||||
file_path = os.path.join(pkg_path, "mod.py")
|
||||
with open(file_path, "w+") as f:
|
||||
f.write("""
|
||||
|
||||
Reference in New Issue
Block a user