Skip to content

Commit

Permalink
Replace several uses of pylib with native Python. Refs devpi#930
Browse files Browse the repository at this point in the history
  • Loading branch information
fschulze authored and markmcclain committed Jan 8, 2024
1 parent 16dd205 commit 7727100
Show file tree
Hide file tree
Showing 28 changed files with 146 additions and 110 deletions.
3 changes: 2 additions & 1 deletion client/devpi/pypirc.py
@@ -1,14 +1,15 @@
"""
helpers for authenticating against info from .pypirc files.
"""
import iniconfig
import py


class Auth:
def __init__(self, path=None):
if path is None:
path = py.path.local._gethomedir().join(".pypirc")
self.ini = py.iniconfig.IniConfig(path)
self.ini = iniconfig.IniConfig(path)

def get_url_auth(self, secname):
section = self.ini[secname]
Expand Down
3 changes: 2 additions & 1 deletion client/devpi/upload.py
@@ -1,3 +1,4 @@
import iniconfig
import os
import sys
import py
Expand Down Expand Up @@ -557,7 +558,7 @@ def sdistformat(format):
def read_setupcfg(hub, path):
setup_cfg = path.join("setup.cfg")
if setup_cfg.exists():
cfg = py.iniconfig.IniConfig(setup_cfg)
cfg = iniconfig.IniConfig(setup_cfg)
hub.line("detected devpi:upload section in %s" % setup_cfg, bold=True)
return cfg.sections.get("devpi:upload", {})
return {}
1 change: 1 addition & 0 deletions client/setup.py
Expand Up @@ -30,6 +30,7 @@ def get_changelog():
"build",
"check-manifest>=0.28",
"devpi_common<4,>=3.6.0",
"iniconfig",
"pep517",
"pkginfo>=1.4.2",
"platformdirs",
Expand Down
31 changes: 21 additions & 10 deletions client/testing/conftest.py
@@ -1,6 +1,8 @@
from __future__ import print_function
from contextlib import closing
from devpi_common.metadata import parse_version
from io import BytesIO
from io import StringIO
import codecs
import os
import pytest
Expand All @@ -17,7 +19,12 @@

import subprocess

print_ = py.builtin.print_

# BBB for Python 2.7
try:
basestring
except NameError:
basestring = str


def pytest_addoption(parser):
Expand All @@ -33,7 +40,7 @@ def pytest_addoption(parser):

def print_info(*args, **kwargs):
kwargs.setdefault("file", sys.stderr)
return py.builtin.print_(*args, **kwargs)
return print(*args, **kwargs)


class PopenFactory:
Expand Down Expand Up @@ -336,7 +343,7 @@ def create_files(base, filedefs):
for key, value in filedefs.items():
if isinstance(value, dict):
create_files(base.ensure(key, dir=1), value)
elif isinstance(value, py.builtin._basestring):
elif isinstance(value, basestring):
s = textwrap.dedent(value)
base.join(key).write(s)

