From b2823ceb0d728c66ab2ff4dfe690d35cc6b9da47 Mon Sep 17 00:00:00 2001 From: vsoch Date: Sun, 7 Sep 2025 23:11:38 -0700 Subject: [PATCH 1/6] wip: plan for fractale feasibility Signed-off-by: vsoch --- README.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dba7c05..17f34d6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,21 @@ This is a delgation plugin in Python, inspired by [Tapasya's](https://github.com/flux-framework/flux-core/pull/6873/files) WIP. I'm using it as a prototype until that one is ready, and I wanted to implement in Python as a proof of concept (since many like writing Python) and to make it easy to quickly update without recompiling something. +## Notes + +We need to add a feasibility check, e.g., "Given these requests for software or other cluster resources, is this going to work?" Normally I think feasibility is run with fluxion, so *after* JobTap, but that doesn't make sense here. It doesn't make sense to send a job to another cluster just to have it rejected. So although this isn't a final design, I think feasibility (across many different options) needs to happen first. Then when we actually submit with a flux proxy (done via interfacing with the other URI) there is actually a better change of acceptance. It's like a pre-flight, fail fast check instead of "try and find out." An issue we might face is that the metadata about clusters and compatibility lives in a user's home, and I'm not sure that the flux instance / flux-core would have that access. + +On the other hand, we don't want to add stress to flux-core to do these expensive checks for every job submit. So maybe what needs to happen is our library performs a local feasibility check, and _then_ formulates the submit request to the local Flux instance, and then the JobTap submits it. To the user, it is one command. And actually for our tool (fractale) we can wrap it in a flux command so it looks like a single flux command. Something like: + +```bash +flux remote-submit ... +flux delegate ... +flux remove +flux remote submit +``` + +I like the last one the best - we would have a suite of commands for multi-cluster. I will work on that. + ## Development Open up the [.devcontainer](.devcontainer) is VSCode. then do: @@ -27,4 +42,4 @@ At this point you have your development environment, You can tweak the Python sc ```bash flux submit --verbose --setattr=delegate.local_uri=$FLUX_URI --dependency=delegate:$FLUX_URI hostname ``` -I added the local uri as an attribute because it would mean we can direct the interaction, saying exactly FROM where and TO where. I'm next wanting to think about how this fits into Fractale. We should have a lookup of clusters we know in the user's home, and then the URIs can come from there after a match is done. I also want to account for something with node features using NFD. \ No newline at end of file +I added the local uri as an attribute because it would mean we can direct the interaction, saying exactly FROM where and TO where. I'm next wanting to think about how this fits into Fractale. We should have a lookup of clusters we know in the user's home, and then the URIs can come from there after a match is done. I also want to account for something with node features using NFD. From 37b5b07fd476fd089a012557790ee6097789492c Mon Sep 17 00:00:00 2001 From: vsoch Date: Mon, 8 Sep 2025 01:21:50 -0700 Subject: [PATCH 2/6] feat: add skeleton of flux remote submit This adds the basic structure for flux remote submit, which basically wraps the flux submit command (and is designed to support other subcommands in the future). This can be moved into the flux libexec cmd directory or just used as is. I next need to parse the submit request and then map attributes, etc. to the user defined compatibility data (cluster and resource needs) and I think then we are good. Signed-off-by: vsoch --- Makefile.am | 14 ++++++- README.md | 7 +--- cmd/flux-remote.py | 101 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 6 deletions(-) create mode 100755 cmd/flux-remote.py diff --git a/Makefile.am b/Makefile.am index 3b9ac24..14c2401 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,6 @@ -# File: Makefile.am (FINAL CORRECTED VERSION with -pthread in LDFLAGS) +########################################################################### +# Build C Stuff Rules +########################################################################### ACLOCAL_AMFLAGS = -I m4 @@ -12,6 +14,16 @@ delegate_c_bridge_la_LDFLAGS = -module -avoid-version -shared -pthread delegate_c_bridge_la_LIBADD = @FLUX_CORE_LIBS@ @PYTHON_LIBS@ -ldl +########################################################################### +# Install Script Rules +########################################################################### + +# $(libexecdir) is a standard autotools thing (e.g., /usr/libexec). +fluxcmddir = $(libexecdir)/flux/cmd + +# Using _SCRIPTS ensures the file is installed with execute permissions. +fluxcmd_SCRIPTS = cmd/flux-remote.py + clean-local: @echo "--- Running cleanup ---" rm -f configure aclocal.m4 Makefile.in config.h.in ltmain.sh diff --git a/README.md b/README.md index 17f34d6..dac522b 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,10 @@ We need to add a feasibility check, e.g., "Given these requests for software or On the other hand, we don't want to add stress to flux-core to do these expensive checks for every job submit. So maybe what needs to happen is our library performs a local feasibility check, and _then_ formulates the submit request to the local Flux instance, and then the JobTap submits it. To the user, it is one command. And actually for our tool (fractale) we can wrap it in a flux command so it looks like a single flux command. Something like: ```bash -flux remote-submit ... -flux delegate ... -flux remove -flux remote submit +flux remote submit ``` -I like the last one the best - we would have a suite of commands for multi-cluster. I will work on that. +The above is implemented to wrap around submit, and that is the extra command in [cmd](cmd) that can be installed to a Flux root (or just run as a one-off script). We just need to add the fractale stuff there. Will work on this week. ## Development diff --git a/cmd/flux-remote.py b/cmd/flux-remote.py new file mode 100755 index 0000000..aa056e0 --- /dev/null +++ b/cmd/flux-remote.py @@ -0,0 +1,101 @@ +############################################################## +# Copyright 2023 Lawrence Livermore National Security, LLC +# (c.f. AUTHORS, NOTICE.LLNS, COPYING) +# +# This file is part of the Flux resource manager framework. +# For details, see https://github.com/flux-framework. +# +# SPDX-License-Identifier: LGPL-3.0 +############################################################## + +import logging +import sys +import argparse + +import flux +import flux.cli.submit as base + +LOGGER = logging.getLogger("flux-remote") + + +def open_logfile(fd): + return open(fd, "w", encoding="utf8", errors="surrogateescape") + + +class SubmitCmd(base.SubmitCmd): + def main(self, args): + """ + Add a step before main to run feasibility check. + + The args have the job info we can further parse! + """ + self.feasibility_check(args) + self.submit_async_with_cc(args) + self.run_and_exit() + + def feasibility_check(self, args): + print("TODO VANESSA add fractale checks here.") + + +class RemoteSubmitCmd(base.SubmitCmd): + """ + RemoteSubmitCmd submits a job, displays the jobid on stdout, and returns. + We extend SubmitCmd from the base class to handle doing a local feasibility + check first. We do this before we send to flux (and JobTap) so we do not + unecessarily send to a cluster that is not already checked. + + Usage: flux remote submit [OPTIONS] cmd ... + """ + + def run_parser(self): + """ + The main remote parser is very simple. It only looks for the subcommand. + """ + parser = argparse.ArgumentParser( + prog="flux remote", + description="A command to interact with a remote Flux instance.", + usage="flux remote [options...]", + ) + parser.add_argument("command", help="Subcommand to run (e.g., 'submit')") + + # This just processes our added command (expecting other subcommands eventually) + args, remaining_argv = parser.parse_known_args() + + # Now, we dispatch to the correct handler based on the command. + if args.command == "submit": + self.handle_submit(remaining_argv) + + def handle_submit(self, argv): + """ + Handle the submit subcommand. + + We need special parsing for help. + """ + submit = SubmitCmd("flux submit", description="enqueue a job") + submit_parser = submit.get_parser() + submit_parser.set_defaults(func=submit.main) + + # We need to handle this manually since it's off base for argparse + if "-h" in argv or "--help" in argv: + submit.parser.print_help() + sys.exit(0) + + sys.argv = ["flux", "submit"] + argv + args = submit_parser.parse_args() + args.func(args) + + +@flux.util.CLIMain(LOGGER) +def main(): + sys.stdout = open_logfile(sys.stdout.fileno()) + sys.stderr = open_logfile(sys.stderr.fileno()) + + # This is going to be a submit parser with extra bells and whistles + submit = RemoteSubmitCmd( + "flux remote", description="enqueue a multi-cluster (including remote) job" + ) + submit.run_parser() + + +if __name__ == "__main__": + main() From c50d5953505ebf4100b97ab9d1b5e295ddf8bf43 Mon Sep 17 00:00:00 2001 From: vsoch Date: Mon, 8 Sep 2025 11:29:41 -0700 Subject: [PATCH 3/6] feat: structure for feasibility within command Signed-off-by: vsoch --- .devcontainer/Dockerfile | 11 +++++-- .pre-commit-config.yaml | 27 +++++++++++++++ README.md | 12 +++++++ cmd/flux-remote.py | 65 +++++++++++++++++++++++++++++++------ configure.ac | 2 +- delegate.toml | 2 -- delegate_c_bridge.c | 2 +- delegate_handler.py | 19 +++++++---- examples/fractale/README.md | 40 +++++++++++++++++++++++ 9 files changed, 158 insertions(+), 22 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 examples/fractale/README.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c951292..ddbffe0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -10,14 +10,21 @@ ENV USERNAME=${USERNAME} ENV USER_UID=${USER_UID} ENV USER_GID=${USER_GID} USER root - + # extra interactive utilities RUN apt-get update \ && apt-get -qq install -y --no-install-recommends \ fd-find \ less \ bats \ - ripgrep + ripgrep \ + lsb-release \ + gnupg2 + +# Python depedencies +RUN python3 -m pip install fractale && \ + wget https://downloads.skewed.de/skewed-keyring/skewed-keyring_1.3_all_$(lsb_release -s -c).deb && \ + dpkg -i skewed-keyring_1.3_all_$(lsb_release -s -c).deb # Add the group and user that match our ids RUN groupadd -g ${USER_GID} ${USERNAME} && \ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..142c17d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,27 @@ +exclude: "examples" +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-added-large-files + args: ["--maxkb=2000"] + - id: check-case-conflict + - id: check-docstring-first + - id: end-of-file-fixer + - id: trailing-whitespace + - id: mixed-line-ending + + - repo: local + hooks: + - id: black + name: black + language: python + types: [python] + entry: black + + - id: isort + name: isort + args: [--filter-files] + language: python + types: [python] + entry: isort diff --git a/README.md b/README.md index dac522b..8a541e7 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,15 @@ At this point you have your development environment, You can tweak the Python sc flux submit --verbose --setattr=delegate.local_uri=$FLUX_URI --dependency=delegate:$FLUX_URI hostname ``` I added the local uri as an attribute because it would mean we can direct the interaction, saying exactly FROM where and TO where. I'm next wanting to think about how this fits into Fractale. We should have a lookup of clusters we know in the user's home, and then the URIs can come from there after a match is done. I also want to account for something with node features using NFD. + +## Fractale + +For integration with Fractale (and flux) we won't require the user to ask for delegation directly. We will provide a command for a remote submit: + +```bash +flux remote submit --dry-run --setattr=requires.software=spack:curl curl +``` + +In the above, the user is asking for a remote submit. This means we are going to receive the request in Flux, compare to local subsystems and clusters defined by the user in their home, and then make a selection of a cluster. The selected cluster will go straight to the JobTap plugin from the `flux remote submit` command without the user needing any subsequent interaction. +What I want to work on / harden is the organization, structure, and query of the cluster and subsystem metadata. I've been forcing use of a graph but I am not convinced that is the best way. +See [examples/fractale](examples/fractale) for the full example, and the [cmd](cmd) that is added to Flux as a WIP to orchestrate this. diff --git a/cmd/flux-remote.py b/cmd/flux-remote.py index aa056e0..d25e41d 100755 --- a/cmd/flux-remote.py +++ b/cmd/flux-remote.py @@ -8,12 +8,19 @@ # SPDX-License-Identifier: LGPL-3.0 ############################################################## +import argparse import logging import sys -import argparse import flux import flux.cli.submit as base +import fractale.defaults as defaults +from compspec.plugin.registry import PluginRegistry +from fractale.store import FractaleStore +from fractale.subsystem import get_subsystem_solver + +registry = PluginRegistry() +registry.discover() LOGGER = logging.getLogger("flux-remote") @@ -23,18 +30,42 @@ def open_logfile(fd): class SubmitCmd(base.SubmitCmd): - def main(self, args): + def main(self, args, remote_args): """ Add a step before main to run feasibility check. The args have the job info we can further parse! """ - self.feasibility_check(args) - self.submit_async_with_cc(args) + # Feasibility check handles args from flux remote + with_delegation = self.feasibility_check(args, remote_args) + + # Submit the jobspec args, which may now have delegation + self.submit_async_with_cc(with_delegation) self.run_and_exit() - def feasibility_check(self, args): - print("TODO VANESSA add fractale checks here.") + def feasibility_check(self, args, remote_args): + """ + Check feasibility based on local user subsystems with fractale library. + """ + jobspec = self.jobspec_create(args) + store = FractaleStore(args.config_dir) + + # TODO Vanessa + # I want to make a hardened organization for this. + # ---- + # 1. The user needs to register different clusters. Each needs a remote URI. + # 2. For feasibility, we first check cluster resources for each known cluster + # 3. We then check subsystem requests that come from requires (e.g. --setattr=requires.software=spack:curl) + # 4. Based on the filtered set, we finalize, add the delegation plugin URI, and we are done. + # 5. Fall through case (no remote matches) we submit as usual to local cluster instance + # Going for a run - will work on this after. + solver = get_subsystem_solver(store.clusters_root, args.solver) + is_satisfied = solver.satisfied(args.jobspec) + + # If we are satisifed, we can get the result, and then add it to the JobSpec as a delegate dependency. We will + # That would look like this: + # args.setattr = [f'delegate.local_uri=${uri}'] + return args class RemoteSubmitCmd(base.SubmitCmd): @@ -56,6 +87,19 @@ def run_parser(self): description="A command to interact with a remote Flux instance.", usage="flux remote [options...]", ) + # Let's not require graph_tool to start, make default database + # I don't think we can assume everything is structed like a graph + parser.add_argument( + "--solver", + help="subsystem solved backend", + default="database", + choices=defaults.solver_backends, + ) + parser.add_argument( + "--config-dir", + dest="config_dir", + help="Fractale configuration directory to store subsystems. Defaults to ~/.fractale", + ) parser.add_argument("command", help="Subcommand to run (e.g., 'submit')") # This just processes our added command (expecting other subcommands eventually) @@ -63,9 +107,9 @@ def run_parser(self): # Now, we dispatch to the correct handler based on the command. if args.command == "submit": - self.handle_submit(remaining_argv) + self.handle_submit(remaining_argv, args) - def handle_submit(self, argv): + def handle_submit(self, argv, remote_args): """ Handle the submit subcommand. @@ -80,9 +124,10 @@ def handle_submit(self, argv): submit.parser.print_help() sys.exit(0) - sys.argv = ["flux", "submit"] + argv + # Repopulate the initial submit args + sys.argv = argv args = submit_parser.parse_args() - args.func(args) + args.func(args, remote_args) @flux.util.CLIMain(LOGGER) diff --git a/configure.ac b/configure.ac index 1c053b9..eb1d681 100644 --- a/configure.ac +++ b/configure.ac @@ -26,4 +26,4 @@ AC_SUBST([PYTHON_CFLAGS]) AC_SUBST([PYTHON_LIBS]) AC_CONFIG_FILES([Makefile]) -AC_OUTPUT \ No newline at end of file +AC_OUTPUT diff --git a/delegate.toml b/delegate.toml index a862536..375631a 100644 --- a/delegate.toml +++ b/delegate.toml @@ -2,5 +2,3 @@ plugins = [ { load = "/usr/lib/flux-delegate-plugin/delegate_c_bridge.so"}, ] - - diff --git a/delegate_c_bridge.c b/delegate_c_bridge.c index 05cec4d..02fe4bd 100644 --- a/delegate_c_bridge.c +++ b/delegate_c_bridge.c @@ -100,4 +100,4 @@ static const struct flux_plugin_handler tab[] = { }; int flux_plugin_init(flux_plugin_t *p) { return flux_plugin_register(p, "delegate-c-bridge", tab); -} \ No newline at end of file +} diff --git a/delegate_handler.py b/delegate_handler.py index 0c4f5e5..c1d9853 100644 --- a/delegate_handler.py +++ b/delegate_handler.py @@ -1,11 +1,14 @@ # File: delegate_handler.py (FINAL CORRECTED VERSION - Submit only) import sys -sys.modules['yaml.cyaml'] = None + +sys.modules["yaml.cyaml"] = None + +import json import flux import flux.job -import json + def handle_delegation(jobid, remote_uri, jobspec_str, local_uri): """ @@ -18,12 +21,16 @@ def handle_delegation(jobid, remote_uri, jobspec_str, local_uri): print(f"Delegate: Starting remote submission for job {jobid} to {remote_uri}") jobspec = json.loads(jobspec_str) - if ("attributes" in jobspec and "system" in jobspec["attributes"] and "dependencies" in jobspec["attributes"]["system"]): + if ( + "attributes" in jobspec + and "system" in jobspec["attributes"] + and "dependencies" in jobspec["attributes"]["system"] + ): del jobspec["attributes"]["system"]["dependencies"] # This would do it infinitely... - if 'delegate' in jobspec['attributes']['system']: - del jobspec['attributes']['system']['delegate'] + if "delegate" in jobspec["attributes"]["system"]: + del jobspec["attributes"]["system"]["delegate"] encoded_jobspec = json.dumps(jobspec) # Use the one helper function that has been proven to work reliably. @@ -32,4 +39,4 @@ def handle_delegation(jobid, remote_uri, jobspec_str, local_uri): aslong = flux.job.JobID(remote_jobid) print(f"Delegate: Job {jobid} submitted. Remote jobid is {remote_jobid}") - return aslong \ No newline at end of file + return aslong diff --git a/examples/fractale/README.md b/examples/fractale/README.md new file mode 100644 index 0000000..f55800a --- /dev/null +++ b/examples/fractale/README.md @@ -0,0 +1,40 @@ +# Fractale Workflow + +This example will walk through the steps to generate local compatibility graphs to describe a user-space, and then use `flux remote` to submit with the JobTap delegation plugin. + +## Install Fractale + +You can pip install, or install from GitHub. + +```bash +pip install fractale + +# or +git clone https://github.com/compspec/fractale +cd fractale +pip install -e . +``` + +## Local Subsystems + +A local subsystem is typically a user-space install of software or other metadata that is associated with a cluster. Local subsystems can be defined for one or more clusters, and all provided to fractale to determine with of the clusters can support the work. For each cluster, the user will use fractale and (via the [compspec](https://github.com/compspec/compspec) library and plugins) generate one or more subsystem graphs associated with different clusters. Let's start with generating metadata for clusters A and B: + +```bash +fractale generate --cluster A spack /home/vanessa/Desktop/Code/spack +``` + +I'm still thinking of how I want these generated and organized. I'm not convinced forcing a graph is the best way. Arguably, each plugin should be able to independently decide and then deliver +its organized information to a common interface. + +## Remote Submit Request + +Satisfy asks two questions: + +1. Which clusters have the subsystem resources that I need? +2. Which clusters have the job resources that I need (containment subsystem)? + +This is the step where we want to say "Run gromacs on 2-4 nodes with these requirements." Since we haven't formalized a way to do that, I'm going to start with a flux jobspec, and then add attributes that can be used to search our subsystems. For example (and currently there are two ways to do this): + +```bash +flux remote submit --dry-run --setattr=requires.software=spack:curl curl +``` From 85a1ad8bfe4f5ea1a6de422d18dd5bc113496ad2 Mon Sep 17 00:00:00 2001 From: vsoch Date: Sat, 20 Sep 2025 23:41:55 -0700 Subject: [PATCH 4/6] feat: add pixi env for easy access to graph tool Signed-off-by: vsoch --- .devcontainer/Dockerfile | 10 +- .gitattributes | 2 + .gitignore | 22 + README.md | 10 + cmd/flux-remote.py | 46 +- pixi.lock | 2507 ++++++++++++++++++++++++++++++++++++++ pixi.toml | 18 + 7 files changed, 2603 insertions(+), 12 deletions(-) create mode 100644 .gitattributes create mode 100644 pixi.lock create mode 100644 pixi.toml diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index ddbffe0..87695a0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -22,9 +22,13 @@ RUN apt-get update \ gnupg2 # Python depedencies -RUN python3 -m pip install fractale && \ - wget https://downloads.skewed.de/skewed-keyring/skewed-keyring_1.3_all_$(lsb_release -s -c).deb && \ - dpkg -i skewed-keyring_1.3_all_$(lsb_release -s -c).deb +ENV PIXI_HOME=/opt/pixi +ENV PATH=/opt/pixi/bin:$PATH +COPY pixi.toml pixi.lock /opt/pixi/ +WORKDIR /opt/pixi +RUN /bin/bash -c "curl -fsSL https://pixi.sh/install.sh | bash" && pixi install + +ENV PYTHONPATH=/usr/lib/python3.10/site-packages # Add the group and user that match our ids RUN groupadd -g ${USER_GID} ${USERNAME} && \ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..887a2c1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# SCM syntax highlighting & preventing 3-way merges +pixi.lock merge=binary linguist-language=YAML linguist-generated=true diff --git a/.gitignore b/.gitignore index 39a0668..4ef92e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,23 @@ .deps +# pixi environments +.pixi/* +!.pixi/config.toml +Makefile +Makefile.in +aclocal.m4 +ar-lib +autom4te.cache +compile +config.* +configure +.libs +install-sh +libtool +m4 +missing +stamp-h1 +depcomp +ltmain.sh +*.la +*.lo +*.o diff --git a/README.md b/README.md index 8a541e7..774370f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ make sudo make install ``` +Enter the pixi shell: + +```bash +pixi shell +``` + ## Usage Once you have installed, you can test by starting a Flux broker in the same directory as [delegate_handler.py](delegate_handler.py). @@ -39,6 +45,7 @@ At this point you have your development environment, You can tweak the Python sc ```bash flux submit --verbose --setattr=delegate.local_uri=$FLUX_URI --dependency=delegate:$FLUX_URI hostname ``` + I added the local uri as an attribute because it would mean we can direct the interaction, saying exactly FROM where and TO where. I'm next wanting to think about how this fits into Fractale. We should have a lookup of clusters we know in the user's home, and then the URIs can come from there after a match is done. I also want to account for something with node features using NFD. ## Fractale @@ -47,6 +54,9 @@ For integration with Fractale (and flux) we won't require the user to ask for de ```bash flux remote submit --dry-run --setattr=requires.software=spack:curl curl + +# Development variant +python cmd/flux-remote.py submit --dry-run --setattr=requires.software=spack:curl curl ``` In the above, the user is asking for a remote submit. This means we are going to receive the request in Flux, compare to local subsystems and clusters defined by the user in their home, and then make a selection of a cluster. The selected cluster will go straight to the JobTap plugin from the `flux remote submit` command without the user needing any subsequent interaction. diff --git a/cmd/flux-remote.py b/cmd/flux-remote.py index d25e41d..8ba2ab6 100755 --- a/cmd/flux-remote.py +++ b/cmd/flux-remote.py @@ -10,11 +10,14 @@ import argparse import logging +import os import sys +import tempfile import flux import flux.cli.submit as base import fractale.defaults as defaults +import fractale.utils as utils from compspec.plugin.registry import PluginRegistry from fractale.store import FractaleStore from fractale.subsystem import get_subsystem_solver @@ -48,20 +51,41 @@ def feasibility_check(self, args, remote_args): Check feasibility based on local user subsystems with fractale library. """ jobspec = self.jobspec_create(args) - store = FractaleStore(args.config_dir) - - # TODO Vanessa - # I want to make a hardened organization for this. + store = FractaleStore(remote_args.config_dir) + + # Detect or discover local cluster resources if no store created + if not os.path.exists(store.root): + store.detect() + + # This is inefficient, but right now we write the jobspec to file + # TODO: expose a means to pass in JobSpec from string or dict (not file) + with tempfile.NamedTemporaryFile( + delete=False, suffix=".yaml", prefix="jobspec-" + ) as temp_file: + temp_file_path = temp_file.name + utils.write_yaml(jobspec.jobspec, temp_file_path) + + # TODO Vanessa - this is parsing the wrong format. I need to update it. + # I want to make a hardened organization for this. Operations across clusters can be in in parallel # ---- - # 1. The user needs to register different clusters. Each needs a remote URI. + # 1. Each detected cluster needs a remote URI or credential (e.g., Kubernetes) + # - TODO: we should be able to detect kubernetes cluster as ephemeral + # - TODO: make compspec-kube for this use case. # 2. For feasibility, we first check cluster resources for each known cluster # 3. We then check subsystem requests that come from requires (e.g. --setattr=requires.software=spack:curl) - # 4. Based on the filtered set, we finalize, add the delegation plugin URI, and we are done. + # 4. Based on the filtered set: + # - For Flux we finalize, add the delegation plugin URI, and we are done. + # - For Kubernetes, it's easier (an API call) and this should also be done by delegation # 5. Fall through case (no remote matches) we submit as usual to local cluster instance - # Going for a run - will work on this after. - solver = get_subsystem_solver(store.clusters_root, args.solver) - is_satisfied = solver.satisfied(args.jobspec) + print("FIX THE FORMAT VANESSA YOU GOBLIN") + import IPython + + IPython.embed() + solver = get_subsystem_solver(store.clusters_root, remote_args.solver) + is_satisfied = solver.satisfied(temp_file_path) + if os.path.exists(temp_file_path): + os.remove(temp_file_path) # If we are satisifed, we can get the result, and then add it to the JobSpec as a delegate dependency. We will # That would look like this: # args.setattr = [f'delegate.local_uri=${uri}'] @@ -108,6 +132,10 @@ def run_parser(self): # Now, we dispatch to the correct handler based on the command. if args.command == "submit": self.handle_submit(remaining_argv, args) + else: + print( + f"{args.command} is not a recognized Flux command. Try `flux remote submit`" + ) def handle_submit(self, argv, remote_args): """ diff --git a/pixi.lock b/pixi.lock new file mode 100644 index 0000000..5f4e4ab --- /dev/null +++ b/pixi.lock @@ -0,0 +1,2507 @@ +version: 6 +environments: + default: + channels: + - url: https://conda.anaconda.org/conda-forge/ + indexes: + - https://pypi.org/simple + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/_x86_64-microarch-level-1-2_x86_64.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb03c661_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb03c661_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cairomm-1.16-1.16.2-h7e731d7_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cairomm-1.16.2-ha770c72_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py313hf01b4d8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py313h7037e92_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h3c4dab8_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-h166bdaf_1.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.60.0-py313h3dea7bd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.1-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.1-h2b0a6b4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.0-hf516916_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/graph-tool-2.98-py313he24b9d1_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/graph-tool-base-2.98-py313h9733e6d_100.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.43-h0c6a113_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.5.0-h15599e2_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_2.tar.bz2 + - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.5.0-pyhfa0c392_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.9-py313hc8edb43_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-36_h4a7cf45_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.86.0-hed09d94_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.86.0-py313hfaae9d9_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb03c661_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb03c661_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb03c661_4.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-36_h0358290_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.24-h86f0d12_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.1-ha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.1-h73754d4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgirepository-1.84.0-h61e2d6e_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.4-he92a37e_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h8261f1e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.1-he9a06e4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.6-py313h683a580_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.3-py313hf6604e3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.3-h26f9b46_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hadf4263_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.5-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-pyhd8ed1ab_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py313ha492abd_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pycairo-1.28.0-py313h3f29d12_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pygobject-3.50.0-py313heb4b809_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.4-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.7-h2b335a9_100_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.2-py313h11c21cd_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sigcpp-3.0-3.6.0-h59595ed_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/sparsehash-2.0.4-hcb278e6_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.13-pyhd8ed1ab_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxinerama-1.1.5-h5888daf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-hb9d3cd8_1004.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + - pypi: https://files.pythonhosted.org/packages/b3/66/e6c0a808950ba5a4042e2fcedd577fc7401536c7db063de4d7c36be06f84/argparse_dataclass-2.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/f9/a1/2945dc1a688d988d4d6d33dea337ba925356350d73d796616e9f65afb30e/clingo-5.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/5c/73/d9c768a50545e3266e1452383bf84605be1ed33a4c17be201f7a606772c4/compspec-0.1.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/ee/a7/d2dc765e71dbcc73e01addb1b0d1640a22c29840b3c89ebcc87b3eb3ba61/compspec_modules-0.0.12-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/83/ff/c590bcd6bfde3c8c3d4521555ae3ff78bf517a5729d8d9150c7900dcfbee/compspec_spack-0.0.12-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/4c/8d/6850fcc11474c358fa55cebff8c1f4e8eb92585d5f9eae4b990968e65d64/fractale-0.0.13-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/a8/ee/a878f2ad010cbccb311f947f0f2f09d38f613938ee28c34e60fceecc75a1/pyaml-25.7.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl +packages: +- conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 + sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 + md5: d7c89558ba9fa0495403155b64376d81 + license: None + purls: [] + size: 2562 + timestamp: 1578324546067 +- conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2 + build_number: 16 + sha256: fbe2c5e56a653bebb982eda4876a9178aedfc2b545f25d0ce9c4c0b508253d22 + md5: 73aaf86a425cc6e73fcf236a5a46396d + depends: + - _libgcc_mutex 0.1 conda_forge + - libgomp >=7.5.0 + constrains: + - openmp_impl 9999 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 23621 + timestamp: 1650670423406 +- conda: https://conda.anaconda.org/conda-forge/noarch/_x86_64-microarch-level-1-2_x86_64.conda + build_number: 2 + sha256: 7623b2b804165b458f520371c40f5a607847336a882a55d3cfbdfb6407082794 + md5: 989cfef32fc3e5fb397e87479bec3809 + depends: + - __archspec 1 x86_64 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 7773 + timestamp: 1717599240447 +- pypi: https://files.pythonhosted.org/packages/b3/66/e6c0a808950ba5a4042e2fcedd577fc7401536c7db063de4d7c36be06f84/argparse_dataclass-2.0.0-py3-none-any.whl + name: argparse-dataclass + version: 2.0.0 + sha256: 3ffc8852a88d9d98d1364b4441a712491320afb91fb56049afd8a51d74bb52d2 + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/noarch/asttokens-3.0.0-pyhd8ed1ab_1.conda + sha256: 93b14414b3b3ed91e286e1cbe4e7a60c4e1b1c730b0814d1e452a8ac4b9af593 + md5: 8f587de4bcf981e26228f268df374a9b + depends: + - python >=3.9 + constrains: + - astroid >=2,<4 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/asttokens?source=hash-mapping + size: 28206 + timestamp: 1733250564754 +- conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-atk-2.38.0-h0630a04_3.tar.bz2 + sha256: 26ab9386e80bf196e51ebe005da77d57decf6d989b4f34d96130560bc133479c + md5: 6b889f174df1e0f816276ae69281af4d + depends: + - at-spi2-core >=2.40.0,<2.41.0a0 + - atk-1.0 >=2.36.0 + - dbus >=1.13.6,<2.0a0 + - libgcc-ng >=9.3.0 + - libglib >=2.68.1,<3.0a0 + license: LGPL-2.1-or-later + license_family: LGPL + purls: [] + size: 339899 + timestamp: 1619122953439 +- conda: https://conda.anaconda.org/conda-forge/linux-64/at-spi2-core-2.40.3-h0630a04_0.tar.bz2 + sha256: c4f9b66bd94c40d8f1ce1fad2d8b46534bdefda0c86e3337b28f6c25779f258d + md5: 8cb2fc4cd6cc63f1369cfa318f581cc3 + depends: + - dbus >=1.13.6,<2.0a0 + - libgcc-ng >=9.3.0 + - libglib >=2.68.3,<3.0a0 + - xorg-libx11 + - xorg-libxi + - xorg-libxtst + license: LGPL-2.1-or-later + license_family: LGPL + purls: [] + size: 658390 + timestamp: 1625848454791 +- conda: https://conda.anaconda.org/conda-forge/linux-64/atk-1.0-2.38.0-h04ea711_2.conda + sha256: df682395d05050cd1222740a42a551281210726a67447e5258968dd55854302e + md5: f730d54ba9cd543666d7220c9f7ed563 + depends: + - libgcc-ng >=12 + - libglib >=2.80.0,<3.0a0 + - libstdcxx-ng >=12 + constrains: + - atk-1.0 2.38.0 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 355900 + timestamp: 1713896169874 +- pypi: https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl + name: attrs + version: 25.3.0 + sha256: 427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3 + requires_dist: + - cloudpickle ; platform_python_implementation == 'CPython' and extra == 'benchmark' + - hypothesis ; extra == 'benchmark' + - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'benchmark' + - pympler ; extra == 'benchmark' + - pytest-codspeed ; extra == 'benchmark' + - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'benchmark' + - pytest-xdist[psutil] ; extra == 'benchmark' + - pytest>=4.3.0 ; extra == 'benchmark' + - cloudpickle ; platform_python_implementation == 'CPython' and extra == 'cov' + - coverage[toml]>=5.3 ; extra == 'cov' + - hypothesis ; extra == 'cov' + - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'cov' + - pympler ; extra == 'cov' + - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'cov' + - pytest-xdist[psutil] ; extra == 'cov' + - pytest>=4.3.0 ; extra == 'cov' + - cloudpickle ; platform_python_implementation == 'CPython' and extra == 'dev' + - hypothesis ; extra == 'dev' + - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'dev' + - pre-commit-uv ; extra == 'dev' + - pympler ; extra == 'dev' + - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'dev' + - pytest-xdist[psutil] ; extra == 'dev' + - pytest>=4.3.0 ; extra == 'dev' + - cogapp ; extra == 'docs' + - furo ; extra == 'docs' + - myst-parser ; extra == 'docs' + - sphinx ; extra == 'docs' + - sphinx-notfound-page ; extra == 'docs' + - sphinxcontrib-towncrier ; extra == 'docs' + - towncrier ; extra == 'docs' + - cloudpickle ; platform_python_implementation == 'CPython' and extra == 'tests' + - hypothesis ; extra == 'tests' + - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests' + - pympler ; extra == 'tests' + - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests' + - pytest-xdist[psutil] ; extra == 'tests' + - pytest>=4.3.0 ; extra == 'tests' + - mypy>=1.11.1 ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests-mypy' + - pytest-mypy-plugins ; python_full_version >= '3.10' and platform_python_implementation == 'CPython' and extra == 'tests-mypy' + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-1.1.0-hb03c661_4.conda + sha256: 294526a54fa13635341729f250d0b1cf8f82cad1e6b83130304cbf3b6d8b74cc + md5: eaf3fbd2aa97c212336de38a51fe404e + depends: + - __glibc >=2.17,<3.0.a0 + - brotli-bin 1.1.0 hb03c661_4 + - libbrotlidec 1.1.0 hb03c661_4 + - libbrotlienc 1.1.0 hb03c661_4 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 19883 + timestamp: 1756599394934 +- conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-bin-1.1.0-hb03c661_4.conda + sha256: 444903c6e5c553175721a16b7c7de590ef754a15c28c99afbc8a963b35269517 + md5: ca4ed8015764937c81b830f7f5b68543 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlidec 1.1.0 hb03c661_4 + - libbrotlienc 1.1.0 hb03c661_4 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 19615 + timestamp: 1756599385418 +- conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_8.conda + sha256: c30daba32ddebbb7ded490f0e371eae90f51e72db620554089103b4a6934b0d5 + md5: 51a19bba1b8ebfb60df25cde030b7ebc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: bzip2-1.0.6 + license_family: BSD + purls: [] + size: 260341 + timestamp: 1757437258798 +- conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2025.8.3-hbd8a1cb_0.conda + sha256: 837b795a2bb39b75694ba910c13c15fa4998d4bb2a622c214a6a5174b2ae53d1 + md5: 74784ee3d225fc3dca89edb635b4e5cc + depends: + - __unix + license: ISC + purls: [] + size: 154402 + timestamp: 1754210968730 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-h3394656_0.conda + sha256: 3bd6a391ad60e471de76c0e9db34986c4b5058587fbf2efa5a7f54645e28c2c7 + md5: 09262e66b19567aff4f592fb53b28760 + depends: + - __glibc >=2.17,<3.0.a0 + - fontconfig >=2.15.0,<3.0a0 + - fonts-conda-ecosystem + - freetype >=2.12.1,<3.0a0 + - icu >=75.1,<76.0a0 + - libexpat >=2.6.4,<3.0a0 + - libgcc >=13 + - libglib >=2.82.2,<3.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libstdcxx >=13 + - libxcb >=1.17.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - pixman >=0.44.2,<1.0a0 + - xorg-libice >=1.1.2,<2.0a0 + - xorg-libsm >=1.2.5,<2.0a0 + - xorg-libx11 >=1.8.11,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxrender >=0.9.12,<0.10.0a0 + license: LGPL-2.1-only or MPL-1.1 + purls: [] + size: 978114 + timestamp: 1741554591855 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairomm-1.16.2-ha770c72_1.conda + sha256: e7a4de2233f7a7734f8430dce4d141a1b66001b45df054ef4edb91a39b22b587 + md5: 20ace0e791efbf4cfd80b59a36456047 + depends: + - cairomm-1.16 1.16.2.* + license: LGPL-2.1-or-later and MPL-1.1 + purls: [] + size: 14619 + timestamp: 1679413416953 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cairomm-1.16-1.16.2-h7e731d7_1.conda + sha256: 62a38a358cdc9b519385a314551650dbbc5157f430356db1dd0f9d8e3cb67c8b + md5: ad95aed5f5511535801dc4d18c98e5ed + depends: + - cairo >=1.16.0,<2.0a0 + - freetype >=2.12.1,<3.0a0 + - libgcc-ng >=12 + - libglib >=2.74.1,<3.0a0 + - libpng >=1.6.39,<1.7.0a0 + - libstdcxx-ng >=12 + - libzlib >=1.2.13,<2.0.0a0 + - sigcpp-3.0 >=3.4.0 + constrains: + - cairomm 1.16.2 + license: LGPL-2.1-or-later and MPL-1.1 + purls: [] + size: 119772 + timestamp: 1679413411441 +- pypi: https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl + name: certifi + version: 2025.8.3 + sha256: f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5 + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-1.17.1-py313hf01b4d8_1.conda + sha256: 2c2d68ef3480c22e0d5837b9314579b4a8484ccfed264b8b7d5da70f695afdd9 + md5: c4a0f01c46bc155d205694bec57bd709 + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=14 + - pycparser + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: MIT + license_family: MIT + purls: + - pkg:pypi/cffi?source=hash-mapping + size: 297231 + timestamp: 1756808418076 +- pypi: https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl + name: charset-normalizer + version: 3.4.3 + sha256: 416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/f9/a1/2945dc1a688d988d4d6d33dea337ba925356350d73d796616e9f65afb30e/clingo-5.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: clingo + version: 5.8.0 + sha256: 967583dff5218adb4ed2cda56a53ec06eb518b52ece961bcf4bb84320e7334f5 + requires_dist: + - cffi + requires_python: '>=3.6' +- pypi: https://files.pythonhosted.org/packages/5c/73/d9c768a50545e3266e1452383bf84605be1ed33a4c17be201f7a606772c4/compspec-0.1.14-py3-none-any.whl + name: compspec + version: 0.1.14 + sha256: 7cdd9ad79d3a3835897a1eb2d28863129d7b2a02b291d7dce7ea4472eb8998ff + requires_dist: + - clingo + - pyaml + - jsonschema + - requests + - argparse-dataclass + - clingo ; extra == 'all' + - pyaml ; extra == 'all' + - jsonschema ; extra == 'all' + - requests ; extra == 'all' + - argparse-dataclass ; extra == 'all' + - pytest>=4.6.2 ; extra == 'all' +- pypi: https://files.pythonhosted.org/packages/ee/a7/d2dc765e71dbcc73e01addb1b0d1640a22c29840b3c89ebcc87b3eb3ba61/compspec_modules-0.0.12-py3-none-any.whl + name: compspec-modules + version: 0.0.12 + sha256: fdd3ded3d0e083f6fe48906722c34fea1acb4616d525d9ed43b3ad47a902cbf8 + requires_dist: + - compspec>=0.1.0 + - compspec>=0.1.0 ; extra == 'all' + - pytest>=4.6.2 ; extra == 'all' +- pypi: https://files.pythonhosted.org/packages/83/ff/c590bcd6bfde3c8c3d4521555ae3ff78bf517a5729d8d9150c7900dcfbee/compspec_spack-0.0.12-py3-none-any.whl + name: compspec-spack + version: 0.0.12 + sha256: 396e5263d41c02c51180a5eab80c8e4310c9e65ad9e536d9b3ea8b4395d6c7e3 + requires_dist: + - compspec>=0.1.0 + - compspec>=0.1.0 ; extra == 'all' + - pytest>=4.6.2 ; extra == 'all' +- conda: https://conda.anaconda.org/conda-forge/linux-64/contourpy-1.3.3-py313h7037e92_2.conda + sha256: 5c31b1113f9e5a21bb6c2434795e10c8ee52e82dbc533fa4ec3041b5a28ea7fa + md5: 6c8b4c12099023fcd85e520af74fd755 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.25 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/contourpy?source=hash-mapping + size: 296706 + timestamp: 1756544800085 +- conda: https://conda.anaconda.org/conda-forge/noarch/cycler-0.12.1-pyhd8ed1ab_1.conda + sha256: 9827efa891e507a91a8a2acf64e210d2aff394e1cde432ad08e1f8c66b12293c + md5: 44600c4667a319d67dbe0681fc0bc833 + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/cycler?source=hash-mapping + size: 13399 + timestamp: 1733332563512 +- conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.16.2-h3c4dab8_0.conda + sha256: 3b988146a50e165f0fa4e839545c679af88e4782ec284cc7b6d07dd226d6a068 + md5: 679616eb5ad4e521c83da4650860aba7 + depends: + - libstdcxx >=13 + - libgcc >=13 + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libexpat >=2.7.0,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - libglib >=2.84.2,<3.0a0 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 437860 + timestamp: 1747855126005 +- conda: https://conda.anaconda.org/conda-forge/noarch/decorator-5.2.1-pyhd8ed1ab_0.conda + sha256: c17c6b9937c08ad63cb20a26f403a3234088e57d4455600974a0ce865cb14017 + md5: 9ce473d1d1be1cc3810856a48b3fab32 + depends: + - python >=3.9 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/decorator?source=hash-mapping + size: 14129 + timestamp: 1740385067843 +- conda: https://conda.anaconda.org/conda-forge/linux-64/epoxy-1.5.10-h166bdaf_1.tar.bz2 + sha256: 1e58ee2ed0f4699be202f23d49b9644b499836230da7dd5b2f63e6766acff89e + md5: a089d06164afd2d511347d3f87214e0b + depends: + - libgcc-ng >=10.3.0 + license: MIT + license_family: MIT + purls: [] + size: 1440699 + timestamp: 1648505042260 +- conda: https://conda.anaconda.org/conda-forge/noarch/exceptiongroup-1.3.0-pyhd8ed1ab_0.conda + sha256: ce61f4f99401a4bd455b89909153b40b9c823276aefcbb06f2044618696009ca + md5: 72e42d28960d875c7654614f8b50939a + depends: + - python >=3.9 + - typing_extensions >=4.6.0 + license: MIT and PSF-2.0 + purls: + - pkg:pypi/exceptiongroup?source=hash-mapping + size: 21284 + timestamp: 1746947398083 +- conda: https://conda.anaconda.org/conda-forge/noarch/executing-2.2.1-pyhd8ed1ab_0.conda + sha256: 210c8165a58fdbf16e626aac93cc4c14dbd551a01d1516be5ecad795d2422cad + md5: ff9efb7f7469aed3c4a8106ffa29593c + depends: + - python >=3.10 + license: MIT + license_family: MIT + purls: + - pkg:pypi/executing?source=compressed-mapping + size: 30753 + timestamp: 1756729456476 +- conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.7.1-hecca717_0.conda + sha256: e981cf62a722f0eb4631ac7b786c288c03883fbc241fa98a276308fb69cb2c59 + md5: 6033d8c2bb9b460929d00ba54154614c + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat 2.7.1 hecca717_0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 140948 + timestamp: 1752719584725 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 + sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b + md5: 0c96522c6bdaed4b1566d11387caaf45 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 397370 + timestamp: 1566932522327 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 + sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c + md5: 34893075a5c9e55cdafac56607368fc6 + license: OFL-1.1 + license_family: Other + purls: [] + size: 96530 + timestamp: 1620479909603 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 + sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 + md5: 4d59c254e01d9cde7957100457e2d5fb + license: OFL-1.1 + license_family: Other + purls: [] + size: 700814 + timestamp: 1620479612257 +- conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda + sha256: 2821ec1dc454bd8b9a31d0ed22a7ce22422c0aef163c59f49dfdf915d0f0ca14 + md5: 49023d73832ef61042f6a237cb2687e7 + license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 + license_family: Other + purls: [] + size: 1620504 + timestamp: 1727511233259 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.15.0-h7e30c49_1.conda + sha256: 7093aa19d6df5ccb6ca50329ef8510c6acb6b0d8001191909397368b65b02113 + md5: 8f5b0b297b59e1ac160ad4beec99dbee + depends: + - __glibc >=2.17,<3.0.a0 + - freetype >=2.12.1,<3.0a0 + - libexpat >=2.6.3,<3.0a0 + - libgcc >=13 + - libuuid >=2.38.1,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 265599 + timestamp: 1730283881107 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 + sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61 + md5: fee5683a3f04bd15cbd8318b096a27ab + depends: + - fonts-conda-forge + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 3667 + timestamp: 1566974674465 +- conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 + sha256: 53f23a3319466053818540bcdf2091f253cbdbab1e0e9ae7b9e509dcaa2a5e38 + md5: f766549260d6815b0c52253f1fb1bb29 + depends: + - font-ttf-dejavu-sans-mono + - font-ttf-inconsolata + - font-ttf-source-code-pro + - font-ttf-ubuntu + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 4102 + timestamp: 1566932280397 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fonttools-4.60.0-py313h3dea7bd_0.conda + sha256: d9d440d04da5099bd706de6a75cbf6c711fb6397bcdf74e9737e681ad7cf8d6f + md5: bd879ff0e94312fae2bca58bd53b8c3e + depends: + - __glibc >=2.17,<3.0.a0 + - brotli + - libgcc >=14 + - munkres + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: MIT + license_family: MIT + purls: + - pkg:pypi/fonttools?source=hash-mapping + size: 2939481 + timestamp: 1758132715123 +- pypi: https://files.pythonhosted.org/packages/4c/8d/6850fcc11474c358fa55cebff8c1f4e8eb92585d5f9eae4b990968e65d64/fractale-0.0.13-py3-none-any.whl + name: fractale + version: 0.0.13 + sha256: 027075bbab15fa9b8d4711d1bb43eb76829c2cc5ce3fc95674f1e398521b74de + requires_dist: + - jsonschema + - jinja2 + - compspec + - compspec-spack + - compspec-modules + - rich + - google-generativeai ; extra == 'agent' + - jsonschema ; extra == 'all' + - jinja2 ; extra == 'all' + - compspec ; extra == 'all' + - compspec-spack ; extra == 'all' + - compspec-modules ; extra == 'all' + - rich ; extra == 'all' + - pytest>=4.6.2 ; extra == 'all' + - google-generativeai ; extra == 'all' +- conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.1-ha770c72_0.conda + sha256: bf8e4dffe46f7d25dc06f31038cacb01672c47b9f45201f065b0f4d00ab0a83e + md5: 4afc585cd97ba8a23809406cd8a9eda8 + depends: + - libfreetype 2.14.1 ha770c72_0 + - libfreetype6 2.14.1 h73754d4_0 + license: GPL-2.0-only OR FTL + purls: [] + size: 173114 + timestamp: 1757945422243 +- conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.16-hb03c661_0.conda + sha256: 858283ff33d4c033f4971bf440cebff217d5552a5222ba994c49be990dacd40d + md5: f9f81ea472684d75b9dd8d0b328cf655 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: LGPL-2.1-or-later + purls: [] + size: 61244 + timestamp: 1757438574066 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gdk-pixbuf-2.44.1-h2b0a6b4_0.conda + sha256: b827285fe001806beeddcc30953d2bd07869aeb0efe4581d56432c92c06b0c48 + md5: 2935d9c0526277bd42373cf23d49d51f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libpng >=1.6.50,<1.7.0a0 + - libtiff >=4.7.0,<4.8.0a0 + license: LGPL-2.1-or-later + license_family: LGPL + purls: [] + size: 579596 + timestamp: 1757867209855 +- conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.86.0-hf516916_0.conda + sha256: b77316bd5c8680bde4e5a7ab7013c8f0f10c1702cc6c3b0fd0fac3923a31fec3 + md5: 1a8e49615381c381659de1bc6a3bf9ec + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libglib 2.86.0 h1fed272_0 + license: LGPL-2.1-or-later + purls: [] + size: 117284 + timestamp: 1757403341964 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda + sha256: 309cf4f04fec0c31b6771a5809a1909b4b3154a2208f52351e1ada006f4c750c + md5: c94a5994ef49749880a8139cf9afcbe1 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: GPL-2.0-or-later OR LGPL-3.0-or-later + purls: [] + size: 460055 + timestamp: 1718980856608 +- conda: https://conda.anaconda.org/conda-forge/linux-64/graph-tool-2.98-py313he24b9d1_100.conda + sha256: c1529cda66ca7e3eb43773625b36d86f55f90bc9a9fda7ab0e91488caa5b395c + md5: 30fc2a8623b1ecc95f427960acd41545 + depends: + - cairomm + - cairomm-1.16 >=1.16.2 + - gdk-pixbuf + - graph-tool-base 2.98 py313h9733e6d_100 + - gtk3 + - libglib >=2.84.3,<3.0a0 + - librsvg + - matplotlib-base + - pycairo + - pygobject + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: LGPL-3.0-or-later + license_family: LGPL + purls: [] + size: 43657 + timestamp: 1755856289827 +- conda: https://conda.anaconda.org/conda-forge/linux-64/graph-tool-base-2.98-py313h9733e6d_100.conda + sha256: df6d58dc76ccdfe87ffc629e20ed026f33b0f22e8ee57dc42d62c34c81e94a6e + md5: 1e73607ae433eef6262ea390fa042633 + depends: + - __glibc >=2.17,<3.0.a0 + - _x86_64-microarch-level >=1 + - expat + - gmp >=6.3.0,<7.0a0 + - libboost >=1.86.0,<1.87.0a0 + - libboost-python >=1.86.0,<1.87.0a0 + - libexpat >=2.7.1,<3.0a0 + - libgcc >=14 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - numpy >=1.23,<3 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + - scipy >=1.0 + - sparsehash >=2.0 + - xorg-xextproto >=7.3.0,<8.0a0 + - zstandard + license: LGPL-3.0-or-later + license_family: LGPL + purls: [] + size: 61046727 + timestamp: 1755855924677 +- conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.14-hecca717_2.conda + sha256: 25ba37da5c39697a77fce2c9a15e48cf0a84f1464ad2aafbe53d8357a9f6cc8c + md5: 2cd94587f3a401ae05e03a6caf09539d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 99596 + timestamp: 1755102025473 +- conda: https://conda.anaconda.org/conda-forge/linux-64/gtk3-3.24.43-h0c6a113_5.conda + sha256: d36263cbcbce34ec463ce92bd72efa198b55d987959eab6210cc256a0e79573b + md5: 67d00e9cfe751cfe581726c5eff7c184 + depends: + - __glibc >=2.17,<3.0.a0 + - at-spi2-atk >=2.38.0,<3.0a0 + - atk-1.0 >=2.38.0 + - cairo >=1.18.4,<2.0a0 + - epoxy >=1.5.10,<1.6.0a0 + - fontconfig >=2.15.0,<3.0a0 + - fonts-conda-ecosystem + - fribidi >=1.0.10,<2.0a0 + - gdk-pixbuf >=2.42.12,<3.0a0 + - glib-tools + - harfbuzz >=11.0.0,<12.0a0 + - hicolor-icon-theme + - libcups >=2.3.3,<2.4.0a0 + - libcups >=2.3.3,<3.0a0 + - libexpat >=2.6.4,<3.0a0 + - libgcc >=13 + - libglib >=2.84.0,<3.0a0 + - liblzma >=5.6.4,<6.0a0 + - libxkbcommon >=1.8.1,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - pango >=1.56.3,<2.0a0 + - wayland >=1.23.1,<2.0a0 + - xorg-libx11 >=1.8.12,<2.0a0 + - xorg-libxcomposite >=0.4.6,<1.0a0 + - xorg-libxcursor >=1.2.3,<2.0a0 + - xorg-libxdamage >=1.1.6,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxi >=1.8.2,<2.0a0 + - xorg-libxinerama >=1.1.5,<1.2.0a0 + - xorg-libxrandr >=1.5.4,<2.0a0 + - xorg-libxrender >=0.9.12,<0.10.0a0 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 5585389 + timestamp: 1743405684985 +- conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-11.5.0-h15599e2_0.conda + sha256: 04d33cef3345ce6e3fbbfb5539ebc8a3730026ea94ce6ace1f8f8d3551fa079c + md5: 47599428437d622bfee24fbd06a2d0b4 + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - graphite2 >=1.3.14,<2.0a0 + - icu >=75.1,<76.0a0 + - libexpat >=2.7.1,<3.0a0 + - libfreetype >=2.14.0 + - libfreetype6 >=2.14.0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 2048134 + timestamp: 1757867460348 +- conda: https://conda.anaconda.org/conda-forge/linux-64/hicolor-icon-theme-0.17-ha770c72_2.tar.bz2 + sha256: 336f29ceea9594f15cc8ec4c45fdc29e10796573c697ee0d57ebb7edd7e92043 + md5: bbf6f174dcd3254e19a2f5d2295ce808 + license: GPL-2.0-or-later + license_family: GPL + purls: [] + size: 13841 + timestamp: 1605162808667 +- conda: https://conda.anaconda.org/conda-forge/linux-64/icu-75.1-he02047a_0.conda + sha256: 71e750d509f5fa3421087ba88ef9a7b9be11c53174af3aa4d06aff4c18b38e8e + md5: 8b189310083baabfb622af68fd9d3ae3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: MIT + license_family: MIT + purls: [] + size: 12129203 + timestamp: 1720853576813 +- pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl + name: idna + version: '3.10' + sha256: 946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 + requires_dist: + - ruff>=0.6.2 ; extra == 'all' + - mypy>=1.11.2 ; extra == 'all' + - pytest>=8.3.2 ; extra == 'all' + - flake8>=7.1.1 ; extra == 'all' + requires_python: '>=3.6' +- conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.5.0-pyhfa0c392_0.conda + sha256: e9ca009d3aab9d8a85f0241d6ada2c7fbc84072008e95f803fa59da3294aa863 + md5: c0916cc4b733577cd41df93884d857b0 + depends: + - __unix + - pexpect >4.3 + - decorator + - exceptiongroup + - ipython_pygments_lexers + - jedi >=0.16 + - matplotlib-inline + - pickleshare + - prompt-toolkit >=3.0.41,<3.1.0 + - pygments >=2.4.0 + - python >=3.11 + - stack_data + - traitlets >=5.13.0 + - typing_extensions >=4.6 + - python + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/ipython?source=hash-mapping + size: 630826 + timestamp: 1756474504536 +- conda: https://conda.anaconda.org/conda-forge/noarch/ipython_pygments_lexers-1.1.1-pyhd8ed1ab_0.conda + sha256: 894682a42a7d659ae12878dbcb274516a7031bbea9104e92f8e88c1f2765a104 + md5: bd80ba060603cc228d9d81c257093119 + depends: + - pygments + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/ipython-pygments-lexers?source=hash-mapping + size: 13993 + timestamp: 1737123723464 +- conda: https://conda.anaconda.org/conda-forge/noarch/jedi-0.19.2-pyhd8ed1ab_1.conda + sha256: 92c4d217e2dc68983f724aa983cca5464dcb929c566627b26a2511159667dba8 + md5: a4f4c5dc9b80bc50e0d3dc4e6e8f1bd9 + depends: + - parso >=0.8.3,<0.9.0 + - python >=3.9 + license: Apache-2.0 AND MIT + purls: + - pkg:pypi/jedi?source=hash-mapping + size: 843646 + timestamp: 1733300981994 +- pypi: https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl + name: jinja2 + version: 3.1.6 + sha256: 85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67 + requires_dist: + - markupsafe>=2.0 + - babel>=2.7 ; extra == 'i18n' + requires_python: '>=3.7' +- pypi: https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl + name: jsonschema + version: 4.25.1 + sha256: 3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63 + requires_dist: + - attrs>=22.2.0 + - jsonschema-specifications>=2023.3.6 + - referencing>=0.28.4 + - rpds-py>=0.7.1 + - fqdn ; extra == 'format' + - idna ; extra == 'format' + - isoduration ; extra == 'format' + - jsonpointer>1.13 ; extra == 'format' + - rfc3339-validator ; extra == 'format' + - rfc3987 ; extra == 'format' + - uri-template ; extra == 'format' + - webcolors>=1.11 ; extra == 'format' + - fqdn ; extra == 'format-nongpl' + - idna ; extra == 'format-nongpl' + - isoduration ; extra == 'format-nongpl' + - jsonpointer>1.13 ; extra == 'format-nongpl' + - rfc3339-validator ; extra == 'format-nongpl' + - rfc3986-validator>0.1.0 ; extra == 'format-nongpl' + - rfc3987-syntax>=1.1.0 ; extra == 'format-nongpl' + - uri-template ; extra == 'format-nongpl' + - webcolors>=24.6.0 ; extra == 'format-nongpl' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl + name: jsonschema-specifications + version: 2025.9.1 + sha256: 98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe + requires_dist: + - referencing>=0.31.0 + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda + sha256: 0960d06048a7185d3542d850986d807c6e37ca2e644342dd0c72feefcf26c2a4 + md5: b38117a3c920364aff79f870c984b4a3 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: LGPL-2.1-or-later + purls: [] + size: 134088 + timestamp: 1754905959823 +- conda: https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.9-py313hc8edb43_1.conda + sha256: 1a046c37e54239efc2768ce4a2fbaf721314cda3ef8358e85c8e544b5e4b133a + md5: 87215c60837a8494bf3453d08b404eed + depends: + - python + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/kiwisolver?source=hash-mapping + size: 77227 + timestamp: 1756467528380 +- conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.3-h659f571_0.conda + sha256: 99df692f7a8a5c27cd14b5fb1374ee55e756631b9c3d659ed3ee60830249b238 + md5: 3f43953b7d3fb3aaa1d0d0723d91e368 + depends: + - keyutils >=1.6.1,<2.0a0 + - libedit >=3.1.20191231,<3.2.0a0 + - libedit >=3.1.20191231,<4.0a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + - openssl >=3.3.1,<4.0a0 + license: MIT + license_family: MIT + purls: [] + size: 1370023 + timestamp: 1719463201255 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.17-h717163a_0.conda + sha256: d6a61830a354da022eae93fa896d0991385a875c6bba53c82263a289deda9db8 + md5: 000e85703f0fd9594c81710dd5066471 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libjpeg-turbo >=3.0.0,<4.0a0 + - libtiff >=4.7.0,<4.8.0a0 + license: MIT + license_family: MIT + purls: [] + size: 248046 + timestamp: 1739160907615 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.44-h1423503_1.conda + sha256: 1a620f27d79217c1295049ba214c2f80372062fd251b569e9873d4a953d27554 + md5: 0be7c6e070c19105f966d3758448d018 + depends: + - __glibc >=2.17,<3.0.a0 + constrains: + - binutils_impl_linux-64 2.44 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 676044 + timestamp: 1752032747103 +- conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h0aef613_1.conda + sha256: 412381a43d5ff9bbed82cd52a0bbca5b90623f62e41007c9c42d3870c60945ff + md5: 9344155d33912347b37f0ae6c410a835 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 264243 + timestamp: 1745264221534 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-36_h4a7cf45_openblas.conda + build_number: 36 + sha256: a1670eb8c9293f37a245e313bd9d72a301c79e8668a6a5d418c90335719fbaff + md5: 2a6122504dc8ea139337046d34a110cb + depends: + - libopenblas >=0.3.30,<0.3.31.0a0 + - libopenblas >=0.3.30,<1.0a0 + constrains: + - liblapacke 3.9.0 36*_openblas + - blas 2.136 openblas + - liblapack 3.9.0 36*_openblas + - mkl <2025 + - libcblas 3.9.0 36*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17421 + timestamp: 1758396490057 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.86.0-hed09d94_4.conda + sha256: 2e9778d8c3bbc6e7698fd87a1499a68ca1f02be37f6aaefa7541eb2728ffbff3 + md5: b708abf3b6a0f3cf2f833d2edf18aff0 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - icu >=75.1,<76.0a0 + - libgcc >=14 + - liblzma >=5.8.1,<6.0a0 + - libstdcxx >=14 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + constrains: + - boost-cpp <0.0a0 + license: BSL-1.0 + purls: [] + size: 2959099 + timestamp: 1756549412040 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-python-1.86.0-py313hfaae9d9_4.conda + sha256: 4a0fa2efab52a6e44b880a64463b3a61b3e2d81433477c6798bc2a8d38580aa3 + md5: e35fd4508ccf85dc853b4273677fafc9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.23,<3 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + constrains: + - py-boost <0.0a0 + - boost <0.0a0 + license: BSL-1.0 + purls: [] + size: 125333 + timestamp: 1756549805505 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hb03c661_4.conda + sha256: 2338a92d1de71f10c8cf70f7bb9775b0144a306d75c4812276749f54925612b6 + md5: 1d29d2e33fe59954af82ef54a8af3fe1 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 69333 + timestamp: 1756599354727 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hb03c661_4.conda + sha256: fcec0d26f67741b122f0d5eff32f0393d7ebd3ee6bb866ae2f17f3425a850936 + md5: 5cb5a1c9a94a78f5b23684bcb845338d + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.1.0 hb03c661_4 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 33406 + timestamp: 1756599364386 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hb03c661_4.conda + sha256: d42c7f0afce21d5279a0d54ee9e64a2279d35a07a90e0c9545caae57d6d7dc57 + md5: 2e55011fa483edb8bfe3fd92e860cd79 + depends: + - __glibc >=2.17,<3.0.a0 + - libbrotlicommon 1.1.0 hb03c661_4 + - libgcc >=14 + license: MIT + license_family: MIT + purls: [] + size: 289680 + timestamp: 1756599375485 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-36_h0358290_openblas.conda + build_number: 36 + sha256: 45110023d1661062288168c6ee01510bcb472ba2f5184492acdcdd3d1af9b58d + md5: 13a3fe5f9812ac8c5710ef8c03105121 + depends: + - libblas 3.9.0 36_h4a7cf45_openblas + constrains: + - liblapacke 3.9.0 36*_openblas + - blas 2.136 openblas + - liblapack 3.9.0 36*_openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17401 + timestamp: 1758396499759 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-hb8b1518_5.conda + sha256: cb83980c57e311783ee831832eb2c20ecb41e7dee6e86e8b70b8cef0e43eab55 + md5: d4a250da4737ee127fb1fa6452a9002e + depends: + - __glibc >=2.17,<3.0.a0 + - krb5 >=1.21.3,<1.22.0a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 4523621 + timestamp: 1749905341688 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.24-h86f0d12_0.conda + sha256: 8420748ea1cc5f18ecc5068b4f24c7a023cc9b20971c99c824ba10641fb95ddf + md5: 64f0c503da58ec25ebd359e4d990afa8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 72573 + timestamp: 1747040452262 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda + sha256: d789471216e7aba3c184cd054ed61ce3f6dac6f87a50ec69291b9297f8c18724 + md5: c277e0a4d549b03ac1e9d6cbbe3d017b + depends: + - ncurses + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 134676 + timestamp: 1738479519902 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.1-hecca717_0.conda + sha256: da2080da8f0288b95dd86765c801c6e166c4619b910b11f9a8446fb852438dc2 + md5: 4211416ecba1866fab0c6470986c22d6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - expat 2.7.1.* + license: MIT + license_family: MIT + purls: [] + size: 74811 + timestamp: 1752719572741 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.6-h2dba641_1.conda + sha256: 764432d32db45466e87f10621db5b74363a9f847d2b8b1f9743746cd160f06ab + md5: ede4673863426c0883c0063d853bbd85 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 57433 + timestamp: 1743434498161 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.1-ha770c72_0.conda + sha256: 4641d37faeb97cf8a121efafd6afd040904d4bca8c46798122f417c31d5dfbec + md5: f4084e4e6577797150f9b04a4560ceb0 + depends: + - libfreetype6 >=2.14.1 + license: GPL-2.0-only OR FTL + purls: [] + size: 7664 + timestamp: 1757945417134 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.1-h73754d4_0.conda + sha256: 4a7af818a3179fafb6c91111752954e29d3a2a950259c14a2fc7ba40a8b03652 + md5: 8e7251989bca326a28f4a5ffbd74557a + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libpng >=1.6.50,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + constrains: + - freetype >=2.14.1 + license: GPL-2.0-only OR FTL + purls: [] + size: 386739 + timestamp: 1757945416744 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.1.0-h767d61c_5.conda + sha256: 0caed73aac3966bfbf5710e06c728a24c6c138605121a3dacb2e03440e8baa6a + md5: 264fbfba7fb20acf3b29cde153e345ce + depends: + - __glibc >=2.17,<3.0.a0 + - _openmp_mutex >=4.5 + constrains: + - libgomp 15.1.0 h767d61c_5 + - libgcc-ng ==15.1.0=*_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 824191 + timestamp: 1757042543820 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.1.0-h69a702a_5.conda + sha256: f54bb9c3be12b24be327f4c1afccc2969712e0b091cdfbd1d763fb3e61cda03f + md5: 069afdf8ea72504e48d23ae1171d951c + depends: + - libgcc 15.1.0 h767d61c_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 29187 + timestamp: 1757042549554 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.1.0-h69a702a_5.conda + sha256: 4c1a526198d0d62441549fdfd668cc8e18e77609da1e545bdcc771dd8dc6a990 + md5: 0c91408b3dec0b97e8a3c694845bd63b + depends: + - libgfortran5 15.1.0 hcea5267_5 + constrains: + - libgfortran-ng ==15.1.0=*_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 29169 + timestamp: 1757042575979 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.1.0-hcea5267_5.conda + sha256: 9d06adc6d8e8187ddc1cad87525c690bc8202d8cb06c13b76ab2fc80a35ed565 + md5: fbd4008644add05032b6764807ee2cba + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=15.1.0 + constrains: + - libgfortran 15.1.0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 1564589 + timestamp: 1757042559498 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgirepository-1.84.0-h61e2d6e_3.conda + sha256: cb3d4179653fc3e5c88cdd0febdc4d1cd2c68ec550d236c7ba2a54570965b402 + md5: c38aca76bd38f6d7170d72e6a5d33d47 + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=14 + - libglib >=2.86.0,<3.0a0 + license: LGPL-2.0-or-later + license_family: LGPL + purls: [] + size: 308651 + timestamp: 1757424099196 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.0-h1fed272_0.conda + sha256: 33336bd55981be938f4823db74291e1323454491623de0be61ecbe6cf3a4619c + md5: b8e4c93f4ab70c3b6f6499299627dbdc + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - pcre2 >=10.46,<10.47.0a0 + constrains: + - glib 2.86.0 *_0 + license: LGPL-2.1-or-later + purls: [] + size: 3978602 + timestamp: 1757403291664 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.1.0-h767d61c_5.conda + sha256: 125051d51a8c04694d0830f6343af78b556dd88cc249dfec5a97703ebfb1832d + md5: dcd5ff1940cd38f6df777cac86819d60 + depends: + - __glibc >=2.17,<3.0.a0 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 447215 + timestamp: 1757042483384 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda + sha256: c467851a7312765447155e071752d7bf9bf44d610a5687e32706f480aad2833f + md5: 915f5995e94f60e9a4826e0b0920ee88 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: LGPL-2.1-only + purls: [] + size: 790176 + timestamp: 1754908768807 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.0-hb9d3cd8_0.conda + sha256: 98b399287e27768bf79d48faba8a99a2289748c65cd342ca21033fab1860d4a4 + md5: 9fa334557db9f63da6c9285fd2a48638 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - jpeg <0.0.0a + license: IJG AND BSD-3-Clause AND Zlib + purls: [] + size: 628947 + timestamp: 1745268527144 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-36_h47877c9_openblas.conda + build_number: 36 + sha256: 1bbd142b34dfc8cb55e1e37c00e78ebba909542ac1054d22fc54843a94797337 + md5: 55daaac7ecf8ebd169cdbe34dc79549e + depends: + - libblas 3.9.0 36_h4a7cf45_openblas + constrains: + - liblapacke 3.9.0 36*_openblas + - libcblas 3.9.0 36*_openblas + - blas 2.136 openblas + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 17409 + timestamp: 1758396509549 +- conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.1-hb9d3cd8_2.conda + sha256: f2591c0069447bbe28d4d696b7fcb0c5bd0b4ac582769b89addbcf26fb3430d8 + md5: 1a580f7796c7bf6393fddb8bbbde58dc + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - xz 5.8.1.* + license: 0BSD + purls: [] + size: 112894 + timestamp: 1749230047870 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb9d3cd8_0.conda + sha256: 3aa92d4074d4063f2a162cd8ecb45dccac93e543e565c01a787e16a43501f7ee + md5: c7e925f37e3b40d893459e625f6a53f1 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 91183 + timestamp: 1748393666725 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_2.conda + sha256: 1b51d1f96e751dc945cc06f79caa91833b0c3326efe24e9b506bd64ef49fc9b0 + md5: dfc5aae7b043d9f56ba99514d5e60625 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + constrains: + - openblas >=0.3.30,<0.3.31.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 5938936 + timestamp: 1755474342204 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.50-h421ea60_1.conda + sha256: e75a2723000ce3a4b9fd9b9b9ce77553556c93e475a4657db6ed01abc02ea347 + md5: 7af8e91b0deb5f8e25d1a595dea79614 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - libzlib >=1.3.1,<2.0a0 + license: zlib-acknowledgement + purls: [] + size: 317390 + timestamp: 1753879899951 +- conda: https://conda.anaconda.org/conda-forge/linux-64/librsvg-2.58.4-he92a37e_3.conda + sha256: a45ef03e6e700cc6ac6c375e27904531cf8ade27eb3857e080537ff283fb0507 + md5: d27665b20bc4d074b86e628b3ba5ab8b + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - freetype >=2.13.3,<3.0a0 + - gdk-pixbuf >=2.42.12,<3.0a0 + - harfbuzz >=11.0.0,<12.0a0 + - libgcc >=13 + - libglib >=2.84.0,<3.0a0 + - libpng >=1.6.47,<1.7.0a0 + - libxml2 >=2.13.7,<2.14.0a0 + - pango >=1.56.3,<2.0a0 + constrains: + - __glibc >=2.17 + license: LGPL-2.1-or-later + purls: [] + size: 6543651 + timestamp: 1743368725313 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.50.4-h0c1763c_0.conda + sha256: 6d9c32fc369af5a84875725f7ddfbfc2ace795c28f246dc70055a79f9b2003da + md5: 0b367fad34931cb79e0d6b7e5c06bb1c + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: blessing + purls: [] + size: 932581 + timestamp: 1753948484112 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.1.0-h8f9b012_5.conda + sha256: 0f5f61cab229b6043541c13538d75ce11bd96fb2db76f94ecf81997b1fde6408 + md5: 4e02a49aaa9d5190cb630fa43528fbe6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc 15.1.0 h767d61c_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 3896432 + timestamp: 1757042571458 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.1.0-h4852527_5.conda + sha256: 7b8cabbf0ab4fe3581ca28fe8ca319f964078578a51dd2ca3f703c1d21ba23ff + md5: 8bba50c7f4679f08c861b597ad2bda6b + depends: + - libstdcxx 15.1.0 h8f9b012_5 + license: GPL-3.0-only WITH GCC-exception-3.1 + license_family: GPL + purls: [] + size: 29233 + timestamp: 1757042603319 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h8261f1e_0.conda + sha256: ddda0d7ee67e71e904a452010c73e32da416806f5cb9145fb62c322f97e717fb + md5: 72b531694ebe4e8aa6f5745d1015c1b4 + depends: + - __glibc >=2.17,<3.0.a0 + - lerc >=4.0.0,<5.0a0 + - libdeflate >=1.24,<1.25.0a0 + - libgcc >=14 + - libjpeg-turbo >=3.1.0,<4.0a0 + - liblzma >=5.8.1,<6.0a0 + - libstdcxx >=14 + - libwebp-base >=1.6.0,<2.0a0 + - libzlib >=1.3.1,<2.0a0 + - zstd >=1.5.7,<1.6.0a0 + license: HPND + purls: [] + size: 437211 + timestamp: 1758278398952 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.1-he9a06e4_0.conda + sha256: 776e28735cee84b97e4d05dd5d67b95221a3e2c09b8b13e3d6dbe6494337d527 + md5: af930c65e9a79a3423d6d36e265cef65 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 37087 + timestamp: 1757334557450 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda + sha256: 3aed21ab28eddffdaf7f804f49be7a7d701e8f0e46c856d801270b470820a37b + md5: aea31d2e5b1091feca96fcfe945c3cf9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + constrains: + - libwebp 1.6.0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 429011 + timestamp: 1752159441324 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda + sha256: 666c0c431b23c6cec6e492840b176dde533d48b7e6fb8883f5071223433776aa + md5: 92ed62436b625154323d40d5f2f11dd7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - pthread-stubs + - xorg-libxau >=1.0.11,<2.0a0 + - xorg-libxdmcp + license: MIT + license_family: MIT + purls: [] + size: 395888 + timestamp: 1727278577118 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.11.0-he8b52b9_0.conda + sha256: 23f47e86cc1386e7f815fa9662ccedae151471862e971ea511c5c886aa723a54 + md5: 74e91c36d0eef3557915c68b6c2bef96 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libstdcxx >=14 + - libxcb >=1.17.0,<2.0a0 + - libxml2 >=2.13.8,<2.14.0a0 + - xkeyboard-config + - xorg-libxau >=1.0.12,<2.0a0 + license: MIT/X11 Derivative + license_family: MIT + purls: [] + size: 791328 + timestamp: 1754703902365 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.13.8-h04c0eec_1.conda + sha256: 03deb1ec6edfafc5aaeecadfc445ee436fecffcda11fcd97fde9b6632acb583f + md5: 10bcbd05e1c1c9d652fccb42b776a9fa + depends: + - __glibc >=2.17,<3.0.a0 + - icu >=75.1,<76.0a0 + - libgcc >=14 + - libiconv >=1.18,<2.0a0 + - liblzma >=5.8.1,<6.0a0 + - libzlib >=1.3.1,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 698448 + timestamp: 1754315344761 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda + sha256: d4bfe88d7cb447768e31650f06257995601f89076080e76df55e3112d4e47dc4 + md5: edb0dca6bc32e4f4789199455a1dbeb8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + constrains: + - zlib 1.3.1 *_2 + license: Zlib + license_family: Other + purls: [] + size: 60963 + timestamp: 1727963148474 +- pypi: https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl + name: markdown-it-py + version: 4.0.0 + sha256: 87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147 + requires_dist: + - mdurl~=0.1 + - psutil ; extra == 'benchmarking' + - pytest ; extra == 'benchmarking' + - pytest-benchmark ; extra == 'benchmarking' + - commonmark~=0.9 ; extra == 'compare' + - markdown~=3.4 ; extra == 'compare' + - mistletoe~=1.0 ; extra == 'compare' + - mistune~=3.0 ; extra == 'compare' + - panflute~=2.3 ; extra == 'compare' + - markdown-it-pyrs ; extra == 'compare' + - linkify-it-py>=1,<3 ; extra == 'linkify' + - mdit-py-plugins>=0.5.0 ; extra == 'plugins' + - gprof2dot ; extra == 'profiling' + - mdit-py-plugins>=0.5.0 ; extra == 'rtd' + - myst-parser ; extra == 'rtd' + - pyyaml ; extra == 'rtd' + - sphinx ; extra == 'rtd' + - sphinx-copybutton ; extra == 'rtd' + - sphinx-design ; extra == 'rtd' + - sphinx-book-theme~=1.0 ; extra == 'rtd' + - jupyter-sphinx ; extra == 'rtd' + - ipykernel ; extra == 'rtd' + - coverage ; extra == 'testing' + - pytest ; extra == 'testing' + - pytest-cov ; extra == 'testing' + - pytest-regressions ; extra == 'testing' + - requests ; extra == 'testing' + requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: markupsafe + version: 3.0.2 + sha256: 15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.10.6-py313h683a580_1.conda + sha256: c85c8135865a2608c52423d28c8bac064cfd95af69f3ff5c0d84e821695d868b + md5: 0483ab1c5b6956442195742a5df64196 + depends: + - __glibc >=2.17,<3.0.a0 + - contourpy >=1.0.1 + - cycler >=0.10 + - fonttools >=4.22.0 + - freetype + - kiwisolver >=1.3.1 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=14 + - libstdcxx >=14 + - numpy >=1.23 + - numpy >=1.23,<3 + - packaging >=20.0 + - pillow >=8 + - pyparsing >=2.3.1 + - python >=3.13,<3.14.0a0 + - python-dateutil >=2.7 + - python_abi 3.13.* *_cp313 + - qhull >=2020.2,<2020.3.0a0 + - tk >=8.6.13,<8.7.0a0 + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/matplotlib?source=hash-mapping + size: 8446545 + timestamp: 1756869894657 +- conda: https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.7-pyhd8ed1ab_1.conda + sha256: 69b7dc7131703d3d60da9b0faa6dd8acbf6f6c396224cf6aef3e855b8c0c41c6 + md5: af6ab708897df59bd6e7283ceab1b56b + depends: + - python >=3.9 + - traitlets + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/matplotlib-inline?source=hash-mapping + size: 14467 + timestamp: 1733417051523 +- pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl + name: mdurl + version: 0.1.2 + sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 + requires_python: '>=3.7' +- conda: https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda + sha256: d09c47c2cf456de5c09fa66d2c3c5035aa1fa228a1983a433c47b876aa16ce90 + md5: 37293a85a0f4f77bbd9cf7aaefc62609 + depends: + - python >=3.9 + license: Apache-2.0 + license_family: Apache + purls: + - pkg:pypi/munkres?source=hash-mapping + size: 15851 + timestamp: 1749895533014 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda + sha256: 3fde293232fa3fca98635e1167de6b7c7fda83caf24b9d6c91ec9eefb4f4d586 + md5: 47e340acb35de30501a76c7c799c41d7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: X11 AND BSD-3-Clause + purls: [] + size: 891641 + timestamp: 1738195959188 +- conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-2.3.3-py313hf6604e3_0.conda + sha256: 88d45c6dbedabbc8ebb19555bb3d04b5e2846ae8a7dfc2c0204b54f5f6efaef7 + md5: 3122d20dc438287e125fb5acff1df170 + depends: + - python + - libgcc >=14 + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - liblapack >=3.9.0,<4.0a0 + - libblas >=3.9.0,<4.0a0 + - python_abi 3.13.* *_cp313 + - libcblas >=3.9.0,<4.0a0 + constrains: + - numpy-base <0a0 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/numpy?source=compressed-mapping + size: 8888776 + timestamp: 1757505485589 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.3-h55fea9a_1.conda + sha256: 0b7396dacf988f0b859798711b26b6bc9c6161dca21bacfd778473da58730afa + md5: 01243c4aaf71bde0297966125aea4706 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - libpng >=1.6.50,<1.7.0a0 + - libstdcxx >=14 + - libtiff >=4.7.0,<4.8.0a0 + - libzlib >=1.3.1,<2.0a0 + license: BSD-2-Clause + license_family: BSD + purls: [] + size: 357828 + timestamp: 1754297886899 +- conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.5.3-h26f9b46_0.conda + sha256: 8c313f79fd9408f53922441fbb4e38f065e2251840f86862f05bdf613da7980f + md5: 72b3dd72e4f0b88cdacf3421313480f0 + depends: + - __glibc >=2.17,<3.0.a0 + - ca-certificates + - libgcc >=14 + license: Apache-2.0 + license_family: Apache + purls: [] + size: 3136554 + timestamp: 1758040407921 +- conda: https://conda.anaconda.org/conda-forge/noarch/packaging-25.0-pyh29332c3_1.conda + sha256: 289861ed0c13a15d7bbb408796af4de72c2fe67e2bcb0de98f4c3fce259d7991 + md5: 58335b26c38bf4a20f399384c33cbcf9 + depends: + - python >=3.8 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/packaging?source=hash-mapping + size: 62477 + timestamp: 1745345660407 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pango-1.56.4-hadf4263_0.conda + sha256: 3613774ad27e48503a3a6a9d72017087ea70f1426f6e5541dbdb59a3b626eaaf + md5: 79f71230c069a287efe3a8614069ddf1 + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - fontconfig >=2.15.0,<3.0a0 + - fonts-conda-ecosystem + - fribidi >=1.0.10,<2.0a0 + - harfbuzz >=11.0.1 + - libexpat >=2.7.0,<3.0a0 + - libfreetype >=2.13.3 + - libfreetype6 >=2.13.3 + - libgcc >=13 + - libglib >=2.84.2,<3.0a0 + - libpng >=1.6.49,<1.7.0a0 + - libzlib >=1.3.1,<2.0a0 + license: LGPL-2.1-or-later + purls: [] + size: 455420 + timestamp: 1751292466873 +- conda: https://conda.anaconda.org/conda-forge/noarch/parso-0.8.5-pyhcf101f3_0.conda + sha256: 30de7b4d15fbe53ffe052feccde31223a236dae0495bab54ab2479de30b2990f + md5: a110716cdb11cf51482ff4000dc253d7 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/parso?source=hash-mapping + size: 81562 + timestamp: 1755974222274 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.46-h1321c63_0.conda + sha256: 5c7380c8fd3ad5fc0f8039069a45586aa452cf165264bc5a437ad80397b32934 + md5: 7fa07cb0fb1b625a089ccc01218ee5b1 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 1209177 + timestamp: 1756742976157 +- conda: https://conda.anaconda.org/conda-forge/noarch/pexpect-4.9.0-pyhd8ed1ab_1.conda + sha256: 202af1de83b585d36445dc1fda94266697341994d1a3328fabde4989e1b3d07a + md5: d0d408b1f18883a944376da5cf8101ea + depends: + - ptyprocess >=0.5 + - python >=3.9 + license: ISC + purls: + - pkg:pypi/pexpect?source=hash-mapping + size: 53561 + timestamp: 1733302019362 +- conda: https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-pyhd8ed1ab_1004.conda + sha256: e2ac3d66c367dada209fc6da43e645672364b9fd5f9d28b9f016e24b81af475b + md5: 11a9d1d09a3615fc07c3faf79bc0b943 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pickleshare?source=hash-mapping + size: 11748 + timestamp: 1733327448200 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-11.3.0-py313ha492abd_3.conda + sha256: b5d03d663d73c682fb88b4f71b9431a79362eca4a6201650a44f1ca9d467a7cf + md5: 3354141a95eee5d29000147578dbc13f + depends: + - python + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - openjpeg >=2.5.3,<3.0a0 + - libwebp-base >=1.6.0,<2.0a0 + - tk >=8.6.13,<8.7.0a0 + - libtiff >=4.7.0,<4.8.0a0 + - libxcb >=1.17.0,<2.0a0 + - libfreetype >=2.14.1 + - libfreetype6 >=2.14.1 + - libzlib >=1.3.1,<2.0a0 + - libjpeg-turbo >=3.1.0,<4.0a0 + - python_abi 3.13.* *_cp313 + - lcms2 >=2.17,<3.0a0 + license: HPND + purls: + - pkg:pypi/pillow?source=compressed-mapping + size: 1040551 + timestamp: 1758208668856 +- conda: https://conda.anaconda.org/conda-forge/noarch/pip-25.2-pyh145f28c_0.conda + sha256: 20fe420bb29c7e655988fd0b654888e6d7755c1d380f82ca2f1bd2493b95d650 + md5: e7ab34d5a93e0819b62563c78635d937 + depends: + - python >=3.13.0a0 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pip?source=hash-mapping + size: 1179951 + timestamp: 1753925011027 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda + sha256: 43d37bc9ca3b257c5dd7bf76a8426addbdec381f6786ff441dc90b1a49143b6a + md5: c01af13bdc553d1a8fbfff6e8db075f0 + depends: + - libgcc >=14 + - libstdcxx >=14 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + license: MIT + license_family: MIT + purls: [] + size: 450960 + timestamp: 1754665235234 +- conda: https://conda.anaconda.org/conda-forge/noarch/ply-3.11-pyhd8ed1ab_3.conda + sha256: bae453e5cecf19cab23c2e8929c6e30f4866d996a8058be16c797ed4b935461f + md5: fd5062942bfa1b0bd5e0d2a4397b099e + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/ply?source=hash-mapping + size: 49052 + timestamp: 1733239818090 +- conda: https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.52-pyha770c72_0.conda + sha256: 4817651a276016f3838957bfdf963386438c70761e9faec7749d411635979bae + md5: edb16f14d920fb3faf17f5ce582942d6 + depends: + - python >=3.10 + - wcwidth + constrains: + - prompt_toolkit 3.0.52 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/prompt-toolkit?source=hash-mapping + size: 273927 + timestamp: 1756321848365 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda + sha256: 9c88f8c64590e9567c6c80823f0328e58d3b1efb0e1c539c0315ceca764e0973 + md5: b3c17d95b5a10c6e64a21fa17573e70e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 8252 + timestamp: 1726802366959 +- conda: https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd8ed1ab_1.conda + sha256: a7713dfe30faf17508ec359e0bc7e0983f5d94682492469bd462cdaae9c64d83 + md5: 7d9daffbb8d8e0af0f769dbbcd173a54 + depends: + - python >=3.9 + license: ISC + purls: + - pkg:pypi/ptyprocess?source=hash-mapping + size: 19457 + timestamp: 1733302371990 +- conda: https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.3-pyhd8ed1ab_1.conda + sha256: 71bd24600d14bb171a6321d523486f6a06f855e75e547fa0cb2a0953b02047f0 + md5: 3bfdfb8dbcdc4af1ae3f9a8eb3948f04 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/pure-eval?source=hash-mapping + size: 16668 + timestamp: 1733569518868 +- pypi: https://files.pythonhosted.org/packages/a8/ee/a878f2ad010cbccb311f947f0f2f09d38f613938ee28c34e60fceecc75a1/pyaml-25.7.0-py3-none-any.whl + name: pyaml + version: 25.7.0 + sha256: ce5d7867cc2b455efdb9b0448324ff7b9f74d99f64650f12ca570102db6b985f + requires_dist: + - pyyaml + - unidecode ; extra == 'anchors' + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/linux-64/pycairo-1.28.0-py313h3f29d12_1.conda + sha256: 34c93155060a8ed83055bba49bafdec27be49d374c1373f4adb67da6fa51d03f + md5: 8d14c033ccb4b1e9f3ced9310921cc5a + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.4,<2.0a0 + - libexpat >=2.7.1,<3.0a0 + - libgcc >=14 + - libzlib >=1.3.1,<2.0a0 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: LGPL-2.1-only OR MPL-1.1 + purls: + - pkg:pypi/pycairo?source=hash-mapping + size: 118135 + timestamp: 1756304163259 +- conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda + sha256: 79db7928d13fab2d892592223d7570f5061c192f27b9febd1a418427b719acc6 + md5: 12c566707c80111f9799308d9e265aef + depends: + - python >=3.9 + - python + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/pycparser?source=hash-mapping + size: 110100 + timestamp: 1733195786147 +- conda: https://conda.anaconda.org/conda-forge/noarch/pygments-2.19.2-pyhd8ed1ab_0.conda + sha256: 5577623b9f6685ece2697c6eb7511b4c9ac5fb607c9babc2646c811b428fd46a + md5: 6b6ece66ebcae2d5f326c77ef2c5a066 + depends: + - python >=3.9 + license: BSD-2-Clause + license_family: BSD + purls: + - pkg:pypi/pygments?source=hash-mapping + size: 889287 + timestamp: 1750615908735 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pygobject-3.50.0-py313heb4b809_1.conda + sha256: 694ab60ca07e4a639327171adda027c3ce0bd8b6e5448fa00db55cde9e6444e9 + md5: ee144a98b05f6a34d6871b91034507d2 + depends: + - __glibc >=2.17,<3.0.a0 + - cairo >=1.18.0,<2.0a0 + - libffi >=3.4,<4.0a0 + - libgcc >=13 + - libgirepository + - libglib >=2.82.1,<3.0a0 + - libiconv + - pycairo + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: LGPL-2.1-or-later + license_family: LGPL + purls: + - pkg:pypi/pygobject?source=hash-mapping + size: 351289 + timestamp: 1728635363270 +- conda: https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.2.4-pyhcf101f3_0.conda + sha256: c3260cf948da6345770d75ae559d716e557580eddcd19623676931d172346969 + md5: bf1f1292fc78307956289707e85cb1bf + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/pyparsing?source=compressed-mapping + size: 104029 + timestamp: 1757767060575 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.13.7-h2b335a9_100_cp313.conda + build_number: 100 + sha256: 16cc30a5854f31ca6c3688337d34e37a79cdc518a06375fe3482ea8e2d6b34c8 + md5: 724dcf9960e933838247971da07fe5cf + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.7.1,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=14 + - liblzma >=5.8.1,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.50.4,<4.0a0 + - libuuid >=2.38.1,<3.0a0 + - libzlib >=1.3.1,<2.0a0 + - ncurses >=6.5,<7.0a0 + - openssl >=3.5.2,<4.0a0 + - python_abi 3.13.* *_cp313 + - readline >=8.2,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + license: Python-2.0 + purls: [] + size: 33583088 + timestamp: 1756911465277 + python_site_packages_path: lib/python3.13/site-packages +- conda: https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda + sha256: d6a17ece93bbd5139e02d2bd7dbfa80bee1a4261dced63f65f679121686bf664 + md5: 5b8d21249ff20967101ffa321cab24e8 + depends: + - python >=3.9 + - six >=1.5 + - python + license: Apache-2.0 + license_family: APACHE + purls: + - pkg:pypi/python-dateutil?source=hash-mapping + size: 233310 + timestamp: 1751104122689 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.13-8_cp313.conda + build_number: 8 + sha256: 210bffe7b121e651419cb196a2a63687b087497595c9be9d20ebe97dd06060a7 + md5: 94305520c52a4aa3f6c2b1ff6008d9f8 + constrains: + - python 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 7002 + timestamp: 1752805902938 +- pypi: https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: pyyaml + version: 6.0.2 + sha256: 70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 + requires_python: '>=3.8' +- conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda + sha256: 776363493bad83308ba30bcb88c2552632581b143e8ee25b1982c8c743e73abc + md5: 353823361b1d27eb3960efb076dfcaf6 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: LicenseRef-Qhull + purls: [] + size: 552937 + timestamp: 1720813982144 +- conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8c095d6_2.conda + sha256: 2d6d0c026902561ed77cd646b5021aef2d4db22e57a5b0178dfc669231e06d2c + md5: 283b96675859b20a825f8fa30f311446 + depends: + - libgcc >=13 + - ncurses >=6.5,<7.0a0 + license: GPL-3.0-only + license_family: GPL + purls: [] + size: 282480 + timestamp: 1740379431762 +- pypi: https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl + name: referencing + version: 0.36.2 + sha256: e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0 + requires_dist: + - attrs>=22.2.0 + - rpds-py>=0.7.0 + - typing-extensions>=4.4.0 ; python_full_version < '3.13' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl + name: requests + version: 2.32.5 + sha256: 2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 + requires_dist: + - charset-normalizer>=2,<4 + - idna>=2.5,<4 + - urllib3>=1.21.1,<3 + - certifi>=2017.4.17 + - pysocks>=1.5.6,!=1.5.7 ; extra == 'socks' + - chardet>=3.0.2,<6 ; extra == 'use-chardet-on-py3' + requires_python: '>=3.9' +- pypi: https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl + name: rich + version: 14.1.0 + sha256: 536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f + requires_dist: + - ipywidgets>=7.5.1,<9 ; extra == 'jupyter' + - markdown-it-py>=2.2.0 + - pygments>=2.13.0,<3.0.0 + requires_python: '>=3.8.0' +- pypi: https://files.pythonhosted.org/packages/03/36/0a14aebbaa26fe7fab4780c76f2239e76cc95a0090bdb25e31d95c492fcd/rpds_py-0.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl + name: rpds-py + version: 0.27.1 + sha256: 2efe4eb1d01b7f5f1939f4ef30ecea6c6b3521eec451fb93191bf84b2a522418 + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/scipy-1.16.2-py313h11c21cd_0.conda + sha256: 3c26c268a4db6ff62103f6b245f650d3cd7478240335405c07e05bae85af4d36 + md5: 85a80978a04be9c290b8fe6d9bccff1c + depends: + - __glibc >=2.17,<3.0.a0 + - libblas >=3.9.0,<4.0a0 + - libcblas >=3.9.0,<4.0a0 + - libgcc >=14 + - libgfortran + - libgfortran5 >=14.3.0 + - liblapack >=3.9.0,<4.0a0 + - libstdcxx >=14 + - numpy <2.6 + - numpy >=1.23,<3 + - numpy >=1.25.2 + - python >=3.13,<3.14.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/scipy?source=compressed-mapping + size: 17034458 + timestamp: 1757682259363 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sigcpp-3.0-3.6.0-h59595ed_0.conda + sha256: 55cf8a2e52bdea0a0ab011d7c91d6ab42b65387078af64ce87ce584c85330907 + md5: 300609abbe486c5f1fcb7f3736f0fd14 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + constrains: + - libsigcpp 3.6.0 + license: LGPL-3.0-or-later + license_family: LGPL + purls: [] + size: 60454 + timestamp: 1696165750713 +- conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda + sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d + md5: 3339e3b65d58accf4ca4fb8748ab16b3 + depends: + - python >=3.9 + - python + license: MIT + license_family: MIT + purls: + - pkg:pypi/six?source=hash-mapping + size: 18455 + timestamp: 1753199211006 +- conda: https://conda.anaconda.org/conda-forge/linux-64/sparsehash-2.0.4-hcb278e6_1.conda + sha256: 8e537be22edab24a2d134f6ff0f25a38c65467e1e161f46f79e212d77328e7ba + md5: 9b831c006d0a2b16c77a34ab26b5d4b0 + depends: + - libgcc-ng >=12 + - libstdcxx-ng >=12 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 86359 + timestamp: 1680030648668 +- conda: https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.3-pyhd8ed1ab_1.conda + sha256: 570da295d421661af487f1595045760526964f41471021056e993e73089e9c41 + md5: b1b505328da7a6b246787df4b5a49fbc + depends: + - asttokens + - executing + - pure_eval + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/stack-data?source=hash-mapping + size: 26988 + timestamp: 1733569565672 +- conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_hd72426e_102.conda + sha256: a84ff687119e6d8752346d1d408d5cf360dee0badd487a472aa8ddedfdc219e1 + md5: a0116df4f4ed05c303811a837d5b39d8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libzlib >=1.3.1,<2.0a0 + license: TCL + license_family: BSD + purls: [] + size: 3285204 + timestamp: 1748387766691 +- conda: https://conda.anaconda.org/conda-forge/noarch/traitlets-5.14.3-pyhd8ed1ab_1.conda + sha256: f39a5620c6e8e9e98357507262a7869de2ae8cc07da8b7f84e517c9fd6c2b959 + md5: 019a7385be9af33791c989871317e1ed + depends: + - python >=3.9 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/traitlets?source=hash-mapping + size: 110051 + timestamp: 1733367480074 +- conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + sha256: 032271135bca55aeb156cee361c81350c6f3fb203f57d024d7e5a1fc9ef18731 + md5: 0caa1af407ecff61170c9437a808404d + depends: + - python >=3.10 + - python + license: PSF-2.0 + license_family: PSF + purls: + - pkg:pypi/typing-extensions?source=hash-mapping + size: 51692 + timestamp: 1756220668932 +- conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025b-h78e105d_0.conda + sha256: 5aaa366385d716557e365f0a4e9c3fca43ba196872abbbe3d56bb610d131e192 + md5: 4222072737ccff51314b5ece9c7d6f5a + license: LicenseRef-Public-Domain + purls: [] + size: 122968 + timestamp: 1742727099393 +- pypi: https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl + name: urllib3 + version: 2.5.0 + sha256: e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc + requires_dist: + - brotli>=1.0.9 ; platform_python_implementation == 'CPython' and extra == 'brotli' + - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'brotli' + - h2>=4,<5 ; extra == 'h2' + - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' + - zstandard>=0.18.0 ; extra == 'zstd' + requires_python: '>=3.9' +- conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.24.0-h3e06ad9_0.conda + sha256: ba673427dcd480cfa9bbc262fd04a9b1ad2ed59a159bd8f7e750d4c52282f34c + md5: 0f2ca7906bf166247d1d760c3422cb8a + depends: + - __glibc >=2.17,<3.0.a0 + - libexpat >=2.7.0,<3.0a0 + - libffi >=3.4.6,<3.5.0a0 + - libgcc >=13 + - libstdcxx >=13 + license: MIT + license_family: MIT + purls: [] + size: 330474 + timestamp: 1751817998141 +- conda: https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.13-pyhd8ed1ab_1.conda + sha256: f21e63e8f7346f9074fd00ca3b079bd3d2fa4d71f1f89d5b6934bf31446dc2a5 + md5: b68980f2495d096e71c7fd9d7ccf63e6 + depends: + - python >=3.9 + license: MIT + license_family: MIT + purls: + - pkg:pypi/wcwidth?source=hash-mapping + size: 32581 + timestamp: 1733231433877 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.45-hb9d3cd8_0.conda + sha256: a5d4af601f71805ec67403406e147c48d6bad7aaeae92b0622b7e2396842d3fe + md5: 397a013c2dc5145a70737871aaa87e98 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.12,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 392406 + timestamp: 1749375847832 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda + sha256: c12396aabb21244c212e488bbdc4abcdef0b7404b15761d9329f5a4a39113c4b + md5: fb901ff28063514abb6046c9ec2c4a45 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 58628 + timestamp: 1734227592886 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda + sha256: 277841c43a39f738927145930ff963c5ce4c4dacf66637a3d95d802a64173250 + md5: 1c74ff8c35dcadf952a16f752ca5aa49 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libuuid >=2.38.1,<3.0a0 + - xorg-libice >=1.1.2,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 27590 + timestamp: 1741896361728 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.12-h4f16b4b_0.conda + sha256: 51909270b1a6c5474ed3978628b341b4d4472cd22610e5f22b506855a5e20f67 + md5: db038ce880f100acc74dba10302b5630 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libxcb >=1.17.0,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 835896 + timestamp: 1741901112627 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb9d3cd8_0.conda + sha256: ed10c9283974d311855ae08a16dfd7e56241fac632aec3b92e3cfe73cff31038 + md5: f6ebe2cb3f82ba6c057dde5d9debe4f7 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 14780 + timestamp: 1734229004433 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcomposite-0.4.6-hb9d3cd8_2.conda + sha256: 753f73e990c33366a91fd42cc17a3d19bb9444b9ca5ff983605fa9e953baf57f + md5: d3c295b50f092ab525ffe3c2aa4b7413 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 13603 + timestamp: 1727884600744 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxcursor-1.2.3-hb9d3cd8_0.conda + sha256: 832f538ade441b1eee863c8c91af9e69b356cd3e9e1350fff4fe36cc573fc91a + md5: 2ccd714aa2242315acaf0a67faea780b + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + size: 32533 + timestamp: 1730908305254 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdamage-1.1.6-hb9d3cd8_0.conda + sha256: 43b9772fd6582bf401846642c4635c47a9b0e36ca08116b3ec3df36ab96e0ec0 + md5: b5fcc7172d22516e1f965490e65e33a4 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 13217 + timestamp: 1727891438799 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb9d3cd8_0.conda + sha256: 6b250f3e59db07c2514057944a3ea2044d6a8cdde8a47b6497c254520fade1ee + md5: 8035c64cb77ed555e3f150b7b3972480 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 19901 + timestamp: 1727794976192 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.6-hb9d3cd8_0.conda + sha256: da5dc921c017c05f38a38bd75245017463104457b63a1ce633ed41f214159c14 + md5: febbab7d15033c913d53c7a2c102309d + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 50060 + timestamp: 1727752228921 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-6.0.1-hb9d3cd8_0.conda + sha256: 2fef37e660985794617716eb915865ce157004a4d567ed35ec16514960ae9271 + md5: 4bdb303603e9821baf5fe5fdff1dc8f8 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 19575 + timestamp: 1727794961233 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda + sha256: 1a724b47d98d7880f26da40e45f01728e7638e6ec69f35a3e11f92acd05f9e7a + md5: 17dcc85db3c7886650b8908b183d6876 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxfixes >=6.0.1,<7.0a0 + license: MIT + license_family: MIT + purls: [] + size: 47179 + timestamp: 1727799254088 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxinerama-1.1.5-h5888daf_1.conda + sha256: 1b9141c027f9d84a9ee5eb642a0c19457c788182a5a73c5a9083860ac5c20a8c + md5: 5e2eb9bf77394fc2e5918beefec9f9ab + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 13891 + timestamp: 1727908521531 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrandr-1.5.4-hb9d3cd8_0.conda + sha256: ac0f037e0791a620a69980914a77cb6bb40308e26db11698029d6708f5aa8e0d + md5: 2de7f99d6581a4a7adbff607b5c278ca + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxrender >=0.9.11,<0.10.0a0 + license: MIT + license_family: MIT + purls: [] + size: 29599 + timestamp: 1727794874300 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda + sha256: 044c7b3153c224c6cedd4484dd91b389d2d7fd9c776ad0f4a34f099b3389f4a1 + md5: 96d57aba173e878a2089d5638016dc5e + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 33005 + timestamp: 1734229037766 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxtst-1.2.5-hb9d3cd8_3.conda + sha256: 752fdaac5d58ed863bbf685bb6f98092fe1a488ea8ebb7ed7b606ccfce08637a + md5: 7bbe9a0cc0df0ac5f5a8ad6d6a11af2f + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - xorg-libx11 >=1.8.10,<2.0a0 + - xorg-libxext >=1.3.6,<2.0a0 + - xorg-libxi >=1.7.10,<2.0a0 + license: MIT + license_family: MIT + purls: [] + size: 32808 + timestamp: 1727964811275 +- conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-hb9d3cd8_1004.conda + sha256: f302a3f6284ee9ad3b39e45251d7ed15167896564dc33e006077a896fd3458a6 + md5: bc4cd53a083b6720d61a1519a1900878 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + license: MIT + license_family: MIT + purls: [] + size: 30549 + timestamp: 1726846235301 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.25.0-py313h54dd161_0.conda + sha256: 9d79d176afe50361cc3fd4366bedff20852dbea1e5b03f358b55f12aca22d60d + md5: 1fe43bd1fc86e22ad3eb0edec637f8a2 + depends: + - python + - cffi >=1.11 + - zstd >=1.5.7,<1.5.8.0a0 + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + - zstd >=1.5.7,<1.6.0a0 + - python_abi 3.13.* *_cp313 + license: BSD-3-Clause + license_family: BSD + purls: + - pkg:pypi/zstandard?source=hash-mapping + size: 471152 + timestamp: 1757930114245 +- conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb8e6e7a_2.conda + sha256: a4166e3d8ff4e35932510aaff7aa90772f84b4d07e9f6f83c614cba7ceefe0eb + md5: 6432cb5d4ac0046c3ac0a8a0f95842f9 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=13 + - libstdcxx >=13 + - libzlib >=1.3.1,<2.0a0 + license: BSD-3-Clause + license_family: BSD + purls: [] + size: 567578 + timestamp: 1742433379869 diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 0000000..300e3b8 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,18 @@ +[workspace] +authors = ["vsoch "] +channels = ["conda-forge"] +name = "flux-delegate-py" +platforms = ["linux-64"] +version = "0.1.0" + +[tasks] + +[dependencies] +graph-tool = ">=2.98,<3" +python = ">=3.13.7,<3.14" +ipython = ">=9.5.0,<10" +pip = ">=25.2,<26" +ply = ">=3.11,<4" + +[pypi-dependencies] +fractale = ">=0.0.13, <0.0.14" From e1d6d53c715ae8421f77b3f59413ceb4df4deb85 Mon Sep 17 00:00:00 2001 From: vsoch Date: Sun, 21 Sep 2025 15:28:09 -0700 Subject: [PATCH 5/6] feat: add (expose) flux detect Signed-off-by: vsoch --- .devcontainer/Dockerfile | 7 +++- cmd/flux-detect.py | 87 ++++++++++++++++++++++++++++++++++++++++ cmd/flux-remote.py | 30 ++++++-------- pixi.toml | 3 ++ set-vars.sh | 2 + 5 files changed, 110 insertions(+), 19 deletions(-) create mode 100755 cmd/flux-detect.py create mode 100755 set-vars.sh diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 87695a0..640724a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -28,7 +28,12 @@ COPY pixi.toml pixi.lock /opt/pixi/ WORKDIR /opt/pixi RUN /bin/bash -c "curl -fsSL https://pixi.sh/install.sh | bash" && pixi install -ENV PYTHONPATH=/usr/lib/python3.10/site-packages +# Need to "install" fluxion +RUN git clone --depth 1 https://github.com/flux-framework/flux-sched /tmp/flux-sched +ENV PYTHONPATH=/usr/lib/python3.10/site-packages:/tmp/flux-sched/src/python + +# This should be set in the pixi environment +ENV NO_AT_BRIDGE=1 # Add the group and user that match our ids RUN groupadd -g ${USER_GID} ${USERNAME} && \ diff --git a/cmd/flux-detect.py b/cmd/flux-detect.py new file mode 100755 index 0000000..13f1894 --- /dev/null +++ b/cmd/flux-detect.py @@ -0,0 +1,87 @@ +############################################################## +# Copyright 2023 Lawrence Livermore National Security, LLC +# (c.f. AUTHORS, NOTICE.LLNS, COPYING) +# +# This file is part of the Flux resource manager framework. +# For details, see https://github.com/flux-framework. +# +# SPDX-License-Identifier: LGPL-3.0 +############################################################## + +import argparse +import logging +import os +import sys +import tempfile + +import flux +import flux.cli.submit as base +import fractale.defaults as defaults +import fractale.utils as utils +from compspec.plugin.registry import PluginRegistry +from fractale.store import FractaleStore +from fractale.subsystem import get_subsystem_solver + +registry = PluginRegistry() +registry.discover() + +LOGGER = logging.getLogger("flux-remote") + + +def open_logfile(fd): + return open(fd, "w", encoding="utf8", errors="surrogateescape") + + +class DetectCmd(base.SubmitCmd): + def main(self, args): + """ + Detect local subsystems. + + This doesn't technically need to be based on submit. + """ + store = FractaleStore(args.config_dir) + store.detect(force=args.force) + + def run_parser(self): + """ + The main remote parser is very simple. It only looks for the subcommand. + """ + parser = argparse.ArgumentParser( + prog="flux detect", + description="Detect and save local subsystem metadata.", + usage="flux detect [options...]", + ) + parser.add_argument( + "--config-dir", + dest="config_dir", + help="Fractale configuration directory to store subsystems. Defaults to ~/.fractale", + ) + parser.add_argument( + "--force", + help="Given existing metadata, force an update.", + action="store_true", + default=False, + ) + + # We need to handle this manually since it's off base for argparse + if "-h" in sys.argv or "--help" in sys.argv: + parser.print_help() + sys.exit(0) + + # This just processes our added command (expecting other subcommands eventually) + args, extra = parser.parse_known_args() + self.main(args) + + +@flux.util.CLIMain(LOGGER) +def main(): + sys.stdout = open_logfile(sys.stdout.fileno()) + sys.stderr = open_logfile(sys.stderr.fileno()) + + # This is going to be a submit parser with extra bells and whistles + detect = DetectCmd("flux detect", description="detect local subsystems") + detect.run_parser() + + +if __name__ == "__main__": + main() diff --git a/cmd/flux-remote.py b/cmd/flux-remote.py index 8ba2ab6..9f254ee 100755 --- a/cmd/flux-remote.py +++ b/cmd/flux-remote.py @@ -33,7 +33,7 @@ def open_logfile(fd): class SubmitCmd(base.SubmitCmd): - def main(self, args, remote_args): + def main(self, args, remote_args, dry_run=False): """ Add a step before main to run feasibility check. @@ -41,6 +41,8 @@ def main(self, args, remote_args): """ # Feasibility check handles args from flux remote with_delegation = self.feasibility_check(args, remote_args) + if dry_run: + sys.exit(0) # Submit the jobspec args, which may now have delegation self.submit_async_with_cc(with_delegation) @@ -57,13 +59,9 @@ def feasibility_check(self, args, remote_args): if not os.path.exists(store.root): store.detect() - # This is inefficient, but right now we write the jobspec to file - # TODO: expose a means to pass in JobSpec from string or dict (not file) - with tempfile.NamedTemporaryFile( - delete=False, suffix=".yaml", prefix="jobspec-" - ) as temp_file: - temp_file_path = temp_file.name - utils.write_yaml(jobspec.jobspec, temp_file_path) + # If we detect and none still found, there are none. + if not os.path.exists(store.root): + sys.exit("No subsystems found.") # TODO Vanessa - this is parsing the wrong format. I need to update it. # I want to make a hardened organization for this. Operations across clusters can be in in parallel @@ -77,15 +75,9 @@ def feasibility_check(self, args, remote_args): # - For Flux we finalize, add the delegation plugin URI, and we are done. # - For Kubernetes, it's easier (an API call) and this should also be done by delegation # 5. Fall through case (no remote matches) we submit as usual to local cluster instance - print("FIX THE FORMAT VANESSA YOU GOBLIN") - import IPython - - IPython.embed() solver = get_subsystem_solver(store.clusters_root, remote_args.solver) - is_satisfied = solver.satisfied(temp_file_path) + is_satisfied = solver.satisfied(jobspec.jobspec) - if os.path.exists(temp_file_path): - os.remove(temp_file_path) # If we are satisifed, we can get the result, and then add it to the JobSpec as a delegate dependency. We will # That would look like this: # args.setattr = [f'delegate.local_uri=${uri}'] @@ -124,6 +116,8 @@ def run_parser(self): dest="config_dir", help="Fractale configuration directory to store subsystems. Defaults to ~/.fractale", ) + # IMPORTANT: if you add more args here, submit will stop working, and you need + # to account for parsing them out. parser.add_argument("command", help="Subcommand to run (e.g., 'submit')") # This just processes our added command (expecting other subcommands eventually) @@ -131,13 +125,13 @@ def run_parser(self): # Now, we dispatch to the correct handler based on the command. if args.command == "submit": - self.handle_submit(remaining_argv, args) + self.handle_submit(remaining_argv, args, dry_run="--dry-run" in sys.argv) else: print( f"{args.command} is not a recognized Flux command. Try `flux remote submit`" ) - def handle_submit(self, argv, remote_args): + def handle_submit(self, argv, remote_args, dry_run=False): """ Handle the submit subcommand. @@ -155,7 +149,7 @@ def handle_submit(self, argv, remote_args): # Repopulate the initial submit args sys.argv = argv args = submit_parser.parse_args() - args.func(args, remote_args) + args.func(args, remote_args, dry_run) @flux.util.CLIMain(LOGGER) diff --git a/pixi.toml b/pixi.toml index 300e3b8..d194bd5 100644 --- a/pixi.toml +++ b/pixi.toml @@ -16,3 +16,6 @@ ply = ">=3.11,<4" [pypi-dependencies] fractale = ">=0.0.13, <0.0.14" + +[activation] +scripts = ["set_vars.sh"] diff --git a/set-vars.sh b/set-vars.sh new file mode 100755 index 0000000..09cbb94 --- /dev/null +++ b/set-vars.sh @@ -0,0 +1,2 @@ +#!/bin/bash +export NO_AT_BRIDGE=1 From 53350c7d3fd655da631c8065e89101c28c091021 Mon Sep 17 00:00:00 2001 From: vsoch Date: Mon, 22 Sep 2025 22:52:41 -0700 Subject: [PATCH 6/6] feat: support for export. This allows adding an --export flag to flux detect, which will either create a temporary context and detect (and export to zip) all local subsytems, or if given a config directory, run detect there (honoring force or not) and then export. Of course not cleaning up if it is not a temporary cluster/subsystem root. Signed-off-by: vsoch --- README.md | 24 ++++++++++++++++++++---- cmd/flux-detect.py | 23 +++++++++++++++++++++++ cmd/flux-remote.py | 12 ++++++------ 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 774370f..6ee2b69 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,28 @@ I added the local uri as an attribute because it would mean we can direct the in For integration with Fractale (and flux) we won't require the user to ask for delegation directly. We will provide a command for a remote submit: ```bash -flux remote submit --dry-run --setattr=requires.software=spack:curl curl +flux remote submit --dry-run -S=requires.software.spack.value=curl curl +flux remote submit --dry-run --solver graph -S=requires.software.spack.name=curl curl # Development variant -python cmd/flux-remote.py submit --dry-run --setattr=requires.software=spack:curl curl +python cmd/flux-remote.py submit --dry-run -S=requires.software.spack.value=curl curl +python cmd/flux-remote.py submit --dry-run --solver graph -S=requires.software.spack.name=curl curl +``` + +In the above, the user is asking for a remote submit. This means we are going to receive the request in Flux, compare to local subsystems and clusters defined by the user in their home, and then make a selection of a cluster. The selected cluster will go straight to the JobTap plugin from the `flux remote submit` command without the user needing any subsequent interaction. To support this process, we have a `flux detect` command that can detect (and generate) local subsystem metadata, and even export it. + +```bash +# Automatic detection of new clusters and subsystems +python cmd/flux-detect.py +flux detect + +# Force detection of existing +python cmd/flux-detect.py --force +flux detect --force + +# Detect and export to archive for import (detects all present) +python cmd/flux-detect.py --export +flux detect --export ``` -In the above, the user is asking for a remote submit. This means we are going to receive the request in Flux, compare to local subsystems and clusters defined by the user in their home, and then make a selection of a cluster. The selected cluster will go straight to the JobTap plugin from the `flux remote submit` command without the user needing any subsequent interaction. -What I want to work on / harden is the organization, structure, and query of the cluster and subsystem metadata. I've been forcing use of a graph but I am not convinced that is the best way. See [examples/fractale](examples/fractale) for the full example, and the [cmd](cmd) that is added to Flux as a WIP to orchestrate this. diff --git a/cmd/flux-detect.py b/cmd/flux-detect.py index 13f1894..bff5883 100755 --- a/cmd/flux-detect.py +++ b/cmd/flux-detect.py @@ -11,8 +11,10 @@ import argparse import logging import os +import shutil import sys import tempfile +from datetime import datetime import flux import flux.cli.submit as base @@ -39,9 +41,24 @@ def main(self, args): This doesn't technically need to be based on submit. """ + # If we are exporting, we are going to run detect in a non-existing directory + cleanup = False + if args.export and not args.config_dir: + args.config_dir = tempfile.mkdtemp(prefix="flux-detect-") + cleanup = True store = FractaleStore(args.config_dir) store.detect(force=args.force) + # Export locally detected subsystems + if args.export: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + archive_name = f"fractale-export-{timestamp}" + shutil.make_archive(archive_name, "zip", args.config_dir) + + # Cleanup if we created a temporary context + if cleanup and os.path.exists(args.config_dir): + shutil.rmtree(args.config_dir) + def run_parser(self): """ The main remote parser is very simple. It only looks for the subcommand. @@ -62,6 +79,12 @@ def run_parser(self): action="store_true", default=False, ) + parser.add_argument( + "--export", + default=False, + action="store_true", + help="Export to local archive for later import.", + ) # We need to handle this manually since it's off base for argparse if "-h" in sys.argv or "--help" in sys.argv: diff --git a/cmd/flux-remote.py b/cmd/flux-remote.py index 9f254ee..1496eb2 100755 --- a/cmd/flux-remote.py +++ b/cmd/flux-remote.py @@ -63,20 +63,20 @@ def feasibility_check(self, args, remote_args): if not os.path.exists(store.root): sys.exit("No subsystems found.") - # TODO Vanessa - this is parsing the wrong format. I need to update it. - # I want to make a hardened organization for this. Operations across clusters can be in in parallel - # ---- # 1. Each detected cluster needs a remote URI or credential (e.g., Kubernetes) # - TODO: we should be able to detect kubernetes cluster as ephemeral # - TODO: make compspec-kube for this use case. # 2. For feasibility, we first check cluster resources for each known cluster - # 3. We then check subsystem requests that come from requires (e.g. --setattr=requires.software=spack:curl) + # 3. We then check subsystem requests that come from requires (e.g. --setattr=requires.software=spack...) + solver = get_subsystem_solver(store.clusters_root, remote_args.solver) + + # 4. This returns batch a match object with count, clusters, etc. + match = solver.satisfied(jobspec.jobspec, return_results=True) + # 4. Based on the filtered set: # - For Flux we finalize, add the delegation plugin URI, and we are done. # - For Kubernetes, it's easier (an API call) and this should also be done by delegation # 5. Fall through case (no remote matches) we submit as usual to local cluster instance - solver = get_subsystem_solver(store.clusters_root, remote_args.solver) - is_satisfied = solver.satisfied(jobspec.jobspec) # If we are satisifed, we can get the result, and then add it to the JobSpec as a delegate dependency. We will # That would look like this: