Module bussilab.installers
Install and build selected external scientific packages.
At present, the functions in this module support Google Colab only.
Functions
def build_viennarna(version: str = '2.7.2-patch2',
output_directory: str | os.PathLike | None = None,
jobs: int | None = None,
verbose: bool = True) ‑> Tuple[pathlib.Path, pathlib.Path]-
Expand source code
def build_viennarna( version: str = _DEFAULT_VIENNARNA_VERSION, output_directory: Optional[PathLike] = None, jobs: Optional[int] = None, verbose: bool = True, ) -> Tuple[Path, Path]: """ Build a patched ViennaRNA archive in Google Colab. The archive and its complete build log receive the same basename. Parameters ---------- version Patched release identifier, for example ``"2.7.2-patch2"``. output_directory Destination for the ``.tgz`` and ``.log`` files. The default is the current working directory. jobs Number of parallel make jobs. The default is at most two, to avoid excessive memory use while compiling the SWIG wrapper. verbose Print progress information and the final elapsed time. Returns ------- archive, log Paths of the generated archive and build log. """ _require_colab() upstream, _ = _parse_viennarna_version(version) if output_directory is None: output_path = Path.cwd() else: output_path = Path(output_directory).expanduser().resolve() output_path.mkdir(parents=True, exist_ok=True) asset_name = _viennarna_asset_name(version) archive = output_path / asset_name log = archive.with_suffix(".log") if jobs is None: jobs = min(2, os.cpu_count() or 1) if jobs < 1: raise ValueError("jobs must be a positive integer.") prefix = Path("/content/ViennaRNA") build_directory = Path("/content/build-viennarna") patch_files = _viennarna_patch_files(version) source_url = ( "https://github.com/ViennaRNA/ViennaRNA/releases/download/" "v{version}/ViennaRNA-{version}.tar.gz" ).format(version=upstream) patch_base_url = ( "https://raw.githubusercontent.com/" "bussilab/ViennaRNA-patches/main" ) script = r""" set -euo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y \ autoconf \ automake \ build-essential \ curl \ libtool \ pkg-config \ python3-dev \ wget python -m pip install --upgrade "swig>=4.3.0" PYTHON_EXE="$(python -c 'import sys; print(sys.executable)')" export PYTHON="$PYTHON_EXE" echo "Build started: $(date --iso-8601=seconds)" echo "Python executable: $PYTHON" python --version swig -version echo "Source URL: $SOURCE_URL" echo "Patch files: $PATCH_FILES" echo "Prefix: $PREFIX" echo "Parallel jobs: $JOBS" rm -rf "$BUILD_DIRECTORY" "$PREFIX" "$ARCHIVE" mkdir -p "$BUILD_DIRECTORY" cd "$BUILD_DIRECTORY" wget -O "ViennaRNA-${UPSTREAM}.tar.gz" "$SOURCE_URL" tar -xzf "ViennaRNA-${UPSTREAM}.tar.gz" read -r -a PATCH_FILE_LIST <<< "$PATCH_FILES" for patch_file in "${PATCH_FILE_LIST[@]}"; do wget -O "$patch_file" "$PATCH_BASE_URL/$patch_file" done cd "ViennaRNA-${UPSTREAM}" for patch_file in "${PATCH_FILE_LIST[@]}"; do patch -p1 < "../${patch_file}" done ./configure \ PYTHON="$PYTHON" \ --prefix="$PREFIX" \ --without-doc \ --with-python make -j"$JOBS" make install find "$PREFIX" \( -name 'RNA.py' -o -name '_RNA*.so' \) -print cd "$(dirname "$PREFIX")" tar -czf "$ARCHIVE" "$(basename "$PREFIX")" echo "Created archive:" ls -lh "$ARCHIVE" echo "Build completed: $(date --iso-8601=seconds)" """ environment = os.environ.copy() environment.update( { "UPSTREAM": upstream, "PATCH_FILES": " ".join(patch_files), "SOURCE_URL": source_url, "PATCH_BASE_URL": patch_base_url, "PREFIX": str(prefix), "BUILD_DIRECTORY": str(build_directory), "ARCHIVE": str(archive), "JOBS": str(jobs), } ) if verbose: print("Building:", asset_name) print("Log:", log) started = time.monotonic() with log.open("w", encoding="utf-8") as log_handle: process = subprocess.Popen( ["bash", "-c", script], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=environment, text=True, bufsize=1, ) assert process.stdout is not None for line in process.stdout: log_handle.write(line) log_handle.flush() if verbose: print(line, end="") return_code = process.wait() elapsed = time.monotonic() - started with log.open("a", encoding="utf-8") as log_handle: log_handle.write( "Elapsed time: {:.1f} seconds ({:.2f} minutes)\n".format( elapsed, elapsed / 60.0, ) ) if verbose: print( "Elapsed time: {:.1f} seconds ({:.2f} minutes)".format( elapsed, elapsed / 60.0, ) ) if return_code != 0: raise RuntimeError( "ViennaRNA build failed with exit status {}. " "See the complete log at {}.".format(return_code, log) ) if not archive.is_file(): raise RuntimeError( "The ViennaRNA build completed without producing {}".format( archive ) ) return archive, logBuild a patched ViennaRNA archive in Google Colab.
The archive and its complete build log receive the same basename.
Parameters
version- Patched release identifier, for example
"2.7.2-patch2". output_directory- Destination for the
.tgzand.logfiles. The default is the current working directory. jobs- Number of parallel make jobs. The default is at most two, to avoid excessive memory use while compiling the SWIG wrapper.
verbose- Print progress information and the final elapsed time.
Returns
archive, log- Paths of the generated archive and build log.
def install_viennarna(version: str = '2.7.2-patch2',
prefix: str | os.PathLike | None = None,
force: bool = False,
verbose: bool = True)-
Expand source code
def install_viennarna( version: str = _DEFAULT_VIENNARNA_VERSION, prefix: Optional[PathLike] = None, force: bool = False, verbose: bool = True, ): """ Install a precompiled patched ViennaRNA distribution in Google Colab. Parameters ---------- version Patched release identifier, for example ``"2.7.2-patch2"``. prefix Installation directory. The default is ``ViennaRNA`` below the current working directory. force Download and extract the archive again if the installation directory already exists. verbose Print progress information. Returns ------- module The imported :mod:`RNA` module. Raises ------ RuntimeError If the function is not running in Google Colab, the archive is malformed, or the installed module cannot be imported. """ _require_colab() _parse_viennarna_version(version) if prefix is None: prefix_path = Path.cwd() / "ViennaRNA" else: prefix_path = Path(prefix).expanduser().resolve() if prefix_path.name != "ViennaRNA": raise ValueError( "The installation prefix must end in 'ViennaRNA', because " "the release archive contains that top-level directory." ) archive_name = _viennarna_asset_name(version) url = _viennarna_release_url(version) if verbose: print("ViennaRNA asset:", archive_name) print("Installation prefix:", prefix_path) if force and prefix_path.exists(): shutil.rmtree(str(prefix_path)) if not prefix_path.exists(): prefix_path.parent.mkdir(parents=True, exist_ok=True) with tempfile.TemporaryDirectory( prefix="bussilab-viennarna-" ) as temporary_directory: archive = Path(temporary_directory) / archive_name if verbose: print("Downloading:", url) try: urllib.request.urlretrieve(url, str(archive)) except Exception as exc: raise RuntimeError( "Could not download the ViennaRNA binary archive.\n" "Expected asset: {}\n" "URL: {}\n" "The current Colab runtime may no longer match an " "available release.".format(archive_name, url) ) from exc _safe_extract_viennarna( archive, prefix_path.parent, ) binary_directory = prefix_path / "bin" library_directory = prefix_path / "lib" python_directory = _viennarna_python_directory(prefix_path) if not python_directory.is_dir(): raise RuntimeError( "ViennaRNA was extracted, but its Python package directory " "was not found: {}".format(python_directory) ) _prepend_environment_path("PATH", binary_directory) _prepend_environment_path("LD_LIBRARY_PATH", library_directory) site.addsitedir(str(python_directory)) importlib.invalidate_caches() # Ensure that a failed or previous import does not hide the installation # that was just selected. sys.modules.pop("RNA", None) try: rna = importlib.import_module("RNA") except Exception as exc: raise RuntimeError( "ViennaRNA was installed at {}, but importing RNA failed.".format( prefix_path ) ) from exc if verbose: print( "ViennaRNA version:", getattr(rna, "__version__", "unknown"), ) print("Installation successful.") return rnaInstall a precompiled patched ViennaRNA distribution in Google Colab.
Parameters
version- Patched release identifier, for example
"2.7.2-patch2". prefix- Installation directory. The default is
ViennaRNAbelow the current working directory. force- Download and extract the archive again if the installation directory already exists.
verbose- Print progress information.
Returns
module- The imported :mod:
RNAmodule.
Raises
RuntimeError- If the function is not running in Google Colab, the archive is malformed, or the installed module cannot be imported.