Expand Down Expand Up @@ -372,7 +379,7 @@ def initproj_(nameversion, filedefs=None, src_root=".", kind="setup.py"):
filedefs = {}
if not src_root:
src_root = "."
if isinstance(nameversion, py.builtin._basestring):
if isinstance(nameversion, basestring):
parts = nameversion.split(str("-"))
if len(parts) == 1:
parts.append("0.1")
Expand Down Expand Up @@ -494,7 +501,7 @@ def resultlog(self, name="pkg1", version=None,
res = ReprResultLog("/%s-%s.tgz" % (name, version),
md5 or self.md5(),
**getplatforminfo())
out = py.io.TextIO()
out = StringIO()
for i in range(passed):
out.write(". test_pass.py::test_pass%s\n" %i)
for i in range(failed):
Expand Down Expand Up @@ -577,11 +584,11 @@ def out_devpi_func(*args, **kwargs):
out, err = cap.reset()
del cap
except:
print_(out)
print_(err)
print(out)
print(err)
raise
print_(out)
print_(err, file=sys.stderr)
print(out)
print(err, file=sys.stderr)
return RunResult(ret, out.split("\n"), None, time.time()-now)
return out_devpi_func

Expand Down Expand Up @@ -702,7 +709,11 @@ class args:
verbose = False
settrusted = False

out = py.io.TextIO()
# BBB for Python 2.7
if sys.version_info < (3,):
out = BytesIO()
else:
out = StringIO()
hub = Hub(args, file=out)

def _getmatcher():
Expand Down
2 changes: 0 additions & 2 deletions client/testing/test_functional.py
@@ -1,6 +1,5 @@
from io import BytesIO
import json
import py
import pytest
import requests
import tarfile
Expand Down Expand Up @@ -231,7 +230,6 @@ def get_mirror_whitelist(self, code=200, indexname=None):

def upload_file_pypi(self, basename, content,
name=None, version=None):
assert py.builtin._isbytes(content)
pkg = self.tmpdir.join(basename)
pkg.write_binary(content)
self.devpi('upload', pkg.strpath)
Expand Down
9 changes: 7 additions & 2 deletions client/testing/test_login.py
@@ -1,8 +1,9 @@
from devpi.main import Hub, hookimpl
from devpi.login import main
from functools import partial
import py
from io import BytesIO, StringIO
import pytest
import sys


class GetPassException(Exception):
Expand All @@ -24,7 +25,11 @@ class args:

@pytest.fixture
def hub(args):
out = py.io.TextIO()
# BBB for Python 2.7
if sys.version_info < (3,):
out = BytesIO()
else:
out = StringIO()
hub = Hub(args, file=out)
hub._out = out
return hub
Expand Down
3 changes: 3 additions & 0 deletions client/testing/test_push.py
Expand Up @@ -237,6 +237,9 @@ def test_derive_token_invalid_token(prefix):
msgs = []

class MockHub:
def info(self, msg):
msgs.append(msg)

def warn(self, msg):
msgs.append(msg)
hub = MockHub()
Expand Down
14 changes: 11 additions & 3 deletions common/devpi_common/archive.py
@@ -1,6 +1,7 @@
"""
remotely based on some code from https://pypi.org/project/Archive/0.3/
"""
from io import BytesIO
import os
import tarfile
import zipfile
Expand Down Expand Up @@ -131,7 +132,7 @@ def extract(self, to_path='', safe=False):

def zip_dir(basedir, dest=None):
if dest is None:
f = py.io.BytesIO()
f = BytesIO()
else:
f = open(str(dest), "wb")
zip = zipfile.ZipFile(f, "w")
Expand All @@ -156,13 +157,20 @@ def _writezip(zip, basedir):


def zip_dict(contentdict):
f = py.io.BytesIO()
f = BytesIO()
zip = zipfile.ZipFile(f, "w")
_writezip_fromdict(zip, contentdict)
zip.close()
return f.getvalue()


# BBB for Python 2.7
try:
unicode
except NameError:
unicode = str


def _writezip_fromdict(zip, contentdict, prefixes=()):
for name, val in contentdict.items():
if isinstance(val, dict):
Expand All @@ -175,6 +183,6 @@ def _writezip_fromdict(zip, contentdict, prefixes=()):
_writezip_fromdict(zip, val, newprefixes)
else:
path = os.sep.join(prefixes + (name,))
if py.builtin._istext(val):
if isinstance(val, unicode):
val = val.encode("ascii")
zip.writestr(path, val)
10 changes: 8 additions & 2 deletions common/devpi_common/metadata.py
@@ -1,6 +1,5 @@
import posixpath
import re
import py
from packaging.version import parse as parse_version
from packaging.requirements import Requirement as BaseRequirement
from .types import CompareMixin
Expand Down Expand Up @@ -151,13 +150,20 @@ def is_prerelease(self):
return False


# BBB for Python 2.7
try:
basestring
except NameError:
basestring = str


class BasenameMeta(CompareMixin):
def __init__(self, obj, sameproject=False):
self.obj = obj
# none of the below should be done lazily, as devpi_server.mirror
# essentially uses this to validate parsed links
basename = getattr(obj, "basename", obj)
if not isinstance(basename, py.builtin._basestring):
if not isinstance(basename, basestring):
raise ValueError("need object with basename attribute")
assert "/" not in basename, (obj, basename)
name, version, ext = splitbasename(basename, checkarch=False)
Expand Down
18 changes: 15 additions & 3 deletions common/devpi_common/types.py
Expand Up @@ -3,7 +3,6 @@
from types import FunctionType
import hashlib
import operator
import py


# re-introduced for 2.0 series but not used anymore
Expand Down Expand Up @@ -134,10 +133,23 @@ def discover_and_call(self, obj, dec):
assert newfunc == func


# BBB for Python 2.7
try:
basestring
except NameError:
basestring = str
try:
unicode
except NameError:
unicode = str


def ensure_unicode(x):
if py.builtin._istext(x):
if isinstance(x, unicode):
return x
return py.builtin._totext(x, "utf8")
if not isinstance(x, basestring):
return unicode(x)
return x.decode("utf8")


def parse_hash_spec(fragment):
Expand Down
7 changes: 4 additions & 3 deletions common/testing/test_archive.py
Expand Up @@ -2,6 +2,7 @@
from devpi_common.archive import UnsupportedArchive
from devpi_common.archive import zip_dict
from devpi_common.archive import zip_dir
from io import BytesIO
from subprocess import Popen, PIPE
import py
import pytest
Expand Down Expand Up @@ -74,7 +75,7 @@ def test_namelist(self, archive):

def test_unknown_archive(self):
with pytest.raises(UnsupportedArchive):
Archive(py.io.BytesIO(b"123"))
Archive(BytesIO(b"123"))

def test_read(self, archive):
assert archive.read("1") == b"file1"
Expand Down Expand Up @@ -109,7 +110,7 @@ def test_tarfile_outofbound(tmpdir):

def test_zip_dict(tmpdir):
content = zip_dict({"one": {"nested": "1"}, "two": {}})
with Archive(py.io.BytesIO(content)) as archive:
with Archive(BytesIO(content)) as archive:
archive.extract(tmpdir)
assert tmpdir.join("one", "nested").read() == "1"
assert tmpdir.join("two").isdir()
Expand All @@ -128,7 +129,7 @@ def test_zip_dir(tmpdir):
assert newdest.join("sub", "subfile").isfile()

newdest.remove()
with Archive(py.io.BytesIO(zip_dir(source))) as archive:
with Archive(BytesIO(zip_dir(source))) as archive:
archive.extract(newdest)
assert newdest.join("file").isfile()
assert newdest.join("sub", "subfile").isfile()
12 changes: 5 additions & 7 deletions server/devpi_server/auth.py
@@ -1,7 +1,6 @@
import base64
import hashlib
import itsdangerous
import py
import secrets
from .log import threadlog
from passlib.context import CryptContext
Expand Down Expand Up @@ -132,7 +131,7 @@ def new_proxy_auth(self, username, password, request=None):
username,
result.get("groups", []),
result.get("from_user_object", False)])
assert py.builtin._totext(pseudopass, 'ascii')
assert pseudopass.encode('ascii')
return {"password": pseudopass,
"expiration": self.LOGIN_EXPIRATION}

