Merge branch 'main' into pip-22.3

This commit is contained in:
Oz N Tiram
2022-10-25 10:06:33 +02:00
committed by GitHub
27 changed files with 262 additions and 6184 deletions
+33 -3
View File
@@ -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
+6
View File
@@ -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 -1
View File
@@ -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
+61 -13
View File
@@ -5,6 +5,7 @@ Pipenv: Python Development Workflow for Humans
[![image](https://img.shields.io/pypi/l/pipenv.svg)](https://python.org/pypi/pipenv)
[![CI](https://github.com/pypa/pipenv/actions/workflows/ci.yaml/badge.svg)](https://github.com/pypa/pipenv/actions/workflows/ci.yaml)
[![image](https://img.shields.io/pypi/pyversions/pipenv.svg)](https://python.org/pypi/pipenv)
[![image](https://api-public.service.runforesight.com/api/v1/badge/test?repoId=a9acfd31-fca9-4ebb-a449-c7bf0f85a481)](https://pypa.app.runforesight.com)
------------------------------------------------------------------------
@@ -36,6 +37,53 @@ You can quickly play with Pipenv right in your browser:
[![Try in browser](https://cdn.rawgit.com/rootnroll/library/assets/try.svg)](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...
+21
View File
@@ -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
View File
@@ -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 -------------------------------------------
+1 -1
View File
@@ -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
View File
@@ -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
-------------------
+34
View File
@@ -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.
+1
View File
@@ -0,0 +1 @@
Remove usage of vistir.cmdparse in favor of pipenv.cmdparse
+1
View File
@@ -0,0 +1 @@
Remove appdirs.py in favor of platformdirs.
+1
View File
@@ -0,0 +1 @@
Add support to export requirements file for a specified set of categories.
+19 -5
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
-23
View File
@@ -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.
-608
View File
@@ -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)))
-1
View File
@@ -1,4 +1,3 @@
appdirs==1.4.4
attrs==21.2.0
cerberus==1.3.4
click-didyoumean==0.0.3
-1
View File
@@ -49,7 +49,6 @@ FILE_WHITE_LIST = (
"__init__.py",
"README.rst",
"README.md",
"appdirs.py",
"safety.zip",
"cacert.pem",
"vendor_pip.txt",
+3 -3
View File
@@ -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)
+2 -3
View File
@@ -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 = """
+41
View File
@@ -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'
+1 -2
View File
@@ -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("""