forked from github.com/pypiserver
Backwards compatibility, deprecation warnings
This commit is contained in:
parent
0763077124
commit
0da6c03c72
@ -8,9 +8,10 @@ from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
import pypiserver
|
||||
from pypiserver.config import PypiserverParserFactory
|
||||
from pypiserver.config import ConfigFactory
|
||||
from pypiserver import bottle
|
||||
|
||||
import functools as ft
|
||||
@ -44,11 +45,8 @@ def _logwrite(logger, level, msg):
|
||||
logger.log(level, msg)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
config = PypiserverParserFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args(args=argv)
|
||||
|
||||
def _run_app_from_config(config):
|
||||
"""Run a bottle application for the given config."""
|
||||
if (not config.authenticate and config.password_file != '.' or
|
||||
config.authenticate and config.password_file == '.'):
|
||||
auth_err = (
|
||||
@ -90,5 +88,30 @@ def main(argv=None):
|
||||
)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
"""Run the deprecated pypi-server command."""
|
||||
PY2 = sys.version_info < (3,)
|
||||
if PY2:
|
||||
# I honestly don't know why Python 2 is not raising this warning
|
||||
# with "default" as the filter.
|
||||
warnings.filterwarnings('always', category=DeprecationWarning)
|
||||
warnings.warn(DeprecationWarning(
|
||||
'The "pypi-server" command has been deprecated and will be removed '
|
||||
'in the next major release. Please use "pypiserver run" or '
|
||||
'"pypiserver update" instead.'
|
||||
))
|
||||
if PY2:
|
||||
warnings.filterwarnings('default', category=DeprecationWarning)
|
||||
config = ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args(args=argv)
|
||||
_run_app_from_config(config)
|
||||
|
||||
|
||||
def _new_main():
|
||||
"""Run the new pypiserver command."""
|
||||
_run_app_from_config(ConfigFactory().get_parsed())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -8,6 +8,7 @@ import re
|
||||
import xml.dom.minidom
|
||||
import zipfile
|
||||
from collections import namedtuple
|
||||
from warnings import warn
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
@ -46,15 +47,26 @@ _bottle_upload_filename_re = re.compile(r'^[a-z0-9_.!+-]+$', re.I)
|
||||
Upload = namedtuple('Upload', 'pkg sig')
|
||||
|
||||
|
||||
def app(config=None, auther=None):
|
||||
def app(config=None, auther=None, **kwargs):
|
||||
"""Return a hydrated app using the provided config and ``auther``.
|
||||
|
||||
:param argparse.Namespace config: a hydrated config namespace
|
||||
:param callable auther: a callable authenticator
|
||||
:param dict kwargs: DEPRECATED. Config keyword arguments.
|
||||
"""
|
||||
if config.auther is None and auther is not None:
|
||||
setattr(config, 'auther', auther)
|
||||
|
||||
if kwargs:
|
||||
warn(DeprecationWarning(
|
||||
'Passing arbitrary keyword arguments to app() has been '
|
||||
'deprecated. Please use config.ConfigFactory to generate '
|
||||
'a config and pass it to this function.'
|
||||
))
|
||||
for key, value in kwargs:
|
||||
if key in config:
|
||||
setattr(config, key, value)
|
||||
|
||||
config, packages = core.configure(config)
|
||||
return create_app(config, packages)
|
||||
|
||||
|
@ -50,7 +50,7 @@ class _Defaults(object):
|
||||
server = 'auto'
|
||||
|
||||
|
||||
class PypiserverHelpFormatter(ArgumentDefaultsHelpFormatter):
|
||||
class _HelpFormatter(ArgumentDefaultsHelpFormatter):
|
||||
"""A custom formatter to flip our one confusing argument.
|
||||
|
||||
``--disable-fallback`` is stored as ``redirect_to_fallback``,
|
||||
@ -64,12 +64,10 @@ class PypiserverHelpFormatter(ArgumentDefaultsHelpFormatter):
|
||||
if '--disable-fallback' in action.option_strings:
|
||||
return action.help + ' (default: False)'
|
||||
else:
|
||||
return super(
|
||||
PypiserverHelpFormatter, self
|
||||
)._get_help_string(action)
|
||||
return super(_HelpFormatter, self)._get_help_string(action)
|
||||
|
||||
|
||||
class PypiserverCustomParsers(object):
|
||||
class _CustomParsers(object):
|
||||
"""Collect custom parsers."""
|
||||
|
||||
@staticmethod
|
||||
@ -125,7 +123,7 @@ class PypiserverCustomParsers(object):
|
||||
return verbosities[-1]
|
||||
|
||||
|
||||
class PypiserverParser(ArgumentParser):
|
||||
class _PypiserverParser(ArgumentParser):
|
||||
"""Allow extra actions following the final parse.
|
||||
|
||||
Actions like "count", and regular "store" actions when "nargs" is
|
||||
@ -135,15 +133,15 @@ class PypiserverParser(ArgumentParser):
|
||||
"""
|
||||
|
||||
extra_parsers = {
|
||||
'authenticate': PypiserverCustomParsers.auth,
|
||||
'hash_algo': PypiserverCustomParsers.hash_algo,
|
||||
'roots': PypiserverCustomParsers.roots,
|
||||
'verbosity': PypiserverCustomParsers.verbosity,
|
||||
'authenticate': _CustomParsers.auth,
|
||||
'hash_algo': _CustomParsers.hash_algo,
|
||||
'roots': _CustomParsers.roots,
|
||||
'verbosity': _CustomParsers.verbosity,
|
||||
}
|
||||
|
||||
def parse_args(self, args=None, namespace=None):
|
||||
"""Parse arguments."""
|
||||
parsed = super(PypiserverParser, self).parse_args(
|
||||
parsed = super(_PypiserverParser, self).parse_args(
|
||||
args=args, namespace=namespace
|
||||
)
|
||||
for attr, parser in self.extra_parsers.items():
|
||||
@ -152,12 +150,11 @@ class PypiserverParser(ArgumentParser):
|
||||
return parsed
|
||||
|
||||
|
||||
class PypiserverParserFactory(object):
|
||||
"""Create a pypiserver argument parser."""
|
||||
class ConfigFactory(object):
|
||||
"""Factory for pypiserver configs and parsers."""
|
||||
|
||||
def __init__(self, parser_cls=PypiserverParser,
|
||||
help_formatter=PypiserverHelpFormatter,
|
||||
parser_type='pypiserver'):
|
||||
def __init__(self, parser_cls=_PypiserverParser,
|
||||
help_formatter=_HelpFormatter, parser_type='pypiserver'):
|
||||
"""Instantiate the factory.
|
||||
|
||||
:param argparse.HelpFormatter help_formatter: the HelpForamtter class
|
||||
@ -169,6 +166,22 @@ class PypiserverParserFactory(object):
|
||||
self.parser_cls = parser_cls
|
||||
self.parser_type = parser_type
|
||||
|
||||
def get_default(self, subcommand='run'):
|
||||
"""Return a parsed config with default argument values.
|
||||
|
||||
:param str subcommand:
|
||||
the subcommand for which to return default arguments.
|
||||
:rtype: argparse.Namespace
|
||||
"""
|
||||
return self.get_parser().parse_args([subcommand])
|
||||
|
||||
def get_parsed(self):
|
||||
"""Return arguments parsed from the commandline.
|
||||
|
||||
:rtype: argparse.Namespace
|
||||
"""
|
||||
return self.get_parser().parse_args()
|
||||
|
||||
def get_parser(self):
|
||||
"""Return an ArgumentParser instance with all arguments populated.
|
||||
|
||||
|
@ -60,10 +60,10 @@ def configure(config):
|
||||
if not callable(config.auther):
|
||||
if config.password_file and config.password_file != '.':
|
||||
from passlib.apache import HtpasswdFile
|
||||
htPsswdFile = HtpasswdFile(config.password_file)
|
||||
ht_pwd_file = HtpasswdFile(config.password_file)
|
||||
else:
|
||||
config.password_file = htPsswdFile = None
|
||||
config.auther = functools.partial(auth_by_htpasswd_file, htPsswdFile)
|
||||
config.password_file = ht_pwd_file = None
|
||||
config.auther = functools.partial(auth_by_htpasswd_file, ht_pwd_file)
|
||||
|
||||
try:
|
||||
# pkg_resources.resource_filename() is not supported for zipfiles,
|
||||
@ -87,11 +87,11 @@ def configure(config):
|
||||
return config, packages
|
||||
|
||||
|
||||
def auth_by_htpasswd_file(htPsswdFile, username, password):
|
||||
def auth_by_htpasswd_file(ht_pwd_file, username, password):
|
||||
"""The default ``config.auther``."""
|
||||
if htPsswdFile is not None:
|
||||
htPsswdFile.load_if_changed()
|
||||
return htPsswdFile.check_password(username, password)
|
||||
if ht_pwd_file is not None:
|
||||
ht_pwd_file.load_if_changed()
|
||||
return ht_pwd_file.check_password(username, password)
|
||||
|
||||
|
||||
mimetypes.add_type("application/octet-stream", ".egg")
|
||||
|
@ -3,7 +3,7 @@
|
||||
import os
|
||||
|
||||
from ._app import app
|
||||
from .config import str2bool, PypiserverParserFactory
|
||||
from .config import str2bool, ConfigFactory
|
||||
|
||||
|
||||
def _str_strip(string):
|
||||
@ -46,7 +46,7 @@ def paste_app_factory(global_config, **local_conf):
|
||||
return os.path.expanduser(root)
|
||||
return root
|
||||
|
||||
c = PypiserverParserFactory(
|
||||
c = ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args([])
|
||||
|
||||
|
5
setup.py
5
setup.py
@ -74,7 +74,10 @@ setup(
|
||||
zip_safe=True,
|
||||
entry_points={
|
||||
'paste.app_factory': ['main=pypiserver.paste:paste_app_factory'],
|
||||
'console_scripts': ['pypi-server=pypiserver.__main__:main']
|
||||
'console_scripts': [
|
||||
'pypi-server=pypiserver.__main__:main',
|
||||
'pypiserver=pypiserver.__main__:_new_main',
|
||||
]
|
||||
},
|
||||
options={
|
||||
'bdist_wheel': {'universal': True},
|
||||
|
@ -30,24 +30,18 @@ __main__.init_logging(level=logging.NOTSET)
|
||||
hp = HTMLParser()
|
||||
|
||||
|
||||
# @pytest.fixture()
|
||||
# def _app(app):
|
||||
# return app.module
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app(tmpdir):
|
||||
conf = config.PypiserverParserFactory(
|
||||
conf = config.ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args(
|
||||
['-a', '.', tmpdir.strpath]
|
||||
)
|
||||
# return app(root=tmpdir.strpath, authenticated=[])
|
||||
return pypiserver.app(conf)
|
||||
|
||||
|
||||
def app_from_args(args):
|
||||
conf = config.PypiserverParserFactory(
|
||||
conf = config.ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args(args)
|
||||
return pypiserver.app(conf)
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Test the ArgumentParser and associated functions."""
|
||||
|
||||
import argparse
|
||||
import logging
|
||||
from os import getcwd
|
||||
from os.path import exists, expanduser
|
||||
@ -39,9 +40,9 @@ def test_argument_formatter(options, expected_help):
|
||||
case.
|
||||
"""
|
||||
action = StubAction(options)
|
||||
assert config.PypiserverHelpFormatter(
|
||||
'prog'
|
||||
)._get_help_string(action) == (expected_help)
|
||||
assert config._HelpFormatter('prog')._get_help_string(action) == (
|
||||
expected_help
|
||||
)
|
||||
|
||||
|
||||
class TestCustomParsers(object):
|
||||
@ -59,28 +60,28 @@ class TestCustomParsers(object):
|
||||
))
|
||||
def test_auth_parse_success(self, arg, exp):
|
||||
"""Test parsing auth strings from the commandline."""
|
||||
assert config.PypiserverCustomParsers.auth(arg) == exp
|
||||
assert config._CustomParsers.auth(arg) == exp
|
||||
|
||||
def test_auth_parse_disallowed_item(self):
|
||||
"""Test that including a non-whitelisted action throws."""
|
||||
with pytest.raises(ValueError):
|
||||
config.PypiserverCustomParsers.auth('download update foo')
|
||||
config._CustomParsers.auth('download update foo')
|
||||
|
||||
def test_roots_parse_abspath(self):
|
||||
"""Test the parsing of root directories returns absolute paths."""
|
||||
assert config.PypiserverCustomParsers.roots(
|
||||
assert config._CustomParsers.roots(
|
||||
['./foo']
|
||||
) == ['{}/foo'.format(getcwd())]
|
||||
|
||||
def test_roots_parse_home(self):
|
||||
"""Test that parsing of root directories expands the user home."""
|
||||
assert config.PypiserverCustomParsers.roots(
|
||||
assert config._CustomParsers.roots(
|
||||
['~/foo']
|
||||
) == ([expanduser('~/foo')])
|
||||
|
||||
def test_roots_parse_both(self):
|
||||
"""Test that root directories are both expanded and absolute-ed."""
|
||||
assert config.PypiserverCustomParsers.roots(
|
||||
assert config._CustomParsers.roots(
|
||||
['~/foo/..']
|
||||
) == [expanduser('~')]
|
||||
|
||||
@ -95,7 +96,7 @@ class TestCustomParsers(object):
|
||||
))
|
||||
def test_verbosity_parse(self, verbosity, exp):
|
||||
"""Test converting a number of -v's into a log level."""
|
||||
assert config.PypiserverCustomParsers.verbosity(verbosity) == exp
|
||||
assert config._CustomParsers.verbosity(verbosity) == exp
|
||||
|
||||
|
||||
class TestDeprecatedParser:
|
||||
@ -104,9 +105,7 @@ class TestDeprecatedParser:
|
||||
@pytest.fixture()
|
||||
def parser(self):
|
||||
"""Return a deprecated parser."""
|
||||
return config.PypiserverParserFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser()
|
||||
return config.ConfigFactory(parser_type='pypi-server').get_parser()
|
||||
|
||||
def test_version_exits(self, parser):
|
||||
"""Test that asking for the version exits the program."""
|
||||
@ -230,7 +229,7 @@ class TestDeprecatedParser:
|
||||
'resource_filename',
|
||||
Mock(side_effect=NotImplementedError)
|
||||
)
|
||||
assert config.PypiserverParserFactory(
|
||||
assert config.ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args([]).welcome_file == const.STANDALONE_WELCOME
|
||||
|
||||
@ -327,7 +326,7 @@ class TestParser:
|
||||
@pytest.fixture()
|
||||
def parser(self):
|
||||
"""Return a deprecated parser."""
|
||||
return config.PypiserverParserFactory().get_parser()
|
||||
return config.ConfigFactory().get_parser()
|
||||
|
||||
# **********************************************************************
|
||||
# Root Command
|
||||
@ -510,7 +509,7 @@ class TestParser:
|
||||
'resource_filename',
|
||||
Mock(side_effect=NotImplementedError)
|
||||
)
|
||||
assert config.PypiserverParserFactory().get_parser().parse_args(
|
||||
assert config.ConfigFactory().get_parser().parse_args(
|
||||
['run']
|
||||
).welcome_file == const.STANDALONE_WELCOME
|
||||
|
||||
@ -604,3 +603,45 @@ class TestParser:
|
||||
"""Test specifying the execute flag."""
|
||||
args.insert(0, 'update')
|
||||
assert parser.parse_args(args).download_directory is exp
|
||||
|
||||
|
||||
class TestReadyMades(object):
|
||||
"""Test generating ready-made configs."""
|
||||
|
||||
def test_get_default(self):
|
||||
"""Test getting the default config."""
|
||||
conf = config.ConfigFactory().get_default()
|
||||
assert any(d in conf for d in vars(config._Defaults))
|
||||
for default, value in vars(config._Defaults).items():
|
||||
if default in conf:
|
||||
if default == 'roots':
|
||||
assert getattr(conf, default) == (
|
||||
[expanduser(v) for v in value]
|
||||
)
|
||||
elif default == 'authenticate':
|
||||
assert getattr(conf, default) == (
|
||||
[a for a in value.split()]
|
||||
)
|
||||
else:
|
||||
assert getattr(conf, default) == value
|
||||
|
||||
def test_get_default_specify_subcommand(self):
|
||||
"""Test getting default args for a non-default subcommand."""
|
||||
conf = config.ConfigFactory().get_default(subcommand='update')
|
||||
exp_defaults = (
|
||||
('execute', False),
|
||||
('pre', False),
|
||||
('download_directory', None)
|
||||
)
|
||||
for default, value in exp_defaults:
|
||||
assert getattr(conf, default) is value
|
||||
|
||||
def test_get_parsed(self, monkeypatch):
|
||||
"""Test getting a Namespace from commandline args."""
|
||||
monkeypatch.setattr(
|
||||
argparse._sys,
|
||||
'argv',
|
||||
['pypiserver', 'run', '--interface', '1.2.3.4']
|
||||
)
|
||||
conf = config.ConfigFactory().get_parsed()
|
||||
assert conf.host == '1.2.3.4'
|
||||
|
@ -1,47 +1,16 @@
|
||||
"""
|
||||
Test module for . . .
|
||||
"""
|
||||
# Standard library imports
|
||||
"""Test module for pypiserver.__init__"""
|
||||
from __future__ import (absolute_import, division,
|
||||
print_function, unicode_literals)
|
||||
import logging
|
||||
from os.path import abspath, dirname, join, realpath
|
||||
from sys import path
|
||||
|
||||
# Third party imports
|
||||
import pytest
|
||||
|
||||
# Local imports
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
test_dir = realpath(dirname(__file__))
|
||||
src_dir = abspath(join(test_dir, '..'))
|
||||
path.append(src_dir)
|
||||
print(path)
|
||||
|
||||
import pypiserver
|
||||
|
||||
|
||||
# @pytest.mark.parametrize('conf_options', [
|
||||
# {},
|
||||
# {'root': '~/stable_packages'},
|
||||
# {'root': '~/unstable_packages', 'authenticated': 'upload',
|
||||
# 'passwords': '~/htpasswd'},
|
||||
# # Verify that the strip parser works properly.
|
||||
# {'authenticated': str('upload')},
|
||||
# ])
|
||||
# def test_paste_app_factory(conf_options, monkeypatch):
|
||||
# """Test the paste_app_factory method"""
|
||||
# monkeypatch.setattr('pypiserver.core.configure',
|
||||
# lambda **x: (x, [x.keys()]))
|
||||
# pypiserver.paste_app_factory({}, **conf_options)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_app_factory(monkeypatch, tmpdir):
|
||||
# monkeypatch.setattr('pypiserver.core.configure',
|
||||
# lambda **x: (x, [x.keys()]))
|
||||
conf = pypiserver.config.PypiserverParserFactory(
|
||||
"""Test creating an app."""
|
||||
conf = pypiserver.config.ConfigFactory(
|
||||
parser_type='pypi-server'
|
||||
).get_parser().parse_args([str(tmpdir)])
|
||||
assert pypiserver.app(conf) is not pypiserver.app(conf)
|
||||
|
@ -1,12 +1,19 @@
|
||||
#! /usr/bin/env py.test
|
||||
"""Test the __main__ module."""
|
||||
|
||||
import sys, os, pytest, logging
|
||||
from pypiserver import __main__
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
try:
|
||||
from unittest import mock
|
||||
except ImportError:
|
||||
import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from pypiserver import __main__
|
||||
|
||||
|
||||
class main_wrapper(object):
|
||||
|
||||
@ -16,7 +23,8 @@ class main_wrapper(object):
|
||||
|
||||
def __call__(self, argv):
|
||||
sys.stdout.write("Running %s\n" % (argv,))
|
||||
__main__.main(argv)
|
||||
with warnings.catch_warnings():
|
||||
__main__.main(argv)
|
||||
return self.run_kwargs
|
||||
|
||||
|
||||
@ -41,140 +49,145 @@ def main(request, monkeypatch):
|
||||
return main
|
||||
|
||||
|
||||
def test_default_pkgdir(main):
|
||||
main([])
|
||||
assert os.path.normpath(main.pkgdir) == (
|
||||
os.path.normpath(os.path.expanduser("~/packages"))
|
||||
)
|
||||
class TestMain(object):
|
||||
"""Test the main() method."""
|
||||
|
||||
def test_default_pkgdir(self, main):
|
||||
main([])
|
||||
assert os.path.normpath(main.pkgdir) == (
|
||||
os.path.normpath(os.path.expanduser("~/packages"))
|
||||
)
|
||||
|
||||
def test_noargs(self, main):
|
||||
assert main([]) == {'host': "0.0.0.0", 'port': 8080, 'server': "auto"}
|
||||
|
||||
def test_port(self, main):
|
||||
expected = dict(host="0.0.0.0", port=8081, server="auto")
|
||||
assert main(["--port=8081"]) == expected
|
||||
assert main(["--port", "8081"]) == expected
|
||||
assert main(["-p", "8081"]) == expected
|
||||
|
||||
def test_server(self, main):
|
||||
assert main(["--server=paste"])["server"] == "paste"
|
||||
assert main(["--server", "cherrypy"])["server"] == "cherrypy"
|
||||
|
||||
@pytest.mark.skipif(True, reason='deprecated')
|
||||
def test_root(self, main):
|
||||
main(["--root", "."])
|
||||
assert main.app.module.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
@pytest.mark.skipif(True, reason='deprecated')
|
||||
def test_root_r(self, main):
|
||||
main(["-r", "."])
|
||||
assert main.app.module.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
def test_fallback_url(self, main):
|
||||
main(["--fallback-url", "https://pypi.mirror/simple"])
|
||||
assert main.app.config.fallback_url == "https://pypi.mirror/simple"
|
||||
|
||||
def test_fallback_url_default(self, main):
|
||||
main([])
|
||||
assert main.app.config.fallback_url == "https://pypi.org/simple"
|
||||
|
||||
def test_hash_algo_default(self, main):
|
||||
main([])
|
||||
assert main.app.config.hash_algo == 'md5'
|
||||
|
||||
def test_hash_algo(self, main):
|
||||
main(['--hash-algo=sha256'])
|
||||
assert main.app.config.hash_algo == 'sha256'
|
||||
|
||||
def test_hash_algo_off(self, main):
|
||||
main(['--hash-algo=off'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=0'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=no'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=false'])
|
||||
assert main.app.config.hash_algo is None
|
||||
|
||||
def test_hash_algo_BAD(self, main):
|
||||
with pytest.raises(SystemExit):
|
||||
main(['--hash-algo', 'BAD'])
|
||||
|
||||
def test_logging(self, main, tmpdir):
|
||||
logfile = tmpdir.mkdir("logs").join('test.log')
|
||||
main(["-v", "--log-file", logfile.strpath])
|
||||
assert logfile.check(), logfile
|
||||
|
||||
# @pytest.mark.filterwarnings('ignore::DeprecationWarning')
|
||||
def test_logging_verbosity(self, main):
|
||||
main([])
|
||||
assert logging.getLogger().level == logging.WARN
|
||||
main(["-v"])
|
||||
assert logging.getLogger().level == logging.INFO
|
||||
main(["-v", "-v"])
|
||||
assert logging.getLogger().level == logging.DEBUG
|
||||
main(["-v", "-v", "-v"])
|
||||
assert logging.getLogger().level == logging.NOTSET
|
||||
|
||||
def test_welcome_file(self, main):
|
||||
sample_msg_file = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"sample_msg.html"
|
||||
)
|
||||
main(["--welcome", sample_msg_file])
|
||||
assert "Hello pypiserver tester!" in main.app.config.welcome_msg
|
||||
|
||||
def test_welcome_file_default(self, main):
|
||||
main([])
|
||||
assert "Welcome to pypiserver!" in main.app.config.welcome_msg
|
||||
|
||||
def test_password_without_auth_list(self, main, monkeypatch):
|
||||
sysexit = mock.MagicMock(side_effect=ValueError('BINGO'))
|
||||
monkeypatch.setattr('sys.exit', sysexit)
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "pswd-file", "-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
def test_password_alone(self, main, monkeypatch):
|
||||
monkeypatch.setitem(sys.modules, 'passlib', mock.MagicMock())
|
||||
monkeypatch.setitem(sys.modules, 'passlib.apache', mock.MagicMock())
|
||||
main(["-P", "pswd-file"])
|
||||
assert main.app.config.authenticate == ['update']
|
||||
|
||||
def test_dot_password_without_auth_list(self, main, monkeypatch):
|
||||
main(["-P", ".", "-a", ""])
|
||||
assert main.app.config.authenticate == []
|
||||
|
||||
main(["-P", ".", "-a", "."])
|
||||
assert main.app.config.authenticate == []
|
||||
|
||||
|
||||
def test_noargs(main):
|
||||
assert main([]) == {'host': "0.0.0.0", 'port': 8080, 'server': "auto"}
|
||||
class TestPypiserverDeprecation(object):
|
||||
"""Test the deprecation of the old pypi-server command.
|
||||
|
||||
Note that these tests should be removed when the pypi-server
|
||||
command is removed.
|
||||
"""
|
||||
|
||||
def test_port(main):
|
||||
expected = dict(host="0.0.0.0", port=8081, server="auto")
|
||||
assert main(["--port=8081"]) == expected
|
||||
assert main(["--port", "8081"]) == expected
|
||||
assert main(["-p", "8081"]) == expected
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_run(self, monkeypatch):
|
||||
"""Monkeypatch argv and the _run_app_from_config method."""
|
||||
monkeypatch.setattr(argparse._sys, 'argv', ['pypi-server'])
|
||||
monkeypatch.setattr(__main__, '_run_app_from_config', lambda c: None)
|
||||
|
||||
|
||||
def test_server(main):
|
||||
assert main(["--server=paste"])["server"] == "paste"
|
||||
assert main(["--server", "cherrypy"])["server"] == "cherrypy"
|
||||
|
||||
|
||||
@pytest.mark.skipif(True, reason='deprecated')
|
||||
def test_root(main):
|
||||
main(["--root", "."])
|
||||
assert main.app.module.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
|
||||
@pytest.mark.skipif(True, reason='deprecated')
|
||||
def test_root_r(main):
|
||||
main(["-r", "."])
|
||||
assert main.app.module.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
|
||||
def test_fallback_url(main):
|
||||
main(["--fallback-url", "https://pypi.mirror/simple"])
|
||||
# assert main.app.module.config.fallback_url == "https://pypi.mirror/simple"
|
||||
assert main.app.config.fallback_url == "https://pypi.mirror/simple"
|
||||
|
||||
|
||||
def test_fallback_url_default(main):
|
||||
main([])
|
||||
# assert main.app.module.config.fallback_url == "https://pypi.org/simple"
|
||||
assert main.app.config.fallback_url == "https://pypi.org/simple"
|
||||
|
||||
|
||||
def test_hash_algo_default(main):
|
||||
main([])
|
||||
assert main.app.config.hash_algo == 'md5'
|
||||
# assert main.app.module.config.hash_algo == 'md5'
|
||||
|
||||
|
||||
def test_hash_algo(main):
|
||||
main(['--hash-algo=sha256'])
|
||||
# assert main.app.module.config.hash_algo == 'sha256'
|
||||
assert main.app.config.hash_algo == 'sha256'
|
||||
|
||||
|
||||
def test_hash_algo_off(main):
|
||||
main(['--hash-algo=off'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=0'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=no'])
|
||||
assert main.app.config.hash_algo is None
|
||||
main(['--hash-algo=false'])
|
||||
assert main.app.config.hash_algo is None
|
||||
|
||||
|
||||
def test_hash_algo_BAD(main):
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
main(['--hash-algo', 'BAD'])
|
||||
|
||||
|
||||
def test_logging(main, tmpdir):
|
||||
logfile = tmpdir.mkdir("logs").join('test.log')
|
||||
main(["-v", "--log-file", logfile.strpath])
|
||||
assert logfile.check(), logfile
|
||||
|
||||
|
||||
def test_logging_verbosity(main):
|
||||
main([])
|
||||
assert logging.getLogger().level == logging.WARN
|
||||
main(["-v"])
|
||||
assert logging.getLogger().level == logging.INFO
|
||||
main(["-v", "-v"])
|
||||
assert logging.getLogger().level == logging.DEBUG
|
||||
main(["-v", "-v", "-v"])
|
||||
assert logging.getLogger().level == logging.NOTSET
|
||||
|
||||
|
||||
def test_welcome_file(main):
|
||||
sample_msg_file = os.path.join(os.path.dirname(__file__), "sample_msg.html")
|
||||
main(["--welcome", sample_msg_file])
|
||||
assert "Hello pypiserver tester!" in main.app.config.welcome_msg
|
||||
|
||||
|
||||
def test_welcome_file_default(main):
|
||||
main([])
|
||||
assert "Welcome to pypiserver!" in main.app.config.welcome_msg
|
||||
|
||||
|
||||
def test_password_without_auth_list(main, monkeypatch):
|
||||
sysexit = mock.MagicMock(side_effect=ValueError('BINGO'))
|
||||
monkeypatch.setattr('sys.exit', sysexit)
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "pswd-file", "-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
|
||||
def test_password_alone(main, monkeypatch):
|
||||
monkeypatch.setitem(sys.modules, 'passlib', mock.MagicMock())
|
||||
monkeypatch.setitem(sys.modules, 'passlib.apache', mock.MagicMock())
|
||||
main(["-P", "pswd-file"])
|
||||
assert main.app.config.authenticate == ['update']
|
||||
|
||||
|
||||
def test_dot_password_without_auth_list(main, monkeypatch):
|
||||
main(["-P", ".", "-a", ""])
|
||||
assert main.app.config.authenticate == []
|
||||
|
||||
main(["-P", ".", "-a", "."])
|
||||
assert main.app.config.authenticate == []
|
||||
def test_warns(self):
|
||||
"""Test that a deprecation warning is thrown."""
|
||||
warnings.simplefilter('always', category=DeprecationWarning)
|
||||
with pytest.warns(DeprecationWarning):
|
||||
__main__.main()
|
||||
|
Loading…
Reference in New Issue
Block a user