From 65eaf93eb9cbc3aab2fcf3b9ea50e637ce9e4dd9 Mon Sep 17 00:00:00 2001 From: Inkaros Date: Sat, 23 Nov 2024 12:14:42 -0500 Subject: [PATCH 1/4] De-coupled the library from ataraxis-base-utilities -- Resolved circular dependency between ataraxis-automation and ataraxis-base-utilities by implementing local console printing functionality. Now, ataraxis-base-utilities will be based on automation, but not the other way around. -- Removed unused tox.ini tasks and modified existing tasks to drop support for python 3.10 and include support for python 3.13 -- Updated dependencies where necessary in pyproject and tox files -- Removed unused imports in testing and source code -- Bumped version to 4.0.0 --- pyproject.toml | 27 +- src/ataraxis_automation/automation.py | 378 +++++++++++-------------- src/ataraxis_automation/automation.pyi | 66 ++--- tests/automation_test.py | 51 +--- tox.ini | 99 ++----- 5 files changed, 244 insertions(+), 377 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 66b76ab..61c980e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,11 +8,11 @@ build-backend = "hatchling.build" # Project metadata section. Provides the general ID information about the project. [project] name = "ataraxis-automation" -version = "3.0.4" +version = "4.0.0" description = "Provides scripts that support tox-based development automation pipelines used by other Sun Lab projects." readme = "README.md" license = { file = "LICENSE" } -requires-python = ">=3.10" +requires-python = ">=3.11" authors = [ { name = "Ivan Kondratyev", email = "ik278@cornell.edu" }, ] @@ -33,9 +33,9 @@ classifiers = [ # License "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", # Supported Python Versions - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", # Supported Operating Systems "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", @@ -47,7 +47,6 @@ dependencies = [ "click>=8,<9", "pyyaml>=6,<7", "appdirs>=1,<2", - "ataraxis-base-utilities>=2,<3", "tomli>=2,<3", ] @@ -73,10 +72,11 @@ condarun = [ conda = [ # Tox "tox>=4,<5", + "tox-uv>=1,<2", # Testing "pytest>=8,<9", - "pytest-cov>=5,<6", + "pytest-cov>=6,<7", "pytest-xdist>=3,<4", # Coverage Reports @@ -84,14 +84,14 @@ conda = [ "junitparser>=3,<4", # Documentation - "sphinx>=7,<8", + "sphinx>=8,<9", "importlib_metadata>=8,<9", - "sphinx-rtd-theme>=2,<3", + "sphinx-rtd-theme>=3,<4", "sphinx-click>=6,<7", "sphinx-autodoc-typehints>=2,<3", # Linting and Stub-generation - "mypy>=1,<2", + "mypy[faster-cache]>=1,<2", "ruff>=0,<1", # Types @@ -112,14 +112,8 @@ conda = [ # Dependencies known to not be installable with conda for at least one supported development platform # (OSX ARM64, WIN AMD64, LIN AMD64). noconda = [ - # Tox - "tox-uv>=1,<2", - # Building "build>=1,<2", - - # Automation - "ataraxis-automation>=3,<4", ] # A shorthand specification that installs tox and all packages required for development tasks. This specification can @@ -146,7 +140,7 @@ packages = ["src/ataraxis_automation"] [tool.ruff] line-length = 120 # Maximum column length is set to 120 for this project. indent-width = 4 # Same as black, indents are 4 spaces -target-version = "py310" # Targets the lowest supported version of python 3.10 +target-version = "py311" # Targets the lowest supported version of python 3.11 src = ["src"] # The name of the source directory # Excludes 'service' .py files, such as sphinx configuration file from linting. @@ -159,10 +153,7 @@ lint.select = ["ALL"] lint.ignore = [ "COM812", # Conflicts with the formatter "ISC001", # Conflicts with the formatter - "ANN101", # "missing-type-self" "PT001", # https://github.com/astral-sh/ruff/issues/8796#issuecomment-1825907715 - "PT004", # https://github.com/astral-sh/ruff/issues/8796#issuecomment-1825907715 - "PT005", # https://github.com/astral-sh/ruff/issues/8796#issuecomment-1825907715 "PT023", # https://github.com/astral-sh/ruff/issues/8796#issuecomment-1825907715 "D107", # Project-specific, __init__ is documented inside the main class docstring where applicable "D205", # Bugs out for file descriptions diff --git a/src/ataraxis_automation/automation.py b/src/ataraxis_automation/automation.py index de45bcd..d5e0416 100644 --- a/src/ataraxis_automation/automation.py +++ b/src/ataraxis_automation/automation.py @@ -9,10 +9,10 @@ import os import re import sys -import time as tm import shutil from typing import Any, Optional from pathlib import Path +import textwrap import subprocess from dataclasses import dataclass from configparser import ConfigParser @@ -20,8 +20,51 @@ import yaml import click import tomli -from appdirs import AppDirs # type: ignore -from ataraxis_base_utilities import LogLevel, console + + +def _format_message(message: str) -> str: + """Formats input message strings to follow the general Ataraxis style. + + This function uses the same parameters as the default Console class implementation available through + the ataraxis-base-utilities library. This function is used to decouple the ataraxis-automation library from + the ataraxis-base-utilities library, removing the circular dependency introduced for these libraries in versions 2 + and 3 and allows mimicking the output of console.error() method. + + Args: + message: The input message string to format. + + Returns: + Formatted message string with appropriate line breaks. + """ + return textwrap.fill( + text=message, + width=120, + break_long_words=False, + break_on_hyphens=False, + ) + + +def _colorize_message(message: str, color: str, format_message: bool = True) -> str: + """Modifies the input string to include an ANSI color code and, if necessary, formats the message by wrapping it + at 120 lines. + + This function uses the same parameters as the default Console class implementation available through + the ataraxis-base-utilities library. This function is used to decouple the ataraxis-automation library from + ataraxis-base-utilities and, together with click.echo, allows mimicking the output of console.echo() method. + + Args: + message: The input message string to format and colorize. + color: The ANSI color code to use for coloring the message. + format_message: If True, the message will be formatted by wrapping it at 120 lines. + + Returns: + Colorized and formatted (if requested) message string. + """ + + if format_message: + message = _format_message(message) + + return click.style(message, fg=color) @dataclass @@ -106,77 +149,6 @@ class EnvironmentCommands: """ -def configure_console( - log_directory: Optional[Path] = None, *, verbose: bool = False, enable_logging: bool = False -) -> None: - """Configures, and, if requested, enables Console class instance exposed by the ataraxis-base-utilities library as - global 'console' variable. - - This function is designed to be called by the main cli group setup code to (optionally) enable sending messages to - terminal and logging them to log files. All functions of this library are expected to use the same global Console - instance, and they should use the tools exposed by the console to issue errors and echo messages. - - Notes: - Since version 1.1.0 of ataraxis-base-utilities and version 2.0.0 of this library, it uses shared 'console' - variable for terminal-printing and file-logging functionality. While effective, this design is potentially - dangerous, as it allows multiple modules to access and alter 'console' configuration. Since this function is - expected to be called from the highest module of the call hierarchy, it reconfigures and enables / disables the - console variable depending on the input arguments. This will interfere with any imported module that also - attempts to modify the console configuration. There should always be only one active module allowed to modify - console variable for each runtime. - - Args: - log_directory: The absolute path to the user logs directory. The function ensures the directory exists, but - relies on the main cli group to provide the directory path. - verbose: Determines whether to print messages and errors to the terminal. - enable_logging: Determines whether to save messages and errors to log files. Note, error log files are - automatically cleaned up after a few days, while message logs are maintained indefinitely. - """ - - # If logging is enabled and a valid log directory path is provided, provides console with log file paths. - if enable_logging and log_directory is not None: - log_file_path = log_directory.joinpath("message_log.txt") - error_file_path = log_directory.joinpath("error_log.txt") - console.set_message_log_path(log_file_path) - console.set_error_log_path(error_file_path) - - # Also enables logging to supported files. - console.set_error_file(True) - console.set_message_file(True) - console.set_debug_file(False) - console.enable() # Also ensures that console is enabled - - # Regardless of the verbose settings below, the console will notify the user about the location of log files - # if logging is enabled: - console.set_message_terminal(True) - console.echo(f"File logging: enabled. Log files can be found inside the following directory: {log_directory}") - tm.sleep(1) # Waits for 1 second to ensure the user sees the message. - else: - # Otherwise, ensures logging to file is disabled. - console.set_error_file(False) - console.set_message_file(False) - console.set_debug_file(False) - - # If console is used in verbose mode, enables terminal-printing. - if verbose: - console.set_message_terminal(True) - console.set_error_terminal(True) - console.set_debug_terminal(False) - console.enable() # Also ensures that console is enabled - else: - # Otherwise, ensures terminal-printing is disabled. - console.set_message_terminal(False) - console.set_error_terminal(False) - console.set_debug_terminal(False) - - # Ensures the console is disabled if neither logging nor terminal-printing is enabled. This is primarily - # helpful for testing purposes, but also ensures consistent performance given that console is potentially - # shared between many different modules. Some of these modules may transiently enable it without disabling, - # which can cause this library to behave unexpectedly with respect to logging. - if not enable_logging and not verbose: - console.disable() - - def resolve_project_directory() -> Path: """Gets the current working directory from the OS and verifies that it points to a valid python project. @@ -205,7 +177,7 @@ def resolve_project_directory() -> Path: f"the project, judged by the presence of '/src', '/envs', 'pyproject.toml' and 'tox.ini'. Current working " f"directory is set to {project_dir}, which does not contain at least one of the required files." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) return Path(project_dir) @@ -263,7 +235,7 @@ def resolve_library_root(project_root: Path) -> Path: f"sub-directories with __init__.py inside the /src directory. Make sure there is an __init__.py " f"inside /src or ONE of the sub-directories under /src." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # If (as expected), there is only one candidate, returns it as the library root return candidates.pop() @@ -290,7 +262,11 @@ def resolve_environment_files(project_root: Path, environment_base_name: str) -> RuntimeError: If the host OS does not match any of the supported operating systems. """ # Stores supported platform names together with their suffixes - supported_platforms: dict[str, str] = {"win32": "_win", "linux": "_lin", "darwin": "_osx"} + supported_platforms: dict[str, str] = { + "win32": "_win", + "linux": "_lin", + "darwin": "_osx", + } os_name: str = sys.platform # Obtains host os name # If the os name is not one of the supported names, issues an error @@ -299,7 +275,7 @@ def resolve_environment_files(project_root: Path, environment_base_name: str) -> f"Unable to resolve the os-specific suffix to use for conda environment file(s). Unsupported host OS " f"detected: {os_name}. Currently, supported OS options are are: {', '.join(supported_platforms.keys())}." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Resolves the absolute path to the 'envs' directory. The function that generates the project root path checks for # the presence of this directory as part of its runtime, so it is assumed that it always exists. @@ -349,10 +325,7 @@ def resolve_conda_engine() -> str: f"to interface with either conda or mamba. Is conda or supported equivalent installed, initialized " f"and added to Path?" ) - console.error(message, error=RuntimeError) - - # Fallback to appease mypy, not reachable. - raise RuntimeError(message) # pragma: no cover + raise RuntimeError(_format_message(message)) def resolve_pip_engine() -> str: @@ -388,10 +361,7 @@ def resolve_pip_engine() -> str: f"the supported pip-engines. Is pip, uv or supported equivalent installed in the currently active " f"virtual / conda environment?" ) - console.error(message, error=RuntimeError) - - # Fallback to appease mypy, not reachable. - raise RuntimeError(message) # pragma: no cover + raise RuntimeError(_format_message(message)) def get_base_name(dependency: str) -> str: @@ -441,7 +411,8 @@ def add_dependency( f"dependency for '{dependency}', listed in pyproject.toml. A dependency should only " f"be found in one of the supported pyproject.toml lists: conda, noconda or condarun." ) - console.error(message, error=ValueError) + raise ValueError(_format_message(message)) + # Wraps dependency in "" to properly handle version specifiers when dependencies are installed via mamba or pip. # Technically, this is only needed for 'special' version specifications that use < or > and similar notations. It # is assumed that most of the projects that use this library will be specifying dependencies using at least '>=' @@ -504,19 +475,23 @@ def resolve_dependencies(project_root: Path) -> tuple[list[str], list[str]]: ) # Processes project run dependencies. Adds extracted dependencies that are not already processed as part of the - # condarun list to pip_dependencies list. + # 'condarun' list to the pip_dependencies list. for dependency in dependencies: # Adds dependency to the pip list if it has not been processed as part of conda dependencies if get_base_name(dependency=dependency) not in processed_dependencies: add_dependency( - dependency=dependency, dependencies_list=pip_dependencies, processed_dependencies=processed_dependencies + dependency=dependency, + dependencies_list=pip_dependencies, + processed_dependencies=processed_dependencies, ) # Adds any missing noconda dependencies to the pip_dependencies list. if "noconda" in optional_dependencies: for dependency in optional_dependencies["noconda"]: add_dependency( - dependency=dependency, dependencies_list=pip_dependencies, processed_dependencies=processed_dependencies + dependency=dependency, + dependencies_list=pip_dependencies, + processed_dependencies=processed_dependencies, ) # Ignores any other optional dependencies @@ -550,7 +525,7 @@ def resolve_dependencies(project_root: Path) -> tuple[list[str], list[str]]: f"dependencies in tox.ini are not found in pyproject.toml: {', '.join(missing_dependencies)}. Add them to " f"one of the pyproject.toml dependency lists: condarun, conda or noconda." ) - console.error(message, error=ValueError) + raise ValueError(_format_message(message)) return conda_dependencies, pip_dependencies @@ -583,7 +558,7 @@ def resolve_project_name(project_root: Path) -> str: f"Unable to parse the pyproject.toml file. The file may be corrupted or contain invalid TOML syntax. " f"Error details: {e}." ) - console.error(message, error=ValueError) + raise ValueError(_format_message(message)) # Extracts the project name from the [project] section project_data: dict[str, Any] = pyproject_data.get("project", {}) @@ -595,10 +570,7 @@ def resolve_project_name(project_root: Path) -> str: f"Unable to resolve the project name from the pyproject.toml file. The 'name' field is missing or empty in " f"the [project] section of the file. Ensure that the project name is correctly defined." ) - console.error(message, error=ValueError) - - # Fallback to appease mypy, not reachable. - raise ValueError(message) # pragma: no cover + raise ValueError(_format_message(message)) elif project_name is not None: return project_name @@ -623,14 +595,14 @@ def generate_typed_marker(library_root: Path) -> None: if not root_py_typed.exists(): root_py_typed.touch() message: str = f"Added py.typed marker to library root ({library_root})." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) # Removes py.typed from all subdirectories for path in library_root.rglob("py.typed"): if path != root_py_typed: path.unlink() message = f"Removed no longer needed py.typed marker file {path}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) def move_stubs(stubs_dir: Path, library_root: Path) -> None: @@ -659,7 +631,7 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: f"Unable to move the generated stub files to appropriate levels of the library directory. Expected exactly " f"one subdirectory with __init__.pyi in '{stubs_dir}', but found {len(valid_sub_dirs)}." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Gets the single valid directory and uses it as the source for .piy files. src_dir: Path = valid_sub_dirs.pop() @@ -674,7 +646,7 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: # Ensures the destination directory exists dst_path.parent.mkdir(parents=True, exist_ok=True) - # Removes old .pyi file if it already exists + # Removes the old .pyi file if it already exists if dst_path.exists(): dst_path.unlink() @@ -682,9 +654,9 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: shutil.move(str(stub_path), str(dst_path)) message = f"Moved stub file from /stubs to /src: {dst_path.name}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) - # This loop is designed to solve a (so far) OSX-unique issue, where this function produces multiple copies that + # This loop is designed to solve an OSX-unique issue, where this function produces multiple copies that # have space+copy_number appended to each file name, rather than a single copy of the .pyi file. # Groups files by their base name (without a space number) @@ -704,9 +676,9 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: # Sorts files by copy number, in descending order sorted_files = sorted( group, - key=lambda x: int(re.findall(r" (\d+)\.pyi$", x.name)[0]) - if re.findall(r" (\d+)\.pyi$", x.name) - else 0, + key=lambda x: ( + int(re.findall(r" (\d+)\.pyi$", x.name)[0]) if re.findall(r" (\d+)\.pyi$", x.name) else 0 + ), reverse=True, ) @@ -717,20 +689,21 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: # Removes duplicate files for file_to_remove in sorted_files[1:]: file_to_remove.unlink() - console.echo( - f"Removed duplicate .pyi file in {dir_path}: {file_to_remove.name}", level=LogLevel.INFO - ) + message = f"Removed duplicate .pyi file in {dir_path}: {file_to_remove.name}" + click.echo(_colorize_message(message, color="white"), color=True) # Renames the kept file to remove the copy number kept_file.rename(new_file_path) - console.echo(f"Renamed stub file in {dir_path}: {kept_file.name} -> {base_name}", level=LogLevel.INFO) + message = f"Renamed stub file in {dir_path}: {kept_file.name} -> {base_name}" + click.echo(_colorize_message(message, color="white"), color=True) # If there's only one file, renames it if it has a copy number elif len(group) == 1 and group[0].name != base_name: file = group[0] new_path = file.with_name(base_name) file.rename(new_path) - console.echo(f"Renamed stub file in {dir_path}: {file.name} -> {base_name}", level=LogLevel.INFO) + message = f"Renamed stub file in {dir_path}: {file.name} -> {base_name}" + click.echo(_colorize_message(message, color="white"), color=True) def delete_stubs(library_root: Path) -> None: @@ -749,7 +722,7 @@ def delete_stubs(library_root: Path) -> None: # Removes the .pyi files pyi_file.unlink() message: str = f"Removed stub file: {pyi_file.name}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) def verify_pypirc(file_path: Path) -> bool: @@ -819,7 +792,7 @@ def rename_all_envs(project_root: Path, new_name: str) -> None: file_path.unlink() message: str = f"Renamed environment .yml file: {file_name} -> {new_file_name}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) # if the file is a _spec.txt file, just renames the file. Spec files to not include environment names. elif file_name.endswith("_spec.txt") and ("_lin" in file_name or "_win" in file_name or "_osx" in file_name): @@ -833,7 +806,7 @@ def rename_all_envs(project_root: Path, new_name: str) -> None: file_path.rename(new_file_path) message = f"Renamed environment spec.txt file: {file_name} -> {new_file_name}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) else: # Skips files that don't match either pattern @@ -872,7 +845,7 @@ def replace_markers_in_file(file_path: Path, markers: dict[str, str]) -> int: if modification_count != 0: file_path.write_text(content, encoding="utf-8") message: str = f"Replaced markers in {file_path}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white"), color=True) # Returns the total number of modifications (0 if no modifications were made) return modification_count @@ -890,10 +863,8 @@ def validate_library_name(_ctx: click.Context, _param: click.Parameter, value: s BadParameter: If the input value contains invalid characters. """ if not re.match(r"^[a-zA-Z0-9_]*$", value): - message: str = console.format_message( - "Library name should contain only letters, numbers, and underscores.", loguru=False - ) - raise click.BadParameter(message) + message: str = "Library name should contain only letters, numbers, and underscores." + raise click.BadParameter(_format_message(message)) return value @@ -909,9 +880,7 @@ def validate_project_name(_ctx: click.Context, _param: click.Parameter, value: s BadParameter: If the input value contains invalid characters. """ if not re.match(r"^[a-zA-Z0-9-]+$", value): - message: str = console.format_message( - "Project name should contain only letters, numbers, or dashes.", loguru=False - ) + message: str = _format_message("Project name should contain only letters, numbers, or dashes.") raise click.BadParameter(message) return value @@ -929,11 +898,10 @@ def validate_author_name(_ctx: click.Context, _param: click.Parameter, value: st """ pattern = r"^([a-zA-Z\s\-']+)(\s*\([a-zA-Z0-9\-]+\))?$" if not re.match(pattern, value): - message: str = console.format_message( + message: str = _format_message( f"Author name should be in the format 'Human Name' or 'Human Name (GitHubUsername)'. " f"The name can contain letters, spaces, hyphens, and apostrophes. The GitHub username " - f"(if provided) should be in parentheses and can contain letters, numbers, and hyphens.", - loguru=False, + f"(if provided) should be in parentheses and can contain letters, numbers, and hyphens." ) raise click.BadParameter(message) return value @@ -951,7 +919,7 @@ def validate_email(_ctx: click.Context, _param: click.Parameter, value: str) -> BadParameter: If the input value contains invalid characters. """ if not re.match(r"^[\w.-]+@[\w.-]+\.\w+$", value): - message: str = console.format_message("Invalid email address.", loguru=False) + message: str = _format_message("Invalid email address.") raise click.BadParameter(message) return value @@ -969,9 +937,7 @@ def validate_env_name(_ctx: click.Context, _param: click.Parameter, value: str) BadParameter: If the input value contains invalid characters. """ if not re.match(r"^[a-zA-Z0-9_]*$", value): - message: str = console.format_message( - "Environment name should contain only letters, numbers, and underscores.", loguru=False - ) + message: str = _format_message("Environment name should contain only letters, numbers, and underscores.") raise click.BadParameter(message) return value @@ -1163,7 +1129,11 @@ def environment_exists(commands: EnvironmentCommands) -> bool: # Verifies that the project- and os-specific conda environment can be activated. try: subprocess.run( - commands.activate_command, shell=True, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL + commands.activate_command, + shell=True, + check=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, ) return True except subprocess.CalledProcessError: @@ -1171,22 +1141,9 @@ def environment_exists(commands: EnvironmentCommands) -> bool: @click.group() -@click.option("--verbose", is_flag=True, help="If provided, enables printing messages and errors to terminal.") -@click.option("--log", is_flag=True, help="If provided, enables saving messages and errors to log files.") -def cli(verbose: bool, log: bool) -> None: # pragma: no cover +def cli() -> None: # pragma: no cover """This command-line interface exposes helper commands used to automate various project development and building - steps. - - In addition to being the main API interface for this library, it configures the logging system used by the library - based on the --verbose and --log options. These options apply to all subcommands of this CLI. - """ - # Resolves the path to user log directory (this information is only used if logging is enabled) - dirs = AppDirs(appname="ataraxis-automation", appauthor="SunLabNBB") - log_dir: Path = Path(dirs.user_log_dir) - - # Creates and configures the Console class instance to use for message handling. The instance is written to the - # global 'console' variable to extend it to all functions of this library. - configure_console(log_directory=log_dir, verbose=verbose, enable_logging=log) + steps.""" @cli.command() @@ -1209,7 +1166,7 @@ def process_typed_markers() -> None: # pragma: no cover # Resolves typed markers. generate_typed_marker(library_root=library_root) message: str = "Typed (py.typed) marker(s) successfully processed." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1239,13 +1196,13 @@ def process_stubs() -> None: # pragma: no cover message: str = ( f"Unable to move generated stub files from {stubs_path} to {library_root}. Stubs directory does not exist." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Moves the stubs to the appropriate source code directories move_stubs(stubs_dir=stubs_path, library_root=library_root) shutil.rmtree(stubs_path) # Removes the /stubs directory once all stubs are moved message = "Stubs successfully distributed to appropriate source directories." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1269,7 +1226,7 @@ def purge_stubs() -> None: # pragma: no cover # Removes all stub files from the library source code folder. delete_stubs(library_root=library_root) message: str = "Existing stub files purged." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1294,12 +1251,12 @@ def generate_recipe_folder() -> None: # pragma: no cover if recipe_path.exists(): shutil.rmtree(recipe_path) message: str = "Existing recipe folder removed." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) # Creates the recipe directory os.makedirs(recipe_path) message = "Recipe folder created." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1339,7 +1296,7 @@ def acquire_pypi_token(replace_token: bool) -> None: # pragma: no cover # If file exists, recreating the file is not requested and the file appears well-formed, ends the runtime. if verify_pypirc(pypirc_path) and not replace_token: message: str = f"Existing PyPI token found inside the '.pypirc' file." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) return # Otherwise, proceeds to generating a new file and token entry. @@ -1348,15 +1305,14 @@ def acquire_pypi_token(replace_token: bool) -> None: # pragma: no cover f"Unable to use the existing PyPI token: '.pypirc' file does not exist, is invalid or doesn't contain a " f"valid token. Proceeding to new token acquisition." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) # Enters the while loop to iteratively ask for the token until a valid token entry is provided. while True: try: - prompt: str = console.format_message( + prompt: str = _format_message( message="Enter your PyPI (API) token. It will be stored inside the .pypirc file for future use. " - "Input is hidden:", - loguru=False, + "Input is hidden:" ) # Asks the user for the token. token: str = click.prompt(text=prompt, hide_input=True, type=str) @@ -1366,17 +1322,18 @@ def acquire_pypi_token(replace_token: bool) -> None: # pragma: no cover message = "Acquired invalidly-formatted PyPI token. PyPI tokens should start with 'pypi-'." # This both logs and re-raises the error. Relies on the error being caught below and converted to a # prompt instead. - console.error(message, error=ValueError) + raise ValueError(_format_message(message)) # Generates the new .pypirc file and saves the valid token data to the file. config = ConfigParser() config["pypi"] = {"username": "__token__", "password": token} with pypirc_path.open("w") as config_file: + # noinspection PyTypeChecker config.write(config_file) # Notifies the user and breaks out of the while loop message = f"Valid PyPI token acquired and added to '.pypirc' for future uses." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) break # This block allows rerunning the token acquisition if an invalid token was provided, and the user has elected @@ -1384,7 +1341,7 @@ def acquire_pypi_token(replace_token: bool) -> None: # pragma: no cover except Exception: if not click.confirm("Do you want to try again?"): message = "PyPI token acquisition: aborted by user." - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1420,7 +1377,9 @@ def install_project(environment_name: str, python_version: str) -> None: # prag # Gets the list of commands that can be used to carry out conda environment operations. commands: EnvironmentCommands = resolve_environment_commands( - project_root=project_root, environment_name=environment_name, python_version=python_version + project_root=project_root, + environment_name=environment_name, + python_version=python_version, ) # Checks if project conda environment is accessible via subprocess activation call. If not, raises an error. @@ -1429,7 +1388,7 @@ def install_project(environment_name: str, python_version: str) -> None: # prag f"Unable to activate the target conda environment '{commands.environment_name}', which likely means" f"that it does not exist. If you need to create the environment, run 'create-env' ('tox -e create')." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Installs the project into the activated conda environment by combining environment activation and project # installation commands. @@ -1437,13 +1396,13 @@ def install_project(environment_name: str, python_version: str) -> None: # prag command: str = f"{commands.activate_command} && {commands.install_project_command}" subprocess.run(command, shell=True, check=True) message = f"Project successfully installed into the requested conda environment '{commands.environment_name}'." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to build and install the project into the conda environment '{commands.environment_name}'. See " f"uv/pip-generated error messages for specific details about the failed operation." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1484,7 +1443,9 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr # Gets the list of commands that can be used to carry out conda environment operations. commands: EnvironmentCommands = resolve_environment_commands( - project_root=project_root, environment_name=environment_name, python_version=python_version + project_root=project_root, + environment_name=environment_name, + python_version=python_version, ) # Attempts to activate the input conda environment. If activation fails, concludes that environment does not exist @@ -1495,7 +1456,7 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr f"Uninstallation process aborted. If you need to create the environment, run 'create-env' " f"('tox -e create')." ) - console.echo(message, level=LogLevel.WARNING) + click.echo(_colorize_message(message, color="orange")) return try: @@ -1504,13 +1465,13 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr message = ( f"Project successfully uninstalled from the requested conda environment '{commands.environment_name}'." ) - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to uninstall the project from the conda environment '{commands.environment_name}'. See " f"uv/pip-generated error messages for specific details about the failed operation. " ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1548,7 +1509,9 @@ def create_env(environment_name: str, python_version: str) -> None: # pragma: n # Gets the list of commands that can be used to carry out conda environment operations. commands: EnvironmentCommands = resolve_environment_commands( - project_root=project_root, environment_name=environment_name, python_version=python_version + project_root=project_root, + environment_name=environment_name, + python_version=python_version, ) # Checks if the project-specific environment is accessible via subprocess activation call. If it is accessible @@ -1559,20 +1522,20 @@ def create_env(environment_name: str, python_version: str) -> None: # pragma: n f"environment, run 'remove-env' ('tox -e remove') command and try again. If you need to reinstall " f"environment packages, run 'provision-env' ('tox -e provision') command instead." ) - console.echo(message, level=LogLevel.WARNING) + click.echo(_colorize_message(message, color="orange")) return # Creates the new environment try: subprocess.run(commands.create_command, shell=True, check=True) message = f"Created '{commands.environment_name}' conda environment." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to create a new conda environment '{commands.environment_name}'. See the conda-issued " f"error-message above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # If environment was successfully created, installs conda-installable dependencies if there are any. try: @@ -1582,19 +1545,19 @@ def create_env(environment_name: str, python_version: str) -> None: # pragma: n f"Installed project dependencies available from conda into created '{commands.environment_name}' " f"conda environment." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) else: message = ( f"Skipped installing project dependencies available from conda into created " f"'{commands.environment_name}' conda environment. Project has no conda-installable dependencies." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to install project dependencies available from conda into created '{commands.environment_name}' " f"conda environment. See conda-generated error message above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # After resolving conda-dependencies, installs pip-installable dependencies, if there are any. try: @@ -1605,27 +1568,27 @@ def create_env(environment_name: str, python_version: str) -> None: # pragma: n f"Installed project dependencies available from PyPI (pip) into created '{commands.environment_name}' " f"conda environment." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) else: message = ( f"Skipped installing project dependencies available from PyPI (pip) into created " f"'{commands.environment_name}' conda environment. Project has no pip-installable dependencies." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to install project dependencies available from PyPI (pip) into created " f"'{commands.environment_name}' conda environment. See pip-generated error message above for more " f"information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Displays the final success message. message = ( f"Created '{commands.environment_name}' conda environment and installed all project dependencies into the " f"environment." ) - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1666,7 +1629,7 @@ def remove_env(environment_name: str) -> None: # pragma: no cover f"Unable to find '{commands.environment_name}' conda environment. Likely, this indicates that the " f"environment already does not exist. Environment removal procedure aborted." ) - console.echo(message, level=LogLevel.WARNING) + click.echo(_colorize_message(message, color="orange")) return # Otherwise, ensures the environment is not active and carries out the removal procedure. @@ -1674,14 +1637,14 @@ def remove_env(environment_name: str) -> None: # pragma: no cover command: str = f"{commands.deactivate_command} && {commands.remove_command}" subprocess.run(command, shell=True, check=True) message = f"Removed '{commands.environment_name}' conda environment." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to remove '{commands.environment_name}' conda environment. See the conda-issued error-message " f"above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1718,7 +1681,9 @@ def provision_env(environment_name: str, python_version: str) -> None: # pragma # Gets the list of commands that can be used to carry out conda environment operations. commands: EnvironmentCommands = resolve_environment_commands( - project_root=project_root, environment_name=environment_name, python_version=python_version + project_root=project_root, + environment_name=environment_name, + python_version=python_version, ) # Checks if the project-specific environment is accessible via subprocess activation call. If it is not accessible @@ -1728,7 +1693,7 @@ def provision_env(environment_name: str, python_version: str) -> None: # pragma "Unable to provision '{commands.environment_name}' conda environment, as environment does not exist. If " "you want to create a new environment, use 'create-env' ('tox -e create') command instead." ) - console.error(message=message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Otherwise, uses 'provision' command to remove all packages and re-installs project dependencies. try: @@ -1738,13 +1703,13 @@ def provision_env(environment_name: str, python_version: str) -> None: # pragma f"Removed all packages from '{commands.environment_name}' conda environment and " f"reinstalled base dependencies (Python, uv, tox and pip)." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to provision '{commands.environment_name}' conda environment. See conda-issued error-message " f"above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # If environment was successfully provisioned (reset), installs conda-installable dependencies if there are any. try: @@ -1754,20 +1719,20 @@ def provision_env(environment_name: str, python_version: str) -> None: # pragma f"Installed project dependencies available from conda into provisioned '{commands.environment_name}' " f"conda environment." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) else: message = ( f"Skipped installing project dependencies available from conda into provisioned " f"'{commands.environment_name}' conda environment. Project has no conda-installable dependencies." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to install project dependencies available from conda into provisioned " f"'{commands.environment_name}' conda environment . See conda-generated error message above for more " f"information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # After resolving conda-dependencies, installs pip-installable dependencies, if there are any. try: @@ -1778,24 +1743,24 @@ def provision_env(environment_name: str, python_version: str) -> None: # pragma f"Installed project dependencies available from PyPI (pip) into provisioned " f"'{commands.environment_name}' conda environment." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) else: message = ( f"Skipped installing project dependencies available from PyPI (pip) into provisioned " f"'{commands.environment_name}' conda environment. Project has no pip-installable dependencies." ) - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) except subprocess.CalledProcessError: message = ( f"Unable to install project dependencies available from PyPI (pip) into provisioned " f"'{commands.environment_name}' conda environment. See pip-generated error message above for more " f"information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Displays the final success message. message = f"Provisioned '{commands.environment_name}' conda environment." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -1830,7 +1795,7 @@ def import_env(environment_name: str) -> None: # pragma: no cover project_root=project_root, environment_name=environment_name ) - # If environment cannot be activated (likely does not exist) and environment .yml file is found inside /envs + # If environment cannot be activated (likely does not exist) and the environment .yml file is found inside /envs # directory, uses .yml file to create a new environment. if not environment_exists(commands=commands) and commands.create_from_yml_command is not None: try: @@ -1838,27 +1803,26 @@ def import_env(environment_name: str) -> None: # pragma: no cover message: str = ( f"'{commands.environment_name}' conda environment imported (created) from existing .yml " f"file." ) - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to import (create) '{commands.environment_name}' conda environment from existing .yml file. " f"See conda-issued error-message above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # If conda environment already exists and .yml file exists, updates the environment using the .yml file. elif commands.update_command is not None: try: subprocess.run(commands.update_command, shell=True, check=True) message = f"Existing '{commands.environment_name}' conda environment updated from .yml file." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to update existing conda environment '{commands.environment_name}' from .yml file. " f"See conda-issued error-message above for more information." ) - console.error(message, error=RuntimeError) - + raise RuntimeError(_format_message(message)) # If the .yml file does not exist, aborts with error. else: message = ( @@ -1866,7 +1830,7 @@ def import_env(environment_name: str) -> None: # pragma: no cover f"file inside the /envs directory for the given project and host-OS combination. Try creating the " f"environment using pyproject.toml dependencies by using 'create-env' ('tox -e create')." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1904,33 +1868,33 @@ def export_env(environment_name: str) -> None: # pragma: no cover f"Unable to activate '{commands.environment_name}' conda environment, which likely indicates that it does " f"not exist. Create the environment with 'create-env' ('tox -e create') before attempting to export it." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Exports environment as a .yml file try: subprocess.run(commands.export_yml_command, shell=True, check=True) message = f"'{commands.environment_name}' conda environment exported to /envs as a .yml file." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to export '{commands.environment_name}' conda environment to .yml file. See conda-issued " f"error-message above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) # Exports environment as a spec.txt file try: subprocess.run(commands.export_spec_command, shell=True, check=True) message = f"'{commands.environment_name}' conda environment exported to /envs as a spec.txt file." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: message = ( f"Unable to export '{commands.environment_name}' conda environment to spec.txt file. See conda-issued " f"error-message above for more information." ) - console.error(message, error=RuntimeError) + raise RuntimeError(_format_message(message)) @cli.command() @@ -1960,7 +1924,7 @@ def rename_environments(new_name: str) -> None: # pragma: no cover # Issues a success message message = f"Renamed all supported environment files inside the /envs directory to use the new base name {new_name}." - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) @cli.command() @@ -2070,7 +2034,7 @@ def adopt_project( new_path = file_path.with_name(new_file_name) file_path.rename(new_path) message: str = f"Renamed file: {file_path} -> {new_path}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) for directory in dirs: # Gets the absolute path to each scanned directory. @@ -2082,7 +2046,7 @@ def adopt_project( new_path = dir_path.with_name(new_dir_name) dir_path.rename(new_path) message = f"Renamed directory: {dir_path} -> {new_path}." - console.echo(message, level=LogLevel.INFO) + click.echo(_colorize_message(message, color="white")) # Update the directory name in the dirs list to avoid potential issues dirs[dirs.index(directory)] = new_dir_name @@ -2093,4 +2057,4 @@ def adopt_project( f"proceeding to the next step. Overall, found and replaced {total_markers} markers in scanned file " f"contents." ) - console.echo(message, level=LogLevel.SUCCESS) + click.echo(_colorize_message(message, color="green")) diff --git a/src/ataraxis_automation/automation.pyi b/src/ataraxis_automation/automation.pyi index 08a59fd..736a742 100644 --- a/src/ataraxis_automation/automation.pyi +++ b/src/ataraxis_automation/automation.pyi @@ -3,6 +3,37 @@ from dataclasses import dataclass import click +def _format_message(message: str) -> str: + """Formats input message strings to follow the general Ataraxis style. + + This function uses the same parameters as the default Console class implementation available through + the ataraxis-base-utilities library. This function is used to decouple the ataraxis-automation library from + the ataraxis-base-utilities library, removing the circular dependency introduced for these libraries in versions 2 + and 3 and allows mimicking the output of console.error() method. + + Args: + message: The input message string to format. + + Returns: + Formatted message string with appropriate line breaks. + """ + +def _colorize_message(message: str, color: str, format_message: bool = True) -> str: + """Modifies the input string to include an ANSI color code and, if necessary, formats the message by wrapping it + at 120 lines. + + This function uses the same parameters as the default Console class implementation available through + the ataraxis-base-utilities library. This function is used to decouple the ataraxis-automation library from + ataraxis-base-utilities and, together with click.echo, allows mimicking the output of console.echo() method. + + Args: + message: The input message string to format and colorize. + color: The ANSI color code to use for coloring the message. + format_message: If True, the message will be formatted by wrapping it at 120 lines. + + Returns: + Colorized and formatted (if requested) message string. + """ @dataclass class EnvironmentCommands: """Provides a convenient interface for storing conda environment commands. @@ -43,33 +74,6 @@ class EnvironmentCommands: provision_command, ) -> None: ... -def configure_console( - log_directory: Path | None = None, *, verbose: bool = False, enable_logging: bool = False -) -> None: - """Configures, and, if requested, enables Console class instance exposed by the ataraxis-base-utilities library as - global 'console' variable. - - This function is designed to be called by the main cli group setup code to (optionally) enable sending messages to - terminal and logging them to log files. All functions of this library are expected to use the same global Console - instance, and they should use the tools exposed by the console to issue errors and echo messages. - - Notes: - Since version 1.1.0 of ataraxis-base-utilities and version 2.0.0 of this library, it uses shared 'console' - variable for terminal-printing and file-logging functionality. While effective, this design is potentially - dangerous, as it allows multiple modules to access and alter 'console' configuration. Since this function is - expected to be called from the highest module of the call hierarchy, it reconfigures and enables / disables the - console variable depending on the input arguments. This will interfere with any imported module that also - attempts to modify the console configuration. There should always be only one active module allowed to modify - console variable for each runtime. - - Args: - log_directory: The absolute path to the user logs directory. The function ensures the directory exists, but - relies on the main cli group to provide the directory path. - verbose: Determines whether to print messages and errors to the terminal. - enable_logging: Determines whether to save messages and errors to log files. Note, error log files are - automatically cleaned up after a few days, while message logs are maintained indefinitely. - """ - def resolve_project_directory() -> Path: """Gets the current working directory from the OS and verifies that it points to a valid python project. @@ -407,13 +411,9 @@ def environment_exists(commands: EnvironmentCommands) -> bool: True if the environment can be activated (and, implicitly, exists) and False if it cannot be activated. """ -def cli(verbose: bool, log: bool) -> None: +def cli() -> None: """This command-line interface exposes helper commands used to automate various project development and building - steps. - - In addition to being the main API interface for this library, it configures the logging system used by the library - based on the --verbose and --log options. These options apply to all subcommands of this CLI. - """ + steps.""" def process_typed_markers() -> None: """Crawls the library root directory and ensures that the 'py.typed' marker is found only at the highest level of diff --git a/tests/automation_test.py b/tests/automation_test.py index fd7e94e..96f7144 100644 --- a/tests/automation_test.py +++ b/tests/automation_test.py @@ -4,7 +4,6 @@ import re import sys from pathlib import Path -import tempfile import textwrap import subprocess from configparser import ConfigParser @@ -13,7 +12,6 @@ import yaml import click import pytest -from click.testing import CliRunner import ataraxis_automation.automation as aa from ataraxis_automation.automation import EnvironmentCommands @@ -53,52 +51,6 @@ def error_format(message: str) -> str: return re.escape(textwrap.fill(message, width=120, break_long_words=False, break_on_hyphens=False)) -def test_configure_console(tmp_path) -> None: - """Verifies the functionality of the configure_console() function.""" - # Setup - log_dir = tmp_path.joinpath("logs") - log_dir.mkdir() - message_log = log_dir.joinpath("message_log.txt") - error_log = log_dir.joinpath("error_log.txt") - - # Verifies initialization with logging enabled generates log files - aa.configure_console(log_dir, verbose=True, enable_logging=True) - assert message_log.exists() - assert error_log.exists() - - # Replaces the log directory. Uses replacement instead of reset due to a permission clash on Windows platforms - # where 'pytest' prevents the log directory from being cleared. - log_dir = tmp_path.joinpath("logs2") - log_dir.mkdir() - message_log = log_dir.joinpath("message_log.txt") - error_log = log_dir.joinpath("error_log.txt") - - # Verifies that disabling logging does not create log files - aa.configure_console(log_dir, verbose=True, enable_logging=False) - assert not message_log.exists() - assert not error_log.exists() - - # Changes the working directory to the general temporary directory to fail the tests below - new_project_directory = tempfile.gettempdir() - os.chdir(new_project_directory) - - # This should do two things: print a formatted message with traceback to the console and (evaluated here) call a - # SystemExit (through default callback). This is the expected 'verbose' console behavior. - # noinspection PyTypeChecker - with pytest.raises((SystemExit, RuntimeError), match="Runtime aborted."): - aa.resolve_project_directory() - - # Reconfigures console to not print or log anything. This also disables() the shared console variable. - aa.configure_console(log_dir, verbose=False, enable_logging=False) - assert not message_log.exists() - assert not error_log.exists() - - # When console is disabled, errors are raised using the standard python 'raise' system, which should be caught by - # pytest. - with pytest.raises(RuntimeError): - aa.resolve_project_directory() - - def test_resolve_project_directory(project_dir) -> None: """Verifies the functionality of the resolve_project_directory() function.""" os.chdir(project_dir) @@ -192,7 +144,7 @@ def test_resolve_environment_files(project_dir, monkeypatch) -> None: assert yml_path == project_dir / "envs" / f"{environment_base_name}_lin.yml" assert spec_path == project_dir / "envs" / f"{environment_base_name}_lin_spec.txt" - # Verifies environment resolution works as expected for the windows platform + # Verifies environment resolution works as expected for the Windows platform monkeypatch.setattr(sys, "platform", "win32") env_name, yml_path, spec_path = aa.resolve_environment_files( project_root=project_dir, environment_base_name=environment_base_name @@ -912,6 +864,7 @@ def test_verify_pypirc(tmp_path, config, expected_result): config_parser = ConfigParser() config_parser.read_dict(config) with pypirc_path.open("w") as f: + # noinspection PyTypeChecker config_parser.write(f) # Runs the verify_pypirc function diff --git a/tox.ini b/tox.ini index d34a450..74b4959 100644 --- a/tox.ini +++ b/tox.ini @@ -8,10 +8,9 @@ requires = tox-uv>=1,<2 tox>=4,<5 envlist = - uninstall lint stubs - {py310, py311, py312}-test + {py311, py312, py313}-test coverage docs install @@ -29,14 +28,12 @@ description = Runs static code formatting, style and typing checkers. Mypy may not work properly until py.typed marker is added by 'stubs' task. deps = - mypy>=1,<2 + mypy[faster-cache]>=1,<2 ruff>=0,<1 types-pyyaml>=6,<7 - ataraxis-automation>=3,<4 -depends = uninstall -basepython = py310 +basepython = py311 commands = - automation-cli --verbose purge-stubs + automation-cli purge-stubs ruff check --select I --fix ruff format mypy . --strict --extra-checks --warn-redundant-cast @@ -48,21 +45,20 @@ description = Generates the py.typed marker and the stub files using the built library wheel. Formats the stubs with ruff before moving them to appropriate source sub-directories. deps = - mypy>=1,<2 + mypy[faster-cache]>=1, <2 ruff>=0,<1 - ataraxis-automation>=3,<4 depends = lint commands = - automation-cli --verbose process-typed-markers + automation-cli process-typed-markers stubgen -o stubs --include-private --include-docstrings -p ataraxis_automation -v - automation-cli --verbose process-stubs + automation-cli process-stubs ruff check --select I --fix ruff format # Note: The test source code should be written to import and use intended library name, as the project is compiled and # installed as a library prior to running the tests. Therefore, the tests need to be designed to test the distributed # library, rather than the source code. -[testenv: {py310, py311, py312}-test] +[testenv: {py311, py312, py313}-test] package = wheel description = Runs unit and integration tests for each of the python versions listed in the task name. Uses 'loadgroup' balancing @@ -70,10 +66,9 @@ description = pytest-xdist documentation). deps = pytest>=8,<9 - pytest-cov>=5,<6 + pytest-cov>=6,<7 pytest-xdist>=3,<4 coverage[toml]>=7,<8 -depends = uninstall setenv = # Sets environment parameters, which includes intermediate coverage aggregation file used by coverage. COVERAGE_FILE = reports{/}.coverage.{envname} @@ -89,7 +84,7 @@ description = Combines test-coverage data from multiple test runs (for different python versions) into a single html file. The file can be viewed by loading the 'reports/coverage_html/index.html'. setenv = COVERAGE_FILE = reports/.coverage -depends = {py310, py311, py312}-test +depends = {py311, py312, py313}-test deps = junitparser>=3,<4 coverage[toml]>=7,<8 @@ -99,20 +94,6 @@ commands = coverage xml coverage html -# Note: since doxygen is not pip-installable, it has to be installed and made available system-wide for this task to -# succeed. Consult https://www.doxygen.nl/manual/install.html for guidance. This task is only included for reference -# purposes. Currently, it is NOT used for this project. It requires certain modifications to the 'docs' task and the -# conf.py file to work as intended. -[testenv:doxygen] -skip_install = true -description = - Generates C++ / C source code documentation using Doxygen. This assumes the source code uses doxygen-compatible - docstrings and that the root directory contains a Doxyfile that minimally configures Doxygen runtime. -allowlist_externals = doxygen -depends = uninstall -commands = - doxygen Doxyfile - # Uses '-j auto' to parallelize the build process and '-v' to make it verbose. [testenv:docs] description = @@ -120,9 +101,9 @@ description = 'docs/build/html/index.html'. depends = uninstall deps = - sphinx>=7,<8 + sphinx>=8,<9 importlib_metadata>=8,<9 - sphinx-rtd-theme>=2,<3 + sphinx-rtd-theme>=3,<4 sphinx-click>=6,<7 sphinx-autodoc-typehints>=2,<3 commands = @@ -149,114 +130,92 @@ description = Uses API token stored in '.pypirc' file or provided by user to authenticate the upload. deps = twine>=5,<6 - ataraxis-automation>=3,<4 allowlist_externals = distutils commands = - automation-cli --verbose acquire-pypi-token {posargs:} + automation-cli acquire-pypi-token {posargs:} twine upload dist/* --skip-existing --config-file .pypirc # Note: This task automatically uses the latest version of the package uploaded to PIP and expects it to contain # sdist archive. Ideally, it should be used together with the build and twine tasks, as that would ensure the recipe # always matches the latest distributed code version. [testenv:recipe] -skip_install = true description = Uses grayskull to parse the source code tarball stored on pip and generate the recipe used to submit the package to conda-forge. The submission process has to be carried out manually, see https://conda-forge.org/docs/maintainer/adding_pkgs/ for more details. deps = grayskull>=2,<3 - ataraxis-automation>=3,<4 commands = - automation-cli --verbose generate-recipe-folder + automation-cli generate-recipe-folder grayskull pypi ataraxis_automation -o recipe --strict-conda-forge --list-missing-deps -m Inkaros [testenv:install] -basepython = py310 -deps = - ataraxis-automation>=3,<4 +basepython = py311 depends = - uninstall lint stubs - {py310, py311, py312}-test + {py311, py312, py313}-test coverage docs description = Builds and installs the project into the specified conda environment. If the environment does not exist, creates it before installing the project. commands = - automation-cli --verbose install-project --environment-name axa_dev --python-version 3.12 + automation-cli install-project --environment-name axa_dev --python-version 3.13 [testenv:uninstall] -basepython = py310 -deps = - ataraxis-automation>=3,<4 +basepython = py311 description = Uninstalls the project from the specified conda environment. If the environment does not exist this task silently succeeds. commands = - automation-cli --verbose uninstall-project --environment-name axa_dev --python-version 3.12 + automation-cli uninstall-project --environment-name axa_dev --python-version 3.13 [testenv:create] -basepython = py310 -deps = - ataraxis-automation>=3,<4 +basepython = py311 description = Creates a minimally-configured conda environment using the requested python version and installs conda- and pip- dependencies extracted from pyproject.toml file into the environment. Does not install the project! commands = - automation-cli --verbose create-env --environment-name axa_dev --python-version 3.12 + automation-cli create-env --environment-name axa_dev --python-version 3.13 [testenv:remove] -basepython = py310 -deps = - ataraxis-automation>=3,<4 +basepython = py311 description = Removes the requested conda environment, if it is installed locally. commands = - automation-cli --verbose remove-env --environment-name axa_dev + automation-cli remove-env --environment-name axa_dev [testenv:provision] -basepython = py310 -deps = - ataraxis-automation>=3,<4 +basepython = py311 description = Provisions an already existing environment by uninstalling all packages from the environment and then installing the project dependencies using pyproject.toml specifications. commands = - automation-cli --verbose provision-env --environment-name axa_dev --python-version 3.12 + automation-cli provision-env --environment-name axa_dev --python-version 3.13 [testenv:export] -deps = - ataraxis-automation>=3,<4 description = Exports the requested conda environment to the 'envs' folder as a .yml file and as a spec.txt with revision history. commands = - automation-cli --verbose export-env --environment-name axa_dev + automation-cli export-env --environment-name axa_dev [testenv:import] -deps = - ataraxis-automation>=3,<4 description = Discovers and imports (installs) a new or updates an already existing environment using the .yml file stored in the 'envs' directory. commands = - automation-cli --verbose import-env --environment-name axa_dev + automation-cli import-env --environment-name axa_dev [testenv:rename] -deps = - ataraxis-automation>=3,<4 description = Replaces the base environment name used by all files inside the 'envs' directory with the user-input name. commands = - automation-cli --verbose rename-environments + automation-cli rename-environments [testenv:adopt] -deps = - ataraxis-automation>=3,<4 description = Adopts a Sun Lab template-generated project by replacing default placeholders with user-provided information. commands = - automation-cli --verbose adopt-project + automation-cli adopt-project From b732985bb6e7ffed623286e416b420b28fa676f7 Mon Sep 17 00:00:00 2001 From: Inkaros Date: Sat, 23 Nov 2024 17:08:37 -0500 Subject: [PATCH 2/4] Improved conda management automation -- Fixed conda activation printing conda 'help' information to terminal on Windows by redirecting activation printouts to Null. -- Improved conda environment location discovery by adding multiple fallback methods for discovering conda environment root folder. In turn, this is now used to make uv target the correct conda environment without using the 'basepython vs target-python' shenanigans. -- Added refreshing to all uv commands to ensure uv always installs the latest compatible dependencies when reinstalling packages. -- Added an additional step to environment removal process that ensures the environment folder is deleted. This fixes an error previously seen on some platform where the remove command did not delete the environment folder after removing all packages. -- Moved uv, tox and tox-uv to pip dependencies. -- Updated tox.ini, readme and pyproject to reflect the latest library changes. -- Updated tests to comply with the changes. -- Rebuilt and exported windows development environment. --- README.md | 118 +++---- envs/axa_dev_win.yml | 191 +++++----- envs/axa_dev_win_spec.txt | 464 ++++++++++++------------- pyproject.toml | 10 +- src/ataraxis_automation/automation.py | 200 +++++++---- src/ataraxis_automation/automation.pyi | 34 +- tests/automation_test.py | 23 +- tox.ini | 10 +- 8 files changed, 545 insertions(+), 505 deletions(-) diff --git a/README.md b/README.md index 8f6fd42..7446c2b 100644 --- a/README.md +++ b/README.md @@ -74,13 +74,6 @@ ___ ### PIP Use the following command to install the library using PIP: ```pip install ataraxis-automation``` - -### Conda / Mamba - -**_Note. Due to conda-forge contributing process being more nuanced than pip uploads, conda versions may lag behind -pip and source code distributions._** - -Use the following command to install the library using Conda or Mamba: ```conda install ataraxis-automation``` ___ ## Usage @@ -117,30 +110,19 @@ This library is intended to be used to augment 'tox' runtimes, and this is alway To use any of the commands as part of a tox 'task,' add it to the 'commands' section of the tox.ini: ``` [testenv:create] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Creates a minimally-configured conda environment using the requested python version and installs conda- and pip- dependencies extracted from pyproject.toml file into the environment. Does not install the project! commands = - automation-cli --verbose create-env --environment-name axa_dev --python-version 3.12 + automation-cli create-env --environment-name axa_dev --python-version 3.13 ``` -#### Logging and Printing -All cli commands come with two parameters exposed through the main cli group: -1. ```--verbose```: Determines whether to display Information, Warning and Success messages to inform the user about - the ongoing runtime. -2. ```--log```: Determines whether to save messages and errors to log files (located in automatically generated folder - inside user log directory). #### Command-specific flags *__Note!__* Many sub-commands of the cli have additional flags and arguments that can be used to further customize their runtime. Consult the API documentation to see these options with detailed descriptions. -*__Warning!__* When using any cli command that uses ```--python-version``` flag from tox, you __have__ to include -```basepython=``` line in the environment configuration __and__ set it to a python version __different__ from the -one provided after ```--python-version``` argument. See the 'testenv:create' example above. - ### Intended cli use pattern All cli commands are intended to be used through tox pipelines. The most recent version of Sun Lab tox configuration is always available from this libraries' [tox.ini file](tox.ini). Since this library plays a large role in our tox @@ -186,12 +168,12 @@ deps = mypy>=1,<2 ruff>=0,<1 types-pyyaml>=6,<7 - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 depends = uninstall # Note! Basepython has to be set to the 'lowest' version supported by your project -basepython = py310 +basepython = py311 commands = - automation-cli --verbose purge-stubs + automation-cli purge-stubs ruff check --select I --fix ruff format mypy . --strict --extra-checks --warn-redundant-cast @@ -215,29 +197,29 @@ description = deps = mypy>=1,<2 ruff>=0,<1 - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 depends = lint commands = - automation-cli --verbose process-typed-markers + automation-cli process-typed-markers stubgen -o stubs --include-private --include-docstrings -p ataraxis_automation -v ruff check --select I --fix ruff format - automation-cli --verbose process-stubs + automation-cli process-stubs ``` #### Test Shell command: ```tox -e pyXXX-test``` This task is available for all python versions supported by each project. For example, automation supports versions -3.10, 3.11, and 3.12. Therefore, it will have ```tox -e py310-test```, ```tox -e py311-test``` and -```tox -e py312-test``` as valid 'test' tasks. These tasks are used to build the project in an isolated environment and +3.11 3.12, and 3.13. Therefore, it will have ```tox -e py311-test```, ```tox -e py312-test``` and +```tox -e py313-test``` as valid 'test' tasks. These tasks are used to build the project in an isolated environment and run the tests expected to be located inside the project_root/tests directory to verify the project works as expected for each python version. This is especially relevant for c-extension projects that compile code for specific python versions and platforms. Example tox.ini section: ``` -[testenv: {py310, py311, py312}-test] +[testenv: {py311, py312, py313}-test] package = wheel description = Runs unit and integration tests for each of the python versions listed in the task name. Uses 'loadgroup' balancing @@ -245,7 +227,7 @@ description = pytest-xdist documentation). deps = pytest>=8,<9 - pytest-cov>=5,<6 + pytest-cov>=6,<7 pytest-xdist>=3,<4 coverage[toml]>=7,<8 depends = uninstall @@ -274,7 +256,7 @@ description = Combines test-coverage data from multiple test runs (for different python versions) into a single html file. The file can be viewed by loading the 'reports/coverage_html/index.html'. setenv = COVERAGE_FILE = reports/.coverage -depends = {py310, py311, py312}-test +depends = {py311, py312, py313}-test deps = junitparser>=3,<4 coverage[toml]>=7,<8 @@ -312,7 +294,7 @@ Shell command: ```tox -e docs``` Uses [sphinx](https://www.sphinx-doc.org/en/master/) to automatically parse docstrings from source code and use them to build API documentation for the project. C-extension projects use a slightly modified version of this task that uses -[breathe](https://breathe.readthedocs.io/en/latest/) to convert doxygen-generated xml files for c-code into a format +[breathe](https://breathe.readthedocs.io/en/latest/) to convert doxygen-generated XML files for c-code into a format that sphinx can parse. This way, c-extension projects can include both Python and C/C++ API documentation as part of the same file. This task relies on the configuration files stored inside /project_root/docs/source folder to define the generated documentation format. Built documentation can be viewed by opening @@ -326,9 +308,9 @@ description = 'docs/build/html/index.html'. depends = uninstall deps = - sphinx>=7,<8 + sphinx>=8,<9 importlib_metadata>=8,<9 - sphinx-rtd-theme>=2,<3 + sphinx-rtd-theme>=3,<4 sphinx-click>=6,<7 sphinx-autodoc-typehints>=2,<3 commands = @@ -416,11 +398,11 @@ description = Uses API token stored in '.pypirc' file or provided by user to authenticate the upload. deps = twine>=5,<6 - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 allowlist_externals = distutils commands = - automation-cli --verbose acquire-pypi-token {posargs:} + automation-cli acquire-pypi-token {posargs:} twine upload dist/* --skip-existing --config-file .pypirc ``` @@ -445,9 +427,9 @@ description = https://conda-forge.org/docs/maintainer/adding_pkgs/ for more details. deps = grayskull>=2,<3 - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 commands = - automation-cli --verbose generate-recipe-folder + automation-cli generate-recipe-folder grayskull pypi ataraxis_automation -o recipe --strict-conda-forge --list-missing-deps -m Inkaros ``` @@ -466,47 +448,40 @@ project development environment. This is a prerequisite for manually running and actively developed. During general 'tox' runtime, this task is used to (re)install the project into the project environment as necessary to avoid collisions with 'tox.' -*__Note!__* The 'basepython' argument should always be set to a version different from '--python-version.' - Example tox.ini section: ``` [testenv:install] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 depends = - uninstall lint stubs - {py310, py311, py312}-test + {py311, py311, py312}-test coverage docs description = Builds and installs the project into the specified conda environment. If the environment does not exist, creates it before installing the project. commands = - automation-cli --verbose install-project --environment-name axa_dev --python-version 3.12 + automation-cli install-project --environment-name axa_dev ``` #### Uninstall Shell command: ```tox -e uninstall``` -Removes the project from the requested environment. This task is used in-conjunction with the 'install' task to -avoid version collisions when running general 'tox' tasks. - -*__Note!__* The 'basepython' argument should always be set to a version different from '--python-version.' +Removes the project from the requested environment. This task is no longer used in most automation pipelines, but is +kept for backward-compatibility. Example tox.ini section: ``` [testenv:uninstall] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Uninstalls the project from the specified conda environment. If the environment does not exist this task silently succeeds. commands = - automation-cli --verbose uninstall-project --environment-name axa_dev --python-version 3.12 + automation-cli uninstall-project --environment-name axa_dev ``` #### Create @@ -518,19 +493,16 @@ To work as intended, it uses automation-cli to parse the contents of tox.ini and list of project dependencies. It assumes that dependencies are stored using Sun Lab format: inside 'conda,' 'noconda,' 'condarun,' and general 'dependencies' section. -*__Note!__* The 'basepython' argument should always be set to a version different from '--python-version.' - Example tox.ini section: ``` [testenv:create] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Creates a minimally-configured conda environment using the requested python version and installs conda- and pip- dependencies extracted from pyproject.toml file into the environment. Does not install the project! commands = - automation-cli --verbose create-env --environment-name axa_dev --python-version 3.12 + automation-cli create-env --environment-name axa_dev --python-version 3.13 ``` #### Remove @@ -542,13 +514,12 @@ after finishing development and to hard-reset the environment (this use is disco Example tox.ini section: ``` [testenv:remove] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Removes the requested conda environment, if it is installed locally. commands = - automation-cli --verbose remove-env --environment-name axa_dev + automation-cli remove-env --environment-name axa_dev ``` #### Provision @@ -559,27 +530,24 @@ them. It first uninstalls all packages in the environment and then re-installs p file. This is the same procedure as used by the 'create' task. Since this task does not remove the environment, it preserves all references used by tools such as IDEs, but completely resets all packages in the environment. This can be used to both reset and actualize project development environments to match the latest version of the -.toml specification. - -*__Note!__* The 'basepython' argument should always be set to a version different from '--python-version.' +.toml specification. ion.' Example tox.ini section: ``` [testenv:provision] -basepython = py310 deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Provisions an already existing environment by uninstalling all packages from the environment and then installing the project dependencies using pyproject.toml specifications. commands = - automation-cli --verbose provision-env --environment-name axa_dev --python-version 3.12 + automation-cli provision-env --environment-name axa_dev --python-version 3.13 ``` #### Export Shell command: ```tox -e export``` -Exports the target development environment as a .yml and spec.txt files. This task is used before distributing new +Exports the target development environment as a .yml and spec.txt file. This task is used before distributing new versions of the project. This allows end-users to generate an identical copy of the development environment, which is a highly encouraged feature for most projects. While our 'create' and 'provision' tasks make this largely obsolete, we still include exported environments in all our project distributions. @@ -588,11 +556,11 @@ Example tox.ini section: ``` [testenv:export] deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Exports the requested conda environment to the 'envs' folder as a .yml file and as a spec.txt with revision history. commands = - automation-cli --verbose export-env --environment-name axa_dev + automation-cli export-env --environment-name axa_dev ``` #### Import @@ -608,12 +576,12 @@ Example tox.ini section: ``` [testenv:import] deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Discovers and imports (installs) a new or updates an already existing environment using the .yml file stored in the 'envs' directory. commands = - automation-cli --verbose import-env --environment-name axa_dev + automation-cli import-env --environment-name axa_dev ``` #### Rename @@ -629,11 +597,11 @@ Example tox.ini section: ``` [testenv:rename] deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Replaces the base environment name used by all files inside the 'envs' directory with the user-input name. commands = - automation-cli --verbose rename-environments + automation-cli rename-environments ``` #### Adopt @@ -648,11 +616,11 @@ Example tox.ini section: ``` [testenv:adopt] deps = - ataraxis-automation>=3,<4 + ataraxis-automation>=4,<5 description = Adopts a Sun Lab template-generated project by replacing default placeholders with user-provided information. commands = - automation-cli --verbose adopt-project + automation-cli adopt-project ``` ___ diff --git a/envs/axa_dev_win.yml b/envs/axa_dev_win.yml index 7a58338..5dfc6dd 100644 --- a/envs/axa_dev_win.yml +++ b/envs/axa_dev_win.yml @@ -3,150 +3,147 @@ channels: - conda-forge - defaults dependencies: - - alabaster=0.7.16=pyhd8ed1ab_0 + - alabaster=1.0.0=pyhd8ed1ab_0 - appdirs=1.4.4=pyh9f0ad1d_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 + - babel=2.16.0=pyhd8ed1ab_0 + - backports=1.0=pyhd8ed1ab_4 + - backports.tarfile=1.2.0=pyhd8ed1ab_0 - beautifulsoup4=4.12.3=pyha770c72_0 - - black=24.4.2=py312h2e8e312_0 - - brotli-python=1.1.0=py312h53d5487_1 + - black=24.10.0=py313hfa70ccb_0 + - brotli-python=1.1.0=py313h5813708_2 - bzip2=1.0.8=h2466b09_7 - - ca-certificates=2024.7.4=h56e8100_0 - - cachetools=5.4.0=pyhd8ed1ab_0 - - certifi=2024.7.4=pyhd8ed1ab_0 - - cffi=1.16.0=py312he70551f_0 - - chardet=5.2.0=py312h2e8e312_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - ca-certificates=2024.8.30=h56e8100_0 + - cachetools=5.5.0=pyhd8ed1ab_0 + - certifi=2024.8.30=pyhd8ed1ab_0 + - cffi=1.17.1=py313ha7868ed_0 + - chardet=5.2.0=py313hfa70ccb_2 + - charset-normalizer=3.4.0=pyhd8ed1ab_0 - click=8.1.7=win_pyh7428d3b_0 - - cmarkgfm=0.8.0=py312he70551f_3 + - cmarkgfm=2024.11.20=py313ha7868ed_0 - colorama=0.4.6=pyhd8ed1ab_0 - conda-souschef=2.2.3=pyhd8ed1ab_0 - - coverage=7.6.0=py312h4389bb4_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.20.1=py312h2e8e312_3 + - coverage=7.6.7=py313hb4c8b1a_0 + - distlib=0.3.9=pyhd8ed1ab_0 + - docutils=0.21.2=pyhd8ed1ab_0 - editables=0.5=pyhd8ed1ab_0 - exceptiongroup=1.2.2=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_0 - - filelock=3.15.4=pyhd8ed1ab_0 + - filelock=3.16.1=pyhd8ed1ab_0 - future=1.0.0=pyhd8ed1ab_0 - - grayskull=2.5.3=pyhd8ed1ab_0 + - grayskull=2.7.3=pyhd8ed1ab_0 - h2=4.1.0=pyhd8ed1ab_0 - - hatchling=1.25.0=pyhd8ed1ab_0 + - hatchling=1.26.3=pypyhff2d567_0 - hpack=4.0.0=pyh9f0ad1d_0 - hyperframe=6.0.1=pyhd8ed1ab_0 - - idna=3.7=pyhd8ed1ab_0 + - idna=3.10=pyhd8ed1ab_0 - imagesize=1.4.1=pyhd8ed1ab_0 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 + - importlib-metadata=8.5.0=pyha770c72_0 + - importlib_metadata=8.5.0=hd8ed1ab_0 + - importlib_resources=6.4.5=pyhd8ed1ab_0 - iniconfig=2.0.0=pyhd8ed1ab_0 - - intel-openmp=2024.2.0=h57928b3_980 + - intel-openmp=2024.2.1=h57928b3_1083 - jaraco.classes=3.4.0=pyhd8ed1ab_1 - jaraco.context=5.3.0=pyhd8ed1ab_1 - jaraco.functools=4.0.0=pyhd8ed1ab_0 - jinja2=3.1.4=pyhd8ed1ab_0 - - junitparser=3.1.2=pyhd8ed1ab_0 - - keyring=25.2.1=pyh7428d3b_0 - - libblas=3.9.0=22_win64_mkl - - libcblas=3.9.0=22_win64_mkl - - libexpat=2.6.2=h63175ca_0 + - junitparser=3.2.0=pyhd8ed1ab_0 + - keyring=25.5.0=pyh7428d3b_0 + - libblas=3.9.0=25_win64_mkl + - libcblas=3.9.0=25_win64_mkl + - libexpat=2.6.4=he0c23c2_0 - libffi=3.4.2=h8ffe710_5 - libhwloc=2.11.1=default_h8125262_1000 - libiconv=1.17=hcfcfb64_2 - - liblapack=3.9.0=22_win64_mkl - - libsqlite=3.46.0=h2466b09_0 - - libxml2=2.12.7=h0f24e4e_4 - - libzlib=1.3.1=h2466b09_1 + - liblapack=3.9.0=25_win64_mkl + - libmpdec=4.0.0=h2466b09_0 + - libsqlite=3.47.0=h2466b09_1 + - libxml2=2.13.5=h442d1da_0 + - libzlib=1.3.1=h2466b09_2 - markdown-it-py=3.0.0=pyhd8ed1ab_0 - - markupsafe=2.1.5=py312he70551f_0 + - markupsafe=3.0.2=py313hb4c8b1a_0 - mdurl=0.1.2=pyhd8ed1ab_0 - - mkl=2024.1.0=h66d3029_692 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mypy=1.10.1=py312h4389bb4_0 + - mkl=2024.2.2=h66d3029_14 + - more-itertools=10.5.0=pyhd8ed1ab_0 + - mypy=1.13.0=py313ha7868ed_0 - mypy_extensions=1.0.0=pyha770c72_0 - - nh3=0.2.18=py312h68c23d6_0 - - numpy=2.0.0=py312h49bc9c5_0 - - openssl=3.3.1=h2466b09_2 - - packaging=24.1=pyhd8ed1ab_0 + - nh3=0.2.18=py313hde2adac_1 + - numpy=2.1.3=py313hee8cc43_0 + - openssl=3.4.0=h2466b09_0 + - packaging=24.2=pyhff2d567_1 - pathspec=0.12.1=pyhd8ed1ab_0 - - pip=24.0=pyhd8ed1ab_0 + - pip=24.3.1=pyh145f28c_0 - pkginfo=1.10.0=pyhd8ed1ab_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 + - platformdirs=4.3.6=pyhd8ed1ab_0 - pluggy=1.5.0=pyhd8ed1ab_0 - - progressbar2=4.4.2=pyhd8ed1ab_0 - - psutil=6.0.0=py312h4389bb4_0 - - pthreads-win32=2.9.1=hfa6e2cd_3 + - progressbar2=4.5.0=pyhd8ed1ab_0 + - psutil=6.1.0=py313ha7868ed_0 + - pthreads-win32=2.9.1=h2466b09_4 - pycparser=2.22=pyhd8ed1ab_0 - pygments=2.18.0=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 + - pyproject-api=1.8.0=pyhd8ed1ab_0 - pysocks=1.7.1=pyh0701188_6 - - pytest=8.3.1=pyhd8ed1ab_0 - - pytest-cov=5.0.0=pyhd8ed1ab_0 + - pytest=8.3.3=pyhd8ed1ab_0 + - pytest-cov=6.0.0=pyhd8ed1ab_0 - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.12.4=h889d299_0_cpython - - python-utils=3.8.2=pyhd8ed1ab_0 - - python_abi=3.12=4_cp312 - - pytz=2024.1=pyhd8ed1ab_0 - - pywin32-ctypes=0.2.2=py312h2e8e312_1 - - pyyaml=6.0.1=py312he70551f_1 - - rapidfuzz=3.9.4=py312h275cf98_0 - - readme_renderer=42.0=pyhd8ed1ab_0 + - python=3.13.0=hf5aa216_100_cp313 + - python-utils=3.9.0=pyhff2d567_1 + - python_abi=3.13=5_cp313 + - pytz=2024.2=pyhd8ed1ab_0 + - pywin32-ctypes=0.2.3=py313hfa70ccb_1 + - pyyaml=6.0.2=py313ha7868ed_1 + - rapidfuzz=3.10.1=py313h5813708_0 + - readme_renderer=44.0=pyhd8ed1ab_0 - requests=2.32.3=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_0 - rfc3986=2.0.0=pyhd8ed1ab_0 - - rich=13.7.1=pyhd8ed1ab_0 - - ruamel.yaml=0.18.6=py312he70551f_0 - - ruamel.yaml.clib=0.2.8=py312he70551f_0 - - ruamel.yaml.jinja2=0.2.4=py_1 - - ruff=0.5.2=py312h7a6832a_0 + - rich=13.9.4=pyhd8ed1ab_0 + - ruamel.yaml=0.18.6=py313ha7868ed_1 + - ruamel.yaml.clib=0.2.8=py313ha7868ed_1 + - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_0 + - ruff=0.8.0=py313h331c231_0 - semver=3.0.2=pyhd8ed1ab_0 - - setuptools=71.0.4=pyhd8ed1ab_0 + - setuptools=75.6.0=pyhff2d567_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.4.7=pyhd8ed1ab_0 - - sphinx-autodoc-typehints=2.2.3=pyhd8ed1ab_0 + - sphinx=8.1.3=pyhd8ed1ab_0 + - sphinx-autodoc-typehints=2.5.0=pyhd8ed1ab_0 - sphinx-click=6.0.0=pyhd8ed1ab_0 - - sphinx-rtd-theme=2.0.0=hd8ed1ab_0 - - sphinx_rtd_theme=2.0.0=pyha770c72_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.6=pyhd8ed1ab_0 + - sphinx-rtd-theme=3.0.1=hd8ed1ab_0 + - sphinx_rtd_theme=3.0.1=pyha770c72_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_0 - sphinxcontrib-jquery=4.1=pyhd8ed1ab_0 - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.8=pyhd8ed1ab_0 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_0 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - stdlib-list=0.10.0=pyhd8ed1ab_0 - - tbb=2021.12.0=hc790b64_3 + - stdlib-list=0.11.0=pyhd8ed1ab_0 + - tbb=2021.13.0=hc790b64_0 - tk=8.6.13=h5226925_1 - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomli-w=1.0.0=pyhd8ed1ab_0 - - tox=4.16.0=pyhd8ed1ab_0 - - trove-classifiers=2024.7.2=pyhd8ed1ab_0 + - tomli=2.1.0=pyhff2d567_0 + - tomli-w=1.1.0=pyhd8ed1ab_0 + - tox=4.23.2=pyhd8ed1ab_0 + - trove-classifiers=2024.10.21.16=pyhd8ed1ab_0 - twine=5.1.1=pyhd8ed1ab_0 - - types-pyyaml=6.0.12.20240311=pyhd8ed1ab_0 + - types-pyyaml=6.0.12.20240917=pyhd8ed1ab_0 - typing_extensions=4.12.2=pyha770c72_0 - - tzdata=2024a=h0c530f3_0 - - ucrt=10.0.22621.0=h57928b3_0 - - urllib3=2.2.2=pyhd8ed1ab_1 - - vc=14.3=h8a93ad2_20 - - vc14_runtime=14.40.33810=ha82c5b3_20 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - vs2015_runtime=14.40.33810=h3bf8584_20 - - wheel=0.43.0=pyhd8ed1ab_1 - - win_inet_pton=1.1.0=pyhd8ed1ab_6 + - tzdata=2024b=hc8b5060_0 + - ucrt=10.0.22621.0=h57928b3_1 + - urllib3=2.2.3=pyhd8ed1ab_0 + - vc=14.3=ha32ba9b_23 + - vc14_runtime=14.42.34433=he29a5d6_23 + - virtualenv=20.27.1=pyhd8ed1ab_0 + - vs2015_runtime=14.42.34433=hdffcdeb_23 + - win_inet_pton=1.1.0=pyh7428d3b_7 - xz=5.2.6=h8d14728_0 - yaml=0.2.5=h8ffe710_2 - - zipp=3.19.2=pyhd8ed1ab_0 - - zstandard=0.23.0=py312h7606c53_0 + - zipp=3.21.0=pyhd8ed1ab_0 + - zstandard=0.23.0=py313h574b89f_1 - zstd=1.5.6=h0ea2cb4_0 - pip: - - ataraxis-automation==3.0.2 - - ataraxis-base-utilities==2.0.1 - - build==1.2.1 - - loguru==0.7.2 - - pyproject-hooks==1.1.0 - - tox-uv==1.9.1 - - uv==0.2.26 - - win32-setctime==1.1.0 + - ataraxis-automation==4.0.0 + - build==1.2.2.post1 + - pyproject-hooks==1.2.0 + - tox-uv==1.16.0 + - uv==0.5.4 diff --git a/envs/axa_dev_win_spec.txt b/envs/axa_dev_win_spec.txt index 086ca6c..ece3de5 100644 --- a/envs/axa_dev_win_spec.txt +++ b/envs/axa_dev_win_spec.txt @@ -1,427 +1,427 @@ -2024-07-17 18:55:02 (rev 0) +2024-11-23 16:30:52 (rev 0) +bzip2-1.0.8 (conda-forge/win-64) - +ca-certificates-2024.7.4 (conda-forge/win-64) - +cachetools-5.4.0 (conda-forge/noarch) + +ca-certificates-2024.8.30 (conda-forge/win-64) + +cachetools-5.5.0 (conda-forge/noarch) +chardet-5.2.0 (conda-forge/win-64) +colorama-0.4.6 (conda-forge/noarch) - +distlib-0.3.8 (conda-forge/noarch) - +filelock-3.15.4 (conda-forge/noarch) - +libexpat-2.6.2 (conda-forge/win-64) + +distlib-0.3.9 (conda-forge/noarch) + +filelock-3.16.1 (conda-forge/noarch) + +libexpat-2.6.4 (conda-forge/win-64) +libffi-3.4.2 (conda-forge/win-64) - +libsqlite-3.46.0 (conda-forge/win-64) + +libmpdec-4.0.0 (conda-forge/win-64) + +libsqlite-3.47.0 (conda-forge/win-64) +libzlib-1.3.1 (conda-forge/win-64) - +openssl-3.3.1 (conda-forge/win-64) - +packaging-24.1 (conda-forge/noarch) - +pip-24.0 (conda-forge/noarch) - +platformdirs-4.2.2 (conda-forge/noarch) + +openssl-3.4.0 (conda-forge/win-64) + +packaging-24.2 (conda-forge/noarch) + +pip-24.3.1 (conda-forge/noarch) + +platformdirs-4.3.6 (conda-forge/noarch) +pluggy-1.5.0 (conda-forge/noarch) - +pyproject-api-1.7.1 (conda-forge/noarch) - +python-3.12.4 (conda-forge/win-64) - +python_abi-3.12 (conda-forge/win-64) - +setuptools-70.3.0 (conda-forge/noarch) + +pyproject-api-1.8.0 (conda-forge/noarch) + +python-3.13.0 (conda-forge/win-64) + +python_abi-3.13 (conda-forge/win-64) +tk-8.6.13 (conda-forge/win-64) - +tomli-2.0.1 (conda-forge/noarch) - +tox-4.16.0 (conda-forge/noarch) - +tzdata-2024a (conda-forge/noarch) + +tomli-2.1.0 (conda-forge/noarch) + +tox-4.23.2 (conda-forge/noarch) + +typing_extensions-4.12.2 (conda-forge/noarch) + +tzdata-2024b (conda-forge/noarch) +ucrt-10.0.22621.0 (conda-forge/win-64) - +uv-0.2.25 (conda-forge/win-64) + +uv-0.5.4 (conda-forge/win-64) +vc-14.3 (conda-forge/win-64) - +vc14_runtime-14.40.33810 (conda-forge/win-64) - +virtualenv-20.26.3 (conda-forge/noarch) - +vs2015_runtime-14.40.33810 (conda-forge/win-64) - +wheel-0.43.0 (conda-forge/noarch) + +vc14_runtime-14.42.34433 (conda-forge/win-64) + +virtualenv-20.27.1 (conda-forge/noarch) + +vs2015_runtime-14.42.34433 (conda-forge/win-64) +xz-5.2.6 (conda-forge/win-64) -2024-07-17 18:55:22 (rev 1) - +alabaster-0.7.16 (conda-forge/noarch) +2024-11-23 16:31:17 (rev 1) + +alabaster-1.0.0 (conda-forge/noarch) +appdirs-1.4.4 (conda-forge/noarch) - +babel-2.14.0 (conda-forge/noarch) + +babel-2.16.0 (conda-forge/noarch) +backports-1.0 (conda-forge/noarch) - +backports.tarfile-1.0.0 (conda-forge/noarch) + +backports.tarfile-1.2.0 (conda-forge/noarch) +beautifulsoup4-4.12.3 (conda-forge/noarch) - +black-24.4.2 (conda-forge/win-64) + +black-24.10.0 (conda-forge/win-64) +brotli-python-1.1.0 (conda-forge/win-64) - +certifi-2024.7.4 (conda-forge/noarch) - +cffi-1.16.0 (conda-forge/win-64) - +charset-normalizer-3.3.2 (conda-forge/noarch) + +certifi-2024.8.30 (conda-forge/noarch) + +cffi-1.17.1 (conda-forge/win-64) + +charset-normalizer-3.4.0 (conda-forge/noarch) +click-8.1.7 (conda-forge/noarch) - +cmarkgfm-0.8.0 (conda-forge/win-64) + +cmarkgfm-2024.11.20 (conda-forge/win-64) +conda-souschef-2.2.3 (conda-forge/noarch) - +coverage-7.6.0 (conda-forge/win-64) - +docutils-0.20.1 (conda-forge/win-64) + +coverage-7.6.7 (conda-forge/win-64) + +docutils-0.21.2 (conda-forge/noarch) +editables-0.5 (conda-forge/noarch) +exceptiongroup-1.2.2 (conda-forge/noarch) +execnet-2.1.1 (conda-forge/noarch) +future-1.0.0 (conda-forge/noarch) - +grayskull-2.5.3 (conda-forge/noarch) + +grayskull-2.7.3 (conda-forge/noarch) +h2-4.1.0 (conda-forge/noarch) - +hatchling-1.25.0 (conda-forge/noarch) + +hatchling-1.26.3 (conda-forge/noarch) +hpack-4.0.0 (conda-forge/noarch) +hyperframe-6.0.1 (conda-forge/noarch) - +idna-3.7 (conda-forge/noarch) + +idna-3.10 (conda-forge/noarch) +imagesize-1.4.1 (conda-forge/noarch) - +importlib-metadata-8.0.0 (conda-forge/noarch) - +importlib_metadata-8.0.0 (conda-forge/noarch) - +importlib_resources-6.4.0 (conda-forge/noarch) + +importlib-metadata-8.5.0 (conda-forge/noarch) + +importlib_metadata-8.5.0 (conda-forge/noarch) + +importlib_resources-6.4.5 (conda-forge/noarch) +iniconfig-2.0.0 (conda-forge/noarch) - +intel-openmp-2024.2.0 (conda-forge/win-64) + +intel-openmp-2024.2.1 (conda-forge/win-64) +jaraco.classes-3.4.0 (conda-forge/noarch) +jaraco.context-5.3.0 (conda-forge/noarch) +jaraco.functools-4.0.0 (conda-forge/noarch) +jinja2-3.1.4 (conda-forge/noarch) - +junitparser-3.1.2 (conda-forge/noarch) - +keyring-25.2.1 (conda-forge/noarch) + +junitparser-3.2.0 (conda-forge/noarch) + +keyring-25.5.0 (conda-forge/noarch) +libblas-3.9.0 (conda-forge/win-64) +libcblas-3.9.0 (conda-forge/win-64) +libhwloc-2.11.1 (conda-forge/win-64) +libiconv-1.17 (conda-forge/win-64) +liblapack-3.9.0 (conda-forge/win-64) - +libxml2-2.12.7 (conda-forge/win-64) + +libxml2-2.13.5 (conda-forge/win-64) +markdown-it-py-3.0.0 (conda-forge/noarch) - +markupsafe-2.1.5 (conda-forge/win-64) + +markupsafe-3.0.2 (conda-forge/win-64) +mdurl-0.1.2 (conda-forge/noarch) - +mkl-2024.1.0 (conda-forge/win-64) - +more-itertools-10.3.0 (conda-forge/noarch) - +mypy-1.10.1 (conda-forge/win-64) + +mkl-2024.2.2 (conda-forge/win-64) + +more-itertools-10.5.0 (conda-forge/noarch) + +mypy-1.13.0 (conda-forge/win-64) +mypy_extensions-1.0.0 (conda-forge/noarch) +nh3-0.2.18 (conda-forge/win-64) - +numpy-2.0.0 (conda-forge/win-64) + +numpy-2.1.3 (conda-forge/win-64) +pathspec-0.12.1 (conda-forge/noarch) +pkginfo-1.10.0 (conda-forge/noarch) - +progressbar2-4.4.2 (conda-forge/noarch) - +psutil-6.0.0 (conda-forge/win-64) + +progressbar2-4.5.0 (conda-forge/noarch) + +psutil-6.1.0 (conda-forge/win-64) +pthreads-win32-2.9.1 (conda-forge/win-64) +pycparser-2.22 (conda-forge/noarch) +pygments-2.18.0 (conda-forge/noarch) +pysocks-1.7.1 (conda-forge/noarch) - +pytest-8.2.2 (conda-forge/noarch) - +pytest-cov-5.0.0 (conda-forge/noarch) + +pytest-8.3.3 (conda-forge/noarch) + +pytest-cov-6.0.0 (conda-forge/noarch) +pytest-xdist-3.6.1 (conda-forge/noarch) - +python-utils-3.8.2 (conda-forge/noarch) - +pytz-2024.1 (conda-forge/noarch) - +pywin32-ctypes-0.2.2 (conda-forge/win-64) - +pyyaml-6.0.1 (conda-forge/win-64) - +rapidfuzz-3.9.4 (conda-forge/win-64) - +readme_renderer-42.0 (conda-forge/noarch) + +python-utils-3.9.0 (conda-forge/noarch) + +pytz-2024.2 (conda-forge/noarch) + +pywin32-ctypes-0.2.3 (conda-forge/win-64) + +pyyaml-6.0.2 (conda-forge/win-64) + +rapidfuzz-3.10.1 (conda-forge/win-64) + +readme_renderer-44.0 (conda-forge/noarch) +requests-2.32.3 (conda-forge/noarch) +requests-toolbelt-1.0.0 (conda-forge/noarch) +rfc3986-2.0.0 (conda-forge/noarch) - +rich-13.7.1 (conda-forge/noarch) + +rich-13.9.4 (conda-forge/noarch) +ruamel.yaml-0.18.6 (conda-forge/win-64) +ruamel.yaml.clib-0.2.8 (conda-forge/win-64) - +ruamel.yaml.jinja2-0.2.4 (conda-forge/noarch) - +ruff-0.5.2 (conda-forge/win-64) + +ruamel.yaml.jinja2-0.2.7 (conda-forge/noarch) + +ruff-0.8.0 (conda-forge/win-64) +semver-3.0.2 (conda-forge/noarch) + +setuptools-75.6.0 (conda-forge/noarch) +snowballstemmer-2.2.0 (conda-forge/noarch) +soupsieve-2.5 (conda-forge/noarch) - +sphinx-7.4.5 (conda-forge/noarch) - +sphinx-autodoc-typehints-2.2.2 (conda-forge/noarch) + +sphinx-8.1.3 (conda-forge/noarch) + +sphinx-autodoc-typehints-2.5.0 (conda-forge/noarch) +sphinx-click-6.0.0 (conda-forge/noarch) - +sphinx-rtd-theme-2.0.0 (conda-forge/noarch) - +sphinx_rtd_theme-2.0.0 (conda-forge/noarch) - +sphinxcontrib-applehelp-1.0.8 (conda-forge/noarch) - +sphinxcontrib-devhelp-1.0.6 (conda-forge/noarch) - +sphinxcontrib-htmlhelp-2.0.5 (conda-forge/noarch) + +sphinx-rtd-theme-3.0.1 (conda-forge/noarch) + +sphinx_rtd_theme-3.0.1 (conda-forge/noarch) + +sphinxcontrib-applehelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-devhelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-htmlhelp-2.1.0 (conda-forge/noarch) +sphinxcontrib-jquery-4.1 (conda-forge/noarch) +sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) - +sphinxcontrib-qthelp-1.0.7 (conda-forge/noarch) + +sphinxcontrib-qthelp-2.0.0 (conda-forge/noarch) +sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) - +stdlib-list-0.10.0 (conda-forge/noarch) - +tbb-2021.12.0 (conda-forge/win-64) + +stdlib-list-0.11.0 (conda-forge/noarch) + +tbb-2021.13.0 (conda-forge/win-64) +toml-0.10.2 (conda-forge/noarch) - +tomli-w-1.0.0 (conda-forge/noarch) - +trove-classifiers-2024.7.2 (conda-forge/noarch) + +tomli-w-1.1.0 (conda-forge/noarch) + +trove-classifiers-2024.10.21.16 (conda-forge/noarch) +twine-5.1.1 (conda-forge/noarch) - +types-pyyaml-6.0.12.20240311 (conda-forge/noarch) - +typing_extensions-4.12.2 (conda-forge/noarch) - +urllib3-2.2.2 (conda-forge/noarch) + +types-pyyaml-6.0.12.20240917 (conda-forge/noarch) + +urllib3-2.2.3 (conda-forge/noarch) +win_inet_pton-1.1.0 (conda-forge/noarch) +yaml-0.2.5 (conda-forge/win-64) - +zipp-3.19.2 (conda-forge/noarch) + +zipp-3.21.0 (conda-forge/noarch) +zstandard-0.23.0 (conda-forge/win-64) +zstd-1.5.6 (conda-forge/win-64) -2024-07-21 15:44:11 (rev 2) - -alabaster-0.7.16 (conda-forge/noarch) +2024-11-23 17:06:32 (rev 2) + -alabaster-1.0.0 (conda-forge/noarch) -appdirs-1.4.4 (conda-forge/noarch) - -babel-2.14.0 (conda-forge/noarch) + -babel-2.16.0 (conda-forge/noarch) -backports-1.0 (conda-forge/noarch) - -backports.tarfile-1.0.0 (conda-forge/noarch) + -backports.tarfile-1.2.0 (conda-forge/noarch) -beautifulsoup4-4.12.3 (conda-forge/noarch) - -black-24.4.2 (conda-forge/win-64) + -black-24.10.0 (conda-forge/win-64) -brotli-python-1.1.0 (conda-forge/win-64) -bzip2-1.0.8 (conda-forge/win-64) - -ca-certificates-2024.7.4 (conda-forge/win-64) - -cachetools-5.4.0 (conda-forge/noarch) - -certifi-2024.7.4 (conda-forge/noarch) - -cffi-1.16.0 (conda-forge/win-64) + -ca-certificates-2024.8.30 (conda-forge/win-64) + -cachetools-5.5.0 (conda-forge/noarch) + -certifi-2024.8.30 (conda-forge/noarch) + -cffi-1.17.1 (conda-forge/win-64) -chardet-5.2.0 (conda-forge/win-64) - -charset-normalizer-3.3.2 (conda-forge/noarch) + -charset-normalizer-3.4.0 (conda-forge/noarch) -click-8.1.7 (conda-forge/noarch) - -cmarkgfm-0.8.0 (conda-forge/win-64) + -cmarkgfm-2024.11.20 (conda-forge/win-64) -colorama-0.4.6 (conda-forge/noarch) -conda-souschef-2.2.3 (conda-forge/noarch) - -coverage-7.6.0 (conda-forge/win-64) - -distlib-0.3.8 (conda-forge/noarch) - -docutils-0.20.1 (conda-forge/win-64) + -coverage-7.6.7 (conda-forge/win-64) + -distlib-0.3.9 (conda-forge/noarch) + -docutils-0.21.2 (conda-forge/noarch) -editables-0.5 (conda-forge/noarch) -exceptiongroup-1.2.2 (conda-forge/noarch) -execnet-2.1.1 (conda-forge/noarch) - -filelock-3.15.4 (conda-forge/noarch) + -filelock-3.16.1 (conda-forge/noarch) -future-1.0.0 (conda-forge/noarch) - -grayskull-2.5.3 (conda-forge/noarch) + -grayskull-2.7.3 (conda-forge/noarch) -h2-4.1.0 (conda-forge/noarch) - -hatchling-1.25.0 (conda-forge/noarch) + -hatchling-1.26.3 (conda-forge/noarch) -hpack-4.0.0 (conda-forge/noarch) -hyperframe-6.0.1 (conda-forge/noarch) - -idna-3.7 (conda-forge/noarch) + -idna-3.10 (conda-forge/noarch) -imagesize-1.4.1 (conda-forge/noarch) - -importlib-metadata-8.0.0 (conda-forge/noarch) - -importlib_metadata-8.0.0 (conda-forge/noarch) - -importlib_resources-6.4.0 (conda-forge/noarch) + -importlib-metadata-8.5.0 (conda-forge/noarch) + -importlib_metadata-8.5.0 (conda-forge/noarch) + -importlib_resources-6.4.5 (conda-forge/noarch) -iniconfig-2.0.0 (conda-forge/noarch) - -intel-openmp-2024.2.0 (conda-forge/win-64) + -intel-openmp-2024.2.1 (conda-forge/win-64) -jaraco.classes-3.4.0 (conda-forge/noarch) -jaraco.context-5.3.0 (conda-forge/noarch) -jaraco.functools-4.0.0 (conda-forge/noarch) -jinja2-3.1.4 (conda-forge/noarch) - -junitparser-3.1.2 (conda-forge/noarch) - -keyring-25.2.1 (conda-forge/noarch) + -junitparser-3.2.0 (conda-forge/noarch) + -keyring-25.5.0 (conda-forge/noarch) -libblas-3.9.0 (conda-forge/win-64) -libcblas-3.9.0 (conda-forge/win-64) - -libexpat-2.6.2 (conda-forge/win-64) + -libexpat-2.6.4 (conda-forge/win-64) -libffi-3.4.2 (conda-forge/win-64) -libhwloc-2.11.1 (conda-forge/win-64) -libiconv-1.17 (conda-forge/win-64) -liblapack-3.9.0 (conda-forge/win-64) - -libsqlite-3.46.0 (conda-forge/win-64) - -libxml2-2.12.7 (conda-forge/win-64) + -libmpdec-4.0.0 (conda-forge/win-64) + -libsqlite-3.47.0 (conda-forge/win-64) + -libxml2-2.13.5 (conda-forge/win-64) -libzlib-1.3.1 (conda-forge/win-64) -markdown-it-py-3.0.0 (conda-forge/noarch) - -markupsafe-2.1.5 (conda-forge/win-64) + -markupsafe-3.0.2 (conda-forge/win-64) -mdurl-0.1.2 (conda-forge/noarch) - -mkl-2024.1.0 (conda-forge/win-64) - -more-itertools-10.3.0 (conda-forge/noarch) - -mypy-1.10.1 (conda-forge/win-64) + -mkl-2024.2.2 (conda-forge/win-64) + -more-itertools-10.5.0 (conda-forge/noarch) + -mypy-1.13.0 (conda-forge/win-64) -mypy_extensions-1.0.0 (conda-forge/noarch) -nh3-0.2.18 (conda-forge/win-64) - -numpy-2.0.0 (conda-forge/win-64) - -openssl-3.3.1 (conda-forge/win-64) - -packaging-24.1 (conda-forge/noarch) + -numpy-2.1.3 (conda-forge/win-64) + -openssl-3.4.0 (conda-forge/win-64) + -packaging-24.2 (conda-forge/noarch) -pathspec-0.12.1 (conda-forge/noarch) - -pip-24.0 (conda-forge/noarch) + -pip-24.3.1 (conda-forge/noarch) -pkginfo-1.10.0 (conda-forge/noarch) - -platformdirs-4.2.2 (conda-forge/noarch) + -platformdirs-4.3.6 (conda-forge/noarch) -pluggy-1.5.0 (conda-forge/noarch) - -progressbar2-4.4.2 (conda-forge/noarch) - -psutil-6.0.0 (conda-forge/win-64) + -progressbar2-4.5.0 (conda-forge/noarch) + -psutil-6.1.0 (conda-forge/win-64) -pthreads-win32-2.9.1 (conda-forge/win-64) -pycparser-2.22 (conda-forge/noarch) -pygments-2.18.0 (conda-forge/noarch) - -pyproject-api-1.7.1 (conda-forge/noarch) + -pyproject-api-1.8.0 (conda-forge/noarch) -pysocks-1.7.1 (conda-forge/noarch) - -pytest-8.2.2 (conda-forge/noarch) - -pytest-cov-5.0.0 (conda-forge/noarch) + -pytest-8.3.3 (conda-forge/noarch) + -pytest-cov-6.0.0 (conda-forge/noarch) -pytest-xdist-3.6.1 (conda-forge/noarch) - -python-3.12.4 (conda-forge/win-64) - -python-utils-3.8.2 (conda-forge/noarch) - -python_abi-3.12 (conda-forge/win-64) - -pytz-2024.1 (conda-forge/noarch) - -pywin32-ctypes-0.2.2 (conda-forge/win-64) - -pyyaml-6.0.1 (conda-forge/win-64) - -rapidfuzz-3.9.4 (conda-forge/win-64) - -readme_renderer-42.0 (conda-forge/noarch) + -python-3.13.0 (conda-forge/win-64) + -python-utils-3.9.0 (conda-forge/noarch) + -python_abi-3.13 (conda-forge/win-64) + -pytz-2024.2 (conda-forge/noarch) + -pywin32-ctypes-0.2.3 (conda-forge/win-64) + -pyyaml-6.0.2 (conda-forge/win-64) + -rapidfuzz-3.10.1 (conda-forge/win-64) + -readme_renderer-44.0 (conda-forge/noarch) -requests-2.32.3 (conda-forge/noarch) -requests-toolbelt-1.0.0 (conda-forge/noarch) -rfc3986-2.0.0 (conda-forge/noarch) - -rich-13.7.1 (conda-forge/noarch) + -rich-13.9.4 (conda-forge/noarch) -ruamel.yaml-0.18.6 (conda-forge/win-64) -ruamel.yaml.clib-0.2.8 (conda-forge/win-64) - -ruamel.yaml.jinja2-0.2.4 (conda-forge/noarch) - -ruff-0.5.2 (conda-forge/win-64) + -ruamel.yaml.jinja2-0.2.7 (conda-forge/noarch) + -ruff-0.8.0 (conda-forge/win-64) -semver-3.0.2 (conda-forge/noarch) - -setuptools-70.3.0 (conda-forge/noarch) + -setuptools-75.6.0 (conda-forge/noarch) -snowballstemmer-2.2.0 (conda-forge/noarch) -soupsieve-2.5 (conda-forge/noarch) - -sphinx-7.4.5 (conda-forge/noarch) - -sphinx-autodoc-typehints-2.2.2 (conda-forge/noarch) + -sphinx-8.1.3 (conda-forge/noarch) + -sphinx-autodoc-typehints-2.5.0 (conda-forge/noarch) -sphinx-click-6.0.0 (conda-forge/noarch) - -sphinx-rtd-theme-2.0.0 (conda-forge/noarch) - -sphinx_rtd_theme-2.0.0 (conda-forge/noarch) - -sphinxcontrib-applehelp-1.0.8 (conda-forge/noarch) - -sphinxcontrib-devhelp-1.0.6 (conda-forge/noarch) - -sphinxcontrib-htmlhelp-2.0.5 (conda-forge/noarch) + -sphinx-rtd-theme-3.0.1 (conda-forge/noarch) + -sphinx_rtd_theme-3.0.1 (conda-forge/noarch) + -sphinxcontrib-applehelp-2.0.0 (conda-forge/noarch) + -sphinxcontrib-devhelp-2.0.0 (conda-forge/noarch) + -sphinxcontrib-htmlhelp-2.1.0 (conda-forge/noarch) -sphinxcontrib-jquery-4.1 (conda-forge/noarch) -sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) - -sphinxcontrib-qthelp-1.0.7 (conda-forge/noarch) + -sphinxcontrib-qthelp-2.0.0 (conda-forge/noarch) -sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) - -stdlib-list-0.10.0 (conda-forge/noarch) - -tbb-2021.12.0 (conda-forge/win-64) + -stdlib-list-0.11.0 (conda-forge/noarch) + -tbb-2021.13.0 (conda-forge/win-64) -tk-8.6.13 (conda-forge/win-64) -toml-0.10.2 (conda-forge/noarch) - -tomli-2.0.1 (conda-forge/noarch) - -tomli-w-1.0.0 (conda-forge/noarch) - -tox-4.16.0 (conda-forge/noarch) - -trove-classifiers-2024.7.2 (conda-forge/noarch) + -tomli-2.1.0 (conda-forge/noarch) + -tomli-w-1.1.0 (conda-forge/noarch) + -tox-4.23.2 (conda-forge/noarch) + -trove-classifiers-2024.10.21.16 (conda-forge/noarch) -twine-5.1.1 (conda-forge/noarch) - -types-pyyaml-6.0.12.20240311 (conda-forge/noarch) + -types-pyyaml-6.0.12.20240917 (conda-forge/noarch) -typing_extensions-4.12.2 (conda-forge/noarch) - -tzdata-2024a (conda-forge/noarch) + -tzdata-2024b (conda-forge/noarch) -ucrt-10.0.22621.0 (conda-forge/win-64) - -urllib3-2.2.2 (conda-forge/noarch) - -uv-0.2.25 (conda-forge/win-64) + -urllib3-2.2.3 (conda-forge/noarch) + -uv-0.5.4 (conda-forge/win-64) -vc-14.3 (conda-forge/win-64) - -vc14_runtime-14.40.33810 (conda-forge/win-64) - -virtualenv-20.26.3 (conda-forge/noarch) - -vs2015_runtime-14.40.33810 (conda-forge/win-64) - -wheel-0.43.0 (conda-forge/noarch) + -vc14_runtime-14.42.34433 (conda-forge/win-64) + -virtualenv-20.27.1 (conda-forge/noarch) + -vs2015_runtime-14.42.34433 (conda-forge/win-64) -win_inet_pton-1.1.0 (conda-forge/noarch) -xz-5.2.6 (conda-forge/win-64) -yaml-0.2.5 (conda-forge/win-64) - -zipp-3.19.2 (conda-forge/noarch) + -zipp-3.21.0 (conda-forge/noarch) -zstandard-0.23.0 (conda-forge/win-64) -zstd-1.5.6 (conda-forge/win-64) -2024-07-21 15:44:36 (rev 3) +2024-11-23 17:06:56 (rev 3) +bzip2-1.0.8 (conda-forge/win-64) - +ca-certificates-2024.7.4 (conda-forge/win-64) - +cachetools-5.4.0 (conda-forge/noarch) + +ca-certificates-2024.8.30 (conda-forge/win-64) + +cachetools-5.5.0 (conda-forge/noarch) +chardet-5.2.0 (conda-forge/win-64) +colorama-0.4.6 (conda-forge/noarch) - +distlib-0.3.8 (conda-forge/noarch) - +filelock-3.15.4 (conda-forge/noarch) - +libexpat-2.6.2 (conda-forge/win-64) + +distlib-0.3.9 (conda-forge/noarch) + +filelock-3.16.1 (conda-forge/noarch) + +libexpat-2.6.4 (conda-forge/win-64) +libffi-3.4.2 (conda-forge/win-64) - +libsqlite-3.46.0 (conda-forge/win-64) + +libmpdec-4.0.0 (conda-forge/win-64) + +libsqlite-3.47.0 (conda-forge/win-64) +libzlib-1.3.1 (conda-forge/win-64) - +openssl-3.3.1 (conda-forge/win-64) - +packaging-24.1 (conda-forge/noarch) - +pip-24.0 (conda-forge/noarch) - +platformdirs-4.2.2 (conda-forge/noarch) + +openssl-3.4.0 (conda-forge/win-64) + +packaging-24.2 (conda-forge/noarch) + +pip-24.3.1 (conda-forge/noarch) + +platformdirs-4.3.6 (conda-forge/noarch) +pluggy-1.5.0 (conda-forge/noarch) - +pyproject-api-1.7.1 (conda-forge/noarch) - +python-3.12.4 (conda-forge/win-64) - +python_abi-3.12 (conda-forge/win-64) - +setuptools-71.0.4 (conda-forge/noarch) + +pyproject-api-1.8.0 (conda-forge/noarch) + +python-3.13.0 (conda-forge/win-64) + +python_abi-3.13 (conda-forge/win-64) +tk-8.6.13 (conda-forge/win-64) - +tomli-2.0.1 (conda-forge/noarch) - +tox-4.16.0 (conda-forge/noarch) - +tzdata-2024a (conda-forge/noarch) + +tomli-2.1.0 (conda-forge/noarch) + +tox-4.23.2 (conda-forge/noarch) + +typing_extensions-4.12.2 (conda-forge/noarch) + +tzdata-2024b (conda-forge/noarch) +ucrt-10.0.22621.0 (conda-forge/win-64) - +uv-0.2.27 (conda-forge/win-64) + +uv-0.5.4 (conda-forge/win-64) +vc-14.3 (conda-forge/win-64) - +vc14_runtime-14.40.33810 (conda-forge/win-64) - +virtualenv-20.26.3 (conda-forge/noarch) - +vs2015_runtime-14.40.33810 (conda-forge/win-64) - +wheel-0.43.0 (conda-forge/noarch) + +vc14_runtime-14.42.34433 (conda-forge/win-64) + +virtualenv-20.27.1 (conda-forge/noarch) + +vs2015_runtime-14.42.34433 (conda-forge/win-64) +xz-5.2.6 (conda-forge/win-64) -2024-07-21 15:44:57 (rev 4) - +alabaster-0.7.16 (conda-forge/noarch) +2024-11-23 17:07:20 (rev 4) + +alabaster-1.0.0 (conda-forge/noarch) +appdirs-1.4.4 (conda-forge/noarch) - +babel-2.14.0 (conda-forge/noarch) + +babel-2.16.0 (conda-forge/noarch) +backports-1.0 (conda-forge/noarch) - +backports.tarfile-1.0.0 (conda-forge/noarch) + +backports.tarfile-1.2.0 (conda-forge/noarch) +beautifulsoup4-4.12.3 (conda-forge/noarch) - +black-24.4.2 (conda-forge/win-64) + +black-24.10.0 (conda-forge/win-64) +brotli-python-1.1.0 (conda-forge/win-64) - +certifi-2024.7.4 (conda-forge/noarch) - +cffi-1.16.0 (conda-forge/win-64) - +charset-normalizer-3.3.2 (conda-forge/noarch) + +certifi-2024.8.30 (conda-forge/noarch) + +cffi-1.17.1 (conda-forge/win-64) + +charset-normalizer-3.4.0 (conda-forge/noarch) +click-8.1.7 (conda-forge/noarch) - +cmarkgfm-0.8.0 (conda-forge/win-64) + +cmarkgfm-2024.11.20 (conda-forge/win-64) +conda-souschef-2.2.3 (conda-forge/noarch) - +coverage-7.6.0 (conda-forge/win-64) - +docutils-0.20.1 (conda-forge/win-64) + +coverage-7.6.7 (conda-forge/win-64) + +docutils-0.21.2 (conda-forge/noarch) +editables-0.5 (conda-forge/noarch) +exceptiongroup-1.2.2 (conda-forge/noarch) +execnet-2.1.1 (conda-forge/noarch) +future-1.0.0 (conda-forge/noarch) - +grayskull-2.5.3 (conda-forge/noarch) + +grayskull-2.7.3 (conda-forge/noarch) +h2-4.1.0 (conda-forge/noarch) - +hatchling-1.25.0 (conda-forge/noarch) + +hatchling-1.26.3 (conda-forge/noarch) +hpack-4.0.0 (conda-forge/noarch) +hyperframe-6.0.1 (conda-forge/noarch) - +idna-3.7 (conda-forge/noarch) + +idna-3.10 (conda-forge/noarch) +imagesize-1.4.1 (conda-forge/noarch) - +importlib-metadata-8.0.0 (conda-forge/noarch) - +importlib_metadata-8.0.0 (conda-forge/noarch) - +importlib_resources-6.4.0 (conda-forge/noarch) + +importlib-metadata-8.5.0 (conda-forge/noarch) + +importlib_metadata-8.5.0 (conda-forge/noarch) + +importlib_resources-6.4.5 (conda-forge/noarch) +iniconfig-2.0.0 (conda-forge/noarch) - +intel-openmp-2024.2.0 (conda-forge/win-64) + +intel-openmp-2024.2.1 (conda-forge/win-64) +jaraco.classes-3.4.0 (conda-forge/noarch) +jaraco.context-5.3.0 (conda-forge/noarch) +jaraco.functools-4.0.0 (conda-forge/noarch) +jinja2-3.1.4 (conda-forge/noarch) - +junitparser-3.1.2 (conda-forge/noarch) - +keyring-25.2.1 (conda-forge/noarch) + +junitparser-3.2.0 (conda-forge/noarch) + +keyring-25.5.0 (conda-forge/noarch) +libblas-3.9.0 (conda-forge/win-64) +libcblas-3.9.0 (conda-forge/win-64) +libhwloc-2.11.1 (conda-forge/win-64) +libiconv-1.17 (conda-forge/win-64) +liblapack-3.9.0 (conda-forge/win-64) - +libxml2-2.12.7 (conda-forge/win-64) + +libxml2-2.13.5 (conda-forge/win-64) +markdown-it-py-3.0.0 (conda-forge/noarch) - +markupsafe-2.1.5 (conda-forge/win-64) + +markupsafe-3.0.2 (conda-forge/win-64) +mdurl-0.1.2 (conda-forge/noarch) - +mkl-2024.1.0 (conda-forge/win-64) - +more-itertools-10.3.0 (conda-forge/noarch) - +mypy-1.10.1 (conda-forge/win-64) + +mkl-2024.2.2 (conda-forge/win-64) + +more-itertools-10.5.0 (conda-forge/noarch) + +mypy-1.13.0 (conda-forge/win-64) +mypy_extensions-1.0.0 (conda-forge/noarch) +nh3-0.2.18 (conda-forge/win-64) - +numpy-2.0.0 (conda-forge/win-64) + +numpy-2.1.3 (conda-forge/win-64) +pathspec-0.12.1 (conda-forge/noarch) +pkginfo-1.10.0 (conda-forge/noarch) - +progressbar2-4.4.2 (conda-forge/noarch) - +psutil-6.0.0 (conda-forge/win-64) + +progressbar2-4.5.0 (conda-forge/noarch) + +psutil-6.1.0 (conda-forge/win-64) +pthreads-win32-2.9.1 (conda-forge/win-64) +pycparser-2.22 (conda-forge/noarch) +pygments-2.18.0 (conda-forge/noarch) +pysocks-1.7.1 (conda-forge/noarch) - +pytest-8.3.1 (conda-forge/noarch) - +pytest-cov-5.0.0 (conda-forge/noarch) + +pytest-8.3.3 (conda-forge/noarch) + +pytest-cov-6.0.0 (conda-forge/noarch) +pytest-xdist-3.6.1 (conda-forge/noarch) - +python-utils-3.8.2 (conda-forge/noarch) - +pytz-2024.1 (conda-forge/noarch) - +pywin32-ctypes-0.2.2 (conda-forge/win-64) - +pyyaml-6.0.1 (conda-forge/win-64) - +rapidfuzz-3.9.4 (conda-forge/win-64) - +readme_renderer-42.0 (conda-forge/noarch) + +python-utils-3.9.0 (conda-forge/noarch) + +pytz-2024.2 (conda-forge/noarch) + +pywin32-ctypes-0.2.3 (conda-forge/win-64) + +pyyaml-6.0.2 (conda-forge/win-64) + +rapidfuzz-3.10.1 (conda-forge/win-64) + +readme_renderer-44.0 (conda-forge/noarch) +requests-2.32.3 (conda-forge/noarch) +requests-toolbelt-1.0.0 (conda-forge/noarch) +rfc3986-2.0.0 (conda-forge/noarch) - +rich-13.7.1 (conda-forge/noarch) + +rich-13.9.4 (conda-forge/noarch) +ruamel.yaml-0.18.6 (conda-forge/win-64) +ruamel.yaml.clib-0.2.8 (conda-forge/win-64) - +ruamel.yaml.jinja2-0.2.4 (conda-forge/noarch) - +ruff-0.5.2 (conda-forge/win-64) + +ruamel.yaml.jinja2-0.2.7 (conda-forge/noarch) + +ruff-0.8.0 (conda-forge/win-64) +semver-3.0.2 (conda-forge/noarch) + +setuptools-75.6.0 (conda-forge/noarch) +snowballstemmer-2.2.0 (conda-forge/noarch) +soupsieve-2.5 (conda-forge/noarch) - +sphinx-7.4.7 (conda-forge/noarch) - +sphinx-autodoc-typehints-2.2.3 (conda-forge/noarch) + +sphinx-8.1.3 (conda-forge/noarch) + +sphinx-autodoc-typehints-2.5.0 (conda-forge/noarch) +sphinx-click-6.0.0 (conda-forge/noarch) - +sphinx-rtd-theme-2.0.0 (conda-forge/noarch) - +sphinx_rtd_theme-2.0.0 (conda-forge/noarch) - +sphinxcontrib-applehelp-1.0.8 (conda-forge/noarch) - +sphinxcontrib-devhelp-1.0.6 (conda-forge/noarch) - +sphinxcontrib-htmlhelp-2.0.6 (conda-forge/noarch) + +sphinx-rtd-theme-3.0.1 (conda-forge/noarch) + +sphinx_rtd_theme-3.0.1 (conda-forge/noarch) + +sphinxcontrib-applehelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-devhelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-htmlhelp-2.1.0 (conda-forge/noarch) +sphinxcontrib-jquery-4.1 (conda-forge/noarch) +sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) - +sphinxcontrib-qthelp-1.0.8 (conda-forge/noarch) + +sphinxcontrib-qthelp-2.0.0 (conda-forge/noarch) +sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) - +stdlib-list-0.10.0 (conda-forge/noarch) - +tbb-2021.12.0 (conda-forge/win-64) + +stdlib-list-0.11.0 (conda-forge/noarch) + +tbb-2021.13.0 (conda-forge/win-64) +toml-0.10.2 (conda-forge/noarch) - +tomli-w-1.0.0 (conda-forge/noarch) - +trove-classifiers-2024.7.2 (conda-forge/noarch) + +tomli-w-1.1.0 (conda-forge/noarch) + +trove-classifiers-2024.10.21.16 (conda-forge/noarch) +twine-5.1.1 (conda-forge/noarch) - +types-pyyaml-6.0.12.20240311 (conda-forge/noarch) - +typing_extensions-4.12.2 (conda-forge/noarch) - +urllib3-2.2.2 (conda-forge/noarch) + +types-pyyaml-6.0.12.20240917 (conda-forge/noarch) + +urllib3-2.2.3 (conda-forge/noarch) +win_inet_pton-1.1.0 (conda-forge/noarch) +yaml-0.2.5 (conda-forge/win-64) - +zipp-3.19.2 (conda-forge/noarch) + +zipp-3.21.0 (conda-forge/noarch) +zstandard-0.23.0 (conda-forge/win-64) +zstd-1.5.6 (conda-forge/win-64) diff --git a/pyproject.toml b/pyproject.toml index 61c980e..14caee4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,10 +70,6 @@ condarun = [ # Dependencies known to be installable with conda for all development platforms (OSX ARM64, WIN AMD64, LIN AMD64). conda = [ - # Tox - "tox>=4,<5", - "tox-uv>=1,<2", - # Testing "pytest>=8,<9", "pytest-cov>=6,<7", @@ -106,7 +102,6 @@ conda = [ # Miscellaneous helpers "black>=24,<25", - "uv>=0,<1" ] # Dependencies known to not be installable with conda for at least one supported development platform @@ -114,6 +109,11 @@ conda = [ noconda = [ # Building "build>=1,<2", + + # Tox + "tox>=4,<5", + "uv>=0,<1", + "tox-uv>=1,<2", ] # A shorthand specification that installs tox and all packages required for development tasks. This specification can diff --git a/src/ataraxis_automation/automation.py b/src/ataraxis_automation/automation.py index d5e0416..96a91f3 100644 --- a/src/ataraxis_automation/automation.py +++ b/src/ataraxis_automation/automation.py @@ -147,6 +147,11 @@ class EnvironmentCommands: dependencies. Overall, this 'actualizes' the local environment to exactly match th pyproject.toml without altering any environment references. """ + environment_directory: Path + """ The path to the directory that stores the target conda environment. This path is used to force uv to target the + desired conda environment and to ensure the environment directory is removed when the environment is deleted. + This avoids problems with certain OSes where removing and environment does not remove teh directory, which, in + turn, interferes with environment re-creation.""" def resolve_project_directory() -> Path: @@ -321,7 +326,7 @@ def resolve_conda_engine() -> str: # If this point in the runtime is reached, this means neither conda nor mamba is installed or accessible. message: str = ( - f"Unable to determine the conda / mamba engine to use for 'conda' commands. Specifically, unable" + f"Unable to determine the conda / mamba engine to use for 'conda' commands. Specifically, unable " f"to interface with either conda or mamba. Is conda or supported equivalent installed, initialized " f"and added to Path?" ) @@ -689,12 +694,12 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: # Removes duplicate files for file_to_remove in sorted_files[1:]: file_to_remove.unlink() - message = f"Removed duplicate .pyi file in {dir_path}: {file_to_remove.name}" + message = f"Removed duplicate .pyi file in {dir_path}: {file_to_remove.name}." click.echo(_colorize_message(message, color="white"), color=True) # Renames the kept file to remove the copy number kept_file.rename(new_file_path) - message = f"Renamed stub file in {dir_path}: {kept_file.name} -> {base_name}" + message = f"Renamed stub file in {dir_path}: {kept_file.name} -> {base_name}." click.echo(_colorize_message(message, color="white"), color=True) # If there's only one file, renames it if it has a copy number @@ -702,7 +707,7 @@ def move_stubs(stubs_dir: Path, library_root: Path) -> None: file = group[0] new_path = file.with_name(base_name) file.rename(new_path) - message = f"Renamed stub file in {dir_path}: {file.name} -> {base_name}" + message = f"Renamed stub file in {dir_path}: {file.name} -> {base_name}." click.echo(_colorize_message(message, color="white"), color=True) @@ -942,8 +947,90 @@ def validate_env_name(_ctx: click.Context, _param: click.Parameter, value: str) return value +def resolve_conda_environments_directory() -> Path: + """Returns the path to the conda / mamba environments directory. + + Raises: + RuntimeError: If conda is not installed and / or not initialized. + """ + conda_prefix = os.environ.get("CONDA_PREFIX") + + # The call above will not resolve Conda environment when this method runs in a tox environment, which is the + # intended runtime scenario. Therefore, attempts to find the conda environments directory manually if the prefix is + # None. + if not conda_prefix: + # Method 1: Checks whether this script is executed from a conda-based python. + python_exe = Path(sys.executable) + + # This assumes that conda is provided by one of the major managers: miniforge, mambaforge or conda. + if any(name in str(python_exe).lower() for name in ("conda", "miniforge", "mambaforge")): + # Navigates up until it finds the conda root. + current = python_exe.parent + while current.parent != current: # Stops at root + if (current / "conda-meta").exists(): + # Found conda root. Then, the /envs folder will be found directly under root + return current / "envs" + + if current.name == "envs": + # Found envs directory directly + return current + + current = current.parent + + # Method 2: Tries to find conda by locating conda executable. This would work if conda executable is in PATH. + conda_exe = os.environ.get("CONDA_EXE") + if conda_exe: + conda_root = Path(conda_exe).parent.parent + envs_dir = conda_root / "envs" + if envs_dir.exists(): + return envs_dir + + # Method 3: Checks common installation locations for the presence of conda manager and environments. This is + # pretty evil and will fail if multiple managers are installed at the same time. It is written in a way to + # prefer miniforge though. + possible_locations = [ + Path.home() / "miniforge3" / "envs", + Path.home() / "mambaforge" / "envs", + Path.home() / "miniconda3" / "envs", + Path.home() / "anaconda3" / "envs", + ] + + # On Windows, also checks the AppData location + if sys.platform == "win32": + possible_locations.extend( + [ + Path(os.environ.get("LOCALAPPDATA", "")) / "miniforge3" / "envs", + Path(os.environ.get("LOCALAPPDATA", "")) / "mambaforge" / "envs", + Path(os.environ.get("LOCALAPPDATA", "")) / "miniconda3" / "envs", + Path(os.environ.get("LOCALAPPDATA", "")) / "anaconda3" / "envs", + ] + ) + + for location in possible_locations: + if location.exists(): + return location + + # If conda is not installed and (or) initialized, conda prefix will be None. + if not conda_prefix: + message: str = ( + f"Unable to resolve the path to the conda / mamba environments directory. Usually, this error is seen " + f"when conda is not activated or installed. Make sure conda is installed and initialized before " + f"using ataraxis-automation cli." + ) + raise RuntimeError(_format_message(message)) + + # If the 'base' environment is active, the prefix points to the root conda manager folder and needs to be + # extended with 'envs'. + if os.environ.get("CONDA_DEFAULT_ENV") == "base": + return Path(os.path.join(conda_prefix, "envs")) + + # Otherwise, for named environments, the root /envs directory is one level below the named directory: + # e.g., /path/to/conda/envs/myenv -> /path/to/conda/envs + return Path(os.path.dirname(os.path.dirname(conda_prefix))) + + def resolve_environment_commands( - project_root: Path, environment_name: str, python_version: str = "3.12" + project_root: Path, environment_name: str, python_version: str = "3.13" ) -> EnvironmentCommands: """Generates the list of conda and pip commands used to manipulate the project- and os-specific conda environment and packages it into EnvironmentCommands class. @@ -954,9 +1041,8 @@ def resolve_environment_commands( Args: project_root: The absolute path to the root directory of the processed project. environment_name: The base-name of the (project) conda environment. - python_version: The Python version to use as part of the new environment creation process. Also, this is used - to 'bias' uv to run in the conda environment instead of the virtualenv created by tox. For this reason, this - has to be different from tox 'basepython' requirement used in any task that uses uv through this library. + python_version: The Python version to use as part of the new environment creation process. This is also + used during environment provisioning to modify the python version in the environment. Returns: EnvironmentCommands class instance that includes all resolved commands as class attributes. @@ -978,6 +1064,10 @@ def resolve_environment_commands( conda_command: str = resolve_conda_engine() pip_command: str = resolve_pip_engine() + # Resolves the physical path to the target conda environment directory. + environment_directory = resolve_conda_environments_directory() + target_environment_directory = environment_directory.joinpath(extended_environment_name) + # Generates commands that depend on the host OS type. Relies on resolve_environment_files() method to err if the # host is running an unsupported OS, as the OS versions evaluated below are the same as used by # resolve_environment_files(). @@ -992,17 +1082,17 @@ def resolve_environment_commands( ) # Conda environment activation and deactivation commands - conda_init = "call conda.bat" - activate_command = f"{conda_init} && conda activate {extended_environment_name}" - deactivate_command = f"{conda_init} &&conda deactivate" + conda_init = "call conda.bat >NUL 2>&1" # Redirects stdout and stderr to null to remove unnecessary text + activate_command = f"{conda_init} && conda activate {target_environment_directory}" + deactivate_command = f"{conda_init} && conda deactivate" elif "_lin" in extended_environment_name: # .yml export export_yml_command = f"{conda_command} env export --name {extended_environment_name} | head -n -1 > {yml_path}" # Conda environment activation command conda_init = ". $(conda info --base)/etc/profile.d/conda.sh" - activate_command = f"{conda_init} && conda activate {extended_environment_name}" - deactivate_command = f"{conda_init} &&conda deactivate" + activate_command = f"{conda_init} && conda activate {target_environment_directory}" + deactivate_command = f"{conda_init} && conda deactivate" elif "_osx" in extended_environment_name: # .yml export export_yml_command = ( @@ -1012,8 +1102,8 @@ def resolve_environment_commands( # Conda environment activation command. conda_init = ". $(conda info --base)/etc/profile.d/conda.sh" - activate_command = f"{conda_init} && conda activate {extended_environment_name}" - deactivate_command = f"{conda_init} &&conda deactivate" + activate_command = f"{conda_init} && conda activate {target_environment_directory}" + deactivate_command = f"{conda_init} && conda deactivate" # Generates the spec.txt export command, which is the same for all OS versions (unlike .yml export) export_spec_command: str = f"{conda_command} list -n {extended_environment_name} --explicit -r > {spec_path}" @@ -1043,20 +1133,20 @@ def resolve_environment_commands( # Modifies some pip commands with additional, engine-specific flags. This is needed because pip and uv pip (the two # supported engines) use slightly different flags for certain commands. if "uv" in pip_command: - # Forces the command to run in conda if tox 'basepython' != python_version - pip_uninstall_command += f" --python={python_version}" + # Forces the command to run in the target conda environment instead of the virtual environment created by tox + pip_uninstall_command += f" --python={target_environment_directory}" - # Prevents cache interference, compiles to bytecode and forces uv to use conda environment - pip_reinstall_command += f" --reinstall-package {project_name} --compile-bytecode --python={python_version}" - # Ensures that uv cache does not interfere with the installation procedure - pip_reinstall_command = f"uv clean && {pip_reinstall_command}" + # Refreshes cache to ensure latest compatible versions are installed, compiles to bytecode and forces uv to + # use conda environment + pip_reinstall_command += ( + f" --resolution highest --refresh --compile-bytecode --python={target_environment_directory} --strict" + ) if pip_dependencies_command is not None: # Forces compilation and forces uv to use conda environment - pip_dependencies_command += f" --compile-bytecode --python={python_version}" - - # Ensures that uv cache does not interfere with the installation procedure - pip_dependencies_command = f"uv clean && {pip_dependencies_command}" + pip_dependencies_command += ( + f" --resolution highest --refresh --compile-bytecode --python={target_environment_directory} --strict" + ) else: # Suppresses confirmation dialogs pip_uninstall_command += f" --yes" @@ -1067,10 +1157,13 @@ def resolve_environment_commands( # Generates conda environment manipulation commands. # Creation (base) generates a minimal conda environment. It is expected that conda and pip dependencies are added - # via separate dependency commands generated above + # via separate dependency commands generated above. Note, installs the latest versions of tox, uv and pip with the + # expectation that dependency installation command use --reinstall to override the versions of these packages as + # necessary. create_command: str = ( - f"{conda_command} create -n {extended_environment_name} python={python_version} tox uv pip --yes" + f"{conda_command} create -n {extended_environment_name} python={python_version} pip tox uv --yes" ) + remove_command: str = f"{conda_command} remove -n {extended_environment_name} --all --yes" # A special command that removes all packages and then re-installs base dependencies to 'reset' the environment to @@ -1107,6 +1200,7 @@ def resolve_environment_commands( install_project_command=pip_reinstall_command, uninstall_project_command=pip_uninstall_command, provision_command=provision_command, + environment_directory=target_environment_directory, ) return command_class @@ -1353,20 +1447,13 @@ def acquire_pypi_token(replace_token: bool) -> None: # pragma: no cover type=str, help="The 'base' name of the project conda environment, e.g: 'project_dev'.", ) -@click.option( - "-pv", - "--python-version", - prompt="Enter the python version of the project conda environment. Has to be different from tox 'basepython':", - required=True, - type=str, - help="The python version of the project conda environment, e.g. '3.12'. Has to be different from tox 'basepython'.", -) -def install_project(environment_name: str, python_version: str) -> None: # pragma: no cover +def install_project(environment_name: str) -> None: # pragma: no cover """Builds and installs the project into the specified conda environment. - This command is intended to be used between tox runtimes to (re)install the project into the development - environment. Removing the project before running tox tasks avoids (rare) tox runtime errors and reinstalling - the project after tox tasks is required for some development-related procedures (e.g: manual testing). + This command is primarily used to support project developing by compiling and installing the developed project into + the environment to allow manual project testing. Since tests have to be written to use compiled package, rather than + the source code to support tox testing, the project has to be rebuilt each time source code is changed, which is + conveniently performed by this command. Raises: RuntimeError: If project installation fails. If project environment does not exist. @@ -1379,13 +1466,12 @@ def install_project(environment_name: str, python_version: str) -> None: # prag commands: EnvironmentCommands = resolve_environment_commands( project_root=project_root, environment_name=environment_name, - python_version=python_version, ) # Checks if project conda environment is accessible via subprocess activation call. If not, raises an error. if not environment_exists(commands=commands): message = ( - f"Unable to activate the target conda environment '{commands.environment_name}', which likely means" + f"Unable to activate the target conda environment '{commands.environment_name}', which likely means " f"that it does not exist. If you need to create the environment, run 'create-env' ('tox -e create')." ) raise RuntimeError(_format_message(message)) @@ -1414,21 +1500,12 @@ def install_project(environment_name: str, python_version: str) -> None: # prag type=str, help="The 'base' name of the project conda environment, e.g: 'project_dev'.", ) -@click.option( - "-pv", - "--python-version", - prompt="Enter the python version of the project conda environment. Has to be different from tox 'basepython':", - required=True, - type=str, - help="The python version of the project conda environment, e.g. '3.12'. Has to be different from tox 'basepython'.", -) -def uninstall_project(environment_name: str, python_version: str) -> None: # pragma: no cover +def uninstall_project(environment_name: str) -> None: # pragma: no cover """Uninstalls the project library from the specified conda environment. - This command is intended to be used between tox runtimes to uninstall the project from the development - environment before running tox. Removing the project before running tox tasks avoids (rare) tox runtime errors - and reinstalling the project after tox tasks is required for some development-related procedures - (e.g: manual testing). + This command is not used in most modern automation pipelines, but is kept for backward compatibility with legacy + projects. Previously, it was used to remove the project from its conda environment before running tests, as + installed projects used to interfere with tox re-building the wheels for testing. Notes: If the environment does not exist or is otherwise not accessible, the function returns without attempting to @@ -1445,7 +1522,6 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr commands: EnvironmentCommands = resolve_environment_commands( project_root=project_root, environment_name=environment_name, - python_version=python_version, ) # Attempts to activate the input conda environment. If activation fails, concludes that environment does not exist @@ -1456,7 +1532,7 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr f"Uninstallation process aborted. If you need to create the environment, run 'create-env' " f"('tox -e create')." ) - click.echo(_colorize_message(message, color="orange")) + click.echo(_colorize_message(message, color="yellow")) return try: @@ -1469,7 +1545,7 @@ def uninstall_project(environment_name: str, python_version: str) -> None: # pr except subprocess.CalledProcessError: message = ( f"Unable to uninstall the project from the conda environment '{commands.environment_name}'. See " - f"uv/pip-generated error messages for specific details about the failed operation. " + f"uv/pip-generated error messages for specific details about the failed operation." ) raise RuntimeError(_format_message(message)) @@ -1522,7 +1598,7 @@ def create_env(environment_name: str, python_version: str) -> None: # pragma: n f"environment, run 'remove-env' ('tox -e remove') command and try again. If you need to reinstall " f"environment packages, run 'provision-env' ('tox -e provision') command instead." ) - click.echo(_colorize_message(message, color="orange")) + click.echo(_colorize_message(message, color="yellow")) return # Creates the new environment @@ -1624,18 +1700,19 @@ def remove_env(environment_name: str) -> None: # pragma: no cover ) # If the environment cannot be activated, it likely does not exist and, therefore, there is nothing to remove. - if not environment_exists(commands=commands): + if not environment_exists(commands=commands) and not commands.environment_directory.exists(): message: str = ( f"Unable to find '{commands.environment_name}' conda environment. Likely, this indicates that the " f"environment already does not exist. Environment removal procedure aborted." ) - click.echo(_colorize_message(message, color="orange")) + click.echo(_colorize_message(message, color="yellow")) return # Otherwise, ensures the environment is not active and carries out the removal procedure. try: command: str = f"{commands.deactivate_command} && {commands.remove_command}" subprocess.run(command, shell=True, check=True) + commands.environment_directory.unlink(missing_ok=True) # Ensures the environment directory is deleted. message = f"Removed '{commands.environment_name}' conda environment." click.echo(_colorize_message(message, color="green")) @@ -1801,7 +1878,7 @@ def import_env(environment_name: str) -> None: # pragma: no cover try: subprocess.run(commands.create_from_yml_command, shell=True, check=True) message: str = ( - f"'{commands.environment_name}' conda environment imported (created) from existing .yml " f"file." + f"'{commands.environment_name}' conda environment imported (created) from existing .yml file." ) click.echo(_colorize_message(message, color="green")) except subprocess.CalledProcessError: @@ -2006,7 +2083,6 @@ def adopt_project( "README.md", "api.rst", "welcome.rst", - "utilities_test.py", ) # Uses the input environment name to rename all environment files inside the 'envs' folder. This renames both file diff --git a/src/ataraxis_automation/automation.pyi b/src/ataraxis_automation/automation.pyi index 736a742..82ddc74 100644 --- a/src/ataraxis_automation/automation.pyi +++ b/src/ataraxis_automation/automation.pyi @@ -56,6 +56,7 @@ class EnvironmentCommands: install_project_command: str uninstall_project_command: str provision_command: str + environment_directory: Path def __init__( self, activate_command, @@ -72,6 +73,7 @@ class EnvironmentCommands: install_project_command, uninstall_project_command, provision_command, + environment_directory, ) -> None: ... def resolve_project_directory() -> Path: @@ -376,8 +378,15 @@ def validate_env_name(_ctx: click.Context, _param: click.Parameter, value: str) BadParameter: If the input value contains invalid characters. """ +def resolve_conda_environments_directory() -> Path: + """Returns the path to the conda / mamba environments directory. + + Raises: + RuntimeError: If conda is not installed and / or not initialized. + """ + def resolve_environment_commands( - project_root: Path, environment_name: str, python_version: str = "3.12" + project_root: Path, environment_name: str, python_version: str = "3.13" ) -> EnvironmentCommands: """Generates the list of conda and pip commands used to manipulate the project- and os-specific conda environment and packages it into EnvironmentCommands class. @@ -388,9 +397,8 @@ def resolve_environment_commands( Args: project_root: The absolute path to the root directory of the processed project. environment_name: The base-name of the (project) conda environment. - python_version: The Python version to use as part of the new environment creation process. Also, this is used - to 'bias' uv to run in the conda environment instead of the virtualenv created by tox. For this reason, this - has to be different from tox 'basepython' requirement used in any task that uses uv through this library. + python_version: The Python version to use as part of the new environment creation process. This is also + used during environment provisioning to modify the python version in the environment. Returns: EnvironmentCommands class instance that includes all resolved commands as class attributes. @@ -481,24 +489,24 @@ def acquire_pypi_token(replace_token: bool) -> None: RuntimeError: If the user aborts the token acquisition process without providing a valid token. """ -def install_project(environment_name: str, python_version: str) -> None: +def install_project(environment_name: str) -> None: """Builds and installs the project into the specified conda environment. - This command is intended to be used between tox runtimes to (re)install the project into the development - environment. Removing the project before running tox tasks avoids (rare) tox runtime errors and reinstalling - the project after tox tasks is required for some development-related procedures (e.g: manual testing). + This command is primarily used to support project developing by compiling and installing the developed project into + the environment to allow manual project testing. Since tests have to be written to use compiled package, rather than + the source code to support tox testing, the project has to be rebuilt each time source code is changed, which is + conveniently performed by this command. Raises: RuntimeError: If project installation fails. If project environment does not exist. """ -def uninstall_project(environment_name: str, python_version: str) -> None: +def uninstall_project(environment_name: str) -> None: """Uninstalls the project library from the specified conda environment. - This command is intended to be used between tox runtimes to uninstall the project from the development - environment before running tox. Removing the project before running tox tasks avoids (rare) tox runtime errors - and reinstalling the project after tox tasks is required for some development-related procedures - (e.g: manual testing). + This command is not used in most modern automation pipelines, but is kept for backward compatibility with legacy + projects. Previously, it was used to remove the project from its conda environment before running tests, as + installed projects used to interfere with tox re-building the wheels for testing. Notes: If the environment does not exist or is otherwise not accessible, the function returns without attempting to diff --git a/tests/automation_test.py b/tests/automation_test.py index 96f7144..cfaab8d 100644 --- a/tests/automation_test.py +++ b/tests/automation_test.py @@ -225,7 +225,7 @@ def mock_run(*args, **kwargs): # When neither conda nor mamba is available, expects a RuntimeError monkeypatch.setattr(subprocess, "run", mock_run) message: str = ( - f"Unable to determine the conda / mamba engine to use for 'conda' commands. Specifically, unable" + f"Unable to determine the conda / mamba engine to use for 'conda' commands. Specifically, unable " f"to interface with either conda or mamba. Is conda or supported equivalent installed, initialized " f"and added to Path?" ) @@ -642,21 +642,15 @@ def mock_resolve_environment_files(*args, **kwargs): else: assert ". $(conda info --base)/etc/profile.d/conda.sh" in result.activate_command assert ". $(conda info --base)/etc/profile.d/conda.sh" in result.deactivate_command - assert f"conda activate test_env{os_suffix}" in result.activate_command + assert f"test_env{os_suffix}" in result.activate_command assert f"conda deactivate" in result.deactivate_command - assert ( - f"{conda_engine} create -n test_env{os_suffix} python={python_version} tox uv pip --yes" - in result.create_command - ) - assert f"{conda_engine} remove -n test_env{os_suffix} --all --yes" in result.remove_command + assert f"python={python_version} pip tox uv --yes" in result.create_command + assert f"test_env{os_suffix} --all --yes" in result.remove_command assert result.environment_name == f"test_env{os_suffix}" # When there are no conda or pip dependencies, the corresponding command is actually set to None if len(dependencies[0]) != 0: - assert ( - f"{conda_engine} install -n test_env{os_suffix} {' '.join(dependencies[0])} --yes" - in result.conda_dependencies_command - ) + assert f"test_env{os_suffix} {' '.join(dependencies[0])} --yes" in result.conda_dependencies_command else: assert result.conda_dependencies_command is None if len(dependencies[1]) != 0: @@ -680,11 +674,11 @@ def mock_resolve_environment_files(*args, **kwargs): # Verifies that pip-engine-dependent additional parameters match expectation. if pip_engine == "uv pip": - assert f"--python={python_version}" in result.uninstall_project_command - command_string = f"--reinstall-package test-project --compile-bytecode --python={python_version}" + assert f"test_env{os_suffix}" in result.uninstall_project_command + command_string = f"--resolution highest --refresh --compile-bytecode" assert command_string in result.install_project_command if len(dependencies[1]) != 0: - assert f"--compile-bytecode --python={python_version}" in result.pip_dependencies_command + assert f"--compile-bytecode --python=" in result.pip_dependencies_command else: assert "--yes" in result.uninstall_project_command assert "--compile" in result.install_project_command @@ -1196,6 +1190,7 @@ def mock_commands(): install_project_command="uv pip install --no-cache-dir .", uninstall_project_command="pip uninstall -y project_name", provision_command="conda install --revision 0 -n test_env", + environment_directory="mock_dir", ) diff --git a/tox.ini b/tox.ini index 74b4959..2b9dd7a 100644 --- a/tox.ini +++ b/tox.ini @@ -151,7 +151,6 @@ commands = grayskull pypi ataraxis_automation -o recipe --strict-conda-forge --list-missing-deps -m Inkaros [testenv:install] -basepython = py311 depends = lint stubs @@ -162,33 +161,30 @@ description = Builds and installs the project into the specified conda environment. If the environment does not exist, creates it before installing the project. commands = - automation-cli install-project --environment-name axa_dev --python-version 3.13 + automation-cli install-project --environment-name axa_dev [testenv:uninstall] -basepython = py311 description = Uninstalls the project from the specified conda environment. If the environment does not exist this task silently succeeds. commands = - automation-cli uninstall-project --environment-name axa_dev --python-version 3.13 + automation-cli uninstall-project --environment-name axa_dev [testenv:create] -basepython = py311 description = Creates a minimally-configured conda environment using the requested python version and installs conda- and pip- dependencies extracted from pyproject.toml file into the environment. Does not install the project! commands = automation-cli create-env --environment-name axa_dev --python-version 3.13 + rm -rf {envdir} [testenv:remove] -basepython = py311 description = Removes the requested conda environment, if it is installed locally. commands = automation-cli remove-env --environment-name axa_dev [testenv:provision] -basepython = py311 description = Provisions an already existing environment by uninstalling all packages from the environment and then installing the project dependencies using pyproject.toml specifications. From f945e13021089330146d31050a598b0420b238e1 Mon Sep 17 00:00:00 2001 From: Ivan Kondratyev Date: Sat, 23 Nov 2024 17:17:20 -0500 Subject: [PATCH 3/4] Tested on linux and rebuilt environment files --- envs/axa_dev_lin.yml | 198 +++++++++++++------------ envs/axa_dev_lin_spec.txt | 302 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 400 insertions(+), 100 deletions(-) diff --git a/envs/axa_dev_lin.yml b/envs/axa_dev_lin.yml index abf8130..cad9f6e 100644 --- a/envs/axa_dev_lin.yml +++ b/envs/axa_dev_lin.yml @@ -4,156 +4,154 @@ channels: dependencies: - _libgcc_mutex=0.1=conda_forge - _openmp_mutex=4.5=2_gnu - - alabaster=0.7.16=pyhd8ed1ab_0 + - alabaster=1.0.0=pyhd8ed1ab_0 - appdirs=1.4.4=pyh9f0ad1d_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 + - babel=2.16.0=pyhd8ed1ab_0 + - backports=1.0=pyhd8ed1ab_4 + - backports.tarfile=1.2.0=pyhd8ed1ab_0 - beautifulsoup4=4.12.3=pyha770c72_0 - - black=24.4.2=py312h7900ff3_0 - - brotli-python=1.1.0=py312h30efb56_1 + - black=24.10.0=py313h78bf25f_0 + - brotli-python=1.1.0=py313h46c70d0_2 - bzip2=1.0.8=h4bc722e_7 - - ca-certificates=2024.7.4=hbcca054_0 - - cachetools=5.4.0=pyhd8ed1ab_0 - - certifi=2024.7.4=pyhd8ed1ab_0 - - cffi=1.16.0=py312hf06ca03_0 - - chardet=5.2.0=py312h7900ff3_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - ca-certificates=2024.8.30=hbcca054_0 + - cachetools=5.5.0=pyhd8ed1ab_0 + - certifi=2024.8.30=pyhd8ed1ab_0 + - cffi=1.17.1=py313hfab6e84_0 + - chardet=5.2.0=py313h78bf25f_2 + - charset-normalizer=3.4.0=pyhd8ed1ab_0 - click=8.1.7=unix_pyh707e725_0 - - cmarkgfm=0.8.0=py312h98912ed_3 + - cmarkgfm=2024.11.20=py313h536fd9c_0 - colorama=0.4.6=pyhd8ed1ab_0 - conda-souschef=2.2.3=pyhd8ed1ab_0 - - coverage=7.6.0=py312h41a817b_0 - - cryptography=42.0.8=py312hbcc2302_0 + - coverage=7.6.7=py313h8060acc_0 + - cryptography=43.0.3=py313h6556f6e_0 - dbus=1.13.6=h5008d03_3 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.20.1=py312h7900ff3_3 + - distlib=0.3.9=pyhd8ed1ab_0 + - docutils=0.21.2=pyhd8ed1ab_0 - editables=0.5=pyhd8ed1ab_0 - exceptiongroup=1.2.2=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - filelock=3.15.4=pyhd8ed1ab_0 + - expat=2.6.4=h5888daf_0 + - filelock=3.16.1=pyhd8ed1ab_0 - future=1.0.0=pyhd8ed1ab_0 - - grayskull=2.5.3=pyhd8ed1ab_0 + - grayskull=2.7.3=pyhd8ed1ab_0 - h2=4.1.0=pyhd8ed1ab_0 - - hatchling=1.25.0=pyhd8ed1ab_0 + - hatchling=1.26.3=pypyhff2d567_0 - hpack=4.0.0=pyh9f0ad1d_0 - hyperframe=6.0.1=pyhd8ed1ab_0 - - idna=3.7=pyhd8ed1ab_0 + - idna=3.10=pyhd8ed1ab_0 - imagesize=1.4.1=pyhd8ed1ab_0 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 + - importlib-metadata=8.5.0=pyha770c72_0 + - importlib_metadata=8.5.0=hd8ed1ab_0 + - importlib_resources=6.4.5=pyhd8ed1ab_0 - iniconfig=2.0.0=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_1 - jaraco.context=5.3.0=pyhd8ed1ab_1 - jaraco.functools=4.0.0=pyhd8ed1ab_0 - jeepney=0.8.0=pyhd8ed1ab_0 - jinja2=3.1.4=pyhd8ed1ab_0 - - junitparser=3.1.2=pyhd8ed1ab_0 - - keyring=25.2.1=pyha804496_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - libblas=3.9.0=22_linux64_openblas - - libcblas=3.9.0=22_linux64_openblas - - libexpat=2.6.2=h59595ed_0 + - junitparser=3.2.0=pyhd8ed1ab_0 + - keyring=25.5.0=pyha804496_0 + - ld_impl_linux-64=2.43=h712a8e2_2 + - libblas=3.9.0=25_linux64_openblas + - libcblas=3.9.0=25_linux64_openblas + - libexpat=2.6.4=h5888daf_0 - libffi=3.4.2=h7f98852_5 - - libgcc-ng=14.1.0=h77fa898_0 - - libgfortran-ng=14.1.0=h69a702a_0 - - libgfortran5=14.1.0=hc5f4f2c_0 - - libglib=2.80.3=h8a4344b_1 - - libgomp=14.1.0=h77fa898_0 + - libgcc=14.2.0=h77fa898_1 + - libgcc-ng=14.2.0=h69a702a_1 + - libgfortran=14.2.0=h69a702a_1 + - libgfortran5=14.2.0=hd5240d6_1 + - libglib=2.82.2=h2ff4ddf_0 + - libgomp=14.2.0=h77fa898_1 - libiconv=1.17=hd590300_2 - - liblapack=3.9.0=22_linux64_openblas - - libnsl=2.0.1=hd590300_0 - - libopenblas=0.3.27=pthreads_hac2b453_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libstdcxx-ng=14.1.0=hc0a3c3a_0 + - liblapack=3.9.0=25_linux64_openblas + - libmpdec=4.0.0=h4bc722e_0 + - libopenblas=0.3.28=pthreads_h94d23a6_1 + - libsqlite=3.47.0=hadc24fc_1 + - libstdcxx=14.2.0=hc0a3c3a_1 + - libstdcxx-ng=14.2.0=h4852527_1 - libuuid=2.38.1=h0b41bf4_0 - - libxcrypt=4.4.36=hd590300_1 - - libzlib=1.3.1=h4ab18f5_1 + - libzlib=1.3.1=hb9d3cd8_2 - markdown-it-py=3.0.0=pyhd8ed1ab_0 - - markupsafe=2.1.5=py312h98912ed_0 + - markupsafe=3.0.2=py313h8060acc_0 - mdurl=0.1.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mypy=1.10.1=py312h9a8786e_0 + - more-itertools=10.5.0=pyhd8ed1ab_0 + - mypy=1.13.0=py313h536fd9c_0 - mypy_extensions=1.0.0=pyha770c72_0 - - ncurses=6.5=h59595ed_0 - - nh3=0.2.18=py312hf008fa9_0 - - numpy=2.0.0=py312h22e1c76_0 - - openssl=3.3.1=h4bc722e_2 - - packaging=24.1=pyhd8ed1ab_0 + - ncurses=6.5=he02047a_1 + - nh3=0.2.18=py313h920b4c0_1 + - numpy=2.1.3=py313h4bf6692_0 + - openssl=3.4.0=hb9d3cd8_0 + - packaging=24.2=pyhff2d567_1 - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pip=24.0=pyhd8ed1ab_0 + - pcre2=10.44=hba22ea6_2 + - pip=24.3.1=pyh145f28c_0 - pkginfo=1.10.0=pyhd8ed1ab_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 + - platformdirs=4.3.6=pyhd8ed1ab_0 - pluggy=1.5.0=pyhd8ed1ab_0 - - progressbar2=4.4.2=pyhd8ed1ab_0 - - psutil=6.0.0=py312h9a8786e_0 + - progressbar2=4.5.0=pyhd8ed1ab_0 + - psutil=6.1.0=py313h536fd9c_0 - pycparser=2.22=pyhd8ed1ab_0 - pygments=2.18.0=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 + - pyproject-api=1.8.0=pyhd8ed1ab_0 - pysocks=1.7.1=pyha2e5f31_6 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-cov=5.0.0=pyhd8ed1ab_0 + - pytest=8.3.3=pyhd8ed1ab_0 + - pytest-cov=6.0.0=pyhd8ed1ab_0 - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.12.4=h194c7f8_0_cpython - - python-utils=3.8.2=pyhd8ed1ab_0 - - python_abi=3.12=4_cp312 - - pytz=2024.1=pyhd8ed1ab_0 - - pyyaml=6.0.1=py312h98912ed_1 - - rapidfuzz=3.9.4=py312hca68cad_0 + - python=3.13.0=h9ebbce0_100_cp313 + - python-utils=3.9.0=pyhff2d567_1 + - python_abi=3.13=5_cp313 + - pytz=2024.2=pyhd8ed1ab_0 + - pyyaml=6.0.2=py313h536fd9c_1 + - rapidfuzz=3.10.1=py313h46c70d0_0 - readline=8.2=h8228510_1 - - readme_renderer=42.0=pyhd8ed1ab_0 + - readme_renderer=44.0=pyhd8ed1ab_0 - requests=2.32.3=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_0 - rfc3986=2.0.0=pyhd8ed1ab_0 - - rich=13.7.1=pyhd8ed1ab_0 - - ruamel.yaml=0.18.6=py312h98912ed_0 - - ruamel.yaml.clib=0.2.8=py312h98912ed_0 - - ruamel.yaml.jinja2=0.2.4=py_1 - - ruff=0.5.2=py312hbe4c86d_0 - - secretstorage=3.3.3=py312h7900ff3_2 + - rich=13.9.4=pyhd8ed1ab_0 + - ruamel.yaml=0.18.6=py313h536fd9c_1 + - ruamel.yaml.clib=0.2.8=py313h536fd9c_1 + - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_0 + - ruff=0.8.0=py313he87ea70_0 + - secretstorage=3.3.3=py313h78bf25f_3 - semver=3.0.2=pyhd8ed1ab_0 - - setuptools=70.3.0=pyhd8ed1ab_0 + - setuptools=75.6.0=pyhff2d567_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.4.5=pyhd8ed1ab_0 - - sphinx-autodoc-typehints=2.2.2=pyhd8ed1ab_0 + - sphinx=8.1.3=pyhd8ed1ab_0 + - sphinx-autodoc-typehints=2.5.0=pyhd8ed1ab_0 - sphinx-click=6.0.0=pyhd8ed1ab_0 - - sphinx-rtd-theme=2.0.0=hd8ed1ab_0 - - sphinx_rtd_theme=2.0.0=pyha770c72_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 + - sphinx-rtd-theme=3.0.1=hd8ed1ab_0 + - sphinx_rtd_theme=3.0.1=pyha770c72_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_0 - sphinxcontrib-jquery=4.1=pyhd8ed1ab_0 - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_0 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - stdlib-list=0.10.0=pyhd8ed1ab_0 + - stdlib-list=0.11.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_h4845f30_101 - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomli-w=1.0.0=pyhd8ed1ab_0 - - tox=4.16.0=pyhd8ed1ab_0 - - trove-classifiers=2024.7.2=pyhd8ed1ab_0 + - tomli=2.1.0=pyhff2d567_0 + - tomli-w=1.1.0=pyhd8ed1ab_0 + - tox=4.23.2=pyhd8ed1ab_0 + - trove-classifiers=2024.10.21.16=pyhd8ed1ab_0 - twine=5.1.1=pyhd8ed1ab_0 - - types-pyyaml=6.0.12.20240311=pyhd8ed1ab_0 + - types-pyyaml=6.0.12.20240917=pyhd8ed1ab_0 - typing_extensions=4.12.2=pyha770c72_0 - - tzdata=2024a=h0c530f3_0 - - urllib3=2.2.2=pyhd8ed1ab_1 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 + - tzdata=2024b=hc8b5060_0 + - urllib3=2.2.3=pyhd8ed1ab_0 + - virtualenv=20.27.1=pyhd8ed1ab_0 - xz=5.2.6=h166bdaf_0 - yaml=0.2.5=h7f98852_2 - - zipp=3.19.2=pyhd8ed1ab_0 - - zstandard=0.23.0=py312h3483029_0 + - zipp=3.21.0=pyhd8ed1ab_0 + - zstandard=0.23.0=py313h80202fe_1 - zstd=1.5.6=ha6fb4c9_0 - pip: - - ataraxis-automation==3.0.2 - - ataraxis-base-utilities==2.0.1 - - build==1.2.1 - - loguru==0.7.2 - - pyproject-hooks==1.1.0 - - tox-uv==1.9.1 - - uv==0.2.26 + - ataraxis-automation==4.0.0 + - build==1.2.2.post1 + - pyproject-hooks==1.2.0 + - tox-uv==1.16.0 + - uv==0.5.4 diff --git a/envs/axa_dev_lin_spec.txt b/envs/axa_dev_lin_spec.txt index 8163319..d6697a0 100644 --- a/envs/axa_dev_lin_spec.txt +++ b/envs/axa_dev_lin_spec.txt @@ -150,3 +150,305 @@ +zstandard-0.23.0 (conda-forge/linux-64) +zstd-1.5.6 (conda-forge/linux-64) +2024-11-23 17:13:58 (rev 2) + -_libgcc_mutex-0.1 (conda-forge/linux-64) + -_openmp_mutex-4.5 (conda-forge/linux-64) + -alabaster-0.7.16 (conda-forge/noarch) + -appdirs-1.4.4 (conda-forge/noarch) + -babel-2.14.0 (conda-forge/noarch) + -backports-1.0 (conda-forge/noarch) + -backports.tarfile-1.0.0 (conda-forge/noarch) + -beautifulsoup4-4.12.3 (conda-forge/noarch) + -black-24.4.2 (conda-forge/linux-64) + -brotli-python-1.1.0 (conda-forge/linux-64) + -bzip2-1.0.8 (conda-forge/linux-64) + -ca-certificates-2024.7.4 (conda-forge/linux-64) + -cachetools-5.4.0 (conda-forge/noarch) + -certifi-2024.7.4 (conda-forge/noarch) + -cffi-1.16.0 (conda-forge/linux-64) + -chardet-5.2.0 (conda-forge/linux-64) + -charset-normalizer-3.3.2 (conda-forge/noarch) + -click-8.1.7 (conda-forge/noarch) + -cmarkgfm-0.8.0 (conda-forge/linux-64) + -colorama-0.4.6 (conda-forge/noarch) + -conda-souschef-2.2.3 (conda-forge/noarch) + -coverage-7.6.0 (conda-forge/linux-64) + -cryptography-42.0.8 (conda-forge/linux-64) + -dbus-1.13.6 (conda-forge/linux-64) + -distlib-0.3.8 (conda-forge/noarch) + -docutils-0.20.1 (conda-forge/linux-64) + -editables-0.5 (conda-forge/noarch) + -exceptiongroup-1.2.2 (conda-forge/noarch) + -execnet-2.1.1 (conda-forge/noarch) + -expat-2.6.2 (conda-forge/linux-64) + -filelock-3.15.4 (conda-forge/noarch) + -future-1.0.0 (conda-forge/noarch) + -grayskull-2.5.3 (conda-forge/noarch) + -h2-4.1.0 (conda-forge/noarch) + -hatchling-1.25.0 (conda-forge/noarch) + -hpack-4.0.0 (conda-forge/noarch) + -hyperframe-6.0.1 (conda-forge/noarch) + -idna-3.7 (conda-forge/noarch) + -imagesize-1.4.1 (conda-forge/noarch) + -importlib-metadata-8.0.0 (conda-forge/noarch) + -importlib_metadata-8.0.0 (conda-forge/noarch) + -importlib_resources-6.4.0 (conda-forge/noarch) + -iniconfig-2.0.0 (conda-forge/noarch) + -jaraco.classes-3.4.0 (conda-forge/noarch) + -jaraco.context-5.3.0 (conda-forge/noarch) + -jaraco.functools-4.0.0 (conda-forge/noarch) + -jeepney-0.8.0 (conda-forge/noarch) + -jinja2-3.1.4 (conda-forge/noarch) + -junitparser-3.1.2 (conda-forge/noarch) + -keyring-25.2.1 (conda-forge/noarch) + -ld_impl_linux-64-2.40 (conda-forge/linux-64) + -libblas-3.9.0 (conda-forge/linux-64) + -libcblas-3.9.0 (conda-forge/linux-64) + -libexpat-2.6.2 (conda-forge/linux-64) + -libffi-3.4.2 (conda-forge/linux-64) + -libgcc-ng-14.1.0 (conda-forge/linux-64) + -libgfortran-ng-14.1.0 (conda-forge/linux-64) + -libgfortran5-14.1.0 (conda-forge/linux-64) + -libglib-2.80.3 (conda-forge/linux-64) + -libgomp-14.1.0 (conda-forge/linux-64) + -libiconv-1.17 (conda-forge/linux-64) + -liblapack-3.9.0 (conda-forge/linux-64) + -libnsl-2.0.1 (conda-forge/linux-64) + -libopenblas-0.3.27 (conda-forge/linux-64) + -libsqlite-3.46.0 (conda-forge/linux-64) + -libstdcxx-ng-14.1.0 (conda-forge/linux-64) + -libuuid-2.38.1 (conda-forge/linux-64) + -libxcrypt-4.4.36 (conda-forge/linux-64) + -libzlib-1.3.1 (conda-forge/linux-64) + -markdown-it-py-3.0.0 (conda-forge/noarch) + -markupsafe-2.1.5 (conda-forge/linux-64) + -mdurl-0.1.2 (conda-forge/noarch) + -more-itertools-10.3.0 (conda-forge/noarch) + -mypy-1.10.1 (conda-forge/linux-64) + -mypy_extensions-1.0.0 (conda-forge/noarch) + -ncurses-6.5 (conda-forge/linux-64) + -nh3-0.2.18 (conda-forge/linux-64) + -numpy-2.0.0 (conda-forge/linux-64) + -openssl-3.3.1 (conda-forge/linux-64) + -packaging-24.1 (conda-forge/noarch) + -pathspec-0.12.1 (conda-forge/noarch) + -pcre2-10.44 (conda-forge/linux-64) + -pip-24.0 (conda-forge/noarch) + -pkginfo-1.10.0 (conda-forge/noarch) + -platformdirs-4.2.2 (conda-forge/noarch) + -pluggy-1.5.0 (conda-forge/noarch) + -progressbar2-4.4.2 (conda-forge/noarch) + -psutil-6.0.0 (conda-forge/linux-64) + -pycparser-2.22 (conda-forge/noarch) + -pygments-2.18.0 (conda-forge/noarch) + -pyproject-api-1.7.1 (conda-forge/noarch) + -pysocks-1.7.1 (conda-forge/noarch) + -pytest-8.2.2 (conda-forge/noarch) + -pytest-cov-5.0.0 (conda-forge/noarch) + -pytest-xdist-3.6.1 (conda-forge/noarch) + -python-3.12.4 (conda-forge/linux-64) + -python-utils-3.8.2 (conda-forge/noarch) + -python_abi-3.12 (conda-forge/linux-64) + -pytz-2024.1 (conda-forge/noarch) + -pyyaml-6.0.1 (conda-forge/linux-64) + -rapidfuzz-3.9.4 (conda-forge/linux-64) + -readline-8.2 (conda-forge/linux-64) + -readme_renderer-42.0 (conda-forge/noarch) + -requests-2.32.3 (conda-forge/noarch) + -requests-toolbelt-1.0.0 (conda-forge/noarch) + -rfc3986-2.0.0 (conda-forge/noarch) + -rich-13.7.1 (conda-forge/noarch) + -ruamel.yaml-0.18.6 (conda-forge/linux-64) + -ruamel.yaml.clib-0.2.8 (conda-forge/linux-64) + -ruamel.yaml.jinja2-0.2.4 (conda-forge/noarch) + -ruff-0.5.2 (conda-forge/linux-64) + -secretstorage-3.3.3 (conda-forge/linux-64) + -semver-3.0.2 (conda-forge/noarch) + -setuptools-70.3.0 (conda-forge/noarch) + -snowballstemmer-2.2.0 (conda-forge/noarch) + -soupsieve-2.5 (conda-forge/noarch) + -sphinx-7.4.5 (conda-forge/noarch) + -sphinx-autodoc-typehints-2.2.2 (conda-forge/noarch) + -sphinx-click-6.0.0 (conda-forge/noarch) + -sphinx-rtd-theme-2.0.0 (conda-forge/noarch) + -sphinx_rtd_theme-2.0.0 (conda-forge/noarch) + -sphinxcontrib-applehelp-1.0.8 (conda-forge/noarch) + -sphinxcontrib-devhelp-1.0.6 (conda-forge/noarch) + -sphinxcontrib-htmlhelp-2.0.5 (conda-forge/noarch) + -sphinxcontrib-jquery-4.1 (conda-forge/noarch) + -sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) + -sphinxcontrib-qthelp-1.0.7 (conda-forge/noarch) + -sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) + -stdlib-list-0.10.0 (conda-forge/noarch) + -tk-8.6.13 (conda-forge/linux-64) + -toml-0.10.2 (conda-forge/noarch) + -tomli-2.0.1 (conda-forge/noarch) + -tomli-w-1.0.0 (conda-forge/noarch) + -tox-4.16.0 (conda-forge/noarch) + -trove-classifiers-2024.7.2 (conda-forge/noarch) + -twine-5.1.1 (conda-forge/noarch) + -types-pyyaml-6.0.12.20240311 (conda-forge/noarch) + -typing_extensions-4.12.2 (conda-forge/noarch) + -tzdata-2024a (conda-forge/noarch) + -urllib3-2.2.2 (conda-forge/noarch) + -uv-0.2.25 (conda-forge/linux-64) + -virtualenv-20.26.3 (conda-forge/noarch) + -wheel-0.43.0 (conda-forge/noarch) + -xz-5.2.6 (conda-forge/linux-64) + -yaml-0.2.5 (conda-forge/linux-64) + -zipp-3.19.2 (conda-forge/noarch) + -zstandard-0.23.0 (conda-forge/linux-64) + -zstd-1.5.6 (conda-forge/linux-64) + +2024-11-23 17:14:06 (rev 3) + +_libgcc_mutex-0.1 (conda-forge/linux-64) + +_openmp_mutex-4.5 (conda-forge/linux-64) + +bzip2-1.0.8 (conda-forge/linux-64) + +ca-certificates-2024.8.30 (conda-forge/linux-64) + +cachetools-5.5.0 (conda-forge/noarch) + +chardet-5.2.0 (conda-forge/linux-64) + +colorama-0.4.6 (conda-forge/noarch) + +distlib-0.3.9 (conda-forge/noarch) + +filelock-3.16.1 (conda-forge/noarch) + +ld_impl_linux-64-2.43 (conda-forge/linux-64) + +libexpat-2.6.4 (conda-forge/linux-64) + +libffi-3.4.2 (conda-forge/linux-64) + +libgcc-14.2.0 (conda-forge/linux-64) + +libgcc-ng-14.2.0 (conda-forge/linux-64) + +libgomp-14.2.0 (conda-forge/linux-64) + +libmpdec-4.0.0 (conda-forge/linux-64) + +libsqlite-3.47.0 (conda-forge/linux-64) + +libstdcxx-14.2.0 (conda-forge/linux-64) + +libuuid-2.38.1 (conda-forge/linux-64) + +libzlib-1.3.1 (conda-forge/linux-64) + +ncurses-6.5 (conda-forge/linux-64) + +openssl-3.4.0 (conda-forge/linux-64) + +packaging-24.2 (conda-forge/noarch) + +pip-24.3.1 (conda-forge/noarch) + +platformdirs-4.3.6 (conda-forge/noarch) + +pluggy-1.5.0 (conda-forge/noarch) + +pyproject-api-1.8.0 (conda-forge/noarch) + +python-3.13.0 (conda-forge/linux-64) + +python_abi-3.13 (conda-forge/linux-64) + +readline-8.2 (conda-forge/linux-64) + +tk-8.6.13 (conda-forge/linux-64) + +tomli-2.1.0 (conda-forge/noarch) + +tox-4.23.2 (conda-forge/noarch) + +typing_extensions-4.12.2 (conda-forge/noarch) + +tzdata-2024b (conda-forge/noarch) + +uv-0.5.4 (conda-forge/linux-64) + +virtualenv-20.27.1 (conda-forge/noarch) + +xz-5.2.6 (conda-forge/linux-64) + +2024-11-23 17:14:16 (rev 4) + +alabaster-1.0.0 (conda-forge/noarch) + +appdirs-1.4.4 (conda-forge/noarch) + +babel-2.16.0 (conda-forge/noarch) + +backports-1.0 (conda-forge/noarch) + +backports.tarfile-1.2.0 (conda-forge/noarch) + +beautifulsoup4-4.12.3 (conda-forge/noarch) + +black-24.10.0 (conda-forge/linux-64) + +brotli-python-1.1.0 (conda-forge/linux-64) + +certifi-2024.8.30 (conda-forge/noarch) + +cffi-1.17.1 (conda-forge/linux-64) + +charset-normalizer-3.4.0 (conda-forge/noarch) + +click-8.1.7 (conda-forge/noarch) + +cmarkgfm-2024.11.20 (conda-forge/linux-64) + +conda-souschef-2.2.3 (conda-forge/noarch) + +coverage-7.6.7 (conda-forge/linux-64) + +cryptography-43.0.3 (conda-forge/linux-64) + +dbus-1.13.6 (conda-forge/linux-64) + +docutils-0.21.2 (conda-forge/noarch) + +editables-0.5 (conda-forge/noarch) + +exceptiongroup-1.2.2 (conda-forge/noarch) + +execnet-2.1.1 (conda-forge/noarch) + +expat-2.6.4 (conda-forge/linux-64) + +future-1.0.0 (conda-forge/noarch) + +grayskull-2.7.3 (conda-forge/noarch) + +h2-4.1.0 (conda-forge/noarch) + +hatchling-1.26.3 (conda-forge/noarch) + +hpack-4.0.0 (conda-forge/noarch) + +hyperframe-6.0.1 (conda-forge/noarch) + +idna-3.10 (conda-forge/noarch) + +imagesize-1.4.1 (conda-forge/noarch) + +importlib-metadata-8.5.0 (conda-forge/noarch) + +importlib_metadata-8.5.0 (conda-forge/noarch) + +importlib_resources-6.4.5 (conda-forge/noarch) + +iniconfig-2.0.0 (conda-forge/noarch) + +jaraco.classes-3.4.0 (conda-forge/noarch) + +jaraco.context-5.3.0 (conda-forge/noarch) + +jaraco.functools-4.0.0 (conda-forge/noarch) + +jeepney-0.8.0 (conda-forge/noarch) + +jinja2-3.1.4 (conda-forge/noarch) + +junitparser-3.2.0 (conda-forge/noarch) + +keyring-25.5.0 (conda-forge/noarch) + +libblas-3.9.0 (conda-forge/linux-64) + +libcblas-3.9.0 (conda-forge/linux-64) + +libgfortran-14.2.0 (conda-forge/linux-64) + +libgfortran5-14.2.0 (conda-forge/linux-64) + +libglib-2.82.2 (conda-forge/linux-64) + +libiconv-1.17 (conda-forge/linux-64) + +liblapack-3.9.0 (conda-forge/linux-64) + +libopenblas-0.3.28 (conda-forge/linux-64) + +libstdcxx-ng-14.2.0 (conda-forge/linux-64) + +markdown-it-py-3.0.0 (conda-forge/noarch) + +markupsafe-3.0.2 (conda-forge/linux-64) + +mdurl-0.1.2 (conda-forge/noarch) + +more-itertools-10.5.0 (conda-forge/noarch) + +mypy-1.13.0 (conda-forge/linux-64) + +mypy_extensions-1.0.0 (conda-forge/noarch) + +nh3-0.2.18 (conda-forge/linux-64) + +numpy-2.1.3 (conda-forge/linux-64) + +pathspec-0.12.1 (conda-forge/noarch) + +pcre2-10.44 (conda-forge/linux-64) + +pkginfo-1.10.0 (conda-forge/noarch) + +progressbar2-4.5.0 (conda-forge/noarch) + +psutil-6.1.0 (conda-forge/linux-64) + +pycparser-2.22 (conda-forge/noarch) + +pygments-2.18.0 (conda-forge/noarch) + +pysocks-1.7.1 (conda-forge/noarch) + +pytest-8.3.3 (conda-forge/noarch) + +pytest-cov-6.0.0 (conda-forge/noarch) + +pytest-xdist-3.6.1 (conda-forge/noarch) + +python-utils-3.9.0 (conda-forge/noarch) + +pytz-2024.2 (conda-forge/noarch) + +pyyaml-6.0.2 (conda-forge/linux-64) + +rapidfuzz-3.10.1 (conda-forge/linux-64) + +readme_renderer-44.0 (conda-forge/noarch) + +requests-2.32.3 (conda-forge/noarch) + +requests-toolbelt-1.0.0 (conda-forge/noarch) + +rfc3986-2.0.0 (conda-forge/noarch) + +rich-13.9.4 (conda-forge/noarch) + +ruamel.yaml-0.18.6 (conda-forge/linux-64) + +ruamel.yaml.clib-0.2.8 (conda-forge/linux-64) + +ruamel.yaml.jinja2-0.2.7 (conda-forge/noarch) + +ruff-0.8.0 (conda-forge/linux-64) + +secretstorage-3.3.3 (conda-forge/linux-64) + +semver-3.0.2 (conda-forge/noarch) + +setuptools-75.6.0 (conda-forge/noarch) + +snowballstemmer-2.2.0 (conda-forge/noarch) + +soupsieve-2.5 (conda-forge/noarch) + +sphinx-8.1.3 (conda-forge/noarch) + +sphinx-autodoc-typehints-2.5.0 (conda-forge/noarch) + +sphinx-click-6.0.0 (conda-forge/noarch) + +sphinx-rtd-theme-3.0.1 (conda-forge/noarch) + +sphinx_rtd_theme-3.0.1 (conda-forge/noarch) + +sphinxcontrib-applehelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-devhelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-htmlhelp-2.1.0 (conda-forge/noarch) + +sphinxcontrib-jquery-4.1 (conda-forge/noarch) + +sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) + +sphinxcontrib-qthelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) + +stdlib-list-0.11.0 (conda-forge/noarch) + +toml-0.10.2 (conda-forge/noarch) + +tomli-w-1.1.0 (conda-forge/noarch) + +trove-classifiers-2024.10.21.16 (conda-forge/noarch) + +twine-5.1.1 (conda-forge/noarch) + +types-pyyaml-6.0.12.20240917 (conda-forge/noarch) + +urllib3-2.2.3 (conda-forge/noarch) + +yaml-0.2.5 (conda-forge/linux-64) + +zipp-3.21.0 (conda-forge/noarch) + +zstandard-0.23.0 (conda-forge/linux-64) + +zstd-1.5.6 (conda-forge/linux-64) + From b4f07b8172c4bbecfc77b24830e9962d959e9f29 Mon Sep 17 00:00:00 2001 From: Inkaros Date: Sat, 23 Nov 2024 17:21:44 -0500 Subject: [PATCH 4/4] Tested and exported macOS environment files --- envs/axa_dev_osx.yml | 176 ++++++++++++------------ envs/axa_dev_osx_spec.txt | 272 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 359 insertions(+), 89 deletions(-) diff --git a/envs/axa_dev_osx.yml b/envs/axa_dev_osx.yml index 727309d..3abfa15 100644 --- a/envs/axa_dev_osx.yml +++ b/envs/axa_dev_osx.yml @@ -2,143 +2,141 @@ name: axa_dev_osx channels: - conda-forge dependencies: - - alabaster=0.7.16=pyhd8ed1ab_0 + - alabaster=1.0.0=pyhd8ed1ab_0 - appdirs=1.4.4=pyh9f0ad1d_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 + - babel=2.16.0=pyhd8ed1ab_0 + - backports=1.0=pyhd8ed1ab_4 + - backports.tarfile=1.2.0=pyhd8ed1ab_0 - beautifulsoup4=4.12.3=pyha770c72_0 - - black=24.4.2=py312h81bd7bf_0 - - brotli-python=1.1.0=py312h9f69965_1 + - black=24.10.0=py313h8f79df9_0 + - brotli-python=1.1.0=py313h3579c5c_2 - bzip2=1.0.8=h99b78c6_7 - - ca-certificates=2024.7.4=hf0a4a13_0 - - cachetools=5.4.0=pyhd8ed1ab_0 - - certifi=2024.7.4=pyhd8ed1ab_0 - - cffi=1.16.0=py312h8e38eb3_0 - - chardet=5.2.0=py312h81bd7bf_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - ca-certificates=2024.8.30=hf0a4a13_0 + - cachetools=5.5.0=pyhd8ed1ab_0 + - certifi=2024.8.30=pyhd8ed1ab_0 + - cffi=1.17.1=py313hc845a76_0 + - chardet=5.2.0=py313h8f79df9_2 + - charset-normalizer=3.4.0=pyhd8ed1ab_0 - click=8.1.7=unix_pyh707e725_0 - - cmarkgfm=0.8.0=py312h02f2b3b_3 + - cmarkgfm=2024.11.20=py313h90d716c_0 - colorama=0.4.6=pyhd8ed1ab_0 - conda-souschef=2.2.3=pyhd8ed1ab_0 - - coverage=7.6.0=py312h7e5086c_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.20.1=py312h81bd7bf_3 + - coverage=7.6.7=py313ha9b7d5b_0 + - distlib=0.3.9=pyhd8ed1ab_0 + - docutils=0.21.2=pyhd8ed1ab_0 - editables=0.5=pyhd8ed1ab_0 - exceptiongroup=1.2.2=pyhd8ed1ab_0 - execnet=2.1.1=pyhd8ed1ab_0 - - filelock=3.15.4=pyhd8ed1ab_0 + - filelock=3.16.1=pyhd8ed1ab_0 - future=1.0.0=pyhd8ed1ab_0 - - grayskull=2.5.3=pyhd8ed1ab_0 + - grayskull=2.7.3=pyhd8ed1ab_0 - h2=4.1.0=pyhd8ed1ab_0 - - hatchling=1.25.0=pyhd8ed1ab_0 + - hatchling=1.26.3=pypyhff2d567_0 - hpack=4.0.0=pyh9f0ad1d_0 - hyperframe=6.0.1=pyhd8ed1ab_0 - - idna=3.7=pyhd8ed1ab_0 + - idna=3.10=pyhd8ed1ab_0 - imagesize=1.4.1=pyhd8ed1ab_0 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 + - importlib-metadata=8.5.0=pyha770c72_0 + - importlib_metadata=8.5.0=hd8ed1ab_0 + - importlib_resources=6.4.5=pyhd8ed1ab_0 - iniconfig=2.0.0=pyhd8ed1ab_0 - jaraco.classes=3.4.0=pyhd8ed1ab_1 - jaraco.context=5.3.0=pyhd8ed1ab_1 - jaraco.functools=4.0.0=pyhd8ed1ab_0 - jinja2=3.1.4=pyhd8ed1ab_0 - - junitparser=3.1.2=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - libblas=3.9.0=22_osxarm64_openblas - - libcblas=3.9.0=22_osxarm64_openblas - - libcxx=18.1.8=h167917d_0 - - libexpat=2.6.2=hebf3989_0 + - junitparser=3.2.0=pyhd8ed1ab_0 + - keyring=25.5.0=pyh534df25_0 + - libblas=3.9.0=25_osxarm64_openblas + - libcblas=3.9.0=25_osxarm64_openblas + - libcxx=19.1.4=ha82da77_0 + - libexpat=2.6.4=h286801f_0 - libffi=3.4.2=h3422bc3_5 - libgfortran=5.0.0=13_2_0_hd922786_3 - libgfortran5=13.2.0=hf226fd6_3 - - liblapack=3.9.0=22_osxarm64_openblas - - libopenblas=0.3.27=openmp_h517c56d_1 - - libsqlite=3.46.0=hfb93653_0 - - libzlib=1.3.1=hfb2fe0b_1 - - llvm-openmp=18.1.8=hde57baf_0 + - liblapack=3.9.0=25_osxarm64_openblas + - libmpdec=4.0.0=h99b78c6_0 + - libopenblas=0.3.28=openmp_hf332438_1 + - libsqlite=3.47.0=hbaaea75_1 + - libzlib=1.3.1=h8359307_2 + - llvm-openmp=19.1.4=hdb05f8b_0 - markdown-it-py=3.0.0=pyhd8ed1ab_0 - - markupsafe=2.1.5=py312he37b823_0 + - markupsafe=3.0.2=py313heb2b014_0 - mdurl=0.1.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mypy=1.10.1=py312h7e5086c_0 + - more-itertools=10.5.0=pyhd8ed1ab_0 + - mypy=1.13.0=py313h63a2874_0 - mypy_extensions=1.0.0=pyha770c72_0 - - ncurses=6.5=hb89a1cb_0 - - nh3=0.2.18=py312h552d48e_0 - - numpy=2.0.0=py312hb544834_0 - - openssl=3.3.1=hfb2fe0b_2 - - packaging=24.1=pyhd8ed1ab_0 + - ncurses=6.5=h7bae524_1 + - nh3=0.2.18=py313h849cdff_1 + - numpy=2.1.3=py313hca4752e_0 + - openssl=3.4.0=h39f12f2_0 + - packaging=24.2=pyhff2d567_1 - pathspec=0.12.1=pyhd8ed1ab_0 - - pip=24.0=pyhd8ed1ab_0 + - pip=24.3.1=pyh145f28c_0 - pkginfo=1.10.0=pyhd8ed1ab_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 + - platformdirs=4.3.6=pyhd8ed1ab_0 - pluggy=1.5.0=pyhd8ed1ab_0 - - progressbar2=4.4.2=pyhd8ed1ab_0 - - psutil=6.0.0=py312h7e5086c_0 + - progressbar2=4.5.0=pyhd8ed1ab_0 + - psutil=6.1.0=py313h63a2874_0 - pycparser=2.22=pyhd8ed1ab_0 - pygments=2.18.0=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 + - pyproject-api=1.8.0=pyhd8ed1ab_0 - pysocks=1.7.1=pyha2e5f31_6 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-cov=5.0.0=pyhd8ed1ab_0 + - pytest=8.3.3=pyhd8ed1ab_0 + - pytest-cov=6.0.0=pyhd8ed1ab_0 - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.12.4=h30c5eda_0_cpython - - python-utils=3.8.2=pyhd8ed1ab_0 - - python_abi=3.12=4_cp312 - - pytz=2024.1=pyhd8ed1ab_0 - - pyyaml=6.0.1=py312h02f2b3b_1 - - rapidfuzz=3.9.4=py312h5c2e7bc_0 + - python=3.13.0=h75c3a9f_100_cp313 + - python-utils=3.9.0=pyhff2d567_1 + - python_abi=3.13=5_cp313 + - pytz=2024.2=pyhd8ed1ab_0 + - pyyaml=6.0.2=py313h20a7fcf_1 + - rapidfuzz=3.10.1=py313h4e5f155_0 - readline=8.2=h92ec313_1 - - readme_renderer=42.0=pyhd8ed1ab_0 + - readme_renderer=44.0=pyhd8ed1ab_0 - requests=2.32.3=pyhd8ed1ab_0 - requests-toolbelt=1.0.0=pyhd8ed1ab_0 - rfc3986=2.0.0=pyhd8ed1ab_0 - - rich=13.7.1=pyhd8ed1ab_0 - - ruamel.yaml=0.18.6=py312he37b823_0 - - ruamel.yaml.clib=0.2.8=py312he37b823_0 - - ruamel.yaml.jinja2=0.2.4=py_1 - - ruff=0.5.2=py312h3402d49_0 + - rich=13.9.4=pyhd8ed1ab_0 + - ruamel.yaml=0.18.6=py313h63a2874_1 + - ruamel.yaml.clib=0.2.8=py313h63a2874_1 + - ruamel.yaml.jinja2=0.2.7=pyhd8ed1ab_0 + - ruff=0.8.0=py313heab95af_0 - semver=3.0.2=pyhd8ed1ab_0 - - setuptools=70.3.0=pyhd8ed1ab_0 + - setuptools=75.6.0=pyhff2d567_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.4.5=pyhd8ed1ab_0 - - sphinx-autodoc-typehints=2.2.2=pyhd8ed1ab_0 + - sphinx=8.1.3=pyhd8ed1ab_0 + - sphinx-autodoc-typehints=2.5.0=pyhd8ed1ab_0 - sphinx-click=6.0.0=pyhd8ed1ab_0 - - sphinx-rtd-theme=2.0.0=hd8ed1ab_0 - - sphinx_rtd_theme=2.0.0=pyha770c72_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 + - sphinx-rtd-theme=3.0.1=hd8ed1ab_0 + - sphinx_rtd_theme=3.0.1=pyha770c72_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_0 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_0 - sphinxcontrib-jquery=4.1=pyhd8ed1ab_0 - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_0 - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - stdlib-list=0.10.0=pyhd8ed1ab_0 + - stdlib-list=0.11.0=pyhd8ed1ab_0 - tk=8.6.13=h5083fa2_1 - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomli-w=1.0.0=pyhd8ed1ab_0 - - tox=4.16.0=pyhd8ed1ab_0 - - trove-classifiers=2024.7.2=pyhd8ed1ab_0 + - tomli=2.1.0=pyhff2d567_0 + - tomli-w=1.1.0=pyhd8ed1ab_0 + - tox=4.23.2=pyhd8ed1ab_0 + - trove-classifiers=2024.10.21.16=pyhd8ed1ab_0 - twine=5.1.1=pyhd8ed1ab_0 - - types-pyyaml=6.0.12.20240311=pyhd8ed1ab_0 + - types-pyyaml=6.0.12.20240917=pyhd8ed1ab_0 - typing_extensions=4.12.2=pyha770c72_0 - - tzdata=2024a=h0c530f3_0 - - urllib3=2.2.2=pyhd8ed1ab_1 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 + - tzdata=2024b=hc8b5060_0 + - urllib3=2.2.3=pyhd8ed1ab_0 + - virtualenv=20.27.1=pyhd8ed1ab_0 - xz=5.2.6=h57fd34a_0 - yaml=0.2.5=h3422bc3_2 - - zipp=3.19.2=pyhd8ed1ab_0 - - zstandard=0.23.0=py312h721a963_0 + - zipp=3.21.0=pyhd8ed1ab_0 + - zstandard=0.23.0=py313hf2da073_1 - zstd=1.5.6=hb46c0d2_0 - pip: - - ataraxis-automation==3.0.2 - - ataraxis-base-utilities==2.0.1 - - build==1.2.1 - - loguru==0.7.2 - - pyproject-hooks==1.1.0 - - tox-uv==1.9.1 - - uv==0.2.26 + - ataraxis-automation==4.0.0 + - build==1.2.2.post1 + - pyproject-hooks==1.2.0 + - tox-uv==1.16.0 + - uv==0.5.4 diff --git a/envs/axa_dev_osx_spec.txt b/envs/axa_dev_osx_spec.txt index c6fd665..9c23c7b 100644 --- a/envs/axa_dev_osx_spec.txt +++ b/envs/axa_dev_osx_spec.txt @@ -135,3 +135,275 @@ +zstandard-0.23.0 (conda-forge/osx-arm64) +zstd-1.5.6 (conda-forge/osx-arm64) +2024-11-23 17:19:34 (rev 2) + -alabaster-0.7.16 (conda-forge/noarch) + -appdirs-1.4.4 (conda-forge/noarch) + -babel-2.14.0 (conda-forge/noarch) + -backports-1.0 (conda-forge/noarch) + -backports.tarfile-1.0.0 (conda-forge/noarch) + -beautifulsoup4-4.12.3 (conda-forge/noarch) + -black-24.4.2 (conda-forge/osx-arm64) + -brotli-python-1.1.0 (conda-forge/osx-arm64) + -bzip2-1.0.8 (conda-forge/osx-arm64) + -ca-certificates-2024.7.4 (conda-forge/osx-arm64) + -cachetools-5.4.0 (conda-forge/noarch) + -certifi-2024.7.4 (conda-forge/noarch) + -cffi-1.16.0 (conda-forge/osx-arm64) + -chardet-5.2.0 (conda-forge/osx-arm64) + -charset-normalizer-3.3.2 (conda-forge/noarch) + -click-8.1.7 (conda-forge/noarch) + -cmarkgfm-0.8.0 (conda-forge/osx-arm64) + -colorama-0.4.6 (conda-forge/noarch) + -conda-souschef-2.2.3 (conda-forge/noarch) + -coverage-7.6.0 (conda-forge/osx-arm64) + -distlib-0.3.8 (conda-forge/noarch) + -docutils-0.20.1 (conda-forge/osx-arm64) + -editables-0.5 (conda-forge/noarch) + -exceptiongroup-1.2.2 (conda-forge/noarch) + -execnet-2.1.1 (conda-forge/noarch) + -filelock-3.15.4 (conda-forge/noarch) + -future-1.0.0 (conda-forge/noarch) + -grayskull-2.5.3 (conda-forge/noarch) + -h2-4.1.0 (conda-forge/noarch) + -hatchling-1.25.0 (conda-forge/noarch) + -hpack-4.0.0 (conda-forge/noarch) + -hyperframe-6.0.1 (conda-forge/noarch) + -idna-3.7 (conda-forge/noarch) + -imagesize-1.4.1 (conda-forge/noarch) + -importlib-metadata-8.0.0 (conda-forge/noarch) + -importlib_metadata-8.0.0 (conda-forge/noarch) + -importlib_resources-6.4.0 (conda-forge/noarch) + -iniconfig-2.0.0 (conda-forge/noarch) + -jaraco.classes-3.4.0 (conda-forge/noarch) + -jaraco.context-5.3.0 (conda-forge/noarch) + -jaraco.functools-4.0.0 (conda-forge/noarch) + -jinja2-3.1.4 (conda-forge/noarch) + -junitparser-3.1.2 (conda-forge/noarch) + -keyring-25.2.1 (conda-forge/noarch) + -libblas-3.9.0 (conda-forge/osx-arm64) + -libcblas-3.9.0 (conda-forge/osx-arm64) + -libcxx-18.1.8 (conda-forge/osx-arm64) + -libexpat-2.6.2 (conda-forge/osx-arm64) + -libffi-3.4.2 (conda-forge/osx-arm64) + -libgfortran-5.0.0 (conda-forge/osx-arm64) + -libgfortran5-13.2.0 (conda-forge/osx-arm64) + -liblapack-3.9.0 (conda-forge/osx-arm64) + -libopenblas-0.3.27 (conda-forge/osx-arm64) + -libsqlite-3.46.0 (conda-forge/osx-arm64) + -libzlib-1.3.1 (conda-forge/osx-arm64) + -llvm-openmp-18.1.8 (conda-forge/osx-arm64) + -markdown-it-py-3.0.0 (conda-forge/noarch) + -markupsafe-2.1.5 (conda-forge/osx-arm64) + -mdurl-0.1.2 (conda-forge/noarch) + -more-itertools-10.3.0 (conda-forge/noarch) + -mypy-1.10.1 (conda-forge/osx-arm64) + -mypy_extensions-1.0.0 (conda-forge/noarch) + -ncurses-6.5 (conda-forge/osx-arm64) + -nh3-0.2.18 (conda-forge/osx-arm64) + -numpy-2.0.0 (conda-forge/osx-arm64) + -openssl-3.3.1 (conda-forge/osx-arm64) + -packaging-24.1 (conda-forge/noarch) + -pathspec-0.12.1 (conda-forge/noarch) + -pip-24.0 (conda-forge/noarch) + -pkginfo-1.10.0 (conda-forge/noarch) + -platformdirs-4.2.2 (conda-forge/noarch) + -pluggy-1.5.0 (conda-forge/noarch) + -progressbar2-4.4.2 (conda-forge/noarch) + -psutil-6.0.0 (conda-forge/osx-arm64) + -pycparser-2.22 (conda-forge/noarch) + -pygments-2.18.0 (conda-forge/noarch) + -pyproject-api-1.7.1 (conda-forge/noarch) + -pysocks-1.7.1 (conda-forge/noarch) + -pytest-8.2.2 (conda-forge/noarch) + -pytest-cov-5.0.0 (conda-forge/noarch) + -pytest-xdist-3.6.1 (conda-forge/noarch) + -python-3.12.4 (conda-forge/osx-arm64) + -python-utils-3.8.2 (conda-forge/noarch) + -python_abi-3.12 (conda-forge/osx-arm64) + -pytz-2024.1 (conda-forge/noarch) + -pyyaml-6.0.1 (conda-forge/osx-arm64) + -rapidfuzz-3.9.4 (conda-forge/osx-arm64) + -readline-8.2 (conda-forge/osx-arm64) + -readme_renderer-42.0 (conda-forge/noarch) + -requests-2.32.3 (conda-forge/noarch) + -requests-toolbelt-1.0.0 (conda-forge/noarch) + -rfc3986-2.0.0 (conda-forge/noarch) + -rich-13.7.1 (conda-forge/noarch) + -ruamel.yaml-0.18.6 (conda-forge/osx-arm64) + -ruamel.yaml.clib-0.2.8 (conda-forge/osx-arm64) + -ruamel.yaml.jinja2-0.2.4 (conda-forge/noarch) + -ruff-0.5.2 (conda-forge/osx-arm64) + -semver-3.0.2 (conda-forge/noarch) + -setuptools-70.3.0 (conda-forge/noarch) + -snowballstemmer-2.2.0 (conda-forge/noarch) + -soupsieve-2.5 (conda-forge/noarch) + -sphinx-7.4.5 (conda-forge/noarch) + -sphinx-autodoc-typehints-2.2.2 (conda-forge/noarch) + -sphinx-click-6.0.0 (conda-forge/noarch) + -sphinx-rtd-theme-2.0.0 (conda-forge/noarch) + -sphinx_rtd_theme-2.0.0 (conda-forge/noarch) + -sphinxcontrib-applehelp-1.0.8 (conda-forge/noarch) + -sphinxcontrib-devhelp-1.0.6 (conda-forge/noarch) + -sphinxcontrib-htmlhelp-2.0.5 (conda-forge/noarch) + -sphinxcontrib-jquery-4.1 (conda-forge/noarch) + -sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) + -sphinxcontrib-qthelp-1.0.7 (conda-forge/noarch) + -sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) + -stdlib-list-0.10.0 (conda-forge/noarch) + -tk-8.6.13 (conda-forge/osx-arm64) + -toml-0.10.2 (conda-forge/noarch) + -tomli-2.0.1 (conda-forge/noarch) + -tomli-w-1.0.0 (conda-forge/noarch) + -tox-4.16.0 (conda-forge/noarch) + -trove-classifiers-2024.7.2 (conda-forge/noarch) + -twine-5.1.1 (conda-forge/noarch) + -types-pyyaml-6.0.12.20240311 (conda-forge/noarch) + -typing_extensions-4.12.2 (conda-forge/noarch) + -tzdata-2024a (conda-forge/noarch) + -urllib3-2.2.2 (conda-forge/noarch) + -uv-0.2.25 (conda-forge/osx-arm64) + -virtualenv-20.26.3 (conda-forge/noarch) + -wheel-0.43.0 (conda-forge/noarch) + -xz-5.2.6 (conda-forge/osx-arm64) + -yaml-0.2.5 (conda-forge/osx-arm64) + -zipp-3.19.2 (conda-forge/noarch) + -zstandard-0.23.0 (conda-forge/osx-arm64) + -zstd-1.5.6 (conda-forge/osx-arm64) + +2024-11-23 17:19:55 (rev 3) + +bzip2-1.0.8 (conda-forge/osx-arm64) + +ca-certificates-2024.8.30 (conda-forge/osx-arm64) + +cachetools-5.5.0 (conda-forge/noarch) + +chardet-5.2.0 (conda-forge/osx-arm64) + +colorama-0.4.6 (conda-forge/noarch) + +distlib-0.3.9 (conda-forge/noarch) + +filelock-3.16.1 (conda-forge/noarch) + +libcxx-19.1.4 (conda-forge/osx-arm64) + +libexpat-2.6.4 (conda-forge/osx-arm64) + +libffi-3.4.2 (conda-forge/osx-arm64) + +libmpdec-4.0.0 (conda-forge/osx-arm64) + +libsqlite-3.47.0 (conda-forge/osx-arm64) + +libzlib-1.3.1 (conda-forge/osx-arm64) + +ncurses-6.5 (conda-forge/osx-arm64) + +openssl-3.4.0 (conda-forge/osx-arm64) + +packaging-24.2 (conda-forge/noarch) + +pip-24.3.1 (conda-forge/noarch) + +platformdirs-4.3.6 (conda-forge/noarch) + +pluggy-1.5.0 (conda-forge/noarch) + +pyproject-api-1.8.0 (conda-forge/noarch) + +python-3.13.0 (conda-forge/osx-arm64) + +python_abi-3.13 (conda-forge/osx-arm64) + +readline-8.2 (conda-forge/osx-arm64) + +tk-8.6.13 (conda-forge/osx-arm64) + +tomli-2.1.0 (conda-forge/noarch) + +tox-4.23.2 (conda-forge/noarch) + +typing_extensions-4.12.2 (conda-forge/noarch) + +tzdata-2024b (conda-forge/noarch) + +uv-0.5.4 (conda-forge/osx-arm64) + +virtualenv-20.27.1 (conda-forge/noarch) + +xz-5.2.6 (conda-forge/osx-arm64) + +2024-11-23 17:20:06 (rev 4) + +alabaster-1.0.0 (conda-forge/noarch) + +appdirs-1.4.4 (conda-forge/noarch) + +babel-2.16.0 (conda-forge/noarch) + +backports-1.0 (conda-forge/noarch) + +backports.tarfile-1.2.0 (conda-forge/noarch) + +beautifulsoup4-4.12.3 (conda-forge/noarch) + +black-24.10.0 (conda-forge/osx-arm64) + +brotli-python-1.1.0 (conda-forge/osx-arm64) + +certifi-2024.8.30 (conda-forge/noarch) + +cffi-1.17.1 (conda-forge/osx-arm64) + +charset-normalizer-3.4.0 (conda-forge/noarch) + +click-8.1.7 (conda-forge/noarch) + +cmarkgfm-2024.11.20 (conda-forge/osx-arm64) + +conda-souschef-2.2.3 (conda-forge/noarch) + +coverage-7.6.7 (conda-forge/osx-arm64) + +docutils-0.21.2 (conda-forge/noarch) + +editables-0.5 (conda-forge/noarch) + +exceptiongroup-1.2.2 (conda-forge/noarch) + +execnet-2.1.1 (conda-forge/noarch) + +future-1.0.0 (conda-forge/noarch) + +grayskull-2.7.3 (conda-forge/noarch) + +h2-4.1.0 (conda-forge/noarch) + +hatchling-1.26.3 (conda-forge/noarch) + +hpack-4.0.0 (conda-forge/noarch) + +hyperframe-6.0.1 (conda-forge/noarch) + +idna-3.10 (conda-forge/noarch) + +imagesize-1.4.1 (conda-forge/noarch) + +importlib-metadata-8.5.0 (conda-forge/noarch) + +importlib_metadata-8.5.0 (conda-forge/noarch) + +importlib_resources-6.4.5 (conda-forge/noarch) + +iniconfig-2.0.0 (conda-forge/noarch) + +jaraco.classes-3.4.0 (conda-forge/noarch) + +jaraco.context-5.3.0 (conda-forge/noarch) + +jaraco.functools-4.0.0 (conda-forge/noarch) + +jinja2-3.1.4 (conda-forge/noarch) + +junitparser-3.2.0 (conda-forge/noarch) + +keyring-25.5.0 (conda-forge/noarch) + +libblas-3.9.0 (conda-forge/osx-arm64) + +libcblas-3.9.0 (conda-forge/osx-arm64) + +libgfortran-5.0.0 (conda-forge/osx-arm64) + +libgfortran5-13.2.0 (conda-forge/osx-arm64) + +liblapack-3.9.0 (conda-forge/osx-arm64) + +libopenblas-0.3.28 (conda-forge/osx-arm64) + +llvm-openmp-19.1.4 (conda-forge/osx-arm64) + +markdown-it-py-3.0.0 (conda-forge/noarch) + +markupsafe-3.0.2 (conda-forge/osx-arm64) + +mdurl-0.1.2 (conda-forge/noarch) + +more-itertools-10.5.0 (conda-forge/noarch) + +mypy-1.13.0 (conda-forge/osx-arm64) + +mypy_extensions-1.0.0 (conda-forge/noarch) + +nh3-0.2.18 (conda-forge/osx-arm64) + +numpy-2.1.3 (conda-forge/osx-arm64) + +pathspec-0.12.1 (conda-forge/noarch) + +pkginfo-1.10.0 (conda-forge/noarch) + +progressbar2-4.5.0 (conda-forge/noarch) + +psutil-6.1.0 (conda-forge/osx-arm64) + +pycparser-2.22 (conda-forge/noarch) + +pygments-2.18.0 (conda-forge/noarch) + +pysocks-1.7.1 (conda-forge/noarch) + +pytest-8.3.3 (conda-forge/noarch) + +pytest-cov-6.0.0 (conda-forge/noarch) + +pytest-xdist-3.6.1 (conda-forge/noarch) + +python-utils-3.9.0 (conda-forge/noarch) + +pytz-2024.2 (conda-forge/noarch) + +pyyaml-6.0.2 (conda-forge/osx-arm64) + +rapidfuzz-3.10.1 (conda-forge/osx-arm64) + +readme_renderer-44.0 (conda-forge/noarch) + +requests-2.32.3 (conda-forge/noarch) + +requests-toolbelt-1.0.0 (conda-forge/noarch) + +rfc3986-2.0.0 (conda-forge/noarch) + +rich-13.9.4 (conda-forge/noarch) + +ruamel.yaml-0.18.6 (conda-forge/osx-arm64) + +ruamel.yaml.clib-0.2.8 (conda-forge/osx-arm64) + +ruamel.yaml.jinja2-0.2.7 (conda-forge/noarch) + +ruff-0.8.0 (conda-forge/osx-arm64) + +semver-3.0.2 (conda-forge/noarch) + +setuptools-75.6.0 (conda-forge/noarch) + +snowballstemmer-2.2.0 (conda-forge/noarch) + +soupsieve-2.5 (conda-forge/noarch) + +sphinx-8.1.3 (conda-forge/noarch) + +sphinx-autodoc-typehints-2.5.0 (conda-forge/noarch) + +sphinx-click-6.0.0 (conda-forge/noarch) + +sphinx-rtd-theme-3.0.1 (conda-forge/noarch) + +sphinx_rtd_theme-3.0.1 (conda-forge/noarch) + +sphinxcontrib-applehelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-devhelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-htmlhelp-2.1.0 (conda-forge/noarch) + +sphinxcontrib-jquery-4.1 (conda-forge/noarch) + +sphinxcontrib-jsmath-1.0.1 (conda-forge/noarch) + +sphinxcontrib-qthelp-2.0.0 (conda-forge/noarch) + +sphinxcontrib-serializinghtml-1.1.10 (conda-forge/noarch) + +stdlib-list-0.11.0 (conda-forge/noarch) + +toml-0.10.2 (conda-forge/noarch) + +tomli-w-1.1.0 (conda-forge/noarch) + +trove-classifiers-2024.10.21.16 (conda-forge/noarch) + +twine-5.1.1 (conda-forge/noarch) + +types-pyyaml-6.0.12.20240917 (conda-forge/noarch) + +urllib3-2.2.3 (conda-forge/noarch) + +yaml-0.2.5 (conda-forge/osx-arm64) + +zipp-3.21.0 (conda-forge/noarch) + +zstandard-0.23.0 (conda-forge/osx-arm64) + +zstd-1.5.6 (conda-forge/osx-arm64) +