BETSE 1.1.1 (Nicer Nestor) released. Significant changes include: * Dependencies bumped: * setuptools >= 38.2.0. The same version of setuptools required by BETSEE is now required by BETSE, ensuring parity between the two codebases and avoiding painful dependency conflicts. For uniformity, this dependency is repeated in both the top-level "pyproject.toml" and "tox.ini" configuration files. * Issues resolved: * pypa/pip#6163 and pypa/pip#6434. This commit circumvents a countably infinite number of issues introduced by both pip 19.0.0 and 19.1.0 - all pertaining to PEP 517 and 518, which is to say "pyproject.toml". The mere existence of a "pyproject.toml" file fundamentally breaks pip in inexplicable and horrifying ways: a significantly worse state of affairs than the pre-PEP 517 and 518 days of setuptools yore. Say what you will of setuptools ("...so much hate"), but at least it sorta worked. The same cannot be said of recent pip versions, which absolutely do not work whatsoever. "Die, pip! Die!" Specifically: * pypa/pip#6163 resolved. All files and subdirectories of the project directory containing the top-level "setup.py" script are now safely registered to be importable modules and packages. Technically, this should not be needed. The current build framework (e.g., pip, setuptools) should implicitly guarantee this to be the case. Indeed, the obsolete setuptools-based "easy_install" script does so. Sadly, pip >= 19.0.0 fails to do so for projects defining a top-level "pyproject.toml" file. Although upstream purports to have resolved this, the most recent stable release of pip continues to suffer this. This is suffering. * pypa/pip#6434 resolved. The top-level "pyproject.toml" file now explicitly declares a default value for the "build-backend" key. Doing so safeguards backward compatibility with pip 19.1.0, which erroneously violated PEP 51{7,8} by failing to fallback to a sane default value in the absence of this key. If this key is left undeclared, pip 19.1.0 fails on attempting to perform an editable (i.e., developer-specific) installation of this project. * tox-dev/tox#765 resolved. "tox" bundles an obsolete version of "virtualenv" itself bundling obsolete versions of both "pip" and "setuptools", which obstructs sanity. Our "tox.ini" configuration resolves this issue by instructing "tox" to manually update both "setuptools" and "virtualenv" to their most recent stable releases. * Entry points (i.e., wrapper scripts) resolved. Specifically: * Windows-specific entry points installable. Entry points yet again install as expected under non-WSL Windows variants (i.e., vanilla, Cygwin Windows). * Dependency entry points preserved. Long-standing issues with a custom monkey patch applied by our top-level "setup.py" script at setuptools-based application installation time have now been resolved. Previously, this patch globally applied to all dependencies installed by "easy_install" (but neither "pip" nor "conda", which fortuitously remain unaffected). Now, this monkey patch only locally applies to this project and downstream consumers of this project (e.g., BETSEE). * Setuptools validation relaxed. Validation of the currently installed version of setuptools has been relaxed to accept recent non-standard version strings (e.g., "41.6.0.post20191029"). * Testing improved: * GitLab CI + "tox". Specifically: * Rewrote the top-level ".gitlab-ci.yml" file from the ground up to test both installation and runtime on all supported Python 3.x versions (rather than runtime on the most recent stable Python 3.x version) and leverage industry standards, including: * A test matrix exercising all official Python version-tagged Docker images rather than a single unofficial Python version-agnostic Docker image (i.e., "continuumio/anaconda3"). Non-slim images are currently preferred to slim variants with names suffixed by "-slim" (e.g., "python:3.8-slim"), as the latter fail to include C and C++ compilers required to build and install wheels for Python packages both lacking official wheels and containing mandatory C extensions (e.g., "psutil"). * The Python-specific "pip" and Debian-based "apt" package managers rather than the Anaconda-based "conda" package manager. An initial "apt" package cache is now explicitly created before attempting to install system-wide packages requiring this cache. * The high-level "tox" wrapper rather than the lower-level "pytest" test harness. * The standard "virtualenv" package rather than GitLab-CI internals for isolating test results between different Python 3.x versions. * YAML anchor-based key mapping interpolation rather than external scripts for resolving DRY between different Python 3.x versions. * Defined a top-level "tox.ini" configuration file, installing all optional runtime dependencies to maximize test coverage. * Removed the top-level "requirements-pip.txt" file, which was frankly superfluous. * Documentation revised: * Installation instructions rewritten. These instructions have been revised from the ground up for simplicity, consistency, and with an increased emphasis on the standard pip ecosystem rather than the increasingly non-standard Anaconda ecosystem. Specifically: * "README.rst" truncated. The top-level "README.rst" file now provides only minimal instructions for installing BETSE under the two most popular platform-agnostic package managers: pip (recommeded) and Anaconda. * "INSTALL.rst" added. A new "doc/rst/INSTALL.rst" file providing verbose platform-specific instructions for installing BETSE under each supported platform (i.e., Linux, macOS, Windows) as well as Git-based development and Docker-based containerization has now been added. * "INSTALL.md" obsoleted. The "doc/md/INSTALL.md" file has been removed in favor of the new "doc/rst/INSTALL.rst" file, whose underlying reStructuredText is significantly easier to maintain. * The sub-level "doc/rst/INSTALL.rst" file * pip-based editable installation. The top-level "README.rst" file now advises developers to leverage pip rather than setuptools when performing an editable installation of this project. * "setup.cfg"-based PyPI documentation. The top-level "setup.cfg" file now transcludes the contents of the top-level "README.rst" file, a substantial improvement over the prior code-based approach strewn throughout the codebase (e.g., "setup.py", "betse_setup.buputil"). * Extraneous files removed. All irrelevant image masks have now been pruned from the "doc/yaml/paper" subdirectory. Doing so reduces the filesize of release tarballs, minimizes the maintenance burden, and presumably eliminates bitrot. * Git maintenance: * pip directories untracked. All top-level pip-specific temporary directories (e.g., "pip-wheel-metadata") are now ignored with respect to Git tracking. * API generalized: * Renamed: * The "betse.util.path.command" subpackage to "betse.util.os.command". * The "betse.util.test.tests" submodule to "betse.util.test.tsttest". * Generalized the top-level py.test-specific "conftest.py" plugin: * Defined a new private _clean_imports() function to perform the following when the active Python interpreter is isolated to a venv (e.g., due to being exercised by "tox"): 1. If the top-level directory for this project is listed in the global list of all import directories (i.e., "sys.path"), remove this directory from this list. Doing so prevents this test session from accidentally importing from modules not isolated to this venv, including this project being tested. 2. If the first directory on this list is not isolated to this venv, raise an exception. This condition implies that modules will be imported from outside this venv, which entirely defeats the purpose of isolating tests with "tox" to a venv. 3. If the top-level "betse" package is not isolated to this venv, raise an exception. This condition implies that this project has been imported from outside this venv. * Refactored the pytest_sessionstart() hook run at test session startup to sanitize import directories by calling the newly defined _clean_imports() function. Specifically, if this session is isolated to a venv, this hook now removes all import directories not isolated to this venv from "sys.path" -- as required for sane "tox"-based testing. (See above.) * Generalized the top-level "setup.py" script: * Called the newly defined betse_setup.buputil.die_unless_setuptools_version_at_least() validator to ensure the currently installed version of setuptools satisfies all installation-time requirements. * Added a new "test" key-value pair to the setuptools-specific "extras_require" dictionary, enabling "tox" to install all mandatory testing requirements of this application without duplicating those requirements in the top-level "tox.ini" file. * Generalized the "betse.exceptions" submodule: * Defined new "BetseFunctionUnimplementedException", "BetseProcessException", and "BetseProcessNotFoundException" classes. * Renamed the "BetseOSShellEnvException" class to "BetseShellEnvException". * Generalized the "betse.metadeps" submodule: * Defined a new "SETUPTOOLS_VERSION_MIN" global, providing the minimum version of "setuptools" required at both install- and runtime. Previously, this global was inaccessibly hardcoded into the coarse-grained "RUNTIME_MANDATORY" global. * Generalized the "betse.lib.setuptools.command.supcommand" submodule: * Defined a new "SetuptoolsCommandDistributionTypes" global tuple of all distribution types commonly passed to methods called by the "setuptools.command.easy_install.easy_install" class, suitable for use in type checking. * Defined a new "betse.lib.setuptools.command.supcmdbuild" submodule, preserving the most critical of the contents of the prior implementation of the "betse_setup.bupbuild" submodule: * For safety, this submodule now safely monkey patches "easy_install" in an application-local manner. * For reusability, this submodule is now generically applicable to arbitrary applications -- including both BETSE and downstream consumers thereof (e.g., BETSEE). * Refactored the _scriptwriter_get_args_patched() class method to: * Accept any "ScriptWriter" or "VersionlessRequirement" instance as the passed "distribution" parameter. * Silently defer to the default ScriptWriter.get_args() method under non-WSL Windows variants (i.e., vanilla, Cygwin Windows). * Generalized the "betse.util.cli.cliabc" submodule: * Improved the CLIABC._options_top() method to print human-readable version specifiers when the "-V" and "--version" options are passed, complete with optional human-readable codename (e.g., "BETSE 1.1.0 (Nice Nestor)"). * Defined a new "betse.util.os.process" subpackage: * Defined a new "betse.util.os.process.prctest" submodule: * Defined a new is_process_command() tester, returning true only if the parent process of the active Python interpreter is running an external command with the passed basename. This function currently requires the optional "psutil" dependency -- but could theoretically be expanded with platform-specific implementations circumventing this requirement. * Generalized the "betse.util.os.shell.shellenv" submodule: * Refactored the to_str() converter in terms of the mappings.to_str_flat() converter. * Defined a new "betse.util.py.module.pyimport" submodule: * Renamed the prior betse.util.py.pys.add_import_dirname() function to register_dir() for brevity and clarity. * Defined a new to_str_modules_imported_name() converter, returning a human-readable string of the fully-qualified names of all previously imported modules. * Defined a new "betse.util.py.pyvenv" submodule: * Defined a new is_venv() tester, returning true only if the active Python interpreter is isolated to a venv. * Defined a new get_system_prefix() getter, returning the absolute dirname of the top-level directory containing the system-wide Python interpreter. * Generalized the "betse.util.type.cls.classes" submodule: * Revised the die_unless_subclass() docstring to note that all classes are considered to be subclasses of themselves within the context of this function, complete with a minimal length example (MLE) demonstrating this. * Generalized the "betse.util.type.iterable.mapping.mappings" submodule: * Defined a new to_str_flat() converter, flattening the passed string-keyed and -valued dictionary into a human-readable string. * Refactored the "betse_setup.bupbuild" submodule to defer to the new "betse.lib.setuptools.command.supcmdbuild" submodule. * Generalized the "betse.lib.setuptools.command.supcmdtest" submodule: * Refactored the "test" subclass to inherit the test suite-specific "setuptools.command.test.test" superclass rather than the generic "setuptools.Command" superclass. * Generalized the "betse.util.path.dirs" submodule: * Renamed for disambiguity: * copy() to copy_dir(). * copy_into_dir() to copy_dir_into_dir(). * Defined a new die_if_subdir() function, raising an exception if the second passed directory is a subdirectory of the first passed directory. * Defined a new is_subdir() function, returning true if the second passed directory is a subdirectory of the first passed directory. * Defined a new remove_dir() function, recursively removing the passed directory after logging a warning and waiting several seconds for user intervention. * Revised docstrings for various existing functions. * Generalized the "betse.util.path.files" submodule: * Renamed for disambiguity: * remove() to remove_file(). * remove_if_found() to remove_file_if_found(). * Generalized the "betse.util.path.paths" submodule: * Renamed for disambiguity: * move() to move_path(). * Defined a new remove_path() function, either recursively removing the passed path if a directory or non-recursively removing this path if a file. * Generalized the "betse.util.type.obj.objtest" submodule: * Defined a new die_unless_is() validator, raising an exception if any passed object is not identical to every passed object. * Refactored the "betse_setup.bupbuild" submodule to defer to the new "betse.lib.setuptools.command.supcmdbuild" submodule. * Generalized the "betse_setup.buputil" submodule: * Minimized this submodule to the smallest set of requisite functions required by the top-level "setup.py" script. * Defined a new die_unless_setuptools_version_at_least() validator, copied verbatim from the "betsee.beuputil" submodule. * Generalized the die_unless_setuptools_version_at_least() function to use the general-purpose "distutils.version.LooseVersion" class rather than the strict "distutils.version.StrictVersion" class. * Debugged the "betse_test.func.sim.test_sim" submodule: * Improved the test_cli_sim_compat() functional test to squelch (i.e., silence) warnings emitted by matplotlib during this test. Specifically, interactive visualizations are now disabled during this test by enabling the "betse_cli_sim_compat" fixture to overwrite the old simulation configuration required by this test. (Bituminous arbiter delicately dangles the provocative invocation!)