From ebc42ff4921d6dfb4c8672f16cd436ce25aa67a4 Mon Sep 17 00:00:00 2001 From: Gary Reynolds Date: Mon, 23 Apr 2018 08:57:52 +1000 Subject: [PATCH] Add two new optional configuration locations to consider. While earlier Python package uploading tooling only looked only for ~/.pypirc file there is no need to stick to this convention forever. This patch introduces a secondary user level configuration path, namespaced to this tool, and also a system-wide location that allows system administrators to provide a sensible default. This implementation uses the appdirs project to handle the cross platform decision making for us (initial use case is to provide a Windows user experience managed across a fleet of workstations equally to Linux development environments). Linux precedence for jsmith: - /home/jsmith/.config/twine/.pypirc - /home/jsmith/.pypirc - /etc/xdg/twine/.pypirc Windows precedence for jsmith: - c:\Users\jsmith\AppData\Roaming\twine\.pypirc - c:\Users\jsmith\.pypirc - c:\ProgramData\twine\.pypirc This does not attempt to teach twine to overload a lower precedence configuration with a higher one. --- AUTHORS | 1 + README.rst | 11 +++++++++++ setup.py | 2 ++ twine/commands/register.py | 2 +- twine/commands/upload.py | 2 +- twine/utils.py | 33 +++++++++++++++++++++++++++++---- 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index deb63c10..57ab5bda 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,3 +18,4 @@ Andrew Watts Anna Martelli Ravenscroft Sumana Harihareswara Dustin Ingram (https://di.codes) +Gary Reynolds diff --git a/README.rst b/README.rst index bfecb796..ffd1311c 100644 --- a/README.rst +++ b/README.rst @@ -249,6 +249,17 @@ For completeness, its usage: containing the private key and the certificate in PEM format. +Configuration File +^^^^^^^^^^^^^^^^^^ + +Twine will search for a `.pypirc` file in the following locations when it is not +specified on the command line. + +1. In the twine folder of the user's configuration directory +2. In the user's home directory +3. In the twine folder of the system configuration directory + + Environment Variables ^^^^^^^^^^^^^^^^^^^^^ diff --git a/setup.py b/setup.py index 32b75118..44a97627 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,8 @@ install_requires = [ + "appdirs >= 1.4.3", + "first >= 2.0.1", "tqdm >= 4.14", "pkginfo >= 1.4.2", "requests >= 2.5.0, != 2.15, != 2.16", diff --git a/twine/commands/register.py b/twine/commands/register.py index d31fde33..d41339f6 100644 --- a/twine/commands/register.py +++ b/twine/commands/register.py @@ -108,7 +108,7 @@ def main(args): ) parser.add_argument( "--config-file", - default="~/.pypirc", + default=utils.PYPIRC, help="The .pypirc config file to use.", ) parser.add_argument( diff --git a/twine/commands/upload.py b/twine/commands/upload.py index e2ebdba2..8111eea2 100644 --- a/twine/commands/upload.py +++ b/twine/commands/upload.py @@ -226,7 +226,7 @@ def main(args): ) parser.add_argument( "--config-file", - default="~/.pypirc", + default=utils.PYPIRC, help="The .pypirc config file to use.", ) parser.add_argument( diff --git a/twine/utils.py b/twine/utils.py index 6fd66553..d2a5622c 100644 --- a/twine/utils.py +++ b/twine/utils.py @@ -14,14 +14,17 @@ from __future__ import absolute_import, division, print_function from __future__ import unicode_literals -import os -import os.path +import argparse import functools import getpass +import os +import os.path import sys -import argparse import warnings +from appdirs import site_config_dir, user_config_dir +from first import first + try: import configparser except ImportError: # pragma: no cover @@ -41,11 +44,33 @@ input_func = raw_input +# Pick up a .pypirc from the first place we find it. Use appdirs to produce +# sensible locations on various platforms. Similar to pip (although they use a +# vendored version of appdirs with customisations). +DEFAULT_PYPIRC = '~/.pypirc' # backwards compatible location +PYPIRC = first( + [ + # twine specific user configuration has highest precedence. On Windows + # the user may be part of a network environment with a roaming profile; + # we will prefer a local profile to a roaming one, but check for each. + # The `roaming` option has no effect on other platforms and both these + # paths will be the same. + os.path.join( + user_config_dir('twine', False, roaming=False), '.pypirc'), + os.path.join(user_config_dir('twine', False, roaming=True), '.pypirc'), + # the historical default is $HOME/.pypirc so take it next + os.path.expanduser(DEFAULT_PYPIRC), + # introduce a twine specific location to allow system wide config + os.path.join(site_config_dir('twine', False), '.pypirc'), + ], + default=DEFAULT_PYPIRC, + key=os.path.exists) + DEFAULT_REPOSITORY = "https://upload.pypi.org/legacy/" TEST_REPOSITORY = "https://test.pypi.org/legacy/" -def get_config(path="~/.pypirc"): +def get_config(path=PYPIRC): # Expand user strings in the path path = os.path.expanduser(path)