Standalone conf, Dockerfile updates, pub interface

* Fixed config for standalone package to handle the expected error in
`pkg_resources.resource_file()`
* Ensured the `pypiserver` user in the Dockerfile is part of the
`pypiserver` group
* Ensured `__updated__` is available in the public interface by moving
it back into `__init__.py`
* Added `const.py` for defining, you guessed it, constants
This commit is contained in:
Matthew Planchard 2018-07-05 19:27:39 -05:00
parent 38d51dfbce
commit 0763077124
8 changed files with 69 additions and 12 deletions

@ -4,8 +4,8 @@ FROM python:3.6-alpine
COPY . /code
WORKDIR /code
RUN adduser -S -u 9898 pypiserver && \
addgroup -S -g 9898 pypiserver && \
RUN addgroup -S -g 9898 pypiserver && \
adduser -S -u 9898 -G pypiserver pypiserver && \
python setup.py install && \
pip install passlib && \
cd / && \

@ -4,6 +4,7 @@
__title__ = "pypiserver"
__summary__ = "A minimal PyPI server for use with pip/easy_install."
__uri__ = "https://github.com/pypiserver/pypiserver"
__updated__ = "2018-06-12 20:15:10"
# Interface
from ._app import app # noqa

@ -4,4 +4,3 @@ import re
__version__ = version = "1.2.2"
__version_info__ = tuple(re.split('[.-]', __version__))
__updated__ = "2018-06-12 20:15:10"

@ -11,6 +11,7 @@ import pkg_resources
from . import __version__
from .bottle import server_names
from .const import STANDALONE_WELCOME
_AUTH_RE = re.compile(r'[, ]+')
@ -23,6 +24,14 @@ def str2bool(string):
return string.lower() not in _FALSES
def _get_welcome_file():
"""Get the welcome file or set a constant for the standalone package."""
try:
return pkg_resources.resource_filename('pypiserver', 'welcome.html')
except NotImplementedError: # raised in standalone zipfile.
return STANDALONE_WELCOME
class _Defaults(object):
"""Define default constants."""
@ -348,7 +357,7 @@ class PypiserverParserFactory(object):
'--welcome',
default=environ.get(
'PYPISERVER_WELCOME',
pkg_resources.resource_filename('pypiserver', 'welcome.html'),
_get_welcome_file()
),
dest='welcome_file',
metavar='HTML_FILE',

3
pypiserver/const.py Normal file

@ -0,0 +1,3 @@
"""Constant values for pypiserver."""
STANDALONE_WELCOME = 'standalone'

@ -10,12 +10,16 @@ import os
import re
import sys
if sys.version_info < (3,):
from io import open
import pkg_resources
from .const import STANDALONE_WELCOME
log = logging.getLogger(__name__)
_archive_suffix_rx = re.compile(
r"(\.zip|\.tar\.gz|\.tgz|\.tar\.bz2|-py[23]\.\d-.*|"
"\.win-amd64-py[23]\.\d\..*|\.win32-py[23]\.\d\..*|\.egg)$",
@ -62,8 +66,15 @@ def configure(config):
config.auther = functools.partial(auth_by_htpasswd_file, htPsswdFile)
try:
with open(config.welcome_file, 'r', encoding='utf-8') as fd:
config.welcome_msg = fd.read()
# pkg_resources.resource_filename() is not supported for zipfiles,
# so we rely on resource_string() instead.
if config.welcome_file == STANDALONE_WELCOME:
config.welcome_msg = pkg_resources.resource_string(
__name__, 'welcome.html'
).decode('utf-8')
else:
with open(config.welcome_file, 'r', encoding='utf-8') as fd:
config.welcome_msg = fd.read()
except Exception:
log.warning(
"Could not load welcome file(%s)!",

@ -4,9 +4,15 @@ import logging
from os import getcwd
from os.path import exists, expanduser
try:
from unittest.mock import Mock
except ImportError: # py2
from mock import Mock
import pytest
from pypiserver import config
from pypiserver import const
class StubAction:
@ -217,6 +223,17 @@ class TestDeprecatedParser:
else:
assert parser.parse_args(args).welcome_file == exp
def test_standalone_welcome(self, monkeypatch):
"""Test that the error raised in the standalone package is handled."""
monkeypatch.setattr(
config.pkg_resources,
'resource_filename',
Mock(side_effect=NotImplementedError)
)
assert config.PypiserverParserFactory(
parser_type='pypi-server'
).get_parser().parse_args([]).welcome_file == const.STANDALONE_WELCOME
@pytest.mark.parametrize('args, exp', (
([], None),
(['--cache-control', '12'], 12),
@ -486,6 +503,17 @@ class TestParser:
else:
assert parser.parse_args(args).welcome_file == exp
def test_standalone_welcome(self, monkeypatch):
"""Test that the error raised in the standalone package is handled."""
monkeypatch.setattr(
config.pkg_resources,
'resource_filename',
Mock(side_effect=NotImplementedError)
)
assert config.PypiserverParserFactory().get_parser().parse_args(
['run']
).welcome_file == const.STANDALONE_WELCOME
@pytest.mark.parametrize('args, exp', (
([], None),
(['--cache-control', '12'], 12),

@ -1,6 +1,7 @@
#! /usr/bin/env py.test
# -*- coding: utf-8 -*-
# TODO: write more tests for core!
import logging
import os
@ -9,8 +10,7 @@ import pytest
from pypiserver import __main__, core
## Enable logging to detect any problems with it
##
# Enable logging to detect any problems with it
__main__.init_logging(level=logging.NOTSET)
@ -57,18 +57,21 @@ files = [
("package-name-0.0.1.alpha.1.win-amd64-py3.2.exe", "package-name", "0.0.1.alpha.1"),
]
def _capitalize_ext(fpath):
f, e = os.path.splitext(fpath)
if e != '.whl':
e = e.upper()
return f + e
@pytest.mark.parametrize(("filename", "pkgname", "version"), files)
def test_guess_pkgname_and_version(filename, pkgname, version):
exp = (pkgname, version)
assert core.guess_pkgname_and_version(filename) == exp
assert core.guess_pkgname_and_version(_capitalize_ext(filename)) == exp
@pytest.mark.parametrize(("filename", "pkgname", "version"), files)
def test_guess_pkgname_and_version_asc(filename, pkgname, version):
exp = (pkgname, version)
@ -81,10 +84,13 @@ def test_listdir_bad_name(tmpdir):
res = list(core.listdir(tmpdir.strpath))
assert res == []
hashes = [
('sha256', 'e3b0c44298fc1c149afbf4c8996fb924'), # empty-sha256
('md5', 'd41d8cd98f00b204e9800998ecf8427e'), # empty-md5
('sha256', 'e3b0c44298fc1c149afbf4c8996fb924'), # empty-sha256
('md5', 'd41d8cd98f00b204e9800998ecf8427e'), # empty-md5
]
@pytest.mark.parametrize(("algo", "digest"), hashes)
def test_hashfile(tmpdir, algo, digest):
f = tmpdir.join("empty")