Skip to content

Commit

Permalink
Fixes #10 - do not require a setup.py
Browse files Browse the repository at this point in the history
If setup.cfg or pyproject.toml present, use a minimal setup.py without
creating a file on disk.
  • Loading branch information
chrisjbillington committed Aug 6, 2021
1 parent 889c409 commit b8ae4b5
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
23 changes: 11 additions & 12 deletions setuptools_conda/__main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
from subprocess import call, check_output
import shlex
import sys
import argparse
import textwrap
Expand Down Expand Up @@ -182,7 +183,7 @@ def main():
)

def run_conda_cmd(cmd, **kwargs):
print('[running]:', ' '.join(cmd))
print('[running]:', *[shlex.quote(arg) for arg in cmd])
# Shell=True is necessary on Windows for calls to conda, otherwise we get
# mysterious breakage. But shell=True with a list of args totally changes this
# function on unix so we avoid it:
Expand All @@ -191,15 +192,8 @@ def run_conda_cmd(cmd, **kwargs):
sys.exit(rc)
return rc

def run(cmd, **kwargs):
print('[running]:', ' '.join(cmd))
rc = call(cmd, **kwargs)
if rc:
sys.exit(rc)
return rc

def get_output(cmd, **kwargs):
print('[running]:', ' '.join(cmd))
print('[running]:', *[shlex.quote(arg) for arg in cmd])
return check_output(cmd, shell=WINDOWS, **kwargs).decode('utf8').strip()

def getargvalue(argname, args):
Expand All @@ -220,7 +214,7 @@ def getargvalue(argname, args):
return arg.split(f'--{argname}=', 1)[1]

def get_project_name(proj):
return get_output([sys.executable, 'setup.py', '--name'], cwd=str(proj))
return get_output([sys.executable, *setup_py(proj), '--name'], cwd=str(proj))

def get_build_requires(proj, args):
arg = 'setup-requires'
Expand Down Expand Up @@ -253,7 +247,7 @@ def get_run_requires(proj, args, name):
if requires is not None:
print("Using run requirements from [dist_conda]/setup_requires")
return requires
get_output([sys.executable, 'setup.py', 'egg_info'], cwd=str(proj))
get_output([sys.executable, *setup_py(proj), 'egg_info'], cwd=str(proj))
requires_file = Path(proj, f'{name.replace("-", "_")}.egg-info', 'requires.txt')
requires = requires_file.read_text().splitlines()
# Ignore extras sections:
Expand Down Expand Up @@ -336,6 +330,8 @@ def remove_projects(requirements, projects):
evaluate_requirements,
condify_requirement,
split,
setup_py,
run,
)

all_build_requires = []
Expand Down Expand Up @@ -370,7 +366,10 @@ def remove_projects(requirements, projects):
print("\nBuilding...")
proj = Path(args.projects[0])
sys.exit(
run([sys.executable, 'setup.py', 'dist_conda'] + setup_args, cwd=str(proj))
run(
[sys.executable, *setup_py(proj), 'dist_conda'] + setup_args,
cwd=str(proj),
)
)

print("\nGetting run requirements...")
Expand Down
43 changes: 38 additions & 5 deletions setuptools_conda/setuptools_conda.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import sys
import os
import shutil
from subprocess import check_call
from subprocess import call
import shlex
from setuptools import Command
import json
from textwrap import dedent
Expand Down Expand Up @@ -36,6 +37,38 @@
}


# Command line args that can be used in place of "setup.py" for projects that lack a
# setup.py, runs a minimal setup.py similar to what pip does for projects with no
# setup.py.
_SETUP_PY_STUB = [
"-c",
'import sys, setuptools; sys.argv[0] = __file__ = "setup.py"; setuptools.setup()',
]


def run(cmd, **kwargs):
print('[running]:', *[shlex.quote(arg) for arg in cmd])
rc = call(cmd, **kwargs)
if rc:
sys.exit(rc)
return rc


def setup_py(project_dir):
"""Returns a list of command line arguments to be used in place of ["setup.py"]. If
setup.py exists, then this is just ["setup.py"]. Otherwise, if setup.cfg or
pyproject.toml exists, returns args that pass a code snippet to Python with "-c" to
execute a minimal setup.py calling setuptools.setup(). If none of pyproject.toml,
setup.cfg, or setup.py exists, raises an exception."""
if Path(project_dir, 'setup.py').exists():
return ['setup.py']
elif any(Path(project_dir, s).exists() for s in ['setup.cfg', 'pyproject.toml']):
return _SETUP_PY_STUB
msg = f"""{project_dir} does not look like a python project directory: contains no
setup.py, setup.cfg, or pyproject.toml"""
raise RuntimeError(' '.join(msg.split))


# Couldn't figure out how to use PyYAML to produce output looking like conda recipes are
# usually formatted:
def yaml_lines(obj, indent=2):
Expand Down Expand Up @@ -542,19 +575,19 @@ def run(self):
self.BUILD_DIR,
f'{self.NAME}=={self.VERSION}',
]
check_call(cmd)
run(cmd)

else:
# Run sdist or bdist_wheel to make a source tarball or wheel in the recipe
# dir:
cmd = [sys.executable, 'setup.py']
cmd = [sys.executable, *setup_py('.')]
if self.from_wheel:
cmd += ['bdist_wheel']
else:
cmd += ['sdist', '--formats=gztar']
cmd += ['--dist-dir=' + self.BUILD_DIR]

check_call(cmd)
run(cmd)

if self.from_wheel or self.from_downloaded_wheel:
dist = [p for p in os.listdir(self.BUILD_DIR) if p.endswith('.whl')][0]
Expand Down Expand Up @@ -627,7 +660,7 @@ def run(self):

environ = os.environ.copy()
environ['CONDA_BLD_PATH'] = os.path.abspath(self.CONDA_BLD_PATH)
check_call(
run(
['conda-build', '--no-test', self.RECIPE_DIR] + channel_args, env=environ,
)

Expand Down

0 comments on commit b8ae4b5

Please sign in to comment.