Expand All @@ -141,11 +140,11 @@ def getpwhash(password, salt):
hash = hashlib.sha256()
hash.update(salt.encode("ascii"))
hash.update(password.encode("utf-8"))
return py.builtin._totext(hash.hexdigest())
return hash.hexdigest()


def newsalt():
return py.builtin._totext(base64.b64encode(secrets.token_bytes(16)), "ascii")
return base64.b64encode(secrets.token_bytes(16)).decode("ascii")


class DevpiHandler(MinimalHandler):
Expand Down Expand Up @@ -186,10 +185,9 @@ def verify_and_update_password_hash(password, hash, salt=None):
if salt is not None:
hash = "%s:%s" % (salt, hash)
(valid, newhash) = pwd_context.verify_and_update(password, hash)
if newhash:
newhash = py.builtin._totext(newhash)
assert newhash is None or isinstance(newhash, str)
return (valid, newhash)


def hash_password(password):
return py.builtin._totext(pwd_context.hash(password))
return pwd_context.hash(password)
5 changes: 2 additions & 3 deletions server/devpi_server/filestore.py
Expand Up @@ -6,7 +6,6 @@
import hashlib
import mimetypes
from wsgiref.handlers import format_date_time
import py
import re
from devpi_common.metadata import splitbasename
from devpi_common.types import parse_hash_spec
Expand Down Expand Up @@ -87,8 +86,8 @@ def key_from_link(keyfs, link, user, index):


def unicode_if_bytes(val):
if isinstance(val, py.builtin.bytes):
val = py.builtin._totext(val)
if isinstance(val, bytes):
return val.decode('ascii')
return val


Expand Down

0 comments on commit 7727100

Please sign in to comment.