Skip to content

Commit

Permalink
Merge pull request #202 from sigmavirus24/read-environment-vars
Browse files Browse the repository at this point in the history
Read environment vars
  • Loading branch information
sigmavirus24 authored Aug 3, 2016
2 parents 9e04fcc + f272c4d commit 26a7c44
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 6 deletions.
12 changes: 12 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
Changelog
=========

* :release:`1.8.0 <2016-xx-yy>`

* :feature:`201` Switch from upload.pypi.io to upload.pypi.org.

* :feature:`144` Retrieve configuration from the environment as a default.

- Repository URL will default to ``TWINE_REPOSITORY``

- Username will default to ``TWINE_USERNAME``

- Password will default to ``TWINE_PASSWORD``

* :release:`1.7.4 <2016-07-09>`

* Correct a packaging error.
Expand Down
40 changes: 40 additions & 0 deletions tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2016 Ian Cordasco
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Test functions useful across twine's tests."""

import contextlib
import os


@contextlib.contextmanager
def set_env(**environ):
"""Set the process environment variables temporarily.
>>> with set_env(PLUGINS_DIR=u'test/plugins'):
... "PLUGINS_DIR" in os.environ
True
>>> "PLUGINS_DIR" in os.environ
False
:param environ: Environment variables to set
:type environ: dict[str, unicode]
"""
old_environ = dict(os.environ)
os.environ.update(environ)
try:
yield
finally:
os.environ.clear()
os.environ.update(old_environ)
24 changes: 22 additions & 2 deletions tests/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import pytest

from twine.commands import upload
from twine import package
from twine import package, cli
import twine

import helpers

WHEEL_FIXTURE = 'tests/fixtures/twine-1.5.0-py2.py3-none-any.whl'

Expand All @@ -48,7 +50,8 @@ def test_ensure_if_no_wheel_files():

def test_find_dists_expands_globs():
files = sorted(upload.find_dists(['twine/__*.py']))
expected = ['twine/__init__.py', 'twine/__main__.py']
expected = [os.path.join('twine', '__init__.py'),
os.path.join('twine', '__main__.py')]
assert expected == files


Expand Down Expand Up @@ -124,3 +127,20 @@ def test_skip_upload_respects_skip_existing(monkeypatch):
assert upload.skip_upload(response=response,
skip_existing=False,
package=pkg) is False


def test_password_and_username_from_env(monkeypatch):
def none_upload(*args, **kwargs): pass
replaced_upload = pretend.call_recorder(none_upload)
monkeypatch.setattr(twine.commands.upload, "upload", replaced_upload)
testenv = {"TWINE_USERNAME": "pypiuser",
"TWINE_PASSWORD": "pypipassword"}
with helpers.set_env(**testenv):
cli.dispatch(["upload", "path/to/file"])
cli.dispatch(["upload", "path/to/file"])
result_kwargs = replaced_upload.calls[0].kwargs
assert "pypipassword" == result_kwargs["password"]
assert "pypiuser" == result_kwargs["username"]
result_kwargs = replaced_upload.calls[1].kwargs
assert None is result_kwargs["password"]
assert None is result_kwargs["username"]
28 changes: 28 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@

import os.path
import textwrap

import pytest

from twine.utils import DEFAULT_REPOSITORY, get_config, get_userpass_value
from twine import utils

import helpers


def test_get_config(tmpdir):
Expand Down Expand Up @@ -121,3 +125,27 @@ def test_get_config_deprecated_pypirc():
def test_get_userpass_value(cli_value, config, key, strategy, expected):
ret = get_userpass_value(cli_value, config, key, strategy)
assert ret == expected


@pytest.mark.parametrize(
('env_name', 'default', 'environ', 'expected'),
[
('MY_PASSWORD', None, {}, None),
('MY_PASSWORD', None, {'MY_PASSWORD': 'foo'}, 'foo'),
('URL', 'https://example.org', {}, 'https://example.org'),
('URL', 'https://example.org', {'URL': 'https://pypi.org'},
'https://pypi.org'),
],
)
def test_default_to_environment_action(env_name, default, environ, expected):
option_strings = ('-x', '--example')
dest = 'example'
with helpers.set_env(**environ):
action = utils.EnvironmentDefault(
env=env_name,
default=default,
option_strings=option_strings,
dest=dest,
)
assert action.env == env_name
assert action.default == expected
14 changes: 12 additions & 2 deletions twine/commands/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,27 @@ def main(args):
parser = argparse.ArgumentParser(prog="twine register")
parser.add_argument(
"-r", "--repository",
action=utils.EnvironmentDefault,
env='TWINE_REPOSITORY',
default="pypi",
help="The repository to register the package to (default: "
"%(default)s)",
)
parser.add_argument(
"-u", "--username",
help="The username to authenticate to the repository as",
action=utils.EnvironmentDefault,
env='TWINE_USERNAME',
required=False, help="The username to authenticate to the repository "
"as (can also be set via %(env)s environment "
"variable)",
)
parser.add_argument(
"-p", "--password",
help="The password to authenticate to the repository with",
action=utils.EnvironmentDefault,
env='TWINE_PASSWORD',
required=False, help="The password to authenticate to the repository "
"with (can also be set via %(env)s environment "
"variable)",
)
parser.add_argument(
"-c", "--comment",
Expand Down
14 changes: 12 additions & 2 deletions twine/commands/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def main(args):
parser = argparse.ArgumentParser(prog="twine upload")
parser.add_argument(
"-r", "--repository",
action=utils.EnvironmentDefault,
env="TWINE_REPOSITORY",
default="pypi",
help="The repository to upload the files to (default: %(default)s)",
)
Expand All @@ -169,11 +171,19 @@ def main(args):
)
parser.add_argument(
"-u", "--username",
help="The username to authenticate to the repository as",
action=utils.EnvironmentDefault,
env="TWINE_USERNAME",
required=False, help="The username to authenticate to the repository "
"as (can also be set via %(env)s environment "
"variable)",
)
parser.add_argument(
"-p", "--password",
help="The password to authenticate to the repository with",
action=utils.EnvironmentDefault,
env="TWINE_PASSWORD",
required=False, help="The password to authenticate to the repository "
"with (can also be set via %(env)s environment "
"variable)",
)
parser.add_argument(
"-c", "--comment",
Expand Down
20 changes: 20 additions & 0 deletions twine/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import functools
import getpass
import sys
import argparse


try:
import configparser
Expand Down Expand Up @@ -172,3 +174,21 @@ def password_prompt(prompt_text): # Always expects unicode for our own sanity
get_userpass_value,
key='client_cert',
)


class EnvironmentDefault(argparse.Action):
"""Get values from environment variable."""

def __init__(self, env, required=True, default=None, **kwargs):
default = os.environ.get(env, default)
self.env = env
if default:
required = False
super(EnvironmentDefault, self).__init__(
default=default,
required=required,
**kwargs
)

def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)

0 comments on commit 26a7c44

Please sign in to comment.