Skip to content

Commit

Permalink
REL: add module install.py
Browse files Browse the repository at this point in the history
  • Loading branch information
johnyf committed Dec 10, 2023
1 parent 5b8b88a commit 93823b1
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include CHANGES.md
include AUTHORS
include requirements.txt
include download.py
include install.py
include tests/README.md
include tests/pytest.ini
include tests/inspect_cython_signatures.py
Expand Down
145 changes: 145 additions & 0 deletions install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
"""Install `dd`, including C extensions wrapping CUDD.
Running this file will attempt to download
the source code of CUDD from the internet.
To run this file:
```shell
python install.py
```
This script is a shorthand for defining environment
variables when running `pip install .` for the
source code of the package `dd`.
"""
import argparse as _arg
import os
import re
import shlex as _sh
import subprocess as _sbp
import tempfile as _tmp

try:
import cython
except ImportError as error:
cython = None
_cython_error = error


def _main(
) -> None:
"""Entry point."""
args, unknown_args = _parse_args()
_assert_cython()
if not _ask_about_downloading(args):
print('Exiting without installing.')
return
with _tmp.NamedTemporaryFile('wt') as fd:
_install_using_pip(fd, unknown_args)


def _install_using_pip(
fd,
unknown_args:
list[str]
) -> None:
"""Install `dd` using `pip`.
The installation includes `dd.cudd`.
Writes a temporary file to
the file system, used as requirements
file for `pip`.
"""
env = dict(os.environ)
env.update(dict(
DD_FETCH='1',
DD_CUDD='1',
DD_CUDD_ZDD='1',
DD_CUDD_ADD='1'))
cmd_line = f'''
pip install
.
-vvv
--use-pep517
--no-build-isolation
'''
cmd = _sh.split(cmd_line)
cmd.extend(unknown_args)
_sbp.run(cmd, env=env)


def _parse_args(
) -> tuple[
_arg.Namespace,
list[str]]:
"""Return command-line arguments."""
parser = _arg.ArgumentParser(description='''
Install package `dd` from its source,
including the modules `dd.cudd`, `dd.cudd_zdd`,
and `dd.cudd_add` (which are C extensions
that need `cython` and `gcc` to be compiled).
Attempts to download the source code of
CUDD from the internet.
Unknown arguments are passed to `pip install`.
''')
parser.add_argument(
'-y', '--yes',
action='store_true',
help='go ahead and download CUDD '
'source code tarball '
'(checking its SHA hash) '
'without stopping and '
'prompting the user '
'for whether to do so.')
args, unknown_args = parser.parse_known_args()
return args, unknown_args


def _assert_cython(
) -> None:
"""Assert that `cython` is installed.
Raise `ImportError` if not.
"""
if cython is not None:
return
raise ImportError(
'Installing `dd.cudd` requires the '
'Python package `cython`, which can '
'be installed from '
'the Python Package Index (PyPI) '
'by running `pip install cython`. '
'For installing `dd` with only '
'its pure-Python modules, '
'running `pip install .` suffices, '
'no need to run `python install.py`.'
) from _cython_error


def _ask_about_downloading(
args:
_arg.Namespace
) -> bool:
"""Ask whether to download CUDD tarball."""
if args.yes:
return True
choice = input(
'This script downloads '
'CUDD sources from the internet '
'(details in the file `download.py`).\n'
'Proceed?\n'
'(answers: yes / no)\n')
match choice:
case 'yes' | 'no':
return (choice == 'yes')
raise ValueError(
'Expected `yes` or '
'`no` as input.')


if __name__ == '__main__':
_main()

0 comments on commit 93823b1

Please sign in to comment.