import os
import re
import shutil
import subprocess
import sys
import pytest
SETUP_TEMPLATE = """\
from setuptools import setup
setup(
name='{name}',
version='{version}',
description='{name}',
packages=['{pkgdirname}'],
install_requires={pkgdeps},
entry_points={{
'console_scripts': [
'{pkgdirname}={pkgdirname}:main'
]
}}
)
"""
# All packages generated via generate_pip_package will have the functions below
INIT_TEMPLATE = """\
def main():
print('This is {name}')
def hello(actor='world'):
print('Hello {{}}! This is {name}'.format(actor))
"""
HTML_TEMPLATE = """\
Links for {name}
{name}-{version}.tar.gz
"""
# Creates a simple python source distribution and copies this into a specified
# directory which is to serve as a mock python repository
#
# Args:
# tmpdir (str): Directory in which the source files will be created
# pypi (str): Directory serving as a mock python repository
# name (str): The name of the package to be created
# version (str): The version of the package to be created
#
# Returns:
# None
#
def generate_pip_package(tmpdir, pypi, name, version="0.1", dependencies=None):
if dependencies is None:
dependencies = []
# check if package already exists in pypi
pypi_package = os.path.join(pypi, re.sub("[^0-9a-zA-Z]+", "-", name))
if os.path.exists(pypi_package):
return
# create the package source files in tmpdir resulting in a directory
# tree resembling the following structure:
#
# tmpdir
# |-- setup.py
# `-- package
# `-- __init__.py
#
setup_file = os.path.join(tmpdir, "setup.py")
pkgdirname = re.sub("[^0-9a-zA-Z]+", "", name)
with open(setup_file, "w") as f:
f.write(SETUP_TEMPLATE.format(name=name, version=version, pkgdirname=pkgdirname, pkgdeps=dependencies))
os.chmod(setup_file, 0o755)
package = os.path.join(tmpdir, pkgdirname)
os.makedirs(package)
main_file = os.path.join(package, "__init__.py")
with open(main_file, "w") as f:
f.write(INIT_TEMPLATE.format(name=name))
os.chmod(main_file, 0o644)
# Run sdist with a fresh process
subprocess.run([sys.executable, "setup.py", "sdist"], cwd=tmpdir, check=True)
# create directory for this package in pypi resulting in a directory
# tree resembling the following structure:
#
# pypi
# `-- pypi_package
# |-- index.html
# `-- foo-0.1.tar.gz
#
os.makedirs(pypi_package)
# add an index html page
index_html = os.path.join(pypi_package, "index.html")
with open(index_html, "w") as f:
f.write(HTML_TEMPLATE.format(name=name, version=version))
# copy generated tarfile to pypi package
dist_dir = os.path.join(tmpdir, "dist")
for tar in os.listdir(dist_dir):
tarpath = os.path.join(dist_dir, tar)
shutil.copy(tarpath, pypi_package)
@pytest.fixture
def setup_pypi_repo(tmpdir):
def create_pkgdir(package):
pkgdirname = re.sub("[^0-9a-zA-Z]+", "", package)
pkgdir = os.path.join(str(tmpdir), pkgdirname)
os.makedirs(pkgdir)
return pkgdir
def add_packages(packages, pypi_repo):
for package, dependencies in packages.items():
pkgdir = create_pkgdir(package)
generate_pip_package(pkgdir, pypi_repo, package, dependencies=list(dependencies.keys()))
for dependency, dependency_dependencies in dependencies.items():
add_packages({dependency: dependency_dependencies}, pypi_repo)
return add_packages