From 85081c2ec87ee91039c71c5974792f523ec8ce61 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 02:18:09 -0800 Subject: [PATCH 01/54] Use all available Sherlock partitions --- doc/workflows.rst | 10 +++++----- runscripts/nextflow/config.template | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/workflows.rst b/doc/workflows.rst index a614dd58c..4db8c1eb3 100644 --- a/doc/workflows.rst +++ b/doc/workflows.rst @@ -619,18 +619,18 @@ lines from ``runscripts/nextflow/config.template`` and always set ``build_runtime_image`` to false in your config JSONs (see :ref:`sherlock-config`):: process.container = 'IMAGE_NAME' + ... apptainer.enabled = true If your HPC cluster also uses the SLURM scheduler, -you can use vEcoli on that cluster by changing the ``process.queue`` option in -``runscripts/nextflow/config.template`` and all strings of the format -``--partition=QUEUE`` in :py:mod:`runscripts.workflow` to the right queue for your -cluster. +you can use vEcoli on that cluster by changing the ``queue`` option in +``runscripts/nextflow/config.template`` and ``--partition=QUEUE`` in +:py:mod:`runscripts.workflow` to the right queue for your cluster. If your HPC cluster uses a different scheduler, refer to the Nextflow `executor documentation `_ for more information on configuring the right executor, starting with -``process.executor`` in ``runscripts/nextflow/config.template``. +``executor`` in ``runscripts/nextflow/config.template``. .. _progress: diff --git a/runscripts/nextflow/config.template b/runscripts/nextflow/config.template index d84c3fa79..14c084aa3 100644 --- a/runscripts/nextflow/config.template +++ b/runscripts/nextflow/config.template @@ -81,7 +81,7 @@ profiles { memory = 2.GB } container = params.container_image - queue = 'mcovert,owners' + queue = 'mcovert,owners,dev,normal' executor = 'slurm' // Single core sims are slightly slower but can have shorter // queue times and is less damaging to future job priority From 92cfb5f28721ede88c22db4e8d45d180e7c0acd7 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 10:50:40 -0800 Subject: [PATCH 02/54] Try different lineage seed for rich media Jenkins test --- runscripts/jenkins/configs/ecoli-with-aa.json | 1 + 1 file changed, 1 insertion(+) diff --git a/runscripts/jenkins/configs/ecoli-with-aa.json b/runscripts/jenkins/configs/ecoli-with-aa.json index de7abd429..593d97e79 100644 --- a/runscripts/jenkins/configs/ecoli-with-aa.json +++ b/runscripts/jenkins/configs/ecoli-with-aa.json @@ -4,6 +4,7 @@ "generations": 8, "fail_at_total_time": true, "sim_data_path": null, + "lineage_seed": 100, "emitter": "parquet", "emitter_arg": { "out_dir": "/scratch/groups/mcovert/vecoli" From 5cc766dcf961a62714f38859a3669c86a2504c71 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 11:08:16 -0800 Subject: [PATCH 03/54] Go back to running ParCa as separate SLURM job --- runscripts/jenkins/configs/ecoli-anaerobic.json | 3 +++ runscripts/jenkins/configs/ecoli-glucose-minimal.json | 3 +++ runscripts/jenkins/configs/ecoli-new-gene-gfp.json | 3 ++- .../jenkins/configs/ecoli-no-growth-rate-control.json | 3 +++ runscripts/jenkins/configs/ecoli-no-operons.json | 3 ++- .../jenkins/configs/ecoli-superhelical-density.json | 3 +++ runscripts/jenkins/configs/ecoli-with-aa.json | 3 +++ runscripts/nextflow/config.template | 8 +++----- 8 files changed, 22 insertions(+), 7 deletions(-) diff --git a/runscripts/jenkins/configs/ecoli-anaerobic.json b/runscripts/jenkins/configs/ecoli-anaerobic.json index b6d804670..50b5de190 100644 --- a/runscripts/jenkins/configs/ecoli-anaerobic.json +++ b/runscripts/jenkins/configs/ecoli-anaerobic.json @@ -29,5 +29,8 @@ "runtime_image_name": "runtime-image", "build_runtime_image": true, "jenkins": true + }, + "parca_options": { + "cpus": 4 } } diff --git a/runscripts/jenkins/configs/ecoli-glucose-minimal.json b/runscripts/jenkins/configs/ecoli-glucose-minimal.json index d0eb9cf70..f871d903b 100644 --- a/runscripts/jenkins/configs/ecoli-glucose-minimal.json +++ b/runscripts/jenkins/configs/ecoli-glucose-minimal.json @@ -15,5 +15,8 @@ "runtime_image_name": "runtime-image", "build_runtime_image": true, "jenkins": true + }, + "parca_options": { + "cpus": 4 } } diff --git a/runscripts/jenkins/configs/ecoli-new-gene-gfp.json b/runscripts/jenkins/configs/ecoli-new-gene-gfp.json index 512fb2331..c63dab09d 100644 --- a/runscripts/jenkins/configs/ecoli-new-gene-gfp.json +++ b/runscripts/jenkins/configs/ecoli-new-gene-gfp.json @@ -9,7 +9,8 @@ "out_dir": "/scratch/groups/mcovert/vecoli" }, "parca_options": { - "new_genes": "gfp" + "new_genes": "gfp", + "cpus": 4 }, "analysis_options": { "single": {"mass_fraction_summary": {}} diff --git a/runscripts/jenkins/configs/ecoli-no-growth-rate-control.json b/runscripts/jenkins/configs/ecoli-no-growth-rate-control.json index cbb767432..eac43d634 100644 --- a/runscripts/jenkins/configs/ecoli-no-growth-rate-control.json +++ b/runscripts/jenkins/configs/ecoli-no-growth-rate-control.json @@ -22,5 +22,8 @@ "runtime_image_name": "runtime-image", "build_runtime_image": true, "jenkins": true + }, + "parca_options": { + "cpus": 4 } } diff --git a/runscripts/jenkins/configs/ecoli-no-operons.json b/runscripts/jenkins/configs/ecoli-no-operons.json index dfbda0562..bf5d497f6 100644 --- a/runscripts/jenkins/configs/ecoli-no-operons.json +++ b/runscripts/jenkins/configs/ecoli-no-operons.json @@ -9,7 +9,8 @@ "out_dir": "/scratch/groups/mcovert/vecoli" }, "parca_options": { - "operons": false + "operons": false, + "cpus": 4 }, "analysis_options": { "single": {"mass_fraction_summary": {}} diff --git a/runscripts/jenkins/configs/ecoli-superhelical-density.json b/runscripts/jenkins/configs/ecoli-superhelical-density.json index ad1be06dc..57f459d82 100644 --- a/runscripts/jenkins/configs/ecoli-superhelical-density.json +++ b/runscripts/jenkins/configs/ecoli-superhelical-density.json @@ -15,5 +15,8 @@ "sherlock": { "runtime_image_name": "runtime-image", "jenkins": true + }, + "parca_options": { + "cpus": 4 } } diff --git a/runscripts/jenkins/configs/ecoli-with-aa.json b/runscripts/jenkins/configs/ecoli-with-aa.json index 593d97e79..936843796 100644 --- a/runscripts/jenkins/configs/ecoli-with-aa.json +++ b/runscripts/jenkins/configs/ecoli-with-aa.json @@ -20,5 +20,8 @@ "runtime_image_name": "runtime-image", "build_runtime_image": true, "jenkins": true + }, + "parca_options": { + "cpus": 4 } } diff --git a/runscripts/nextflow/config.template b/runscripts/nextflow/config.template index 14c084aa3..72581b7ef 100644 --- a/runscripts/nextflow/config.template +++ b/runscripts/nextflow/config.template @@ -69,16 +69,14 @@ profiles { } sherlock { process { - // Run analyses, create variants, and run ParCa locally with + // Run analyses and create variants locally with // the job used to launch workflow to avoid long queue times withLabel: short { executor = 'local' } - // ParCa 4 CPUs in ~15 min, 1 CPU in ~30 min, not too bad withLabel: parca { - executor = 'local' - cpus = 1 - memory = 2.GB + cpus = params.parca_cpus + memory = params.parca_cpus * 2.GB } container = params.container_image queue = 'mcovert,owners,dev,normal' From 5152889ae16afd2e8536eec2b17f12fb34ffc17f Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 14:59:33 -0800 Subject: [PATCH 04/54] Honor lineage seed setting --- runscripts/workflow.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/runscripts/workflow.py b/runscripts/workflow.py index f95217dc7..18287843a 100644 --- a/runscripts/workflow.py +++ b/runscripts/workflow.py @@ -238,10 +238,14 @@ def generate_code(config): seed = config.get("seed", 0) generations = config.get("generations", 0) if generations: + lineage_seed = config.get("lineage_seed", 0) n_init_sims = config.get("n_init_sims") + print( + f"Specified generations: initial lineage seed {lineage_seed}, {n_init_sims} initial sims" + ) single_daughters = config.get("single_daughters", True) sim_imports, sim_workflow = generate_lineage( - seed, + lineage_seed, n_init_sims, generations, single_daughters, From a1662b0492c0cf76ad9422df7e238e2a5154faa6 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 20:21:09 -0800 Subject: [PATCH 05/54] Automatic unique index generation --- doc/stores.rst | 8 +- .../analysis/antibiotics_colony/validation.py | 4 +- ecoli/experiments/ecoli_master_sim.py | 15 -- ecoli/library/initial_conditions.py | 14 +- ecoli/library/json_state.py | 9 +- ecoli/library/schema.py | 128 ++++++++++++++---- ecoli/processes/cell_division.py | 1 + ecoli/processes/chemotaxis/flagella_motor.py | 8 +- ecoli/processes/chromosome_replication.py | 21 +-- ecoli/processes/chromosome_structure.py | 9 -- ecoli/processes/polypeptide_initiation.py | 8 -- ecoli/processes/rna_degradation.py | 1 + ecoli/processes/transcript_elongation.py | 1 + ecoli/processes/transcript_initiation.py | 11 +- 14 files changed, 139 insertions(+), 99 deletions(-) diff --git a/doc/stores.rst b/doc/stores.rst index eb75dc762..da26c555b 100644 --- a/doc/stores.rst +++ b/doc/stores.rst @@ -331,9 +331,11 @@ for that class of unique molecules (e.g. ``coordinates`` for a ``gene`` unique molecule). All unique molecules will have the following named fields: 1. ``unique_index`` (:py:class:`int`): Unique identifier for each unique molecule - When processes add new unique molecules, the helper function - :py:func:`ecoli.library.schema.create_unique_indexes` is used to generate - unique indices for each molecule to be added. + When processes add new unique molecules, it is recommended that you let the + :py:meth:`updater ` + generate the new unique indices. If you need to reference the unique + indices of new molecules in the same process AND timestep in which they + are generated, see :py:meth:`ecoli.library.schema.UniqueNumpyUpdater.updater`. 2. ``_entryState`` (:py:attr:`numpy.int8`): 1 for active row, 0 for inactive row When unique molecules are deleted (e.g. RNA degradation), all of their data, including the ``_entryState`` field, is set to 0. When unique molecues are diff --git a/ecoli/analysis/antibiotics_colony/validation.py b/ecoli/analysis/antibiotics_colony/validation.py index f548e1619..b386b88c8 100644 --- a/ecoli/analysis/antibiotics_colony/validation.py +++ b/ecoli/analysis/antibiotics_colony/validation.py @@ -117,13 +117,13 @@ def plot_colony_growth( for antibiotic_conc, treatment_data in treatment_groups: if antibiotic_conc != 0: auc_dict[antibiotic_conc] = max( - np.trapz(treatment_data["Dry mass"], x=treatment_data["Time"]) + np.trapezoid(treatment_data["Dry mass"], x=treatment_data["Time"]) # type: ignore[attr-defined] - background_auc, 0, ) else: baseline_auc = ( - np.trapz(treatment_data["Dry mass"], x=treatment_data["Time"]) + np.trapezoid(treatment_data["Dry mass"], x=treatment_data["Time"]) # type: ignore[attr-defined] - background_auc ) antibiotic_concs = np.log10(np.array(list(auc_dict.keys()))) diff --git a/ecoli/experiments/ecoli_master_sim.py b/ecoli/experiments/ecoli_master_sim.py index 4f89c34d7..6d10c9e5b 100644 --- a/ecoli/experiments/ecoli_master_sim.py +++ b/ecoli/experiments/ecoli_master_sim.py @@ -631,13 +631,6 @@ def build_ecoli(self): ``True``. Spatial environment config options are loaded from ``config['spatial_environment_config`]``. See ``ecoli/composites/ecoli_configs/spatial.json`` for an example. - - .. note:: - When loading from a saved state with a file name of the format - ``vivecoli_t{save time}``, the simulation seed is automatically - set to ``config['seed'] + {save_time}`` to prevent - :py:func:`~ecoli.library.schema.create_unique_indexes` from - generating clashing indices. """ # build processes, topology, configs self.processes = self._retrieve_processes( @@ -653,14 +646,6 @@ def build_ecoli(self): self.process_configs, self.processes ) - # Prevent clashing unique indices by reseeding when loading - # a saved state (assumed to have name 'vivecoli_t{save time}') - initial_state_path = self.config.get("initial_state_file", "") - if initial_state_path.startswith("vivecoli"): - time_str = initial_state_path[len("vivecoli_t") :] - seed = int(float(time_str)) - self.config["seed"] += seed - # initialize the ecoli composer ecoli_composer = ecoli.composites.ecoli_master.Ecoli(self.config) diff --git a/ecoli/library/initial_conditions.py b/ecoli/library/initial_conditions.py index 7c103921e..181c8f2f8 100644 --- a/ecoli/library/initial_conditions.py +++ b/ecoli/library/initial_conditions.py @@ -8,7 +8,12 @@ from typing import Any from unum import Unum -from ecoli.library.schema import attrs, bulk_name_to_idx, create_unique_indexes, counts +from ecoli.library.schema import ( + attrs, + bulk_name_to_idx, + counts, + MetadataArray, +) from ecoli.processes.polypeptide_elongation import ( calculate_trna_charging, REMOVED_FROM_CHARGING, @@ -225,8 +230,9 @@ def create_new_unique_molecules(name, n_mols, sim_data, random_state, **attrs): unique_mols = np.zeros(n_mols, dtype=dtypes) for attr_name, attr_value in attrs.items(): unique_mols[attr_name] = attr_value - unique_mols["unique_index"] = create_unique_indexes(n_mols, random_state) + unique_mols["unique_index"] = np.arange(n_mols) unique_mols["_entryState"] = 1 + unique_mols = MetadataArray(unique_mols, n_mols) return unique_mols @@ -1227,6 +1233,10 @@ def initialize_transcription( massDiff_mRNA=rna_masses[TU_index_full_mRNAs], ) unique_molecules["RNA"] = np.concatenate((partial_rnas, full_rnas)) + unique_molecules["RNA"] = MetadataArray( + unique_molecules["RNA"], + unique_molecules["RNA"]["unique_index"].size, + ) # Reset counts of bulk mRNAs to zero bulk_state["count"][mRNA_idx] = 0 diff --git a/ecoli/library/json_state.py b/ecoli/library/json_state.py index 5cfcfb3bf..b99dcacfc 100644 --- a/ecoli/library/json_state.py +++ b/ecoli/library/json_state.py @@ -3,6 +3,8 @@ import numpy as np import concurrent.futures +from ecoli.library.schema import MetadataArray + from vivarium.core.serialize import deserialize_value from wholecell.utils import units @@ -27,8 +29,11 @@ def numpy_molecules(states): for key, dtypes in states.pop("unique_dtypes").items(): dtypes = ast.literal_eval(dtypes) unique_tuples = [tuple(mol) for mol in states["unique"][key]] - states["unique"][key] = np.array(unique_tuples, dtype=dtypes) - states["unique"][key].flags.writeable = False + unique_arr = np.array(unique_tuples, dtype=dtypes) + unique_arr.flags.writeable = False + states["unique"][key] = MetadataArray( + unique_arr, unique_arr["unique_index"].max() + ) if "environment" in states: if "exchange_data" in states["environment"]: states["environment"]["exchange_data"]["constrained"] = { diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index b314b3bdb..05ca50b18 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -109,6 +109,31 @@ """ +class MetadataArray(np.ndarray): + """Subclass of Numpy array that allows for metadata to be stored with the array. + Currently used to store next unique molecule index for unique molecule arrays.""" + + def __new__(cls, input_array, metadata=None): + # Input array should be an array instance + obj = np.asarray(input_array).view(cls) + obj.metadata = metadata + return obj + + def __array_finalize__(self, obj): + # metadata is set in __new__ when creating new array + if obj is None: + return + # Views should inherit metadata from parent + self.metadata = getattr(obj, "metadata", None) + + def __array_wrap__(self, out_arr, context=None): + # If the result is a scalar, return it as a base scalar type + if out_arr.shape == (): + return out_arr.item() + else: + return super(MetadataArray, self).__array_wrap__(out_arr, context) + + def array_from(d: dict) -> np.ndarray: """Makes a Numpy array from dictionary values. @@ -122,19 +147,24 @@ def array_from(d: dict) -> np.ndarray: def create_unique_indexes( - n_indexes: int, random_state: np.random.RandomState -) -> List[int]: - """Creates a list of unique indexes by making them random. + n_indexes: int, unique_molecules: MetadataArray +) -> np.ndarray: + """We strongly recommend letting + :py:meth:`UniqueNumpyUpdater.updater` generate unique indices + for new unique molecules. If that is not possible, this function + can be used to generate unique indices that should not conflict + with any existing unique indices. Args: n_indexes: Number of indexes to generate. - random_state: PRNG. + unique_molecules: Structured Numpy array of unique molecules. Returns: - List of indexes. Each index is a string representing a number in - the range :math:`[0, 2^{63})`. + List of unique indexes for new unique molecules. """ - return [num for num in random_state.randint(0, 2**63, n_indexes)] + next_unique_index = unique_molecules.metadata + unique_molecules.metadata += n_indexes + return np.arange(next_unique_index, next_unique_index + n_indexes) def not_a_process(value): @@ -270,7 +300,7 @@ def bulk_numpy_updater( return result -def attrs(states: np.ndarray, attributes: List[str]) -> List[np.ndarray]: +def attrs(states: MetadataArray, attributes: List[str]) -> List[np.ndarray]: """Helper function to pull out arrays for unique molecule attributes Args: @@ -286,12 +316,12 @@ def attrs(states: np.ndarray, attributes: List[str]) -> List[np.ndarray]: """ # _entryState has dtype int8 so this works mol_mask = states["_entryState"].view(np.bool_) - return [states[attribute][mol_mask] for attribute in attributes] + return [np.asarray(states[attribute][mol_mask]) for attribute in attributes] def get_free_indices( - result: np.ndarray, n_objects: int -) -> Tuple[np.ndarray, np.ndarray]: + result: MetadataArray, n_objects: int +) -> Tuple[MetadataArray, np.ndarray]: """Find inactive rows for new molecules and expand array if needed Args: @@ -315,7 +345,10 @@ def get_free_indices( old_size = result.size n_new_entries = max(int(old_size * 0.1), n_objects - n_free_indices) - result = np.append(result, np.zeros(int(n_new_entries), dtype=result.dtype)) + result = MetadataArray( + np.append(result, np.zeros(int(n_new_entries), dtype=result.dtype)), + result.metadata, + ) free_indices = np.concatenate( (free_indices, old_size + np.arange(n_new_entries)) @@ -353,7 +386,7 @@ def __init__(self): self.set_updates = [] self.delete_updates = [] - def updater(self, current: np.ndarray, update: Dict[str, Any]) -> np.ndarray: + def updater(self, current: MetadataArray, update: Dict[str, Any]) -> MetadataArray: """Accumulates updates in instance attributes until given signal to apply all updates in the following order: ``set``, ``add``, ``delete`` @@ -362,23 +395,33 @@ def updater(self, current: np.ndarray, update: Dict[str, Any]) -> np.ndarray: update: Dictionary of updates to apply that can contain any combination of the following keys: - - ``set``: List of dictionaries + - ``set``: Dictionary or list of dictionaries Each key is an attribute of the given unique molecule and each value is an array. Each array contains the new attribute values for all active unique - molecules in a givne timestep. + molecules in a givne timestep. Can have multiple such + dictionaries in a list to apply multiple ``set`` updates. - - ``add``: List of dictionaries + - ``add``: Dictionary or list of dictionaries Each key is an attribute of the given unique moleucle and each value is an array. The nth element of each array is the value for the corresponding - attribute for the nth unique molecule to be added. - - - ``delete``: List-like + attribute for the nth unique molecule to be added. If not + provided, unique indices for the ``unique_index`` attribute + are automatically generated for each new molecule. If + you need to reference the unique indices of new molecules in + the same process and time step in which you generated them, + you MUST use the :py:func:`ecoli.library.schema.create_unique_indices` + to generate the indices and supply them under the ``unique_index`` + key of your ``add`` update. Can have multiple such + dictionaries in a list to apply multiple ``add`` updates. + + - ``delete``: List or 1D Numpy array of integers, or list of those List of **active** molecule indices to delete. Note that ``current`` may have rows that are marked as inactive, so deleting the 10th active molecule may not equate to - deleting the value in the 10th row of ``current``. + deleting the value in the 10th row of ``current``. Can have + multiple such lists in a list to apply multiple ``delete`` updates. - ``update``: Boolean Special key that should only be included in the update of @@ -398,11 +441,45 @@ def updater(self, current: np.ndarray, update: Dict[str, Any]) -> np.ndarray: # following order: set, add, delete (prevents overwriting) for update_type, update_val in update.items(): if update_type == "add": - self.add_updates.append(update_val) + if isinstance(update_val, list): + self.add_updates.extend(update_val) + elif isinstance(update_val, dict): + self.add_updates.append(update_val) + else: + raise ValueError( + "Add updates must be dictionaries or lists of dictionaries" + ) elif update_type == "set": - self.set_updates.append(update_val) + if isinstance(update_val, list): + self.set_updates.extend(update_val) + elif isinstance(update_val, dict): + self.set_updates.append(update_val) + else: + raise ValueError( + "Add updates must be dictionaries or lists of dictionaries" + ) elif update_type == "delete": - self.delete_updates.append(update_val) + if isinstance(update_val, list): + if isinstance(update_val[0], list) or isinstance( + update_val[0], np.ndarray + ): + self.delete_updates.extend(update_val) + elif isinstance(update_val[0], int): + self.delete_updates.append(update_val) + else: + raise ValueError( + "Delete updates must be lists/arrays of integers " + "OR lists of lists/arrays of integers" + ) + elif isinstance(update_val, np.ndarray) and np.issubdtype( + update_val.dtype, np.integer + ): + self.delete_updates.append(update_val) + else: + raise ValueError( + "Delete updates must be lists/arrays of integers " + "OR lists of lists/arrays of integers" + ) if not update.get("update", False): return current @@ -426,6 +503,11 @@ def updater(self, current: np.ndarray, update: Dict[str, Any]) -> np.ndarray: # for the corresponding column of the nth new molecule to be added. n_new_molecules = len(next(iter(add_update.values()))) result, free_indices = get_free_indices(result, n_new_molecules) + if "unique_index" not in add_update: + result["unique_index"][free_indices] = ( + np.arange(n_new_molecules) + result.metadata + ) + result.metadata += n_new_molecules for col, col_values in add_update.items(): result[col][free_indices] = col_values result["_entryState"][free_indices] = 1 diff --git a/ecoli/processes/cell_division.py b/ecoli/processes/cell_division.py index 8ba4f13ab..59badb1e1 100644 --- a/ecoli/processes/cell_division.py +++ b/ecoli/processes/cell_division.py @@ -48,6 +48,7 @@ def next_update(self, timestep, states): divide_at_time = division_time[~has_triggered_division].min() if states["global_time"] >= divide_at_time: divide_at_time_index = np.where(division_time == divide_at_time)[0][0] + has_triggered_division = has_triggered_division.copy() has_triggered_division[divide_at_time_index] = True # Set flag for ensuing division Step to trigger division return { diff --git a/ecoli/processes/chemotaxis/flagella_motor.py b/ecoli/processes/chemotaxis/flagella_motor.py index e1b98d314..0a4e0676e 100644 --- a/ecoli/processes/chemotaxis/flagella_motor.py +++ b/ecoli/processes/chemotaxis/flagella_motor.py @@ -31,8 +31,6 @@ from vivarium.core.emitter import timeseries_from_data from vivarium.plots.simulation_output import plot_simulation_output -from ecoli.library.schema import create_unique_indexes - # plots from matplotlib import colors, pyplot as plt from matplotlib.patches import Patch @@ -214,9 +212,9 @@ def next_update(self, timestep, states): elif new_flagella > 0: flagella_update["_add"] = [] - new_flagella_indexes = create_unique_indexes( - new_flagella, self.random_state - ) + new_flagella_indexes = [ + num for num in self.random_state.randint(0, 2**63, new_flagella) + ] for index in range(new_flagella): flagella_id = new_flagella_indexes[index] flagella_update["_add"].append( diff --git a/ecoli/processes/chromosome_replication.py b/ecoli/processes/chromosome_replication.py index e21ab8ae7..4e8d79965 100644 --- a/ecoli/processes/chromosome_replication.py +++ b/ecoli/processes/chromosome_replication.py @@ -19,7 +19,6 @@ import numpy as np from ecoli.library.schema import ( - create_unique_indexes, numpy_schema, counts, attrs, @@ -106,9 +105,6 @@ def __init__(self, parameters=None): # random state self.seed = self.parameters["seed"] self.random_state = np.random.RandomState(seed=self.seed) - # Use separate random state instance to create unique indices - # so results are directly comparable with wcEcoli - self.unique_idx_random_state = np.random.RandomState(seed=self.seed) self.emit_unique = self.parameters.get("emit_unique", True) @@ -299,11 +295,7 @@ def evolve_state(self, timestep, states): # Add new oriC's, and reset attributes of existing oriC's # All oriC's must be assigned new domain indexes update["oriCs"]["set"] = {"domain_index": domain_index_new[:n_oriC]} - new_oric_indexes = create_unique_indexes( - n_oriC, self.unique_idx_random_state - ) update["oriCs"]["add"] = { - "unique_index": new_oric_indexes, "domain_index": domain_index_new[n_oriC:], } @@ -319,11 +311,7 @@ def evolve_state(self, timestep, states): n_new_replisome, self.replisome_protein_mass if self.mechanistic_replisome else 0.0, ) - new_replisome_indexes = create_unique_indexes( - n_new_replisome, self.unique_idx_random_state - ) update["active_replisomes"]["add"] = { - "unique_index": new_replisome_indexes, "coordinates": coordinates_replisome, "right_replichore": right_replichore, "domain_index": domain_index_new_replisome, @@ -335,12 +323,8 @@ def evolve_state(self, timestep, states): new_child_domains = np.full( (n_new_domain, 2), self.no_child_place_holder, dtype=np.int32 ) - new_domain_indexes = create_unique_indexes( - n_new_domain, self.unique_idx_random_state - ) new_domains_update = { "add": { - "unique_index": new_domain_indexes, "domain_index": domain_index_new, "child_domains": new_child_domains, } @@ -501,6 +485,7 @@ def evolve_state(self, timestep, states): # Modify domain index of one existing full chromosome to # index of first child domain + domain_index_full_chroms = domain_index_full_chroms.copy() domain_index_full_chroms[ np.where(domain_index_full_chroms == terminated_domain_index)[0] ] = child_domains_this_domain[0] @@ -516,12 +501,8 @@ def evolve_state(self, timestep, states): # Generate new full chromosome molecules if n_new_chromosomes > 0: - new_chromosome_indexes = create_unique_indexes( - n_new_chromosomes, self.unique_idx_random_state - ) chromosome_add_update = { "add": { - "unique_index": new_chromosome_indexes, "domain_index": domain_index_new_full_chroms, "division_time": states["global_time"] + self.D_period, "has_triggered_division": False, diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index eb49aefaf..d57bdc2f8 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -15,7 +15,6 @@ from ecoli.processes.registries import topology_registry from ecoli.library.schema import ( - create_unique_indexes, listener_schema, numpy_schema, attrs, @@ -762,11 +761,9 @@ def get_replicated_motif_attributes(old_coordinates, old_domain_indexes): ) # Add new promoters with new domain indexes - promoter_indices = create_unique_indexes(n_new_promoters, self.random_state) update["promoters"].update( { "add": { - "unique_index": promoter_indices, "TU_index": promoter_TU_indexes_new, "coordinates": promoter_coordinates_new, "domain_index": promoter_domain_indexes_new, @@ -796,11 +793,9 @@ def get_replicated_motif_attributes(old_coordinates, old_domain_indexes): ) # Add new genes with new domain indexes - gene_indices = create_unique_indexes(n_new_genes, self.random_state) update["genes"].update( { "add": { - "unique_index": gene_indices, "cistron_index": gene_cistron_indexes_new, "coordinates": gene_coordinates_new, "domain_index": gene_domain_indexes_new, @@ -829,12 +824,8 @@ def get_replicated_motif_attributes(old_coordinates, old_domain_indexes): ) # Add new DnaA boxes with new domain indexes - DnaA_box_indices = create_unique_indexes( - n_new_DnaA_boxes, self.random_state - ) dict_dna = { "add": { - "unique_index": DnaA_box_indices, "coordinates": DnaA_box_coordinates_new, "domain_index": DnaA_box_domain_indexes_new, "DnaA_bound": np.zeros(n_new_DnaA_boxes, dtype=np.bool_), diff --git a/ecoli/processes/polypeptide_initiation.py b/ecoli/processes/polypeptide_initiation.py index 74b28c63f..193eb204e 100644 --- a/ecoli/processes/polypeptide_initiation.py +++ b/ecoli/processes/polypeptide_initiation.py @@ -15,7 +15,6 @@ from vivarium.core.composition import simulate_process from ecoli.library.schema import ( - create_unique_indexes, numpy_schema, attrs, counts, @@ -106,9 +105,6 @@ def __init__(self, parameters=None): self.seed = self.parameters["seed"] self.random_state = np.random.RandomState(seed=self.seed) - # Use separate random state instance to create unique indices - # so results are directly comparable with wcEcoli - self.unique_idx_random_state = np.random.RandomState(seed=self.seed) self.empty_update = { "listeners": { @@ -417,9 +413,6 @@ def evolve_state(self, timestep, states): start_index += protein_counts # Create active 70S ribosomes and assign their attributes - ribosome_indices = create_unique_indexes( - n_ribosomes_to_activate, self.unique_idx_random_state - ) update = { "bulk": [ (self.ribosome30S_idx, -n_new_proteins.sum()), @@ -427,7 +420,6 @@ def evolve_state(self, timestep, states): ], "active_ribosome": { "add": { - "unique_index": ribosome_indices, "protein_index": protein_indexes, "peptide_length": np.zeros(n_ribosomes_to_activate, dtype=np.int64), "mRNA_index": mRNA_indexes, diff --git a/ecoli/processes/rna_degradation.py b/ecoli/processes/rna_degradation.py index 281aeba27..b6aa62be1 100644 --- a/ecoli/processes/rna_degradation.py +++ b/ecoli/processes/rna_degradation.py @@ -409,6 +409,7 @@ def evolve_state(self, timestep, states): # Deactivate and degrade unique RNAs TU_index, can_translate = attrs(states["RNAs"], ["TU_index", "can_translate"]) + can_translate = can_translate.copy() n_deactivated_unique_RNA = self.n_unique_RNAs_to_deactivate # Deactive unique RNAs diff --git a/ecoli/processes/transcript_elongation.py b/ecoli/processes/transcript_elongation.py index 6311baf7a..f8df9758e 100644 --- a/ecoli/processes/transcript_elongation.py +++ b/ecoli/processes/transcript_elongation.py @@ -337,6 +337,7 @@ def evolve_state(self, timestep, states): "RNAP_index", ], ) + length_all_RNAs = length_all_RNAs.copy() update = {"listeners": {"growth_limits": {}}} diff --git a/ecoli/processes/transcript_initiation.py b/ecoli/processes/transcript_initiation.py index 72d3e10b5..3ab05ca25 100644 --- a/ecoli/processes/transcript_initiation.py +++ b/ecoli/processes/transcript_initiation.py @@ -269,9 +269,6 @@ def __init__(self, parameters=None): self.seed = self.parameters["seed"] self.random_state = np.random.RandomState(seed=self.seed) - # Use separate random state instance to create unique indices - # so results are directly comparable with wcEcoli - self.unique_idx_random_state = np.random.RandomState(seed=self.seed) # Helper indices for Numpy indexing self.ppgpp_idx = None @@ -542,9 +539,7 @@ def evolve_state(self, timestep, states): is_forward = self.transcription_direction[TU_index_partial_RNAs] # new RNAPs - RNAP_indexes = create_unique_indexes( - n_RNAPs_to_activate, self.unique_idx_random_state - ) + RNAP_indexes = create_unique_indexes(n_RNAPs_to_activate, states["RNAs"]) update["active_RNAPs"].update( { "add": { @@ -561,13 +556,9 @@ def evolve_state(self, timestep, states): # Add partially transcribed RNAs is_mRNA = np.isin(TU_index_partial_RNAs, self.idx_mRNA) - rna_indices = create_unique_indexes( - n_RNAPs_to_activate, self.unique_idx_random_state - ) update["RNAs"].update( { "add": { - "unique_index": rna_indices, "TU_index": TU_index_partial_RNAs, "transcript_length": np.zeros(cast(int, n_RNAPs_to_activate)), "is_mRNA": is_mRNA, From bb278a126ef1cb1e56615dcefbbff55737f33815 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 3 Dec 2024 20:43:17 -0800 Subject: [PATCH 06/54] Remove full process parallelization because it is currently not practical --- doc/experiments.rst | 17 +++--- ecoli/composites/ecoli_master.py | 38 +++++++++++-- ecoli/library/sim_data.py | 95 +++++++++++--------------------- 3 files changed, 73 insertions(+), 77 deletions(-) diff --git a/doc/experiments.rst b/doc/experiments.rst index 1e1a8f2fc..59630efb3 100644 --- a/doc/experiments.rst +++ b/doc/experiments.rst @@ -181,9 +181,6 @@ documented in :ref:`/workflows.rst`. # to this initial agent ID for each daughter cell (only "0" if not # simulating both daughter cells, see "Workflow" documentation). "agent_id": "0", - # Run each Process in parallel. This incurs a lot of overhead and most - # processes in our model are Steps anyways. Keep at default: False. - "parallel": false, # Whether to add processes and associated topologies for cell # division. See "Division Modifications" heading in "Composites" docs. "divide": true, @@ -453,12 +450,18 @@ Configuring Colony Simulations All of the configuration options listed above still apply to simulations started with -:py:mod:`~ecoli.experiments.ecoli_engine_process`. There are only two new options: +:py:mod:`~ecoli.experiments.ecoli_engine_process`. There are only three new options: - ``engine_process_reports``: List of paths (e.g. ``["bulk"]`` for bulk store) inside each cell to save in final colony output. - ``emit_paths``: List of paths in outer simulation (e.g. locations of each cell in spatial environment) to save in final colony output. +- ``parallel``: In :py:mod:`~ecoli.experiments.ecoli_engine_process`, each simulated + cell is contained within a single process (specifically, an instance of + :py:class:`~ecoli.processes.engine_process.EngineProcess`). Therefore, assuming + cells only need to communicate a tiny amount of information between one another, + interprocess overhead is low and running these cells in parallel can greatly speed + up the colony simulation. In addition to these new configuration options, several previously mentioned options become much more useful in the context of colony simulations: @@ -468,12 +471,6 @@ become much more useful in the context of colony simulations: ``initial_state_file`` without having to wait for 16 generations every time. The names of the files saved can be given an optional prefix configured via the ``colony_save_prefix`` option. -- ``parallel``: In :py:mod:`~ecoli.experiments.ecoli_engine_process`, each simulated - cell is contained within a single process (specifically, an instance of - :py:class:`~ecoli.processes.engine_process.EngineProcess`). Therefore, assuming - cells only need to communicate a tiny amount of information between one another, - interprocess overhead is low and running these cells in parallel can greatly speed - up the colony simulation. - ``spatial_environment`` and ``spatial_environment_config``: The benefit of running simulations inside a shared, dynamic spatial environment is only fully realized when many cells are interacting with one another inside this environment. diff --git a/ecoli/composites/ecoli_master.py b/ecoli/composites/ecoli_master.py index b99c45e12..07d6dd623 100644 --- a/ecoli/composites/ecoli_master.py +++ b/ecoli/composites/ecoli_master.py @@ -242,7 +242,11 @@ def generate_processes_and_steps( ``defaults`` attribute of the process should be used as its config. In the case of a dictionary config, the dictionary will be merged with the result of :py:meth:`~ecoli.library.sim_data.LoadSimData.get_config_by_name` - if possible, or the ``defaults`` attribute if not. + if possible, or the ``defaults`` attribute if not. You can set the + special ``_parallel`` key to true in a dictionary config to run + that process in its own OS process. Unfortunately, this greatly increases + memory usage and, for most current processes, is much slower than not + using this key due to interprocess communication overhead. * ``processes``: Mapping of all process names (:py:class:`str`) @@ -334,20 +338,44 @@ def generate_processes_and_steps( self.partitioned_processes = [] for process_name, process_class in config["processes"].items(): if issubclass(process_class, PartitionedProcess): + parallel = process_configs[process_name].pop("_parallel", False) + if parallel and process_name == "ecoli-transcript-initiation": + raise ValueError( + "Transcript initiation cannot be run in parallel due to " + "creation of unique indices in the process." + ) process = process_class(process_configs[process_name]) if config["log_updates"]: steps[f"{process_name}_evolver"] = make_logging_process(Evolver)( - {"time_step": time_step, "process": process} + { + "time_step": time_step, + "process": process, + "_parallel": parallel, + } ) steps[f"{process_name}_requester"] = make_logging_process( Requester - )({"time_step": time_step, "process": process}) + )( + { + "time_step": time_step, + "process": process, + "_parallel": parallel, + } + ) else: steps[f"{process_name}_evolver"] = Evolver( - {"time_step": time_step, "process": process} + { + "time_step": time_step, + "process": process, + "_parallel": parallel, + } ) steps[f"{process_name}_requester"] = Requester( - {"time_step": time_step, "process": process} + { + "time_step": time_step, + "process": process, + "_parallel": parallel, + } ) self.partitioned_processes.append(process_name) elif issubclass(process_class, Step): diff --git a/ecoli/library/sim_data.py b/ecoli/library/sim_data.py index de7d40c6f..a142f968b 100644 --- a/ecoli/library/sim_data.py +++ b/ecoli/library/sim_data.py @@ -561,7 +561,7 @@ def get_rna_indices(self, names): def _seedFromName(self, name): return binascii.crc32(name.encode("utf-8"), self.seed) & 0xFFFFFFFF - def get_config_by_name(self, name, time_step=1, parallel=False): + def get_config_by_name(self, name, time_step=1): name_config_mapping = { "ecoli-tf-binding": self.get_tf_config, "ecoli-transcript-initiation": self.get_transcript_initiation_config, @@ -599,13 +599,13 @@ def get_config_by_name(self, name, time_step=1, parallel=False): } try: - return name_config_mapping[name](time_step=time_step, parallel=parallel) + return name_config_mapping[name](time_step=time_step) except KeyError: raise KeyError( f"Process of name {name} is not known to LoadSimData.get_config_by_name" ) - def get_chromosome_replication_config(self, time_step=1, parallel=False): + def get_chromosome_replication_config(self, time_step=1): get_dna_critical_mass = self.sim_data.mass.get_dna_critical_mass doubling_time = self.sim_data.condition_to_doubling_time[ self.sim_data.condition @@ -633,7 +633,6 @@ def get_chromosome_replication_config(self, time_step=1, parallel=False): chromosome_replication_config = { "time_step": time_step, - "_parallel": parallel, "max_time_step": self.sim_data.process.replication.max_time_step, "get_dna_critical_mass": get_dna_critical_mass, "criticalInitiationMass": get_dna_critical_mass(doubling_time), @@ -663,10 +662,9 @@ def get_chromosome_replication_config(self, time_step=1, parallel=False): return chromosome_replication_config - def get_tf_config(self, time_step=1, parallel=False): + def get_tf_config(self, time_step=1): tf_binding_config = { "time_step": time_step, - "_parallel": parallel, "tf_ids": self.sim_data.process.transcription_regulation.tf_ids, "rna_ids": self.sim_data.process.transcription.rna_data["id"], "delta_prob": self.sim_data.process.transcription_regulation.delta_prob, @@ -690,10 +688,9 @@ def get_tf_config(self, time_step=1, parallel=False): return tf_binding_config - def get_transcript_initiation_config(self, time_step=1, parallel=False): + def get_transcript_initiation_config(self, time_step=1): transcript_initiation_config = { "time_step": time_step, - "_parallel": parallel, "fracActiveRnapDict": self.sim_data.process.transcription.rnapFractionActiveDict, "rnaLengths": self.sim_data.process.transcription.rna_data["length"], "rnaPolymeraseElongationRateDict": self.sim_data.process.transcription.rnaPolymeraseElongationRateDict, @@ -750,10 +747,9 @@ def get_transcript_initiation_config(self, time_step=1, parallel=False): return transcript_initiation_config - def get_transcript_elongation_config(self, time_step=1, parallel=False): + def get_transcript_elongation_config(self, time_step=1): transcript_elongation_config = { "time_step": time_step, - "_parallel": parallel, "max_time_step": self.sim_data.process.transcription.max_time_step, "rnaPolymeraseElongationRateDict": self.sim_data.process.transcription.rnaPolymeraseElongationRateDict, "rnaIds": self.sim_data.process.transcription.rna_data["id"], @@ -789,7 +785,7 @@ def get_transcript_elongation_config(self, time_step=1, parallel=False): return transcript_elongation_config - def get_rna_degradation_config(self, time_step=1, parallel=False): + def get_rna_degradation_config(self, time_step=1): transcription = self.sim_data.process.transcription rna_ids = list(transcription.rna_data["id"]) mature_rna_ids = list(transcription.mature_rna_data["id"]) @@ -802,7 +798,6 @@ def get_rna_degradation_config(self, time_step=1, parallel=False): rna_degradation_config = { "time_step": time_step, - "_parallel": parallel, "rna_ids": rna_ids, "mature_rna_ids": mature_rna_ids, "cistron_ids": cistron_ids, @@ -905,10 +900,9 @@ def get_rna_degradation_config(self, time_step=1, parallel=False): return rna_degradation_config - def get_polypeptide_initiation_config(self, time_step=1, parallel=False): + def get_polypeptide_initiation_config(self, time_step=1): polypeptide_initiation_config = { "time_step": time_step, - "_parallel": parallel, "protein_lengths": self.sim_data.process.translation.monomer_data[ "length" ].asNumber(), @@ -943,7 +937,7 @@ def get_polypeptide_initiation_config(self, time_step=1, parallel=False): return polypeptide_initiation_config - def get_polypeptide_elongation_config(self, time_step=1, parallel=False): + def get_polypeptide_elongation_config(self, time_step=1): constants = self.sim_data.constants molecule_ids = self.sim_data.molecule_ids translation = self.sim_data.process.translation @@ -952,7 +946,6 @@ def get_polypeptide_elongation_config(self, time_step=1, parallel=False): polypeptide_elongation_config = { "time_step": time_step, - "_parallel": parallel, # simulation options "aa_supply_in_charging": self.aa_supply_in_charging, "adjust_timestep_for_charging": self.adjust_timestep_for_charging, @@ -1060,10 +1053,9 @@ def get_polypeptide_elongation_config(self, time_step=1, parallel=False): return polypeptide_elongation_config - def get_complexation_config(self, time_step=1, parallel=False): + def get_complexation_config(self, time_step=1): complexation_config = { "time_step": time_step, - "_parallel": parallel, "stoichiometry": self.sim_data.process.complexation.stoich_matrix() .astype(np.int64) .T, @@ -1077,10 +1069,9 @@ def get_complexation_config(self, time_step=1, parallel=False): return complexation_config - def get_two_component_system_config(self, time_step=1, parallel=False): + def get_two_component_system_config(self, time_step=1): two_component_system_config = { "time_step": time_step, - "_parallel": parallel, "jit": False, # TODO -- wcEcoli has this in 1/mmol, why? "n_avogadro": self.sim_data.constants.n_avogadro.asNumber(1 / units.mmol), @@ -1096,10 +1087,9 @@ def get_two_component_system_config(self, time_step=1, parallel=False): # return two_component_system_config, stoichI, stoichJ, stoichV return two_component_system_config - def get_equilibrium_config(self, time_step=1, parallel=False): + def get_equilibrium_config(self, time_step=1): equilibrium_config = { "time_step": time_step, - "_parallel": parallel, "jit": False, "n_avogadro": self.sim_data.constants.n_avogadro.asNumber(1 / units.mol), "cell_density": self.sim_data.constants.cell_density.asNumber( @@ -1118,10 +1108,9 @@ def get_equilibrium_config(self, time_step=1, parallel=False): return equilibrium_config - def get_protein_degradation_config(self, time_step=1, parallel=False): + def get_protein_degradation_config(self, time_step=1): protein_degradation_config = { "time_step": time_step, - "_parallel": parallel, "raw_degradation_rate": self.sim_data.process.translation.monomer_data[ "deg_rate" ].asNumber(1 / units.s), @@ -1140,7 +1129,7 @@ def get_protein_degradation_config(self, time_step=1, parallel=False): return protein_degradation_config - def get_metabolism_redux_config(self, time_step=1, parallel=False): + def get_metabolism_redux_config(self, time_step=1): metabolism = self.sim_data.process.metabolism aa_names = self.sim_data.molecule_groups.amino_acids aa_exchange_names = np.array( @@ -1177,7 +1166,6 @@ def get_metabolism_redux_config(self, time_step=1, parallel=False): metabolism_config = { "time_step": time_step, - "_parallel": parallel, # stoich "stoich_dict": metabolism.reaction_stoich, "maintenance_reaction": metabolism.maintenance_reaction, @@ -1242,7 +1230,7 @@ def get_metabolism_redux_config(self, time_step=1, parallel=False): return metabolism_config - def get_metabolism_config(self, time_step=1, parallel=False): + def get_metabolism_config(self, time_step=1): # bad_rxns = ["RXN-12440", "TRANS-RXN-121", "TRANS-RXN-300"] # for rxn in bad_rxns: # self.sim_data.process.metabolism.reaction_stoich.pop(rxn, None) @@ -1285,7 +1273,6 @@ def get_metabolism_config(self, time_step=1, parallel=False): metabolism_config = { "time_step": time_step, - "_parallel": parallel, # metabolism parameters "stoichiometry": metabolism.reaction_stoich, "catalyst_ids": metabolism.catalyst_ids, @@ -1341,7 +1328,7 @@ def get_metabolism_config(self, time_step=1, parallel=False): return metabolism_config - def get_mass_config(self, time_step=1, parallel=False): + def get_mass_config(self, time_step=1): bulk_ids = self.sim_data.internal_state.bulk_molecules.bulk_data["id"] molecular_weights = {} for molecule_id in bulk_ids: @@ -1370,7 +1357,7 @@ def get_mass_config(self, time_step=1, parallel=False): } return mass_config - def get_mass_listener_config(self, time_step=1, parallel=False): + def get_mass_listener_config(self, time_step=1): u_masses = self.sim_data.internal_state.unique_molecule.unique_molecule_masses molecule_ids = tuple(sorted(u_masses["id"])) molecule_id_to_mass = {} @@ -1423,10 +1410,9 @@ def get_mass_listener_config(self, time_step=1, parallel=False): return mass_config - def get_rna_counts_listener_config(self, time_step=1, parallel=False): + def get_rna_counts_listener_config(self, time_step=1): counts_config = { "time_step": time_step, - "_parallel": parallel, "all_TU_ids": self.sim_data.process.transcription.rna_data["id"], "mRNA_indexes": np.where( self.sim_data.process.transcription.rna_data["is_mRNA"] @@ -1459,10 +1445,9 @@ def get_rna_counts_listener_config(self, time_step=1, parallel=False): return counts_config - def get_monomer_counts_listener_config(self, time_step=1, parallel=False): + def get_monomer_counts_listener_config(self, time_step=1): monomer_counts_config = { "time_step": time_step, - "_parallel": parallel, # Get IDs of all bulk molecules "bulk_molecule_ids": self.sim_data.internal_state.bulk_molecules.bulk_data[ "id" @@ -1509,12 +1494,11 @@ def get_monomer_counts_listener_config(self, time_step=1, parallel=False): return monomer_counts_config - def get_allocator_config(self, time_step=1, parallel=False, process_names=None): + def get_allocator_config(self, time_step=1, process_names=None): if not process_names: process_names = [] allocator_config = { "time_step": time_step, - "_parallel": parallel, "molecule_names": self.sim_data.internal_state.bulk_molecules.bulk_data[ "id" ], @@ -1532,14 +1516,13 @@ def get_allocator_config(self, time_step=1, parallel=False, process_names=None): } return allocator_config - def get_chromosome_structure_config(self, time_step=1, parallel=False): + def get_chromosome_structure_config(self, time_step=1): transcription = self.sim_data.process.transcription mature_rna_ids = transcription.mature_rna_data["id"] unprocessed_rna_indexes = np.where(transcription.rna_data["is_unprocessed"])[0] chromosome_structure_config = { "time_step": time_step, - "_parallel": parallel, # Load parameters "rna_sequences": transcription.transcription_sequences, "protein_sequences": self.sim_data.process.translation.translation_sequences, @@ -1579,10 +1562,9 @@ def get_chromosome_structure_config(self, time_step=1, parallel=False): } return chromosome_structure_config - def get_rna_interference_config(self, time_step=1, parallel=False): + def get_rna_interference_config(self, time_step=1): rna_interference_config = { "time_step": time_step, - "_parallel": parallel, "srna_ids": self.srna_ids, "target_tu_ids": self.target_tu_ids, "binding_probs": self.binding_probs, @@ -1594,14 +1576,13 @@ def get_rna_interference_config(self, time_step=1, parallel=False): } return rna_interference_config - def get_tetracycline_ribosome_equilibrium_config(self, time_step=1, parallel=False): + def get_tetracycline_ribosome_equilibrium_config(self, time_step=1): rna_ids = self.sim_data.process.transcription.rna_data["id"] is_trna = self.sim_data.process.transcription.rna_data["is_tRNA"].astype( np.bool_ ) tetracycline_ribosome_equilibrium_config = { "time_step": time_step, - "_parallel": parallel, "trna_ids": rna_ids[is_trna], # Ensure that a new seed is set upon division "seed": self.random_state.randint(RAND_MAX), @@ -1609,14 +1590,13 @@ def get_tetracycline_ribosome_equilibrium_config(self, time_step=1, parallel=Fal } return tetracycline_ribosome_equilibrium_config - def get_rna_maturation_config(self, time_step=1, parallel=False): + def get_rna_maturation_config(self, time_step=1): transcription = self.sim_data.process.transcription rna_data = transcription.rna_data mature_rna_data = transcription.mature_rna_data config = { "time_step": time_step, - "_parallel": parallel, # Get matrices and vectors that describe maturation reactions "stoich_matrix": transcription.rna_maturation_stoich_matrix, "enzyme_matrix": transcription.rna_maturation_enzyme_matrix.astype(int), @@ -1678,10 +1658,9 @@ def calculate_delta_nt_counts(main_id, variant_ids): return config - def get_tf_unbinding_config(self, time_step=1, parallel=False): + def get_tf_unbinding_config(self, time_step=1): config = { "time_step": time_step, - "_parallel": parallel, "tf_ids": self.sim_data.process.transcription_regulation.tf_ids, "submass_indices": self.submass_indices, "emit_unique": self.emit_unique, @@ -1697,10 +1676,9 @@ def get_tf_unbinding_config(self, time_step=1, parallel=False): ).asNumber(units.fg) return config - def get_rna_synth_prob_listener_config(self, time_step=1, parallel=False): + def get_rna_synth_prob_listener_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "gene_ids": self.sim_data.process.transcription.cistron_data["gene_id"], "rna_ids": self.sim_data.process.transcription.rna_data["id"], "tf_ids": self.sim_data.process.transcription_regulation.tf_ids, @@ -1709,28 +1687,25 @@ def get_rna_synth_prob_listener_config(self, time_step=1, parallel=False): "emit_unique": self.emit_unique, } - def get_dna_supercoiling_listener_config(self, time_step=1, parallel=False): + def get_dna_supercoiling_listener_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "relaxed_DNA_base_pairs_per_turn": self.sim_data.process.chromosome_structure.relaxed_DNA_base_pairs_per_turn, "emit_unique": self.emit_unique, } - def get_unique_molecule_counts_config(self, time_step=1, parallel=False): + def get_unique_molecule_counts_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "unique_ids": self.sim_data.internal_state.unique_molecule.unique_molecule_masses[ "id" ], "emit_unique": self.emit_unique, } - def get_ribosome_data_listener_config(self, time_step=1, parallel=False): + def get_ribosome_data_listener_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "monomer_ids": self.sim_data.process.translation.monomer_data[ "id" ].tolist(), @@ -1747,10 +1722,9 @@ def get_ribosome_data_listener_config(self, time_step=1, parallel=False): "emit_unique": self.emit_unique, } - def get_rnap_data_listener_config(self, time_step=1, parallel=False): + def get_rnap_data_listener_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "stable_RNA_indexes": np.where( np.logical_or( self.sim_data.process.transcription.rna_data["is_rRNA"], @@ -1762,17 +1736,16 @@ def get_rnap_data_listener_config(self, time_step=1, parallel=False): "emit_unique": self.emit_unique, } - def get_exchange_data_config(self, time_step=1, parallel=False): + def get_exchange_data_config(self, time_step=1): return { "time_step": time_step, - "_parallel": parallel, "external_state": self.sim_data.external_state, "environment_molecules": list( self.sim_data.external_state.env_to_exchange_map.keys() ), } - def get_media_update_config(self, time_step=1, parallel=False): + def get_media_update_config(self, time_step=1): # if current_timeline_id is specified by a variant in sim_data, # look it up in saved_timelines. if self.sim_data.external_state.current_timeline_id: @@ -1783,12 +1756,11 @@ def get_media_update_config(self, time_step=1, parallel=False): current_timeline = self.media_timeline return { "time_step": time_step, - "_parallel": parallel, "saved_media": self.sim_data.external_state.saved_media, "media_id": current_timeline[0][1], } - def get_bulk_timeline_config(self, time_step=1, parallel=False): + def get_bulk_timeline_config(self, time_step=1): # if current_timeline_id is specified by a variant in sim_data, look it up in saved_timelines. if self.sim_data.external_state.current_timeline_id: current_timeline = self.sim_data.external_state.saved_timelines[ @@ -1798,7 +1770,6 @@ def get_bulk_timeline_config(self, time_step=1, parallel=False): current_timeline = self.media_timeline return { "time_step": time_step, - "_parallel": parallel, "timeline": { time: {("media_id",): media_id} for time, media_id in current_timeline }, From a8156b317226f124bff4e58d1031aeeeefc6fbc4 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Wed, 4 Dec 2024 19:04:22 -0800 Subject: [PATCH 07/54] Convert unique molecules back to normal Numpy arrays for JSON --- ecoli/experiments/ecoli_master_sim.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ecoli/experiments/ecoli_master_sim.py b/ecoli/experiments/ecoli_master_sim.py index 6d10c9e5b..db150eddb 100644 --- a/ecoli/experiments/ecoli_master_sim.py +++ b/ecoli/experiments/ecoli_master_sim.py @@ -157,6 +157,7 @@ def prepare_save_state(state: dict[str, Any]) -> None: state["bulk_dtypes"] = str(state["bulk"].dtype) state["unique_dtypes"] = {} for name, mols in state["unique"].items(): + state["unique"][name] = np.asarray(mols) state["unique_dtypes"][name] = str(mols.dtype) From 62b17e104dc00804f1530f0b1062362894443477 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Wed, 4 Dec 2024 20:21:39 -0800 Subject: [PATCH 08/54] Fix mypy errors --- ecoli/library/schema.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index 05ca50b18..a86b53200 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -610,7 +610,7 @@ def divide_bulk(state: np.ndarray) -> tuple[np.ndarray, np.ndarray]: def divide_ribosomes_by_RNA( - values: np.ndarray, state: Dict[str, Any] + values: MetadataArray, state: Dict[str, Any] ) -> tuple[np.ndarray, np.ndarray]: """Divider function for active ribosome unique molecules. Automatically added to ports schema by :py:func:`ecoli.library.schema.numpy_schema` when @@ -673,7 +673,7 @@ def divide_ribosomes_by_RNA( return np.zeros(0, dtype=values.dtype), np.zeros(0, dtype=values.dtype) -def divide_domains(state: dict[str, np.ndarray]) -> dict[str, np.ndarray]: +def divide_domains(state: dict[str, MetadataArray]) -> dict[str, np.ndarray]: """Divider function for chromosome domains. Ensures that all chromosome domains associated with a full chromosome go to the same daughter cell that the full chromosome does. @@ -746,7 +746,7 @@ def divide_by_domain( def divide_RNAs_by_domain( - values: np.ndarray, state: Dict[str, Any] + values: MetadataArray, state: Dict[str, Any] ) -> tuple[np.ndarray, np.ndarray]: """Divider function for RNA unique molecules. Ensures that incomplete transcripts are divided in accordance with how active RNAPs are From 5d48139b85cc83b73b0a33e3e5cb004689e69aa4 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Wed, 4 Dec 2024 20:58:04 -0800 Subject: [PATCH 09/54] Clarify unique indices and fix chromosome segment unique indices --- doc/stores.rst | 7 +++++-- ecoli/processes/chromosome_structure.py | 14 -------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/doc/stores.rst b/doc/stores.rst index da26c555b..b9f8e2dd1 100644 --- a/doc/stores.rst +++ b/doc/stores.rst @@ -331,11 +331,14 @@ for that class of unique molecules (e.g. ``coordinates`` for a ``gene`` unique molecule). All unique molecules will have the following named fields: 1. ``unique_index`` (:py:class:`int`): Unique identifier for each unique molecule - When processes add new unique molecules, it is recommended that you let the + When processes add new unique molecules, you can let :py:meth:`updater ` generate the new unique indices. If you need to reference the unique indices of new molecules in the same process AND timestep in which they - are generated, see :py:meth:`ecoli.library.schema.UniqueNumpyUpdater.updater`. + are generated, see :py:meth:`ecoli.library.schema.create_unique_indices`. + Note that unique indices are only unique for a cell and its ancestors. For + example, two daughter cells from the same parent cell will have conflicting + unique indices. 2. ``_entryState`` (:py:attr:`numpy.int8`): 1 for active row, 0 for inactive row When unique molecules are deleted (e.g. RNA degradation), all of their data, including the ``_entryState`` field, is set to 0. When unique molecues are diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index d57bdc2f8..5df0a32ca 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -136,12 +136,6 @@ def __init__(self, parameters=None): self.emit_unique = self.parameters.get("emit_unique", True) - self.chromosome_segment_index = 0 - self.promoter_index = 60000 - self.DnaA_box_index = 60000 - - self.random_state = np.random.RandomState(seed=self.parameters["seed"]) - def ports_schema(self): ports = { "listeners": { @@ -544,17 +538,9 @@ def get_removed_molecules_mask(domain_indexes, coordinates): ) # Add new chromosomal segments - n_segments = len(all_new_linking_numbers) - - self.chromosome_segment_index = chromosomal_segment_indexes.max() + 1 - update["chromosomal_segments"].update( { "add": { - "unique_index": np.arange( - self.chromosome_segment_index, - self.chromosome_segment_index + n_segments, - ), "boundary_molecule_indexes": all_new_boundary_molecule_indexes, "boundary_coordinates": all_new_boundary_coordinates, "domain_index": all_new_segment_domain_indexes, From 75d14990e28dc61def7ff265f287334f83648039 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Wed, 4 Dec 2024 21:04:02 -0800 Subject: [PATCH 10/54] Fit RNA deg Km with minimization --- .../ecoli/dataclasses/process/rna_decay.py | 167 ++++-------------- reconstruction/ecoli/fit_sim_data_1.py | 135 +++++--------- 2 files changed, 81 insertions(+), 221 deletions(-) diff --git a/reconstruction/ecoli/dataclasses/process/rna_decay.py b/reconstruction/ecoli/dataclasses/process/rna_decay.py index 065e9ec59..bdd6b7116 100644 --- a/reconstruction/ecoli/dataclasses/process/rna_decay.py +++ b/reconstruction/ecoli/dataclasses/process/rna_decay.py @@ -56,166 +56,63 @@ def km_loss_function(self, vMax, rnaConc, kDeg, isEndoRnase, alpha): Generates the functions used for estimating the per-RNA affinities (Michaelis-Menten constants) to the endoRNAses. - The optimization problem is formulated as a multidimensional root-finding problem; the goal - is to find a set of Michaelis-Menten constants such that the endoRNAse-mediated degradation - under basal concentrations is consistent with the experimentally observed half-lives, thus + The goal is to find a set of Michaelis-Menten constants such that the + endoRNAse-mediated degradation under basal concentrations is consistent + with the experimentally observed half-lives. - (nonlinear rate) = (linear rate) + If ``nonlinear`` is the rate of degradation predicted by Michaelis-Menten kinetics + and ``linear`` is the rate of degradation from observed half-lives, we want:: - where the nonlinear rate is the rate as predicted from some kinetic rate law, and the - linear rate is proportional to the inverse of the observed half-life. Then, reordering, + nonlinear - linear = 0 - 0 = (nonlinear rate) - (linear rate) + In reality, there will be residuals ``R_aux = ``nonlinear - linear``. We care about + the residuals after normalizing by the linear rate:: ``R = nonlinear / linear - 1``. - is (for the moment) the root we wish to find, for each RNA species, giving us the - multidimensional function + In order to turn this into a minimization problem, we define the loss function + as the squared sum of the residuals. Additionally, to ensure that all Km values + are positive, the loss function accepts as input the logarithm of the final Km + values and exponentiates them before calculating the residuals. - R_aux = (nonlinear rate) - (linear rate) - - This is the unnormalized residual function; the normalized residuals are - - R = (nonlinear rate)/(linear rate) - 1 - - In addition to matching our half-lives we also desire the Michaelis-Menten constants to be - non-negative (negative values have no physical meaning). Thus we introduce a penalty term - for negative values. TODO (John): explain penalty term - - The two terms (the residuals R and the negative value penalty Rneg) are combined into one - 'loss' function L (alpha is the weighting on the negative value penalty): - - L = ln((exp(R) + exp(alpha*Rneg))/2) - = ln(exp(R) + exp(alpha*Rneg)) - ln(2) - - The loss function has one element for each RNA. This functional form is a soft - (continuous and differentiable) approximation to - - L = max(R, alpha*Rneg) - - The root finder, provided with L, will attempt to make each element of L as close to zero - as possible, and therefore minimize both R and Rneg. - - The third-party package Jax uses autodiff to calculate the Jacobian. + The third-party package Jax uses autodiff to calculate Jacobians for our loss + function that can be used during minimization. Parameters ---------- - vMax: scalar - The total endoRNAse capacity, in dimensions of amount per volume per time. - rnaConc: 1-D array, float - Concentrations of RNAs (that will be degraded), in dimensions of amount per volume. - kDeg: 1-D array, float - Experimentally observed degradation rates (computed from half-lives), in dimensions of - per unit time. - isEndoRnase: 1-D array, bool - A vector that is True everywhere that an RNA corresponds to an endoRNAse; that is, an - endoRNAse (or endoRNAse subunit) mRNA. - alpha: scalar, >0 - Regularization weight, used to penalize for negative Michaelis-Menten value predictions - during the course of the optimization. Typical value is 0.5. + vMax (float): The total endoRNase capacity, in units of amount per volume per time. + rnaConc (np.ndarray): Concentrations of RNAs (amount per volume). + kDeg (np.ndarray): Experimental degradation rates (per unit time). + isEndoRnase (np.ndarray): Boolean array indicating endoRNase RNAs. Returns ------- - L: function - The 'loss' function. - Rneg: function - The negative Michaelis-Menten constant penalty terms. - R: function - The residual error (deviation from steady-state). - Lp: function - The Jacobian of the loss function L with respect to the Michaelis-Menten constants. - R_aux: function - Unnormalized 'residual' function. - L_aux: function - Unnormalized 'loss' function. - Lp_aux: function - Jacobian of the unnormalized 'loss' function. - Jacob: function - Duplicate with Lp. - Jacob_aux: function - Duplicate with Lp_aux. - - Notes - ----- - The regularization term also includes a penalty for the endoRNAse residuals, as well as a - fixed weighting (WFendoR = 0.1). - TODO (John): Why is this needed? It seems redundant. - TODO (John): How do we know this weight is sufficient? - - All of the outputs are functions, and take a 1-D array of Michaelis-Menten constants - as their sole inputs. All of the functions return a 1-D array, with the exception of the - Jacobians, which return matrices. - - TODO (John): Remove the redundant outputs. - - TODO (John): Consider redesigning this as an objective minimization problem rather than a - root finding problem. - - TODO (John): Consider replacing the Michaelis-Menten constants with logarithmic - equivalents, thereby eliminating the requirement for the negative value penalty. - - TODO (John): Consider moving this method out of this class, as it is, in fact, a static - method, and isn't utilized anywhere within this class. + tuple: + A tuple containing the following functions: + + - **L** (*function*): The loss function to minimize. + - **Lp** (*function*): The Jacobian of the loss function `L`. + - **residual_f** (*function*): The residual error function. + - **residual_aux_f** (*function*): The unnormalized residual error function. """ def residual_f(km): - return vMax / km / kDeg / (1 + (rnaConc / km).sum()) - 1 + return vMax / km / kDeg / (1 + jnp.sum(rnaConc / km)) - 1 def residual_aux_f(km): - return vMax * rnaConc / km / (1 + (rnaConc / km).sum()) - kDeg * rnaConc - - def regularizationNegativeNumbers_f(km): - return (1 - km / jnp.abs(km)).sum() / rnaConc.size + return vMax * rnaConc / km / (1 + jnp.sum(rnaConc / km)) - kDeg * rnaConc - def L(km): - residual = residual_f(km) - regularizationNegativeNumbers = regularizationNegativeNumbers_f(km) - - # Regularization for endoRNAse Km values - regularizationEndoR = (isEndoRnase * jnp.abs(residual)).sum() - - # Multi-objective regularization - WFendoR = 0.1 # weighting factor to protect Km optimized of EndoRNases - regularization = ( - regularizationNegativeNumbers + WFendoR * regularizationEndoR - ) + def L(log_km): + km = jnp.exp(log_km) + residual_squared = residual_f(km) ** 2 # Loss function - return jnp.log( - jnp.exp(residual) + jnp.exp(alpha * regularization) - ) - jnp.log(2) - - def L_aux(km): - residual = residual_f(km) - residual_aux = residual_aux_f(km) - regularizationNegativeNumbers = regularizationNegativeNumbers_f(km) - - # Regularization for endoRNAse Km values - regularizationEndoR = (isEndoRnase * jnp.abs(residual)).sum() - - # Multi-objective regularization - WFendoR = 0.1 # weighting factor to protect Km optimized of EndoRNases - regularization = ( - regularizationNegativeNumbers + WFendoR * regularizationEndoR - ) - - # Loss function - return jnp.log( - jnp.exp(residual_aux) + jnp.exp(alpha * regularization) - ) - jnp.log(2) + return jnp.sum(residual_squared) def Lp(km): return jacfwd(L)(km) - def Lp_aux(km): - return jacfwd(L_aux)(km) - return ( L, - regularizationNegativeNumbers_f, - residual_f, Lp, + residual_f, residual_aux_f, - L_aux, - Lp_aux, - Lp, - Lp_aux, ) diff --git a/reconstruction/ecoli/fit_sim_data_1.py b/reconstruction/ecoli/fit_sim_data_1.py index f7d41a3d0..acf6e1d9d 100644 --- a/reconstruction/ecoli/fit_sim_data_1.py +++ b/reconstruction/ecoli/fit_sim_data_1.py @@ -4227,23 +4227,18 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: if VERBOSE: print("Alpha = %f" % alpha) - LossFunction, Rneg, R, LossFunctionP, R_aux, L_aux, Lp_aux, Jacob, Jacob_aux = ( - sim_data.process.rna_decay.km_loss_function( - total_endo_rnase_capacity_mol_l_s, - rna_conc_mol_l, - degradation_rates_s, - isEndoRnase, - alpha, - ) + loss, loss_jac, res, res_aux = sim_data.process.rna_decay.km_loss_function( + total_endo_rnase_capacity_mol_l_s, + rna_conc_mol_l, + degradation_rates_s, + isEndoRnase, + alpha, ) - Km_cooperative_model = scipy.optimize.fsolve( - LossFunction, Km_counts, fprime=LossFunctionP + Km_cooperative_model = np.exp( + scipy.optimize.minimize(loss, np.log(Km_counts), jac=loss_jac).x ) sim_data.process.rna_decay.sensitivity_analysis_alpha_residual[alpha] = np.sum( - np.abs(R_aux(Km_cooperative_model)) - ) - sim_data.process.rna_decay.sensitivity_analysis_alpha_regulari_neg[alpha] = ( - np.sum(np.abs(Rneg(Km_cooperative_model))) + np.abs(res_aux(Km_cooperative_model)) ) alpha = 0.5 @@ -4258,40 +4253,36 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: print("Kcat = %f" % kcat) totalEndoRNcap = units.sum(endoRNaseConc * kcat) - LossFunction, Rneg, R, LossFunctionP, R_aux, L_aux, Lp_aux, Jacob, Jacob_aux = ( - sim_data.process.rna_decay.km_loss_function( - totalEndoRNcap.asNumber(units.mol / units.L), - rna_conc_mol_l, - degradation_rates_s, - isEndoRnase, - alpha, - ) + loss, loss_jac, res, res_aux = sim_data.process.rna_decay.km_loss_function( + totalEndoRNcap.asNumber(units.mol / units.L), + rna_conc_mol_l, + degradation_rates_s, + isEndoRnase, + alpha, ) - KmcountsIni = ( + km_counts_ini = ( (totalEndoRNcap / degradation_rates.asNumber()) - rna_conc ).asNumber() - Km_cooperative_model = scipy.optimize.fsolve( - LossFunction, KmcountsIni, fprime=LossFunctionP + Km_cooperative_model = np.exp( + scipy.optimize.minimize(loss, np.log(km_counts_ini), jac=loss_jac).x ) sim_data.process.rna_decay.sensitivity_analysis_kcat[kcat] = ( Km_cooperative_model ) sim_data.process.rna_decay.sensitivity_analysis_kcat_res_ini[kcat] = np.sum( - np.abs(R_aux(Km_counts)) + np.abs(res_aux(km_counts_ini)) ) sim_data.process.rna_decay.sensitivity_analysis_kcat_res_opt[kcat] = np.sum( - np.abs(R_aux(Km_cooperative_model)) + np.abs(res_aux(Km_cooperative_model)) ) # Loss function, and derivative - LossFunction, Rneg, R, LossFunctionP, R_aux, L_aux, Lp_aux, Jacob, Jacob_aux = ( - sim_data.process.rna_decay.km_loss_function( - total_endo_rnase_capacity_mol_l_s, - rna_conc_mol_l, - degradation_rates_s, - isEndoRnase, - alpha, - ) + loss, loss_jac, res, res_aux = sim_data.process.rna_decay.km_loss_function( + total_endo_rnase_capacity_mol_l_s, + rna_conc_mol_l, + degradation_rates_s, + isEndoRnase, + alpha, ) # The checksum in the filename picks independent caches for distinct cases @@ -4315,7 +4306,7 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: Km_cooperative_model = Km_cache["Km_cooperative_model"] if ( Km_counts.shape != Km_cooperative_model.shape - or np.sum(np.abs(R_aux(Km_cooperative_model))) > 1e-15 + or np.sum(np.abs(res_aux(Km_cooperative_model))) > 1e-15 or arrays_differ( Km_cache["total_endo_rnase_capacity_mol_l_s"], total_endo_rnase_capacity_mol_l_s, @@ -4330,9 +4321,8 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: if needToUpdate: if VERBOSE: print(f"Running non-linear optimization to {needToUpdate} {km_filepath}") - Km_cooperative_model = scipy.optimize.fsolve( - LossFunction, Km_counts, fprime=LossFunctionP - ) + sol = scipy.optimize.minimize(loss, np.log(Km_counts), jac=loss_jac) + Km_cooperative_model = np.exp(sol.x) Km_cache = dict( Km_cooperative_model=Km_cooperative_model, total_endo_rnase_capacity_mol_l_s=total_endo_rnase_capacity_mol_l_s, @@ -4350,82 +4340,55 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: ) ) + # Calculate log Km for loss functions + log_Km_cooperative_model = np.log(Km_cooperative_model) + log_Km_counts = np.log(Km_counts) + if VERBOSE > 1: - print( - "Loss function (Km inital) = %f" % np.sum(np.abs(LossFunction(Km_counts))) - ) + print("Loss function (Km inital) = %f" % np.sum(np.abs(loss(log_Km_counts)))) print( "Loss function (optimized Km) = %f" - % np.sum(np.abs(LossFunction(Km_cooperative_model))) + % np.sum(np.abs(loss(log_Km_cooperative_model))) ) - print("Negative km ratio = %f" % np.sum(np.abs(Rneg(Km_cooperative_model)))) - print("Residuals (Km initial) = %f" % np.sum(np.abs(R(Km_counts)))) - print("Residuals optimized = %f" % np.sum(np.abs(R(Km_cooperative_model)))) + print("Residuals (Km initial) = %f" % np.sum(np.abs(res(Km_counts)))) + print("Residuals optimized = %f" % np.sum(np.abs(res(Km_cooperative_model)))) print( "EndoR residuals (Km initial) = %f" - % np.sum(np.abs(isEndoRnase * R(Km_counts))) + % np.sum(np.abs(isEndoRnase * res(Km_counts))) ) print( "EndoR residuals optimized = %f" - % np.sum(np.abs(isEndoRnase * R(Km_cooperative_model))) + % np.sum(np.abs(isEndoRnase * res(Km_cooperative_model))) ) print( "Residuals (scaled by Kdeg * RNAcounts) Km initial = %f" - % np.sum(np.abs(R_aux(Km_counts))) + % np.sum(np.abs(res_aux(Km_counts))) ) print( "Residuals (scaled by Kdeg * RNAcounts) optimized = %f" - % np.sum(np.abs(R_aux(Km_cooperative_model))) - ) - - # Evaluate Jacobian around solutions (Kmcounts and KmCooperativeModel) - JacobDiag = np.diag(Jacob(Km_cooperative_model)) - Jacob_auxDiag = np.diag(Jacob_aux(Km_cooperative_model)) - - # Compute convergence of non-linear optimization: g'(Km) - Gkm = np.abs(1.0 - JacobDiag) - Gkm_aux = np.abs(1.0 - Jacob_auxDiag) - sim_data.process.rna_decay.Km_convergence = Gkm_aux - - # Convergence is guaranteed if g'(Km) <= K < 1 - if VERBOSE: - print( - "Convergence (Jacobian) = %.0f%% ( = %.5f)" - % (len(Gkm[Gkm < 1.0]) / float(len(Gkm)) * 100.0, np.mean(Gkm)) - ) - print( - "Convergence (Jacobian_aux) = %.0f%% ( = %.5f)" - % ( - len(Gkm_aux[Gkm_aux < 1.0]) / float(len(Gkm_aux)) * 100.0, - np.mean(Gkm_aux[Gkm_aux < 1.0]), - ) + % np.sum(np.abs(res_aux(Km_cooperative_model))) ) # Save statistics KM optimization - sim_data.process.rna_decay.stats_fit["LossKm"] = np.sum( - np.abs(LossFunction(Km_counts)) - ) + sim_data.process.rna_decay.stats_fit["LossKm"] = np.sum(np.abs(loss(log_Km_counts))) sim_data.process.rna_decay.stats_fit["LossKmOpt"] = np.sum( - np.abs(LossFunction(Km_cooperative_model)) - ) - sim_data.process.rna_decay.stats_fit["RnegKmOpt"] = np.sum( - np.abs(Rneg(Km_cooperative_model)) + np.abs(loss(log_Km_cooperative_model)) ) - sim_data.process.rna_decay.stats_fit["ResKm"] = np.sum(np.abs(R(Km_counts))) + sim_data.process.rna_decay.stats_fit["ResKm"] = np.sum(np.abs(res(Km_counts))) sim_data.process.rna_decay.stats_fit["ResKmOpt"] = np.sum( - np.abs(R(Km_cooperative_model)) + np.abs(res(Km_cooperative_model)) ) sim_data.process.rna_decay.stats_fit["ResEndoRNKm"] = np.sum( - np.abs(isEndoRnase * R(Km_counts)) + np.abs(isEndoRnase * res(Km_counts)) ) sim_data.process.rna_decay.stats_fit["ResEndoRNKmOpt"] = np.sum( - np.abs(isEndoRnase * R(Km_cooperative_model)) + np.abs(isEndoRnase * res(Km_cooperative_model)) ) sim_data.process.rna_decay.stats_fit["ResScaledKm"] = np.sum( - np.abs(R_aux(Km_counts)) + np.abs(res_aux(Km_counts)) ) sim_data.process.rna_decay.stats_fit["ResScaledKmOpt"] = np.sum( - np.abs(R_aux(Km_cooperative_model)) + np.abs(res_aux(Km_cooperative_model)) ) return units.mol / units.L * Km_cooperative_model From 7b068a7a8451f75b4d96e06539276ecadf619302 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Fri, 6 Dec 2024 02:01:29 -0800 Subject: [PATCH 11/54] 64-bit Jax and sweet spot minimization tolerance --- reconstruction/ecoli/dataclasses/process/rna_decay.py | 3 ++- reconstruction/ecoli/fit_sim_data_1.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/reconstruction/ecoli/dataclasses/process/rna_decay.py b/reconstruction/ecoli/dataclasses/process/rna_decay.py index bdd6b7116..db5c8ce89 100644 --- a/reconstruction/ecoli/dataclasses/process/rna_decay.py +++ b/reconstruction/ecoli/dataclasses/process/rna_decay.py @@ -4,10 +4,11 @@ from wholecell.utils import units -from jax import jacfwd +from jax import config, jacfwd import jax.numpy as jnp import numpy as np +config.update("jax_enable_x64", True) class RnaDecay(object): """RnaDecay""" diff --git a/reconstruction/ecoli/fit_sim_data_1.py b/reconstruction/ecoli/fit_sim_data_1.py index acf6e1d9d..05b1b35f3 100644 --- a/reconstruction/ecoli/fit_sim_data_1.py +++ b/reconstruction/ecoli/fit_sim_data_1.py @@ -4321,7 +4321,7 @@ def arrays_differ(a: np.ndarray, b: np.ndarray) -> bool: if needToUpdate: if VERBOSE: print(f"Running non-linear optimization to {needToUpdate} {km_filepath}") - sol = scipy.optimize.minimize(loss, np.log(Km_counts), jac=loss_jac) + sol = scipy.optimize.minimize(loss, np.log(Km_counts), jac=loss_jac, tol=1e-8) Km_cooperative_model = np.exp(sol.x) Km_cache = dict( Km_cooperative_model=Km_cooperative_model, From 42b296dc21fa7ca631a656fb2d9dc843a211cefa Mon Sep 17 00:00:00 2001 From: thalassemia Date: Fri, 6 Dec 2024 21:12:46 -0800 Subject: [PATCH 12/54] Start setting up uv install --- .gitignore | 13 +- pyproject.toml | 78 + uv.lock | 3683 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 3762 insertions(+), 12 deletions(-) create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.gitignore b/.gitignore index 771c9a5af..d6cbc365b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ /build /dist /doc/_build -/vivarium_ecoli.egg-info +/vEcoli.egg-info /Build_sequences.egg-info /Fast_polymerize_sums.egg-info /Monte_carlo_complexation.egg-info @@ -38,12 +38,6 @@ __pycache__ .python-version .pytest_cache -# Pipenv files # -################ -Pipfile -Pipfile.lock -pyproject.toml - # VS Code files # ################# /.vscode @@ -61,8 +55,3 @@ cache/ ################## .nextflow* nextflow_temp - -# Other files # -################## -/notebooks/ck/ -/notebooks/ck_example/ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..2df0c4fc2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,78 @@ +[build-system] +requires = [ + "setuptools", + "wheel", + "Cython", + "numpy" +] +build-backend = "setuptools.build_meta" + +[project] +name = "vEcoli" +version = "1.1.0" +description = "Whole Cell E. coli Model" +requires-python = "==3.12.8" +dependencies = [ + "numpy", + "scipy", + "biopython", + "cvxpy", + "cython", + "dill", + "duckdb", + "ete3", + "gcsfs", + "pyarrow", + "hvplot", + "ipdb", + "ipython", + "jupyter", + "line-profiler", + "altair", + "numba", + "orjson", + # Can be removed once cvxpy supports newer ortools + "ortools<=9.9.3963", + "pandas", + "polars", + "pymunk", + "scikit-image", + "scikit-learn", + "seaborn", + "swiglpk", + "sympy", + "tqdm", + "unum", + "jax", + "vivarium-core", + "pysal", + "opencv-python-headless", + "statsmodels", + "ecos", + "nbclassic", + "matplotlib", + "pyqt5", + "iteround", + "wheel", + # Can change to regular stochastic-arrow once PR merged + "stochastic-arrow @ git+https://github.com/CovertLab/arrow@numpy2" +] + +[project.optional-dependencies] +dev = [ + "pytest", + "pytest-cov", + "mypy", + "ruff" +] + +[tool.setuptools] +packages = [ + "data", + "ecoli", + "migration", + "reconstruction", + "runscripts", + "validation", + "wholecell" +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 000000000..b128f72a9 --- /dev/null +++ b/uv.lock @@ -0,0 +1,3683 @@ +version = 1 +requires-python = "==3.12.8" +resolution-markers = [ + "platform_system == 'Darwin'", + "platform_machine == 'aarch64' and platform_system == 'Linux'", + "(platform_machine != 'aarch64' and platform_system != 'Darwin') or (platform_system != 'Darwin' and platform_system != 'Linux')", +] + +[[package]] +name = "absl-py" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/8f/fc001b92ecc467cc32ab38398bd0bfb45df46e7523bf33c2ad22a505f06e/absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff", size = 118055 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/ad/e0d3c824784ff121c03cc031f944bc7e139a8f1870ffd2845cc2dd76f6c4/absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308", size = 133706 }, +] + +[[package]] +name = "access" +version = "1.1.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/aa/f4abc735d9cae07162f60f5c9582df4aa97e44c469273311b0ab4c3b1b43/access-1.1.9.tar.gz", hash = "sha256:89d0043e3596854701b72c77dfedb677839a5b416a18362c222b7d321ad02138", size = 38560 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/e0/be59a75ad3d0b0fea7f8c6c55439772c4bb791406f3653aa25880ec68d7f/access-1.1.9-py3-none-any.whl", hash = "sha256:47e147aee8d44bbbad77ab45a8dbcd6bd39c038bca2f1c3613c07f9cb0ea9cec", size = 21998 }, +] + +[[package]] +name = "affine" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/98/d2f0bb06385069e799fc7d2870d9e078cfa0fa396dc8a2b81227d0da08b9/affine-2.4.0.tar.gz", hash = "sha256:a24d818d6a836c131976d22f8c27b8d3ca32d0af64c1d8d29deb7bafa4da1eea", size = 17132 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/f7/85273299ab57117850cc0a936c64151171fac4da49bc6fba0dad984a7c5f/affine-2.4.0-py3-none-any.whl", hash = "sha256:8a3df80e2b2378aef598a83c1392efd47967afec4242021a0b06b4c7cbc61a92", size = 15662 }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756 }, +] + +[[package]] +name = "aiohttp" +version = "3.11.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/c4/3b5a937b16f6c2a0ada842a9066aad0b7a5708427d4a202a07bf09c67cbb/aiohttp-3.11.10.tar.gz", hash = "sha256:b1fc6b45010a8d0ff9e88f9f2418c6fd408c99c211257334aff41597ebece42e", size = 7668832 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/17/1dbe2f619f77795409c1a13ab395b98ed1b215d3e938cacde9b8ffdac53d/aiohttp-3.11.10-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b78f053a7ecfc35f0451d961dacdc671f4bcbc2f58241a7c820e9d82559844cf", size = 704448 }, + { url = "https://files.pythonhosted.org/packages/e3/9b/112247ad47e9d7f6640889c6e42cc0ded8c8345dd0033c66bcede799b051/aiohttp-3.11.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab7485222db0959a87fbe8125e233b5a6f01f4400785b36e8a7878170d8c3138", size = 463829 }, + { url = "https://files.pythonhosted.org/packages/8a/36/a64b583771fc673062a7a1374728a6241d49e2eda5a9041fbf248e18c804/aiohttp-3.11.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cf14627232dfa8730453752e9cdc210966490992234d77ff90bc8dc0dce361d5", size = 455774 }, + { url = "https://files.pythonhosted.org/packages/e5/75/ee1b8f510978b3de5f185c62535b135e4fc3f5a247ca0c2245137a02d800/aiohttp-3.11.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076bc454a7e6fd646bc82ea7f98296be0b1219b5e3ef8a488afbdd8e81fbac50", size = 1682134 }, + { url = "https://files.pythonhosted.org/packages/87/46/65e8259432d5f73ca9ebf5edb645ef90e5303724e4e52477516cb4042240/aiohttp-3.11.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:482cafb7dc886bebeb6c9ba7925e03591a62ab34298ee70d3dd47ba966370d2c", size = 1736757 }, + { url = "https://files.pythonhosted.org/packages/03/f6/a6d1e791b7153fb2d101278f7146c0771b0e1569c547f8a8bc3035651984/aiohttp-3.11.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf3d1a519a324af764a46da4115bdbd566b3c73fb793ffb97f9111dbc684fc4d", size = 1793033 }, + { url = "https://files.pythonhosted.org/packages/a8/e9/1ac90733e36e7848693aece522936a13bf17eeb617da662f94adfafc1c25/aiohttp-3.11.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24213ba85a419103e641e55c27dc7ff03536c4873470c2478cce3311ba1eee7b", size = 1691609 }, + { url = "https://files.pythonhosted.org/packages/6d/a6/77b33da5a0bc04566c7ddcca94500f2c2a2334eecab4885387fffd1fc600/aiohttp-3.11.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b99acd4730ad1b196bfb03ee0803e4adac371ae8efa7e1cbc820200fc5ded109", size = 1619082 }, + { url = "https://files.pythonhosted.org/packages/48/94/5bf5f927d9a2fedd2c978adfb70a3680e16f46d178361685b56244eb52ed/aiohttp-3.11.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:14cdb5a9570be5a04eec2ace174a48ae85833c2aadc86de68f55541f66ce42ab", size = 1641186 }, + { url = "https://files.pythonhosted.org/packages/99/2d/e85103aa01d1064e51bc50cb51e7b40150a8ff5d34e5a3173a46b241860b/aiohttp-3.11.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7e97d622cb083e86f18317282084bc9fbf261801b0192c34fe4b1febd9f7ae69", size = 1646280 }, + { url = "https://files.pythonhosted.org/packages/7b/e0/44651fda8c1d865a51b3a81f1956ea55ce16fc568fe7a3e05db7fc22f139/aiohttp-3.11.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:012f176945af138abc10c4a48743327a92b4ca9adc7a0e078077cdb5dbab7be0", size = 1701862 }, + { url = "https://files.pythonhosted.org/packages/4e/1e/0804459ae325a5b95f6f349778fb465f29d2b863e522b6a349db0aaad54c/aiohttp-3.11.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44224d815853962f48fe124748227773acd9686eba6dc102578defd6fc99e8d9", size = 1734373 }, + { url = "https://files.pythonhosted.org/packages/07/87/b8f6721668cad74bcc9c7cfe6d0230b304d1250196b221e54294a0d78dbe/aiohttp-3.11.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c87bf31b7fdab94ae3adbe4a48e711bfc5f89d21cf4c197e75561def39e223bc", size = 1694343 }, + { url = "https://files.pythonhosted.org/packages/4b/20/42813fc60d9178ba9b1b86c58a5441ddb6cf8ffdfe66387345bff173bcff/aiohttp-3.11.10-cp312-cp312-win32.whl", hash = "sha256:06a8e2ee1cbac16fe61e51e0b0c269400e781b13bcfc33f5425912391a542985", size = 411118 }, + { url = "https://files.pythonhosted.org/packages/3a/51/df9c263c861ce93998b5ad2ba3212caab2112d5b66dbe91ddbe90c41ded4/aiohttp-3.11.10-cp312-cp312-win_amd64.whl", hash = "sha256:be2b516f56ea883a3e14dda17059716593526e10fb6303189aaf5503937db408", size = 437424 }, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, +] + +[[package]] +name = "altair" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "narwhals" }, + { name = "packaging" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/b1/f2969c7bdb8ad8bbdda031687defdce2c19afba2aa2c8e1d2a17f78376d8/altair-5.5.0.tar.gz", hash = "sha256:d960ebe6178c56de3855a68c47b516be38640b73fb3b5111c2a9ca90546dd73d", size = 705305 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl", hash = "sha256:91a310b926508d560fe0148d02a194f38b824122641ef528113d029fcd129f8c", size = 731200 }, +] + +[[package]] +name = "anyio" +version = "4.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/7a/4daaf3b6c08ad7ceffea4634ec206faeff697526421c20f07628c7372156/anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352", size = 93052 }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, +] + +[[package]] +name = "argon2-cffi" +version = "23.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argon2-cffi-bindings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124 }, +] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/e9/184b8ccce6683b0aa2fbb7ba5683ea4b9c5763f1356347f1312c32e3c66e/argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", size = 1779911 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/13/838ce2620025e9666aa8f686431f67a29052241692a3dd1ae9d3692a89d3/argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", size = 29658 }, + { url = "https://files.pythonhosted.org/packages/b3/02/f7f7bb6b6af6031edb11037639c697b912e1dea2db94d436e681aea2f495/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", size = 80583 }, + { url = "https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", size = 86168 }, + { url = "https://files.pythonhosted.org/packages/74/f6/4a34a37a98311ed73bb80efe422fed95f2ac25a4cacc5ae1d7ae6a144505/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", size = 82709 }, + { url = "https://files.pythonhosted.org/packages/74/2b/73d767bfdaab25484f7e7901379d5f8793cccbb86c6e0cbc4c1b96f63896/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", size = 83613 }, + { url = "https://files.pythonhosted.org/packages/4f/fd/37f86deef67ff57c76f137a67181949c2d408077e2e3dd70c6c42912c9bf/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", size = 84583 }, + { url = "https://files.pythonhosted.org/packages/6f/52/5a60085a3dae8fded8327a4f564223029f5f54b0cb0455a31131b5363a01/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", size = 88475 }, + { url = "https://files.pythonhosted.org/packages/8b/95/143cd64feb24a15fa4b189a3e1e7efbaeeb00f39a51e99b26fc62fbacabd/argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", size = 27698 }, + { url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", size = 30817 }, + { url = "https://files.pythonhosted.org/packages/5a/e4/bf8034d25edaa495da3c8a3405627d2e35758e44ff6eaa7948092646fdcc/argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", size = 53104 }, +] + +[[package]] +name = "arrow" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "types-python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, +] + +[[package]] +name = "async-lru" +version = "2.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/80/e2/2b4651eff771f6fd900d233e175ddc5e2be502c7eb62c0c42f975c6d36cd/async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627", size = 10019 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224", size = 6111 }, +] + +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "babel" +version = "2.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/ca/824b1195773ce6166d388573fc106ce56d4a805bd7427b624e063596ec58/beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051", size = 581181 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 }, +] + +[[package]] +name = "biopython" +version = "1.84" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/7f/eaca4de03f0ee06c9d578d2730fd55858a57cee3620c62d3bc17b5da5447/biopython-1.84.tar.gz", hash = "sha256:60fbe6f996e8a6866a42698c17e552127d99a9aab3259d6249fbaabd0e0cc7b4", size = 25793001 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/f6/a61af0d2c8c04e446bce4727e8124797132858f518b6d6543d0e7213abed/biopython-1.84-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ba58a6d76288333c5f178a426116953fa68204bd0cfc401694087dd4f96d0059", size = 2755863 }, + { url = "https://files.pythonhosted.org/packages/e9/1a/25c7df41987383070987f7b9842f48d3a33b0a78a85c2ca9d93ed810fa2a/biopython-1.84-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee3566f6dc3acf20e238540daf896f0af20cff531521bf41fdf5143f73e209ae", size = 2738072 }, + { url = "https://files.pythonhosted.org/packages/a2/b2/c7f2a0a151208c634ac1eaa5d6345899659b1d5a700a84ef2e4f2b0e80a9/biopython-1.84-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89ef3967f5a88b5bb6344bef75ae83386de53fed3966d5c8c334ad885f8db08a", size = 3186633 }, + { url = "https://files.pythonhosted.org/packages/46/37/7db2bcbb396edba3f767dd89ac23ef5adc35c7a92ef3912c06d1e71469e1/biopython-1.84-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61765b71f84814a1eeb55ab222f43330aa7ad3e55ab91e8b444706149c67a281", size = 3206061 }, + { url = "https://files.pythonhosted.org/packages/b2/12/6c9d73cbb8c9d19ab4187aaf187f967de6e83738947b7180fdd8bc9211a2/biopython-1.84-cp312-cp312-win32.whl", hash = "sha256:52b6098f47d6b90fc8a5e8579b81ee50047e9108f0976e69c891ae0c4817e42d", size = 2756622 }, + { url = "https://files.pythonhosted.org/packages/d1/53/91d12cc254a804c797afaefec91ede04bc1f7cbd788a04ebbea9e31ee0cf/biopython-1.84-cp312-cp312-win_amd64.whl", hash = "sha256:ecff2fcf5da29b600474c0bfcdbbac0f98b25e22fe60a853d0ee798c00f7396c", size = 2792652 }, +] + +[[package]] +name = "bleach" +version = "6.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, +] + +[[package]] +name = "bokeh" +version = "3.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "jinja2" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "pyyaml" }, + { name = "tornado" }, + { name = "xyzservices" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/9d/cc9c561e1db8cbecc5cfad972159020700fff2339bdaa316498ace1cb04c/bokeh-3.6.2.tar.gz", hash = "sha256:2f3043d9ecb3d5dc2e8c0ebf8ad55727617188d4e534f3e7208b36357e352396", size = 6247610 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/12/2c266a0dc57379c60b4e73a2f93e71343db4170bf26c5a76a74e7d8bce2a/bokeh-3.6.2-py3-none-any.whl", hash = "sha256:fddc4b91f8b40178c0e3e83dfcc33886d7803a3a1f041a840834255e435a18c2", size = 6866799 }, +] + +[[package]] +name = "cachetools" +version = "5.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/38/a0f315319737ecf45b4319a8cd1f3a908e29d9277b46942263292115eee7/cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a", size = 27661 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/07/14f8ad37f2d12a5ce41206c21820d8cb6561b728e51fad4530dff0552a67/cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292", size = 9524 }, +] + +[[package]] +name = "certifi" +version = "2024.8.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, +] + +[[package]] +name = "clarabel" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/93/fb4b178a6697d04690c392289bb504032116eaf9f46c501fb23eb42a069d/clarabel-0.9.0.tar.gz", hash = "sha256:0d6d3fe8800be5b4b5d40a8e14bd492667b3e46cc5dbe37677ce5ed25f0719d4", size = 199359 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/b9/e41f5316a2d4261c340d9fa6aa1694dd57d12cc45f1e5dfc5773d2b53d39/clarabel-0.9.0-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:702cc4666c0ccf893c936f9f1f55cbb3233ae2d5fa05f67b370ac3e7ec50f222", size = 1713421 }, + { url = "https://files.pythonhosted.org/packages/65/75/b4f2b5f4a0af6975c463efe9ef580debff98ade6795e6e885babf7527586/clarabel-0.9.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8ea616757b460153ead375b3dd3ce763d46fc3717248077bbfa7b2c844b1775f", size = 890154 }, + { url = "https://files.pythonhosted.org/packages/a5/2e/096e0bc32ffa7eadb69f6e768fbbc58acf0b0e4003db4bd70c79b1856c47/clarabel-0.9.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b5ae16d7dd87aabf72260cf9590ba0d037c52d48555bcf3a86b1f0d9cf88dd4", size = 1761144 }, + { url = "https://files.pythonhosted.org/packages/d9/1a/4319fa902c9c3e350d134d78d79baa61c6e2e5e51050861ecc147c73f6a7/clarabel-0.9.0-cp37-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:85cb560a5c4cdfb079e3437e21f0b62b69ba766ae082aeb96ced0b5763214077", size = 1831888 }, + { url = "https://files.pythonhosted.org/packages/8c/12/e92ba69884f84e0f16a9fb5093522924502995348f0269cc42ed062f2edc/clarabel-0.9.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0eaeb3fbb5a90b598700d5435c7f102592a1a79ee25df5a097e0af575838786b", size = 1784994 }, + { url = "https://files.pythonhosted.org/packages/2e/1f/ce55955a7ad5946cacd1f0aa76233ee354d4c357669ce81f1e5dc69be971/clarabel-0.9.0-cp37-abi3-win32.whl", hash = "sha256:759c2fa0ccc61ae1a02691c43753638a0ae793bf1de81c6f6763c346789a7e25", size = 699668 }, + { url = "https://files.pythonhosted.org/packages/36/be/110fe7ca190e024e3185d6351645346b785da6933ce3fb382d4811215f8c/clarabel-0.9.0-cp37-abi3-win_amd64.whl", hash = "sha256:d24e4ed1b686eb2fe2a1b6e77935af6ad62a2c044131e70801ec1d3ef3d33280", size = 736436 }, +] + +[[package]] +name = "click" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, +] + +[[package]] +name = "click-plugins" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/1d/45434f64ed749540af821fd7e42b8e4d23ac04b1eda7c26613288d6cd8a8/click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b", size = 8164 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/da/824b92d9942f4e472702488857914bdd50f73021efea15b4cad9aca8ecef/click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8", size = 7497 }, +] + +[[package]] +name = "cligj" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/0d/837dbd5d8430fd0f01ed72c4cfb2f548180f4c68c635df84ce87956cff32/cligj-0.7.2.tar.gz", hash = "sha256:a4bc13d623356b373c2c27c53dbd9c68cae5d526270bfa71f6c6fa69669c6b27", size = 9803 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/86/43fa9f15c5b9fb6e82620428827cd3c284aa933431405d1bcf5231ae3d3e/cligj-0.7.2-py3-none-any.whl", hash = "sha256:c1ca117dbce1fe20a5809dc96f01e1c2840f6dcc939b3ddbb1111bf330ba82df", size = 7069 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "colorcet" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/c3/ae78e10b7139d6b7ce080d2e81d822715763336aa4229720f49cb3b3e15b/colorcet-3.1.0.tar.gz", hash = "sha256:2921b3cd81a2288aaf2d63dbc0ce3c26dcd882e8c389cc505d6886bf7aa9a4eb", size = 2183107 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/c6/9963d588cc3d75d766c819e0377a168ef83cf3316a92769971527a1ad1de/colorcet-3.1.0-py3-none-any.whl", hash = "sha256:2a7d59cc8d0f7938eeedd08aad3152b5319b4ba3bcb7a612398cc17a384cb296", size = 260286 }, +] + +[[package]] +name = "comm" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180 }, +] + +[[package]] +name = "contourpy" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/c2/fc7193cc5383637ff390a712e88e4ded0452c9fbcf84abe3de5ea3df1866/contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699", size = 13465753 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/6b/175f60227d3e7f5f1549fcb374592be311293132207e451c3d7c654c25fb/contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509", size = 271494 }, + { url = "https://files.pythonhosted.org/packages/6b/6a/7833cfae2c1e63d1d8875a50fd23371394f540ce809d7383550681a1fa64/contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc", size = 255444 }, + { url = "https://files.pythonhosted.org/packages/7f/b3/7859efce66eaca5c14ba7619791b084ed02d868d76b928ff56890d2d059d/contourpy-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454", size = 307628 }, + { url = "https://files.pythonhosted.org/packages/48/b2/011415f5e3f0a50b1e285a0bf78eb5d92a4df000553570f0851b6e309076/contourpy-1.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80", size = 347271 }, + { url = "https://files.pythonhosted.org/packages/84/7d/ef19b1db0f45b151ac78c65127235239a8cf21a59d1ce8507ce03e89a30b/contourpy-1.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec", size = 318906 }, + { url = "https://files.pythonhosted.org/packages/ba/99/6794142b90b853a9155316c8f470d2e4821fe6f086b03e372aca848227dd/contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9", size = 323622 }, + { url = "https://files.pythonhosted.org/packages/3c/0f/37d2c84a900cd8eb54e105f4fa9aebd275e14e266736778bb5dccbf3bbbb/contourpy-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b", size = 1266699 }, + { url = "https://files.pythonhosted.org/packages/3a/8a/deb5e11dc7d9cc8f0f9c8b29d4f062203f3af230ba83c30a6b161a6effc9/contourpy-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d", size = 1326395 }, + { url = "https://files.pythonhosted.org/packages/1a/35/7e267ae7c13aaf12322ccc493531f1e7f2eb8fba2927b9d7a05ff615df7a/contourpy-1.3.1-cp312-cp312-win32.whl", hash = "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e", size = 175354 }, + { url = "https://files.pythonhosted.org/packages/a1/35/c2de8823211d07e8a79ab018ef03960716c5dff6f4d5bff5af87fd682992/contourpy-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d", size = 220971 }, +] + +[[package]] +name = "coverage" +version = "7.6.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/d2/c25011f4d036cf7e8acbbee07a8e09e9018390aee25ba085596c4b83d510/coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d", size = 801710 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/52/b16af8989a2daf0f80a88522bd8e8eed90b5fcbdecf02a6888f3e80f6ba7/coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8", size = 207325 }, + { url = "https://files.pythonhosted.org/packages/0f/79/6b7826fca8846c1216a113227b9f114ac3e6eacf168b4adcad0cb974aaca/coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a", size = 207563 }, + { url = "https://files.pythonhosted.org/packages/a7/07/0bc73da0ccaf45d0d64ef86d33b7d7fdeef84b4c44bf6b85fb12c215c5a6/coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015", size = 240580 }, + { url = "https://files.pythonhosted.org/packages/71/8a/9761f409910961647d892454687cedbaccb99aae828f49486734a82ede6e/coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3", size = 237613 }, + { url = "https://files.pythonhosted.org/packages/8b/10/ee7d696a17ac94f32f2dbda1e17e730bf798ae9931aec1fc01c1944cd4de/coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae", size = 239684 }, + { url = "https://files.pythonhosted.org/packages/16/60/aa1066040d3c52fff051243c2d6ccda264da72dc6d199d047624d395b2b2/coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4", size = 239112 }, + { url = "https://files.pythonhosted.org/packages/4e/e5/69f35344c6f932ba9028bf168d14a79fedb0dd4849b796d43c81ce75a3c9/coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6", size = 237428 }, + { url = "https://files.pythonhosted.org/packages/32/20/adc895523c4a28f63441b8ac645abd74f9bdd499d2d175bef5b41fc7f92d/coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f", size = 239098 }, + { url = "https://files.pythonhosted.org/packages/a9/a6/e0e74230c9bb3549ec8ffc137cfd16ea5d56e993d6bffed2218bff6187e3/coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692", size = 209940 }, + { url = "https://files.pythonhosted.org/packages/3e/18/cb5b88349d4aa2f41ec78d65f92ea32572b30b3f55bc2b70e87578b8f434/coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97", size = 210726 }, +] + +[[package]] +name = "cvxpy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "clarabel" }, + { name = "numpy" }, + { name = "osqp" }, + { name = "scipy" }, + { name = "scs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/ea/a17a84693b40d2370e876ad57d7db7e787ec1dea466cd42ddb8b4d3205b5/cvxpy-1.6.0.tar.gz", hash = "sha256:679a9531877dfe0e2defabe106bc62a3e7ea094a7fcfcb797e121127ff8ff39a", size = 1603379 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/68/bf7ce539485e3b3817ba5e5b0f5765485363db9dfc493c57ec2e085fac3e/cvxpy-1.6.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3ad0a0928dbd051d3e3b34bf76b078ee3e3b3b3418a86e406c048f9c06196ffa", size = 1479295 }, + { url = "https://files.pythonhosted.org/packages/59/89/bd47ad4f67f26b82d54ec980962b5ec252f80aabeba67986613894d1eba5/cvxpy-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc013ce8f868c2c25917a79c33e78ca6da7e9f4a498a35c3172a57a5d2626851", size = 1143566 }, + { url = "https://files.pythonhosted.org/packages/ba/17/81def8155f2e4fe0b7802b1f081ace0b9116cd232726a356b91a259a1139/cvxpy-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a4305e85cc4c916a560818f03fe61521492c7cd4d43783e9e8713ed9dd6854d", size = 1195034 }, + { url = "https://files.pythonhosted.org/packages/03/9c/e411ea2cf60dd41862bc27be88159a8f3ab4ab09c0f370fe3c95b1dc3f05/cvxpy-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12067d6a540037c0bf2d936961b84482002a231f37a994b5c9adff71360ba7a2", size = 1220972 }, + { url = "https://files.pythonhosted.org/packages/53/bf/9763b0ba84cdbea29d09b1dcfa816bb2041a2ca1a3f1f7412722bafbac98/cvxpy-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca12f4045e6118a296e2fdbc451d4fa5f4c3bb1f4e8a770e5065b070144b9342", size = 1083986 }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, +] + +[[package]] +name = "cython" +version = "3.0.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/4d/b720d6000f4ca77f030bd70f12550820f0766b568e43f11af7f7ad9061aa/cython-3.0.11.tar.gz", hash = "sha256:7146dd2af8682b4ca61331851e6aebce9fe5158e75300343f80c07ca80b1faff", size = 2755544 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/50/fbb23239efe2183e4eaf76689270d6f5b3bbcf9be9ad1eb97cc34349e6fc/Cython-3.0.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:11996c40c32abf843ba652a6d53cb15944c88d91f91fc4e6f0028f5df8a8f8a1", size = 3141274 }, + { url = "https://files.pythonhosted.org/packages/87/e5/76379edb21fd5bb9e2aaa1d305492bc35bba96dfb51f5d96867d9863b6df/Cython-3.0.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63f2c892e9f9c1698ecfee78205541623eb31cd3a1b682668be7ac12de94aa8e", size = 3340904 }, + { url = "https://files.pythonhosted.org/packages/9a/ef/44af6aded89444dc45f4466ff207a05d3376c641cf1146c03fd14c55ae64/Cython-3.0.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b14c24f1dc4c4c9d997cca8d1b7fb01187a218aab932328247dcf5694a10102", size = 3514052 }, + { url = "https://files.pythonhosted.org/packages/e0/d5/ef8c7b6aa7a83c508f5c3bf0dfb9eb0a2a9be910c0b1f205f842128269c3/Cython-3.0.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8eed5c015685106db15dd103fd040948ddca9197b1dd02222711815ea782a27", size = 3573721 }, + { url = "https://files.pythonhosted.org/packages/e5/4a/58d6c208563504a35febff94904bb291b368a8b0f28a5e0593c770967caa/Cython-3.0.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780f89c95b8aec1e403005b3bf2f0a2afa060b3eba168c86830f079339adad89", size = 3393594 }, + { url = "https://files.pythonhosted.org/packages/a0/92/a60a400be286dc661609da9db903680bba1423362000b689cf8ef0aec811/Cython-3.0.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a690f2ff460682ea985e8d38ec541be97e0977fa0544aadc21efc116ff8d7579", size = 3601319 }, + { url = "https://files.pythonhosted.org/packages/ac/11/f02fc24d1a071b93e1d07497b0a528687b1f93bb4945c635119480fab3c0/Cython-3.0.11-cp312-cp312-win32.whl", hash = "sha256:2252b5aa57621848e310fe7fa6f7dce5f73aa452884a183d201a8bcebfa05a00", size = 2608335 }, + { url = "https://files.pythonhosted.org/packages/35/00/78ffea3a0ab176267a25ff049518b2582db7ac265bbf27944243d1a81ce2/Cython-3.0.11-cp312-cp312-win_amd64.whl", hash = "sha256:da394654c6da15c1d37f0b7ec5afd325c69a15ceafee2afba14b67a5df8a82c8", size = 2792586 }, + { url = "https://files.pythonhosted.org/packages/43/39/bdbec9142bc46605b54d674bf158a78b191c2b75be527c6dcf3e6dfe90b8/Cython-3.0.11-py2.py3-none-any.whl", hash = "sha256:0e25f6425ad4a700d7f77cd468da9161e63658837d1bc34861a9861a4ef6346d", size = 1171267 }, +] + +[[package]] +name = "debugpy" +version = "1.8.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/92/15b454c516c4c53cc8c03967e4be12b65a1ea36db3bb4513a7453f75c8d8/debugpy-1.8.9.zip", hash = "sha256:1339e14c7d980407248f09824d1b25ff5c5616651689f1e0f0e51bdead3ea13e", size = 4921695 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/ab/1420baf8404d2b499349a44de5037133e06d489009032ce016fedb66eea1/debugpy-1.8.9-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:957363d9a7a6612a37458d9a15e72d03a635047f946e5fceee74b50d52a9c8e2", size = 2504180 }, + { url = "https://files.pythonhosted.org/packages/58/ec/e0f88c6764314bda7887274e0b980812709b3d6363dcae124a49a9ceaa3c/debugpy-1.8.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e565fc54b680292b418bb809f1386f17081d1346dca9a871bf69a8ac4071afe", size = 4224563 }, + { url = "https://files.pythonhosted.org/packages/dd/49/d9ea004ee2e4531d2b528841689ee2ba01c6a4b58840efd15e57dd866a86/debugpy-1.8.9-cp312-cp312-win32.whl", hash = "sha256:3e59842d6c4569c65ceb3751075ff8d7e6a6ada209ceca6308c9bde932bcef11", size = 5163641 }, + { url = "https://files.pythonhosted.org/packages/b1/63/c8b0718024c1187a446316037680e1564bf063c6665c815f17b42c244aba/debugpy-1.8.9-cp312-cp312-win_amd64.whl", hash = "sha256:66eeae42f3137eb428ea3a86d4a55f28da9bd5a4a3d369ba95ecc3a92c1bba53", size = 5203862 }, + { url = "https://files.pythonhosted.org/packages/2d/23/3f5804202da11c950dc0caae4a62d0c9aadabdb2daeb5f7aa09838647b5d/debugpy-1.8.9-py2.py3-none-any.whl", hash = "sha256:cc37a6c9987ad743d9c3a14fa1b1a14b7e4e6041f9dd0c8abf8895fe7a97b899", size = 5166094 }, +] + +[[package]] +name = "decorator" +version = "5.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, +] + +[[package]] +name = "deprecation" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/d3/8ae2869247df154b64c1884d7346d412fed0c49df84db635aab2d1c40e62/deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff", size = 173788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/c3/253a89ee03fc9b9682f1541728eb66db7db22148cd94f89ab22528cd1e1b/deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a", size = 11178 }, +] + +[[package]] +name = "dill" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/43/86fe3f9e130c4137b0f1b50784dd70a5087b911fe07fa81e53e0c4c47fea/dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c", size = 187000 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/d1/e73b6ad76f0b1fb7f23c35c6d95dbc506a9c8804f43dda8cb5b0fa6331fd/dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a", size = 119418 }, +] + +[[package]] +name = "dnspython" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, +] + +[[package]] +name = "duckdb" +version = "1.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/d7/ec014b351b6bb026d5f473b1d0ec6bd6ba40786b9abbf530b4c9041d9895/duckdb-1.1.3.tar.gz", hash = "sha256:68c3a46ab08836fe041d15dcbf838f74a990d551db47cb24ab1c4576fc19351c", size = 12240672 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/ff/7ee500f4cff0d2a581c1afdf2c12f70ee3bf1a61041fea4d88934a35a7a3/duckdb-1.1.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:a433ae9e72c5f397c44abdaa3c781d94f94f4065bcbf99ecd39433058c64cb38", size = 15482881 }, + { url = "https://files.pythonhosted.org/packages/28/16/dda10da6bde54562c3cb0002ca3b7678e3108fa73ac9b7509674a02c5249/duckdb-1.1.3-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:d08308e0a46c748d9c30f1d67ee1143e9c5ea3fbcccc27a47e115b19e7e78aa9", size = 32349440 }, + { url = "https://files.pythonhosted.org/packages/2e/c2/06f7f7a51a1843c9384e1637abb6bbebc29367710ffccc7e7e52d72b3dd9/duckdb-1.1.3-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:5d57776539211e79b11e94f2f6d63de77885f23f14982e0fac066f2885fcf3ff", size = 16953473 }, + { url = "https://files.pythonhosted.org/packages/1a/84/9991221ef7dde79d85231f20646e1b12d645490cd8be055589276f62847e/duckdb-1.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e59087dbbb63705f2483544e01cccf07d5b35afa58be8931b224f3221361d537", size = 18491915 }, + { url = "https://files.pythonhosted.org/packages/aa/76/330fe16f12b7ddda0c664ba9869f3afbc8773dbe17ae750121d407dc0f37/duckdb-1.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ebf5f60ddbd65c13e77cddb85fe4af671d31b851f125a4d002a313696af43f1", size = 20150288 }, + { url = "https://files.pythonhosted.org/packages/c4/88/e4b08b7a5d08c0f65f6c7a6594de64431ce7df38d7258511417ba7989ad3/duckdb-1.1.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4ef7ba97a65bd39d66f2a7080e6fb60e7c3e41d4c1e19245f90f53b98e3ac32", size = 18296560 }, + { url = "https://files.pythonhosted.org/packages/1a/32/011e6e3ce14375a1ba01a588c119ad82be757f847c6b60207e0762d9ec3a/duckdb-1.1.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f58db1b65593ff796c8ea6e63e2e144c944dd3d51c8d8e40dffa7f41693d35d3", size = 21635270 }, + { url = "https://files.pythonhosted.org/packages/f2/eb/58d4e0eccdc7b3523c062d008ad9eef28edccf88591d1a78659c809fe6e8/duckdb-1.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:e86006958e84c5c02f08f9b96f4bc26990514eab329b1b4f71049b3727ce5989", size = 10955715 }, +] + +[[package]] +name = "ecos" +version = "2.0.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/5f/17716c533da95ed110815b159efa22b1064c8c41fd5c862f21aff7a7fec0/ecos-2.0.14.tar.gz", hash = "sha256:64b3201c0e0a7f0129050557c4ac50b00031e80a10534506dba1200c8dc1efe4", size = 142430 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/c3/84e392f2410f51fa557198937cc52a2e80f887c517ef4e3fb6d46e3bb008/ecos-2.0.14-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4a7e2704a3ef9acfb8146d594deff9942d3a0f0d0399de8fe2e0bd95e8b0855c", size = 92545 }, + { url = "https://files.pythonhosted.org/packages/82/12/42f4d953f9284571726b085f99e13bfa84522bf63bf2e7a81460013b09e6/ecos-2.0.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3cbb1a66ecf10955a1a4bcd6b99db55148000cb79fd176bfac26d98b21a4814", size = 222132 }, + { url = "https://files.pythonhosted.org/packages/56/9a/ca30572f3e3ff3cef6a0ea8aa6cdc12c36f9fefe559f65c7d6265713196a/ecos-2.0.14-cp312-cp312-win_amd64.whl", hash = "sha256:718eb62afb8e45426bcc365ebaf3ca9f610afcbb754de6073ef5f104da8fca1f", size = 72248 }, +] + +[[package]] +name = "esda" +version = "2.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "libpysal" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/5f/567e4f9589eff3d8187784eda7d7f34067487019a7f8d4734b6c1cee179e/esda-2.6.0.tar.gz", hash = "sha256:95a3732bf222f93509dff72300dd2ae5687ffefacd7862e56ab44a27297d5274", size = 44177113 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/1b/84eaa84fa0e2b56464665f1d2135e0afe8ab1df481e6aa1fcdcb480032d6/esda-2.6.0-py3-none-any.whl", hash = "sha256:d825247f1e3dd7bf63e59835989d934a5edc03ece6cb816bbccb3cd9a3f313fc", size = 135362 }, +] + +[[package]] +name = "ete3" +version = "3.1.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/59/f26e8bfab088a3989bf1f61b836637039758a22df2d9fc6be491c5a6ccef/ete3-3.1.3.tar.gz", hash = "sha256:06a3b7fa8ed90187b076a8dbbe5b1b62acee94201d3c6e822f55f449601ef6f2", size = 4768608 } + +[[package]] +name = "executing" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/e3/7d45f492c2c4a0e8e0fad57d081a7c8a0286cdd86372b070cca1ec0caa1e/executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab", size = 977485 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/fd/afcd0496feca3276f509df3dbd5dae726fcc756f1a08d9e25abe1733f962/executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", size = 25805 }, +] + +[[package]] +name = "fastjsonschema" +version = "2.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 }, +] + +[[package]] +name = "fiona" +version = "1.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "certifi" }, + { name = "click" }, + { name = "click-plugins" }, + { name = "cligj" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/51/e0/71b63839cc609e1d62cea2fc9774aa605ece7ea78af823ff7a8f1c560e72/fiona-1.10.1.tar.gz", hash = "sha256:b00ae357669460c6491caba29c2022ff0acfcbde86a95361ea8ff5cd14a86b68", size = 444606 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/ab/036c418d531afb74abe4ca9a8be487b863901fe7b42ddba1ba2fb0681d77/fiona-1.10.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:7338b8c68beb7934bde4ec9f49eb5044e5e484b92d940bc3ec27defdb2b06c67", size = 16114589 }, + { url = "https://files.pythonhosted.org/packages/ba/45/693c1cca53023aaf6e3adc11422080f5fa427484e7b85e48f19c40d6357f/fiona-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8c77fcfd3cdb0d3c97237965f8c60d1696a64923deeeb2d0b9810286cbe25911", size = 14754603 }, + { url = "https://files.pythonhosted.org/packages/dc/78/be204fb409b59876ef4658710a022794f16f779a3e9e7df654acc38b2104/fiona-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:537872cbc9bda7fcdf73851c91bc5338fca2b502c4c17049ccecaa13cde1f18f", size = 17223639 }, + { url = "https://files.pythonhosted.org/packages/7e/0d/914fd3c4c32043c2c512fa5021e83b2348e1b7a79365d75a0a37cb545362/fiona-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:41cde2c52c614457e9094ea44b0d30483540789e62fe0fa758c2a2963e980817", size = 24464921 }, +] + +[[package]] +name = "flexcache" +version = "0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/b0/8a21e330561c65653d010ef112bf38f60890051d244ede197ddaa08e50c1/flexcache-0.3.tar.gz", hash = "sha256:18743bd5a0621bfe2cf8d519e4c3bfdf57a269c15d1ced3fb4b64e0ff4600656", size = 15816 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/cd/c883e1a7c447479d6e13985565080e3fea88ab5a107c21684c813dba1875/flexcache-0.3-py3-none-any.whl", hash = "sha256:d43c9fea82336af6e0115e308d9d33a185390b8346a017564611f1466dcd2e32", size = 13263 }, +] + +[[package]] +name = "flexparser" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/99/b4de7e39e8eaf8207ba1a8fa2241dd98b2ba72ae6e16960d8351736d8702/flexparser-0.4.tar.gz", hash = "sha256:266d98905595be2ccc5da964fe0a2c3526fbbffdc45b65b3146d75db992ef6b2", size = 31799 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/5e/3be305568fe5f34448807976dc82fc151d76c3e0e03958f34770286278c1/flexparser-0.4-py3-none-any.whl", hash = "sha256:3738b456192dcb3e15620f324c447721023c0293f6af9955b481e91d00179846", size = 27625 }, +] + +[[package]] +name = "fonttools" +version = "4.55.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/3a/6ab28db8f90c99e6b502436fb642912b590c352d5ba83e0b22b46db209da/fonttools-4.55.2.tar.gz", hash = "sha256:45947e7b3f9673f91df125d375eb57b9a23f2a603f438a1aebf3171bffa7a205", size = 3492954 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/62/7ac990a52c2bb249e9de6de0036a24eba5a5a8e8446819ab5a5751a0a45e/fonttools-4.55.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:18f082445b8fe5e91c53e6184f4c1c73f3f965c8bcc614c6cd6effd573ce6c1a", size = 2754521 }, + { url = "https://files.pythonhosted.org/packages/4a/bd/a8034bf5d685f825cec0aca6759639277b1d3b0b1d38842b5f30edfb4176/fonttools-4.55.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c0f91adbbd706e8acd1db73e3e510118e62d0ffb651864567dccc5b2339f90", size = 2287092 }, + { url = "https://files.pythonhosted.org/packages/70/ad/edf4f4e0efdda8205893007d30d62da09f92d3f0b0f1a3faf85bd5df9952/fonttools-4.55.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d8ccce035320d63dba0c35f52499322f5531dbe85bba1514c7cea26297e4c54", size = 4782490 }, + { url = "https://files.pythonhosted.org/packages/7a/5f/f757e5860cc4f187fdf8eacf53abc92613cdbc55355e13ba07e2c937d217/fonttools-4.55.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96e126df9615df214ec7f04bebcf60076297fbc10b75c777ce58b702d7708ffb", size = 4854787 }, + { url = "https://files.pythonhosted.org/packages/92/1b/c647b89e5603f9ae9b8f14885dfaf523351eb9d0b5dcbafaf1512d0d4d97/fonttools-4.55.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:508ebb42956a7a931c4092dfa2d9b4ffd4f94cea09b8211199090d2bd082506b", size = 4763330 }, + { url = "https://files.pythonhosted.org/packages/57/09/117e2b5b2d2fcd607b360e241939a652505577c752f9ca15b2fb9e4fc540/fonttools-4.55.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1b9de46ef7b683d50400abf9f1578eaceee271ff51c36bf4b7366f2be29f498", size = 4990999 }, + { url = "https://files.pythonhosted.org/packages/b9/e5/9be5bd4bfb83187fb83f46b9be6676f653c08a430b975e0a3355fd248c37/fonttools-4.55.2-cp312-cp312-win32.whl", hash = "sha256:2df61d9fc15199cc86dad29f64dd686874a3a52dda0c2d8597d21f509f95c332", size = 2151234 }, + { url = "https://files.pythonhosted.org/packages/f3/c5/0eda5db19bd5fe3f6b8dc30ca5be512999b4923268b9b82fd14c211217b5/fonttools-4.55.2-cp312-cp312-win_amd64.whl", hash = "sha256:d337ec087da8216a828574aa0525d869df0a2ac217a2efc1890974ddd1fbc5b9", size = 2198133 }, + { url = "https://files.pythonhosted.org/packages/69/94/c4d8dfe26a971e00e34df99b46e9518425f59918c8993830e904171e21f9/fonttools-4.55.2-py3-none-any.whl", hash = "sha256:8e2d89fbe9b08d96e22c7a81ec04a4e8d8439c31223e2dc6f2f9fc8ff14bdf9f", size = 1100792 }, +] + +[[package]] +name = "fqdn" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, +] + +[[package]] +name = "frozenlist" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, + { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, + { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, + { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, + { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, + { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, + { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, + { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, + { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, + { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, + { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, + { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, + { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, + { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, + { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, + { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, +] + +[[package]] +name = "fsspec" +version = "2024.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/52/f16a068ebadae42526484c31f4398e62962504e5724a8ba5dc3409483df2/fsspec-2024.10.0.tar.gz", hash = "sha256:eda2d8a4116d4f2429db8550f2457da57279247dd930bb12f821b58391359493", size = 286853 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/b2/454d6e7f0158951d8a78c2e1eb4f69ae81beb8dca5fee9809c6c99e9d0d0/fsspec-2024.10.0-py3-none-any.whl", hash = "sha256:03b9a6785766a4de40368b88906366755e2819e758b83705c88cd7cb5fe81871", size = 179641 }, +] + +[[package]] +name = "gcsfs" +version = "2024.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "decorator" }, + { name = "fsspec" }, + { name = "google-auth" }, + { name = "google-auth-oauthlib" }, + { name = "google-cloud-storage" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e5/1e/1d8c4593d9e2eb04918fec43253ab152823d67ad51ad9e3ab6b3a78c431a/gcsfs-2024.10.0.tar.gz", hash = "sha256:5df54cfe568e8fdeea5aafa7fed695cdc69a9a674e991ca8c1ce634f5df1d314", size = 79588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/96/d60e835fb7d10166c77aef0c1fa30e634153c03a0f486786977b95f88fde/gcsfs-2024.10.0-py2.py3-none-any.whl", hash = "sha256:bb2d23547e61203ea2dda5fa6c4b91a0c34b74ebe8bb6ab1926f6c33381bceb2", size = 34953 }, +] + +[[package]] +name = "geopandas" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pyogrio" }, + { name = "pyproj" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/39/08/2cf5d85356e45b10b8d066cf4c3ba1e9e3185423c48104eed87e8afd0455/geopandas-1.0.1.tar.gz", hash = "sha256:b8bf70a5534588205b7a56646e2082fb1de9a03599651b3d80c99ea4c2ca08ab", size = 317736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/64/7d344cfcef5efddf9cf32f59af7f855828e9d74b5f862eddf5bfd9f25323/geopandas-1.0.1-py3-none-any.whl", hash = "sha256:01e147d9420cc374d26f51fc23716ac307f32b49406e4bd8462c07e82ed1d3d6", size = 323587 }, +] + +[[package]] +name = "giddy" +version = "2.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "esda" }, + { name = "libpysal" }, + { name = "quantecon" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/0b/14b02b3360ba02e718eef048ea4ebd9ea7f5334dc81dd670c3cc63f97ad8/giddy-2.3.5.tar.gz", hash = "sha256:e2b87b003aea7bff67095e152f23cafb9d26f08193e383538709777d3ba9940b", size = 11165667 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/19/9125c0ec03be4e4345b95c8a8490d4552fb224cb86ed27e0ef2d37d09e06/giddy-2.3.5-py3-none-any.whl", hash = "sha256:42730e5cbfbdce004470d8fb17b5319c5221476fe5f49d41430a059bd92ec824", size = 61087 }, +] + +[[package]] +name = "google-api-core" +version = "2.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/6b/b98553c2061c4e2186f5bbfb1aa1a6ef13fc0775c096d18595d3c99ba023/google_api_core-2.23.0.tar.gz", hash = "sha256:2ceb087315e6af43f256704b871d99326b1f12a9d6ce99beaedec99ba26a0ace", size = 160094 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/a4/c26886d57d90032c5f74c2e80aefdc38ec58551fc46bd4ce79fb2c9389fa/google_api_core-2.23.0-py3-none-any.whl", hash = "sha256:c20100d4c4c41070cf365f1d8ddf5365915291b5eb11b83829fbd1c999b5122f", size = 156554 }, +] + +[[package]] +name = "google-auth" +version = "2.36.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/71/4c5387d8a3e46e3526a8190ae396659484377a73b33030614dd3b28e7ded/google_auth-2.36.0.tar.gz", hash = "sha256:545e9618f2df0bcbb7dcbc45a546485b1212624716975a1ea5ae8149ce769ab1", size = 268336 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/9a/3d5087d27865c2f0431b942b5c4500b7d1b744dd3262fdc973a4c39d099e/google_auth-2.36.0-py2.py3-none-any.whl", hash = "sha256:51a15d47028b66fd36e5c64a82d2d57480075bccc7da37cde257fc94177a61fb", size = 209519 }, +] + +[[package]] +name = "google-auth-oauthlib" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "requests-oauthlib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/0f/1772edb8d75ecf6280f1c7f51cbcebe274e8b17878b382f63738fd96cee5/google_auth_oauthlib-1.2.1.tar.gz", hash = "sha256:afd0cad092a2eaa53cd8e8298557d6de1034c6cb4a740500b5357b648af97263", size = 24970 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/8e/22a28dfbd218033e4eeaf3a0533b2b54852b6530da0c0fe934f0cc494b29/google_auth_oauthlib-1.2.1-py2.py3-none-any.whl", hash = "sha256:2d58a27262d55aa1b87678c3ba7142a080098cbc2024f903c62355deb235d91f", size = 24930 }, +] + +[[package]] +name = "google-cloud-core" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/1f/9d1e0ba6919668608570418a9a51e47070ac15aeff64261fb092d8be94c0/google-cloud-core-2.4.1.tar.gz", hash = "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073", size = 35587 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/0f/2e2061e3fbcb9d535d5da3f58cc8de4947df1786fe6a1355960feb05a681/google_cloud_core-2.4.1-py2.py3-none-any.whl", hash = "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61", size = 29233 }, +] + +[[package]] +name = "google-cloud-storage" +version = "2.19.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/76/4d965702e96bb67976e755bed9828fa50306dca003dbee08b67f41dd265e/google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2", size = 5535488 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/94/6db383d8ee1adf45dc6c73477152b82731fa4c4a46d9c1932cc8757e0fd4/google_cloud_storage-2.19.0-py2.py3-none-any.whl", hash = "sha256:aeb971b5c29cf8ab98445082cbfe7b161a1f48ed275822f59ed3f1524ea54fba", size = 131787 }, +] + +[[package]] +name = "google-crc32c" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/67/72/c3298da1a3773102359c5a78f20dae8925f5ea876e37354415f68594a6fb/google_crc32c-1.6.0.tar.gz", hash = "sha256:6eceb6ad197656a1ff49ebfbbfa870678c75be4344feb35ac1edf694309413dc", size = 14472 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/41/65a91657d6a8123c6c12f9aac72127b6ac76dda9e2ba1834026a842eb77c/google_crc32c-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ed767bf4ba90104c1216b68111613f0d5926fb3780660ea1198fc469af410e9d", size = 30268 }, + { url = "https://files.pythonhosted.org/packages/59/d0/ee743a267c7d5c4bb8bd865f7d4c039505f1c8a4b439df047fdc17be9769/google_crc32c-1.6.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:62f6d4a29fea082ac4a3c9be5e415218255cf11684ac6ef5488eea0c9132689b", size = 30113 }, + { url = "https://files.pythonhosted.org/packages/25/53/e5e449c368dd26ade5fb2bb209e046d4309ed0623be65b13f0ce026cb520/google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c87d98c7c4a69066fd31701c4e10d178a648c2cac3452e62c6b24dc51f9fcc00", size = 32995 }, + { url = "https://files.pythonhosted.org/packages/52/12/9bf6042d5b0ac8c25afed562fb78e51b0641474097e4139e858b45de40a5/google_crc32c-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd5e7d2445d1a958c266bfa5d04c39932dc54093fa391736dbfdb0f1929c1fb3", size = 32614 }, + { url = "https://files.pythonhosted.org/packages/76/29/fc20f5ec36eac1eea0d0b2de4118c774c5f59c513f2a8630d4db6991f3e0/google_crc32c-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:7aec8e88a3583515f9e0957fe4f5f6d8d4997e36d0f61624e70469771584c760", size = 33445 }, +] + +[[package]] +name = "google-resumable-media" +version = "2.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/5a/0efdc02665dca14e0837b62c8a1a93132c264bd02054a15abb2218afe0ae/google_resumable_media-2.7.2.tar.gz", hash = "sha256:5280aed4629f2b60b847b0d42f9857fd4935c11af266744df33d8074cae92fe0", size = 2163099 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/35/b8d3baf8c46695858cb9d8835a53baa1eeb9906ddaf2f728a5f5b640fd1e/google_resumable_media-2.7.2-py2.py3-none-any.whl", hash = "sha256:3ce7551e9fe6d99e9a126101d2536612bb73486721951e9562fee0f90c6ababa", size = 81251 }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.66.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/a7/8e9cccdb1c49870de6faea2a2764fa23f627dd290633103540209f03524c/googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c", size = 114376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/0f/c0713fb2b3d28af4b2fded3291df1c4d4f79a00d15c2374a9e010870016c/googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed", size = 221682 }, +] + +[[package]] +name = "h11" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + +[[package]] +name = "holoviews" +version = "1.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bokeh" }, + { name = "colorcet" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "panel" }, + { name = "param" }, + { name = "pyviz-comms" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/6d/460e318557121a3d22fa1dd60db44cac7357cf83a2890b2f781a91b5be25/holoviews-1.20.0.tar.gz", hash = "sha256:29d183045fafa3d846deda999d9687b99b8abdc1a8c06712e54afa576bb02b3e", size = 4590760 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/89/8df4efa78df8b129847c8a7c0e492376cca62ab68453e5a20375a1c6291b/holoviews-1.20.0-py3-none-any.whl", hash = "sha256:dc810b6790e1dd2c90f16406b292e08db10efa377b2554e46755a130e12044c5", size = 5016222 }, +] + +[[package]] +name = "httpcore" +version = "1.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, +] + +[[package]] +name = "hvplot" +version = "0.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bokeh" }, + { name = "colorcet" }, + { name = "holoviews" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "panel" }, + { name = "param" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/09/e5fe45bf64fefadd4e4dd9cc64c9c9757e28562c88d5db94b9e560820e5f/hvplot-0.11.1.tar.gz", hash = "sha256:989ed0389189adc47edcd2601d2eab18bf366e74b07f5e2873e021323c4a14bb", size = 6979548 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/7c/9342dfd03f2bdad4d1e6f2532631d346557286ce254c40f7bd5e66abecc2/hvplot-0.11.1-py3-none-any.whl", hash = "sha256:1cef5bf1ab4157c50b5ee265da760a8034b8dbb7fc81867d6050962a2eab9b35", size = 161240 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "imageio" +version = "2.36.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/aa/2e7a49259339e691ff2b477ae0696b1784a09313c5872700bbbdd00a3030/imageio-2.36.1.tar.gz", hash = "sha256:e4e1d231f47f9a9e16100b0f7ce1a86e8856fb4d1c0fa2c4365a316f1746be62", size = 389522 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/f9/f78e7f5ac8077c481bf6b43b8bc736605363034b3d5eb3ce8eb79f53f5f1/imageio-2.36.1-py3-none-any.whl", hash = "sha256:20abd2cae58e55ca1af8a8dcf43293336a59adf0391f1917bf8518633cfc2cdf", size = 315435 }, +] + +[[package]] +name = "immutabledict" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/c5/4240186fbabc58fba41bbe17c5f0cd37ffd4c0b85a5029ab104f946df175/immutabledict-4.2.1.tar.gz", hash = "sha256:d91017248981c72eb66c8ff9834e99c2f53562346f23e7f51e7a5ebcf66a3bcc", size = 6228 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/56/25ca7b848164b7d93dbd5fc97dd7751700c93e324fe854afbeb562ee2f98/immutabledict-4.2.1-py3-none-any.whl", hash = "sha256:c56a26ced38c236f79e74af3ccce53772827cef5c3bce7cab33ff2060f756373", size = 4700 }, +] + +[[package]] +name = "inequality" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/cf/c64ec812f1bd2b05d6c10c6d97565a775fd80935388746138cac46cd6904/inequality-1.0.1.tar.gz", hash = "sha256:d42fc0d605228b52dc65b7988c95390c9035cd9f5060f61aab1c6b3bb9b519c3", size = 430540 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/70/01825bb1140513493cc0a12e1c736f80006a097ac20661ca87382f3e36a4/inequality-1.0.1-py3-none-any.whl", hash = "sha256:65b447f5f444b6e9998ecbe803f60023123a882da5a4e4c062fc5d6544ba28b8", size = 15789 }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + +[[package]] +name = "ipdb" +version = "0.13.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "ipython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130 }, +] + +[[package]] +name = "ipykernel" +version = "6.29.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "platform_system == 'Darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173 }, +] + +[[package]] +name = "ipython" +version = "8.30.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/8b/710af065ab8ed05649afa5bd1e07401637c9ec9fb7cfda9eac7e91e9fbd4/ipython-8.30.0.tar.gz", hash = "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e", size = 5592205 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/f3/1332ba2f682b07b304ad34cad2f003adcfeb349486103f4b632335074a7c/ipython-8.30.0-py3-none-any.whl", hash = "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321", size = 820765 }, +] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/69/fbeffffc05236398ebfcfb512b6d2511c622871dca1746361006da310399/ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8", size = 22208 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8", size = 26343 }, +] + +[[package]] +name = "ipywidgets" +version = "8.1.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "comm" }, + { name = "ipython" }, + { name = "jupyterlab-widgets" }, + { name = "traitlets" }, + { name = "widgetsnbextension" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/4c/dab2a281b07596a5fc220d49827fe6c794c66f1493d7a74f1df0640f2cc5/ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17", size = 116723 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245", size = 139767 }, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "arrow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, +] + +[[package]] +name = "iteround" +version = "1.0.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/c7/68d920f791cd99919d82dd6db9fc0aca3790dc8d67c69b559a447ca2a914/iteround-1.0.4-py3-none-any.whl", hash = "sha256:17947dd5479177e6fb186b0a3d5d594b55eedea14dc722c6da7e84bbed45f5b2", size = 7333 }, +] + +[[package]] +name = "jax" +version = "0.4.36" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jaxlib" }, + { name = "ml-dtypes" }, + { name = "numpy" }, + { name = "opt-einsum" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/79/b8033b443d15671725ef4aef7f756c8b0026a7add3e807981d4d7c6abba7/jax-0.4.36.tar.gz", hash = "sha256:088bff0575d01fc82682a9af4eb07433d60de7e5164686bd2cea3439492e608a", size = 1915594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/d5/1240192a0bc7b284bca9f753e69e92645afb82a6b2c3e1138520698938f4/jax-0.4.36-py3-none-any.whl", hash = "sha256:4d86a99fab7c25ea0deda2672b429ef650e5eac819884e74d35c32c6e86a5856", size = 2221127 }, +] + +[[package]] +name = "jaxlib" +version = "0.4.36" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ml-dtypes" }, + { name = "numpy" }, + { name = "scipy" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/0e/3b4a99c09431ee5820624d4dcf4efa7becd3c83b56ff0f09a078f4c421a2/jaxlib-0.4.36-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:5972aa85f6d771ecc8cc72148c1fa64250ca33cbdf2bf24407cdee8a5299d25d", size = 98718357 }, + { url = "https://files.pythonhosted.org/packages/d3/46/05e70a1236ec3782333b3e9469f971c9d45af2aa0aebf602acd9d76292eb/jaxlib-0.4.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5597908cd10418c0b42e9af807fc8112036703533cf501a5255a8fbf4011867e", size = 78596060 }, + { url = "https://files.pythonhosted.org/packages/8e/76/6b969cbf197b8c53c84c2642069722e84a3a260af084a8acbbf90ca444ea/jaxlib-0.4.36-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:fbbabaa287378a78a3cf9cbe4de30a1f6f19a99116feb4bd687ff256415cd442", size = 84053202 }, + { url = "https://files.pythonhosted.org/packages/fe/f2/7624a304426daa7b135b85caf1b8eccf879e7cb10bc074656ce628309cb0/jaxlib-0.4.36-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:be295abc209c980817db0488f21f1fbc0644f87326522895e2b9b64729106357", size = 100325610 }, + { url = "https://files.pythonhosted.org/packages/bb/8b/ded8420cd9198eb677869ffd557d9880af5833c7bf39e604e80b56550e09/jaxlib-0.4.36-cp312-cp312-win_amd64.whl", hash = "sha256:d4bbb5d2970628dcd3dabc28a5b97a1125ad3e06a1be822d340fd9f06f7449b3", size = 63338518 }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, +] + +[[package]] +name = "joblib" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/33/60135848598c076ce4b231e1b1895170f45fbcaeaa2c9d5e38b04db70c35/joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e", size = 2116621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", size = 301817 }, +] + +[[package]] +name = "json5" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/3d/bbe62f3d0c05a689c711cff57b2e3ac3d3e526380adb7c781989f075115c/json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559", size = 48202 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/42/797895b952b682c3dafe23b1834507ee7f02f4d6299b65aaa61425763278/json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa", size = 34049 }, +] + +[[package]] +name = "jsonpointer" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, +] + +[[package]] +name = "jsonschema" +version = "4.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, +] + +[package.optional-dependencies] +format-nongpl = [ + { name = "fqdn" }, + { name = "idna" }, + { name = "isoduration" }, + { name = "jsonpointer" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "uri-template" }, + { name = "webcolors" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2024.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 }, +] + +[[package]] +name = "jupyter" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipywidgets" }, + { name = "jupyter-console" }, + { name = "jupyterlab" }, + { name = "nbconvert" }, + { name = "notebook" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, +] + +[[package]] +name = "jupyter-client" +version = "8.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, +] + +[[package]] +name = "jupyter-console" +version = "6.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "pyzmq" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, +] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965 }, +] + +[[package]] +name = "jupyter-events" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "python-json-logger" }, + { name = "pyyaml" }, + { name = "referencing" }, + { name = "rfc3339-validator" }, + { name = "rfc3986-validator" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8d/53/7537a1aa558229bb0b1b178d814c9d68a9c697d3aecb808a1cb2646acf1f/jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22", size = 61516 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/94/059180ea70a9a326e1815176b2370da56376da347a796f8c4f0b830208ef/jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960", size = 18777 }, +] + +[[package]] +name = "jupyter-lsp" +version = "2.2.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/b4/3200b0b09c12bc3b72d943d923323c398eff382d1dcc7c0dbc8b74630e40/jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001", size = 48741 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", size = 69146 }, +] + +[[package]] +name = "jupyter-server" +version = "2.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "argon2-cffi" }, + { name = "jinja2" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "jupyter-events" }, + { name = "jupyter-server-terminals" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "overrides" }, + { name = "packaging" }, + { name = "prometheus-client" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pyzmq" }, + { name = "send2trash" }, + { name = "terminado" }, + { name = "tornado" }, + { name = "traitlets" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/34/88b47749c7fa9358e10eac356c4b97d94a91a67d5c935a73f69bc4a31118/jupyter_server-2.14.2.tar.gz", hash = "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b", size = 719933 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/e1/085edea6187a127ca8ea053eb01f4e1792d778b4d192c74d32eb6730fed6/jupyter_server-2.14.2-py3-none-any.whl", hash = "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd", size = 383556 }, +] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "terminado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656 }, +] + +[[package]] +name = "jupyterlab" +version = "4.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "async-lru" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyter-lsp" }, + { name = "jupyter-server" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "packaging" }, + { name = "setuptools" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6b/2b/a3b8005643a5583841e0ec3e5e187330f5d4e5f4be232b2f00a653ab2d3d/jupyterlab-4.3.2.tar.gz", hash = "sha256:3c0a6882dbddcc0a7bfdd5e2236f351b2b263e48780236e6996c2aca13ac5b22", size = 21797175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/fc/f12dbf6e3f44d8f95645c9142e40e7e7de1e7af284b286f35acf88df5b87/jupyterlab-4.3.2-py3-none-any.whl", hash = "sha256:e87100cbab8b886ff7a4f325c856100ba6fdfe916162a85409daf0e707e19d1d", size = 11664945 }, +] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, +] + +[[package]] +name = "jupyterlab-server" +version = "2.27.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "jinja2" }, + { name = "json5" }, + { name = "jsonschema" }, + { name = "jupyter-server" }, + { name = "packaging" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/c9/a883ce65eb27905ce77ace410d83587c82ea64dc85a48d1f7ed52bcfa68d/jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4", size = 76173 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", size = 59700 }, +] + +[[package]] +name = "jupyterlab-widgets" +version = "3.0.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/73/fa26bbb747a9ea4fca6b01453aa22990d52ab62dd61384f1ac0dc9d4e7ba/jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed", size = 203556 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/93/858e87edc634d628e5d752ba944c2833133a28fa87bb093e6832ced36a3e/jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54", size = 214392 }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/4d/2255e1c76304cbd60b48cee302b66d1dde4468dc5b1160e4b7cb43778f2a/kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60", size = 97286 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/9c/0a11c714cf8b6ef91001c8212c4ef207f772dd84540104952c45c1f0a249/kiwisolver-1.4.7-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:5360cc32706dab3931f738d3079652d20982511f7c0ac5711483e6eab08efff2", size = 121808 }, + { url = "https://files.pythonhosted.org/packages/f2/d8/0fe8c5f5d35878ddd135f44f2af0e4e1d379e1c7b0716f97cdcb88d4fd27/kiwisolver-1.4.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942216596dc64ddb25adb215c3c783215b23626f8d84e8eff8d6d45c3f29f75a", size = 65531 }, + { url = "https://files.pythonhosted.org/packages/80/c5/57fa58276dfdfa612241d640a64ca2f76adc6ffcebdbd135b4ef60095098/kiwisolver-1.4.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:48b571ecd8bae15702e4f22d3ff6a0f13e54d3d00cd25216d5e7f658242065ee", size = 63894 }, + { url = "https://files.pythonhosted.org/packages/8b/e9/26d3edd4c4ad1c5b891d8747a4f81b1b0aba9fb9721de6600a4adc09773b/kiwisolver-1.4.7-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad42ba922c67c5f219097b28fae965e10045ddf145d2928bfac2eb2e17673640", size = 1369296 }, + { url = "https://files.pythonhosted.org/packages/b6/67/3f4850b5e6cffb75ec40577ddf54f7b82b15269cc5097ff2e968ee32ea7d/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:612a10bdae23404a72941a0fc8fa2660c6ea1217c4ce0dbcab8a8f6543ea9e7f", size = 1461450 }, + { url = "https://files.pythonhosted.org/packages/52/be/86cbb9c9a315e98a8dc6b1d23c43cffd91d97d49318854f9c37b0e41cd68/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e838bba3a3bac0fe06d849d29772eb1afb9745a59710762e4ba3f4cb8424483", size = 1579168 }, + { url = "https://files.pythonhosted.org/packages/0f/00/65061acf64bd5fd34c1f4ae53f20b43b0a017a541f242a60b135b9d1e301/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f499f6157236c19f4bbbd472fa55b063db77a16cd74d49afe28992dff8c258", size = 1507308 }, + { url = "https://files.pythonhosted.org/packages/21/e4/c0b6746fd2eb62fe702118b3ca0cb384ce95e1261cfada58ff693aeec08a/kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693902d433cf585133699972b6d7c42a8b9f8f826ebcaf0132ff55200afc599e", size = 1464186 }, + { url = "https://files.pythonhosted.org/packages/0a/0f/529d0a9fffb4d514f2782c829b0b4b371f7f441d61aa55f1de1c614c4ef3/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4e77f2126c3e0b0d055f44513ed349038ac180371ed9b52fe96a32aa071a5107", size = 2247877 }, + { url = "https://files.pythonhosted.org/packages/d1/e1/66603ad779258843036d45adcbe1af0d1a889a07af4635f8b4ec7dccda35/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:657a05857bda581c3656bfc3b20e353c232e9193eb167766ad2dc58b56504948", size = 2404204 }, + { url = "https://files.pythonhosted.org/packages/8d/61/de5fb1ca7ad1f9ab7970e340a5b833d735df24689047de6ae71ab9d8d0e7/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4bfa75a048c056a411f9705856abfc872558e33c055d80af6a380e3658766038", size = 2352461 }, + { url = "https://files.pythonhosted.org/packages/ba/d2/0edc00a852e369827f7e05fd008275f550353f1f9bcd55db9363d779fc63/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:34ea1de54beef1c104422d210c47c7d2a4999bdecf42c7b5718fbe59a4cac383", size = 2501358 }, + { url = "https://files.pythonhosted.org/packages/84/15/adc15a483506aec6986c01fb7f237c3aec4d9ed4ac10b756e98a76835933/kiwisolver-1.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:90da3b5f694b85231cf93586dad5e90e2d71b9428f9aad96952c99055582f520", size = 2314119 }, + { url = "https://files.pythonhosted.org/packages/36/08/3a5bb2c53c89660863a5aa1ee236912269f2af8762af04a2e11df851d7b2/kiwisolver-1.4.7-cp312-cp312-win32.whl", hash = "sha256:18e0cca3e008e17fe9b164b55735a325140a5a35faad8de92dd80265cd5eb80b", size = 46367 }, + { url = "https://files.pythonhosted.org/packages/19/93/c05f0a6d825c643779fc3c70876bff1ac221f0e31e6f701f0e9578690d70/kiwisolver-1.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:58cb20602b18f86f83a5c87d3ee1c766a79c0d452f8def86d925e6c60fbf7bfb", size = 55884 }, + { url = "https://files.pythonhosted.org/packages/d2/f9/3828d8f21b6de4279f0667fb50a9f5215e6fe57d5ec0d61905914f5b6099/kiwisolver-1.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:f5a8b53bdc0b3961f8b6125e198617c40aeed638b387913bf1ce78afb1b0be2a", size = 48528 }, +] + +[[package]] +name = "lazy-loader" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6b/c875b30a1ba490860c93da4cabf479e03f584eba06fe5963f6f6644653d8/lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1", size = 15431 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc", size = 12097 }, +] + +[[package]] +name = "libpysal" +version = "4.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "geopandas" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "platformdirs" }, + { name = "requests" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/a0/677e134b2fcdf50bdb4584c56b7b575ee99eb0b219ea090f832e735aa5ba/libpysal-4.12.1.tar.gz", hash = "sha256:f4eda82d8f78d36ee0f95c5576b335f05d94513ac65b4976c3218b09bb0a1bb0", size = 9780388 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/b0/744e3d450813c645cd092147bd72a7bdec0e3f4c1c4f5e3ff663252c7027/libpysal-4.12.1-py3-none-any.whl", hash = "sha256:ce89d3c9aa944a7df052545ae37a5c802d707c672e04a76f7b1ee93f781110a9", size = 2819823 }, +] + +[[package]] +name = "line-profiler" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/55/3f/f0659eb67f76022b5f7722cdc71a6059536e11f20c9dcc5a96a2f923923d/line_profiler-4.2.0.tar.gz", hash = "sha256:09e10f25f876514380b3faee6de93fb0c228abba85820ba1a591ddb3eb451a96", size = 199037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/7c/f8330f4533434a90daa240ea9a3296e704a5d644339352316e20102add6f/line_profiler-4.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82d29887f1226938a86db30ca3a125b1bde89913768a2a486fa14d0d3f8c0d91", size = 221536 }, + { url = "https://files.pythonhosted.org/packages/29/4b/0f6fba16a9f67e083a277242a24344c0a482263a47462b4ce50c6cc7a5dc/line_profiler-4.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bf60706467203db0a872b93775a5e5902a02b11d79f8f75a8f8ef381b75789e1", size = 141581 }, + { url = "https://files.pythonhosted.org/packages/5c/2b/a3a76c5879a3540b44eacdd0276e566a9c7fc381978fc527b6fc8e67a513/line_profiler-4.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:934fd964eed9bed87e3c01e8871ee6bdc54d10edf7bf14d20e72f7be03567ae3", size = 134641 }, + { url = "https://files.pythonhosted.org/packages/b3/e3/6381342ea05e42205322170cebcc0f0b7c7b6c63e259a2bcade65c6be0b4/line_profiler-4.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d623e5b37fa48c7ad0c29b4353244346a5dcb1bf75e117e19400b8ffd3393d1b", size = 693309 }, + { url = "https://files.pythonhosted.org/packages/28/5a/2aa1c21bf5568f019343a6e8505cba35c70edd9acb0ed863b0b8f928dd15/line_profiler-4.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efcdbed9ba9003792d8bfd56c11bb3d4e29ad7e0d2f583e1c774de73bbf02933", size = 720065 }, + { url = "https://files.pythonhosted.org/packages/4c/d3/e596439f55d347e5c9c6cde8fef6dcdab02f29e3fc8db7b14e0303b38274/line_profiler-4.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:df0149c191a95f2dbc93155b2f9faaee563362d61e78b8986cdb67babe017cdc", size = 1787230 }, + { url = "https://files.pythonhosted.org/packages/75/45/bc7d816ab60f0d8397090a32c3f798a53253ceb18d83f900434425d3b70f/line_profiler-4.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5e3a1ca491a8606ed674882b59354087f6e9ab6b94aa6d5fa5d565c6f2acc7a8", size = 1701460 }, + { url = "https://files.pythonhosted.org/packages/dd/aa/b7c02db2668bfd8de7b84f3d13dc36e4aca7dc8dba978b34f9e56dd0f103/line_profiler-4.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a85ff57d4ef9d899ca12d6b0883c3cab1786388b29d2fb5f30f909e70bb9a691", size = 128330 }, +] + +[[package]] +name = "linkify-it-py" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "uc-micro-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 }, +] + +[[package]] +name = "llvmlite" +version = "0.43.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9f/3d/f513755f285db51ab363a53e898b85562e950f79a2e6767a364530c2f645/llvmlite-0.43.0.tar.gz", hash = "sha256:ae2b5b5c3ef67354824fb75517c8db5fbe93bc02cd9671f3c62271626bc041d5", size = 157069 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/67/9443509e5d2b6d8587bae3ede5598fa8bd586b1c7701696663ea8af15b5b/llvmlite-0.43.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f99b600aa7f65235a5a05d0b9a9f31150c390f31261f2a0ba678e26823ec38f7", size = 31064409 }, + { url = "https://files.pythonhosted.org/packages/a2/9c/24139d3712d2d352e300c39c0e00d167472c08b3bd350c3c33d72c88ff8d/llvmlite-0.43.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:35d80d61d0cda2d767f72de99450766250560399edc309da16937b93d3b676e7", size = 28793145 }, + { url = "https://files.pythonhosted.org/packages/bf/f1/4c205a48488e574ee9f6505d50e84370a978c90f08dab41a42d8f2c576b6/llvmlite-0.43.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eccce86bba940bae0d8d48ed925f21dbb813519169246e2ab292b5092aba121f", size = 42857276 }, + { url = "https://files.pythonhosted.org/packages/00/5f/323c4d56e8401c50185fd0e875fcf06b71bf825a863699be1eb10aa2a9cb/llvmlite-0.43.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6509e1507ca0760787a199d19439cc887bfd82226f5af746d6977bd9f66844", size = 43871781 }, + { url = "https://files.pythonhosted.org/packages/c6/94/dea10e263655ce78d777e78d904903faae39d1fc440762be4a9dc46bed49/llvmlite-0.43.0-cp312-cp312-win_amd64.whl", hash = "sha256:7a2872ee80dcf6b5dbdc838763d26554c2a18aa833d31a2635bff16aafefb9c9", size = 28107442 }, +] + +[[package]] +name = "mapclassify" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "networkx" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scikit-learn" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/b5/3d2baa210db885885f54667cbb90ead5a7e68e74a67519bf1ac32eb1be29/mapclassify-2.8.1.tar.gz", hash = "sha256:306f4cb99ad1ea166b3efd7180c0a199d240bd801de7937327973d829673bc82", size = 4608933 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/e9/d7531a07454927788642373ae253ad6dd8714fec375a789031418ecebf2d/mapclassify-2.8.1-py3-none-any.whl", hash = "sha256:c79ba6ba9e51c16a5c209e824a47c76aa2b6df5773ec8a56a2f3871590d92fb6", size = 59085 }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 }, +] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, +] + +[[package]] +name = "matplotlib" +version = "3.9.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/75/9f/562ed484b11ac9f4bb4f9d2d7546954ec106a8c0f06cc755d6f63e519274/matplotlib-3.9.3.tar.gz", hash = "sha256:cd5dbbc8e25cad5f706845c4d100e2c8b34691b412b93717ce38d8ae803bcfa5", size = 36113438 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/d5/eb2338d21b2d36511f9417230413fa0c30fc82283b33dc0e3643969f3b50/matplotlib-3.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0a361bd5583bf0bcc08841df3c10269617ee2a36b99ac39d455a767da908bbbc", size = 7883049 }, + { url = "https://files.pythonhosted.org/packages/e5/52/3910833a073e7182ab3ae03810ed418f71c7fdcd65e2862cda1c6a14ffc1/matplotlib-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e14485bb1b83eeb3d55b6878f9560240981e7bbc7a8d4e1e8c38b9bd6ec8d2de", size = 7768285 }, + { url = "https://files.pythonhosted.org/packages/92/67/69df4b6636e40e964788b003535561ea3e98e33e46df4d96fa8c34ef99e6/matplotlib-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a8d279f78844aad213c4935c18f8292a9432d51af2d88bca99072c903948045", size = 8192626 }, + { url = "https://files.pythonhosted.org/packages/40/d6/70a196b0cf62e0a5bc64ccab07816ab4f6c98db0414a55280331a481a5bf/matplotlib-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6c12514329ac0d03128cf1dcceb335f4fbf7c11da98bca68dca8dcb983153a9", size = 8305687 }, + { url = "https://files.pythonhosted.org/packages/c3/43/ef6ab78dd2d8eb362c1e5a31f9cec5ece5761e6143a519153d716d85e590/matplotlib-3.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6e9de2b390d253a508dd497e9b5579f3a851f208763ed67fdca5dc0c3ea6849c", size = 9087208 }, + { url = "https://files.pythonhosted.org/packages/30/cb/36844affc69490652b5a99296b9fcee530b96621e23d3143a4839f30fb22/matplotlib-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d796272408f8567ff7eaa00eb2856b3a00524490e47ad505b0b4ca6bb8a7411f", size = 7833105 }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, +] + +[[package]] +name = "mdit-py-plugins" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + +[[package]] +name = "mgwr" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "spglm" }, + { name = "spreg" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/91/e48ba160751a2c058d5f94f10f750c155e305faa785415172a0d6d1f9c1b/mgwr-2.2.1.tar.gz", hash = "sha256:8b00ba992fd85c9528327eae88e104e072939d0d5203b72c513ef29d5c400ff7", size = 45162 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/e8/464f7fc5f1daf1505211f42619143ad6f7634fda8f35a3758fc08aefc8a8/mgwr-2.2.1-py3-none-any.whl", hash = "sha256:8a90748c4fc70f165c87ed1f761105c1742dba976a4df89c15b2ac082055d0e5", size = 47875 }, +] + +[[package]] +name = "mistune" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/c8/f0173fe3bf85fd891aee2e7bcd8207dfe26c2c683d727c5a6cc3aec7b628/mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8", size = 90840 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", size = 47958 }, +] + +[[package]] +name = "ml-dtypes" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/15/76f86faa0902836cc133939732f7611ace68cf54148487a99c539c272dc8/ml_dtypes-0.4.1.tar.gz", hash = "sha256:fad5f2de464fd09127e49b7fd1252b9006fb43d2edc1ff112d390c324af5ca7a", size = 692594 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/1a/99e924f12e4b62139fbac87419698c65f956d58de0dbfa7c028fa5b096aa/ml_dtypes-0.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:827d3ca2097085cf0355f8fdf092b888890bb1b1455f52801a2d7756f056f54b", size = 405077 }, + { url = "https://files.pythonhosted.org/packages/8f/8c/7b610bd500617854c8cc6ed7c8cfb9d48d6a5c21a1437a36a4b9bc8a3598/ml_dtypes-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772426b08a6172a891274d581ce58ea2789cc8abc1c002a27223f314aaf894e7", size = 2181554 }, + { url = "https://files.pythonhosted.org/packages/c7/c6/f89620cecc0581dc1839e218c4315171312e46c62a62da6ace204bda91c0/ml_dtypes-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126e7d679b8676d1a958f2651949fbfa182832c3cd08020d8facd94e4114f3e9", size = 2160488 }, + { url = "https://files.pythonhosted.org/packages/ae/11/a742d3c31b2cc8557a48efdde53427fd5f9caa2fa3c9c27d826e78a66f51/ml_dtypes-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:df0fb650d5c582a9e72bb5bd96cfebb2cdb889d89daff621c8fbc60295eba66c", size = 127462 }, +] + +[[package]] +name = "momepy" +version = "0.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "libpysal" }, + { name = "networkx" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "shapely" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/96/ebfced62eb6ced9dc398c459e4597bb6ef4df37551d4186fc242ebd9e763/momepy-0.9.1.tar.gz", hash = "sha256:12da07e606ee695b216e506e4cc3d6ab386328bec27acc9d694ac5dd71376ff4", size = 30084606 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/62/772a17a5e689d0f81e1dda40e06c94a84faf0cb12fe623f0992f08a0a991/momepy-0.9.1-py3-none-any.whl", hash = "sha256:8947a48c9e9b624dedad2d2044c6da1d4dc65ade4d3943ea6e3411ff28ef5114", size = 1734936 }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, +] + +[[package]] +name = "multidict" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, + { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, + { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, + { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, + { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, + { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, + { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, + { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, + { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, + { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, + { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, + { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, + { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, + { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, + { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, + { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, +] + +[[package]] +name = "mypy" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 }, + { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 }, + { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 }, + { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 }, + { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 }, + { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 }, +] + +[[package]] +name = "narwhals" +version = "1.15.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/21/f1cbabea167eacdb04e4d52083976f2ade516d891993aade5a6ed065f7fa/narwhals-1.15.2.tar.gz", hash = "sha256:bf32c4afc3b4e562be51d50a3ff4fcacd1e0c1d89dc4da1b818af81d7c28e0c7", size = 199294 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/e7/fe3d69098e628e81cf317e860474e5df02a5a681b031acbf2aaf192cef3f/narwhals-1.15.2-py3-none-any.whl", hash = "sha256:00d16ed1c4466b43ba37ef6799142340981e4ac7dcd7686e461d4955abcd921d", size = 233774 }, +] + +[[package]] +name = "nbclassic" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ipykernel" }, + { name = "ipython-genutils" }, + { name = "nest-asyncio" }, + { name = "notebook-shim" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/96/8e506bba6faf6bc299fbf783d2c22dd959f7b2aee63fe8913ebdc78cba8d/nbclassic-1.1.0.tar.gz", hash = "sha256:77b77ba85f9e988f9bad85df345b514e9e64c7f0e822992ab1df4a78ac64fc1e", size = 20194834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/d1/86fcfe1d1e5b66ec61632b014612e2d074a9d2bdf0eed53b90c2536e8dd3/nbclassic-1.1.0-py3-none-any.whl", hash = "sha256:8c0fd6e36e320a18657ff44ed96c3a400f17a903a3744fc322303a515778f2ba", size = 9991768 }, +] + +[[package]] +name = "nbclient" +version = "0.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "nbformat" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/db/25929926860ba8a3f6123d2d0a235e558e0e4be7b46e9db063a7dfefa0a2/nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68", size = 62273 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/1a/ed6d1299b1a00c1af4a033fdee565f533926d819e084caf0d2832f6f87c6/nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d", size = 25344 }, +] + +[[package]] +name = "nbconvert" +version = "7.16.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "bleach" }, + { name = "defusedxml" }, + { name = "jinja2" }, + { name = "jupyter-core" }, + { name = "jupyterlab-pygments" }, + { name = "markupsafe" }, + { name = "mistune" }, + { name = "nbclient" }, + { name = "nbformat" }, + { name = "packaging" }, + { name = "pandocfilters" }, + { name = "pygments" }, + { name = "tinycss2" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/e8/ba521a033b21132008e520c28ceb818f9f092da5f0261e94e509401b29f9/nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4", size = 854422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/bb/bb5b6a515d1584aa2fd89965b11db6632e4bdc69495a52374bcc36e56cfa/nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3", size = 257388 }, +] + +[[package]] +name = "nbformat" +version = "5.10.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastjsonschema" }, + { name = "jsonschema" }, + { name = "jupyter-core" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, +] + +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, +] + +[[package]] +name = "notebook" +version = "7.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, + { name = "jupyterlab" }, + { name = "jupyterlab-server" }, + { name = "notebook-shim" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/1f/6c90511ea21b4ed6444e61ec8bb4137cb8c34db0f3b82402094286babbdf/notebook-7.3.1.tar.gz", hash = "sha256:84381c2a82d867517fd25b86e986dae1fe113a70b98f03edff9b94e499fec8fa", size = 12777449 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/c4/764078234460706fdd2da68f1715ee42359cb24ee18b70db051cfac38455/notebook-7.3.1-py3-none-any.whl", hash = "sha256:212e1486b2230fe22279043f33c7db5cf9a01d29feb063a85cb139747b7c9483", size = 13162639 }, +] + +[[package]] +name = "notebook-shim" +version = "0.2.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-server" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, +] + +[[package]] +name = "numba" +version = "0.60.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "llvmlite" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/93/2849300a9184775ba274aba6f82f303343669b0592b7bb0849ea713dabb0/numba-0.60.0.tar.gz", hash = "sha256:5df6158e5584eece5fc83294b949fd30b9f1125df7708862205217e068aabf16", size = 2702171 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/5c/b5ec752c475e78a6c3676b67c514220dbde2725896bbb0b6ec6ea54b2738/numba-0.60.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d7da4098db31182fc5ffe4bc42c6f24cd7d1cb8a14b59fd755bfee32e34b8404", size = 2647866 }, + { url = "https://files.pythonhosted.org/packages/65/42/39559664b2e7c15689a638c2a38b3b74c6e69a04e2b3019b9f7742479188/numba-0.60.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38d6ea4c1f56417076ecf8fc327c831ae793282e0ff51080c5094cb726507b1c", size = 2650208 }, + { url = "https://files.pythonhosted.org/packages/67/88/c4459ccc05674ef02119abf2888ccd3e2fed12a323f52255f4982fc95876/numba-0.60.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:62908d29fb6a3229c242e981ca27e32a6e606cc253fc9e8faeb0e48760de241e", size = 3466946 }, + { url = "https://files.pythonhosted.org/packages/8b/41/ac11cf33524def12aa5bd698226ae196a1185831c05ed29dc0c56eaa308b/numba-0.60.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0ebaa91538e996f708f1ab30ef4d3ddc344b64b5227b67a57aa74f401bb68b9d", size = 3761463 }, + { url = "https://files.pythonhosted.org/packages/ca/bd/0fe29fcd1b6a8de479a4ed25c6e56470e467e3611c079d55869ceef2b6d1/numba-0.60.0-cp312-cp312-win_amd64.whl", hash = "sha256:f75262e8fe7fa96db1dca93d53a194a38c46da28b112b8a4aca168f0df860347", size = 2707588 }, +] + +[[package]] +name = "numpy" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/75/10dd1f8116a8b796cb2c737b674e02d02e80454bda953fa7e65d8c12b016/numpy-2.0.2.tar.gz", hash = "sha256:883c987dee1880e2a864ab0dc9892292582510604156762362d9326444636e78", size = 18902015 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/40/2e117be60ec50d98fa08c2f8c48e09b3edea93cfcabd5a9ff6925d54b1c2/numpy-2.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:df55d490dea7934f330006d0f81e8551ba6010a5bf035a249ef61a94f21c500b", size = 20895803 }, + { url = "https://files.pythonhosted.org/packages/46/92/1b8b8dee833f53cef3e0a3f69b2374467789e0bb7399689582314df02651/numpy-2.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8df823f570d9adf0978347d1f926b2a867d5608f434a7cff7f7908c6570dcf5e", size = 13471835 }, + { url = "https://files.pythonhosted.org/packages/7f/19/e2793bde475f1edaea6945be141aef6c8b4c669b90c90a300a8954d08f0a/numpy-2.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9a92ae5c14811e390f3767053ff54eaee3bf84576d99a2456391401323f4ec2c", size = 5038499 }, + { url = "https://files.pythonhosted.org/packages/e3/ff/ddf6dac2ff0dd50a7327bcdba45cb0264d0e96bb44d33324853f781a8f3c/numpy-2.0.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:a842d573724391493a97a62ebbb8e731f8a5dcc5d285dfc99141ca15a3302d0c", size = 6633497 }, + { url = "https://files.pythonhosted.org/packages/72/21/67f36eac8e2d2cd652a2e69595a54128297cdcb1ff3931cfc87838874bd4/numpy-2.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05e238064fc0610c840d1cf6a13bf63d7e391717d247f1bf0318172e759e692", size = 13621158 }, + { url = "https://files.pythonhosted.org/packages/39/68/e9f1126d757653496dbc096cb429014347a36b228f5a991dae2c6b6cfd40/numpy-2.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0123ffdaa88fa4ab64835dcbde75dcdf89c453c922f18dced6e27c90d1d0ec5a", size = 19236173 }, + { url = "https://files.pythonhosted.org/packages/d1/e9/1f5333281e4ebf483ba1c888b1d61ba7e78d7e910fdd8e6499667041cc35/numpy-2.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:96a55f64139912d61de9137f11bf39a55ec8faec288c75a54f93dfd39f7eb40c", size = 19634174 }, + { url = "https://files.pythonhosted.org/packages/71/af/a469674070c8d8408384e3012e064299f7a2de540738a8e414dcfd639996/numpy-2.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec9852fb39354b5a45a80bdab5ac02dd02b15f44b3804e9f00c556bf24b4bded", size = 14099701 }, + { url = "https://files.pythonhosted.org/packages/d0/3d/08ea9f239d0e0e939b6ca52ad403c84a2bce1bde301a8eb4888c1c1543f1/numpy-2.0.2-cp312-cp312-win32.whl", hash = "sha256:671bec6496f83202ed2d3c8fdc486a8fc86942f2e69ff0e986140339a63bcbe5", size = 6174313 }, + { url = "https://files.pythonhosted.org/packages/b2/b5/4ac39baebf1fdb2e72585c8352c56d063b6126be9fc95bd2bb5ef5770c20/numpy-2.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cfd41e13fdc257aa5778496b8caa5e856dc4896d4ccf01841daee1d96465467a", size = 15606179 }, +] + +[[package]] +name = "oauthlib" +version = "3.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fa/fbf4001037904031639e6bfbfc02badfc7e12f137a8afa254df6c4c8a670/oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918", size = 177352 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688 }, +] + +[[package]] +name = "opencv-python-headless" +version = "4.10.0.84" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/9b/583c8d9259f6fc19413f83fd18dd8e6cbc8eefb0b4dc6da52dd151fe3272/opencv_python_headless-4.10.0.84-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a4f4bcb07d8f8a7704d9c8564c224c8b064c63f430e95b61ac0bffaa374d330e", size = 54835657 }, + { url = "https://files.pythonhosted.org/packages/c0/7b/b4c67f5dad7a9a61c47f7a39e4050e8a4628bd64b3c3daaeb755d759f928/opencv_python_headless-4.10.0.84-cp37-abi3-macosx_12_0_x86_64.whl", hash = "sha256:5ae454ebac0eb0a0b932e3406370aaf4212e6a3fdb5038cc86c7aea15a6851da", size = 56475470 }, + { url = "https://files.pythonhosted.org/packages/91/61/f838ce2046f3ec3591ea59ea3549085e399525d3b4558c4ed60b55ed88c0/opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46071015ff9ab40fccd8a163da0ee14ce9846349f06c6c8c0f2870856ffa45db", size = 29329705 }, + { url = "https://files.pythonhosted.org/packages/d1/09/248f86a404567303cdf120e4a301f389b68e3b18e5c0cc428de327da609c/opencv_python_headless-4.10.0.84-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:377d08a7e48a1405b5e84afcbe4798464ce7ee17081c1c23619c8b398ff18295", size = 49858781 }, + { url = "https://files.pythonhosted.org/packages/30/c0/66f88d58500e990a9a0a5c06f98862edf1d0a3a430781218a8c193948438/opencv_python_headless-4.10.0.84-cp37-abi3-win32.whl", hash = "sha256:9092404b65458ed87ce932f613ffbb1106ed2c843577501e5768912360fc50ec", size = 28675298 }, + { url = "https://files.pythonhosted.org/packages/26/d0/22f68eb23eea053a31655960f133c0be9726c6a881547e6e9e7e2a946c4f/opencv_python_headless-4.10.0.84-cp37-abi3-win_amd64.whl", hash = "sha256:afcf28bd1209dd58810d33defb622b325d3cbe49dcd7a43a902982c33e5fad05", size = 38754031 }, +] + +[[package]] +name = "opt-einsum" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932 }, +] + +[[package]] +name = "orjson" +version = "3.10.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/04/bb9f72987e7f62fb591d6c880c0caaa16238e4e530cbc3bdc84a7372d75f/orjson-3.10.12.tar.gz", hash = "sha256:0a78bbda3aea0f9f079057ee1ee8a1ecf790d4f1af88dd67493c6b8ee52506ff", size = 5438647 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a1/2f/989adcafad49afb535da56b95d8f87d82e748548b2a86003ac129314079c/orjson-3.10.12-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:53206d72eb656ca5ac7d3a7141e83c5bbd3ac30d5eccfe019409177a57634b0d", size = 248678 }, + { url = "https://files.pythonhosted.org/packages/69/b9/8c075e21a50c387649db262b618ebb7e4d40f4197b949c146fc225dd23da/orjson-3.10.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac8010afc2150d417ebda810e8df08dd3f544e0dd2acab5370cfa6bcc0662f8f", size = 136763 }, + { url = "https://files.pythonhosted.org/packages/87/d3/78edf10b4ab14c19f6d918cf46a145818f4aca2b5a1773c894c5490d3a4c/orjson-3.10.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed459b46012ae950dd2e17150e838ab08215421487371fa79d0eced8d1461d70", size = 149137 }, + { url = "https://files.pythonhosted.org/packages/16/81/5db8852bdf990a0ddc997fa8f16b80895b8cc77c0fe3701569ed2b4b9e78/orjson-3.10.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8dcb9673f108a93c1b52bfc51b0af422c2d08d4fc710ce9c839faad25020bb69", size = 140567 }, + { url = "https://files.pythonhosted.org/packages/fa/a6/9ce1e3e3db918512efadad489630c25841eb148513d21dab96f6b4157fa1/orjson-3.10.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22a51ae77680c5c4652ebc63a83d5255ac7d65582891d9424b566fb3b5375ee9", size = 156620 }, + { url = "https://files.pythonhosted.org/packages/47/d4/05133d6bea24e292d2f7628b1e19986554f7d97b6412b3e51d812e38db2d/orjson-3.10.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910fdf2ac0637b9a77d1aad65f803bac414f0b06f720073438a7bd8906298192", size = 131555 }, + { url = "https://files.pythonhosted.org/packages/b9/7a/b3fbffda8743135c7811e95dc2ab7cdbc5f04999b83c2957d046f1b3fac9/orjson-3.10.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:24ce85f7100160936bc2116c09d1a8492639418633119a2224114f67f63a4559", size = 139743 }, + { url = "https://files.pythonhosted.org/packages/b5/13/95bbcc9a6584aa083da5ce5004ce3d59ea362a542a0b0938d884fd8790b6/orjson-3.10.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8a76ba5fc8dd9c913640292df27bff80a685bed3a3c990d59aa6ce24c352f8fc", size = 131733 }, + { url = "https://files.pythonhosted.org/packages/e8/29/dddbb2ea6e7af426fcc3da65a370618a88141de75c6603313d70768d1df1/orjson-3.10.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ff70ef093895fd53f4055ca75f93f047e088d1430888ca1229393a7c0521100f", size = 415788 }, + { url = "https://files.pythonhosted.org/packages/53/df/4aea59324ac539975919b4705ee086aced38e351a6eb3eea0f5071dd5661/orjson-3.10.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f4244b7018b5753ecd10a6d324ec1f347da130c953a9c88432c7fbc8875d13be", size = 142347 }, + { url = "https://files.pythonhosted.org/packages/55/55/a52d83d7c49f8ff44e0daab10554490447d6c658771569e1c662aa7057fe/orjson-3.10.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:16135ccca03445f37921fa4b585cff9a58aa8d81ebcb27622e69bfadd220b32c", size = 130829 }, + { url = "https://files.pythonhosted.org/packages/a1/8b/b1beb1624dd4adf7d72e2d9b73c4b529e7851c0c754f17858ea13e368b33/orjson-3.10.12-cp312-none-win32.whl", hash = "sha256:2d879c81172d583e34153d524fcba5d4adafbab8349a7b9f16ae511c2cee8708", size = 143659 }, + { url = "https://files.pythonhosted.org/packages/13/91/634c9cd0bfc6a857fc8fab9bf1a1bd9f7f3345e0d6ca5c3d4569ceb6dcfa/orjson-3.10.12-cp312-none-win_amd64.whl", hash = "sha256:fc23f691fa0f5c140576b8c365bc942d577d861a9ee1142e4db468e4e17094fb", size = 135221 }, +] + +[[package]] +name = "ortools" +version = "9.9.3963" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "immutabledict" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "protobuf" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/ad/95504cd7d0bedab94cc3cbcbf4b87003bb82eb9fab7149c115c0246fa78d/ortools-9.9.3963-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:6dcf1974f278952034c727cdaec13de817b9f84d477c97ffb9a5441fccad36dd", size = 19383019 }, + { url = "https://files.pythonhosted.org/packages/79/68/0dd518cb682e0d6f7b7f77862d774d2c0eace55ebb4209b2e0ad8c57a9ff/ortools-9.9.3963-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05b233c700788a2df1869f3579056c5ccca87bc2e74172b94997c3a45507bd4d", size = 18236664 }, + { url = "https://files.pythonhosted.org/packages/8f/25/81e9fa3f7cac305f93802c826617f7b755c98b9c6a9004120d77b76b1a4a/ortools-9.9.3963-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d93448c5c8b8dd7d3dde1a29f72a48316069f1839931e850a0247406d8c971d", size = 23274133 }, + { url = "https://files.pythonhosted.org/packages/3b/e8/d2c34853ddf4e1769d999844a0940a2ec5e5579d54e62978f480d988eb44/ortools-9.9.3963-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55f4f600492f34fc2313c46413c67cea74a637c2b12d03e24694fac3ac68a313", size = 24752048 }, + { url = "https://files.pythonhosted.org/packages/d7/f4/4c5e034aed697483fdcf904f743af999d258387f2b800520263ab649648d/ortools-9.9.3963-cp312-cp312-win_amd64.whl", hash = "sha256:704250c05a10379dfca569e1d8e31650fc90e302346de7ce772cac7e37eba856", size = 113142778 }, +] + +[[package]] +name = "osqp" +version = "0.6.7.post3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "qdldl" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/35/45d4d1832b31d207f83e0f9734d041be125fb4f0dff49413674bd1b08032/osqp-0.6.7.post3.tar.gz", hash = "sha256:b0c5e0a721f21c9724097a4fd50108304d296468d124e16f34ac67046f7020e1", size = 229274 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/26/4cf65e82cf63c4f4ff5186618c006d95a1a5bc9f4f015563ad6d87d75a42/osqp-0.6.7.post3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:023af06764f7aba9c64536ecb7204019906bb7e78237f335f82b404f16623eef", size = 252062 }, + { url = "https://files.pythonhosted.org/packages/ce/bc/ece5348baef40bf355c5ef8000103aaf77973060f4c940da9cce0999e00d/osqp-0.6.7.post3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4cec7cb5bf1615c4129277275dc08e20a037372a874cff35eb891b4b35a463de", size = 237577 }, + { url = "https://files.pythonhosted.org/packages/31/33/f09c305591606e59edc5f09aa5cba3606c0e29e7b0fff42d044585bcc1f4/osqp-0.6.7.post3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb882ab24b97b14843b7c71d2474fb8b415bafc8dd60aa94870c2ef338c20bfb", size = 295407 }, + { url = "https://files.pythonhosted.org/packages/ef/63/356f01888eb0e4cd8603eb8b7711a6865e26bc2d9a1882a1e4562333debd/osqp-0.6.7.post3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:502fde0ae710cef1e6418fb8d26efef9597d1dcba877489a1c2eb9c3eb2ff2e9", size = 300002 }, + { url = "https://files.pythonhosted.org/packages/57/b5/958d4188cb9347e420d3de2d19d8cb1113f691b7a093cdef67f86b598f30/osqp-0.6.7.post3-cp312-cp312-win_amd64.whl", hash = "sha256:468588cfb690becba4d1f460c2a53e75530584e3efcf2caed59f5219032e6888", size = 293164 }, +] + +[[package]] +name = "overrides" +version = "7.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, +] + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pandas" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893 }, + { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475 }, + { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645 }, + { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445 }, + { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 }, + { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 }, + { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 }, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, +] + +[[package]] +name = "panel" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bleach" }, + { name = "bokeh" }, + { name = "linkify-it-py" }, + { name = "markdown" }, + { name = "markdown-it-py" }, + { name = "mdit-py-plugins" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "param" }, + { name = "pyviz-comms" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/66/7f13691d577c3096d8605c307cfc6f662014896086a0c53778cf6e5828ea/panel-1.5.4.tar.gz", hash = "sha256:7644e87afe9b94c32b4fca939d645c5b958d671691bd841d3391e31941090092", size = 29378323 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/9e/6bdbdc6c5ce7d0ba901d8599f6338cd8d945f425348629cd53560d8c05c1/panel-1.5.4-py3-none-any.whl", hash = "sha256:98521ff61dfe2ef684181213842521674d2db95f692c7942ab9103a2c0e882b9", size = 63137025 }, +] + +[[package]] +name = "param" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/39/75203d36ddd59f3819ef930451d4436e60248a674fb1136d9cf126cb9859/param-2.1.1.tar.gz", hash = "sha256:3b1da14abafa75bfd908572378a58696826b3719a723bc31b40ffff2e9a5c852", size = 174619 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/7b/5593a40fcd0981bda85274bb3e622ac433a94ae1e11ef8639de362cfa7de/param-2.1.1-py3-none-any.whl", hash = "sha256:81066d040526fbaa44b6419f3e92348fa8856ea44c8d3915e9245937ddabe2d6", size = 116757 }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[package]] +name = "patsy" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/81/74f6a65b848ffd16c18f920620ce999fe45fe27f01ab3911260ce4ed85e4/patsy-1.0.1.tar.gz", hash = "sha256:e786a9391eec818c054e359b737bbce692f051aee4c661f4141cc88fb459c0c4", size = 396010 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/87/2b/b50d3d08ea0fc419c183a84210571eba005328efa62b6b98bc28e9ead32a/patsy-1.0.1-py2.py3-none-any.whl", hash = "sha256:751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c", size = 232923 }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, +] + +[[package]] +name = "pillow" +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, +] + +[[package]] +name = "pint" +version = "0.24.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flexcache" }, + { name = "flexparser" }, + { name = "platformdirs" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/bb/52b15ddf7b7706ed591134a895dbf6e41c8348171fb635e655e0a4bbb0ea/pint-0.24.4.tar.gz", hash = "sha256:35275439b574837a6cd3020a5a4a73645eb125ce4152a73a2f126bf164b91b80", size = 342225 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/16/bd2f5904557265882108dc2e04f18abc05ab0c2b7082ae9430091daf1d5c/Pint-0.24.4-py3-none-any.whl", hash = "sha256:aa54926c8772159fcf65f82cc0d34de6768c151b32ad1deb0331291c38fe7659", size = 302029 }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "pointpats" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "libpysal" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/58/ee049f1d0e077fd6f38514090c88afec13b9dde721e5210449114eb30350/pointpats-2.5.1.tar.gz", hash = "sha256:1eedb30a17e59746ed9ac68283f419dee5a07c17cd53ed2bc2dadba2b77973ff", size = 4270216 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/9a/a244eded46beaad15b06b81e8889a561e3c869b57311870188f0d793a1c8/pointpats-2.5.1-py3-none-any.whl", hash = "sha256:94aadd1d801048614ddb38c76c8a725608bfe348bbeefdcfefb2dc2093088317", size = 59202 }, +] + +[[package]] +name = "polars" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/80/d845897273be97a3e73b59be711deda375b638330d591a7ef8132c20f52f/polars-1.16.0.tar.gz", hash = "sha256:dd99808b833872babe02434a809fd45c1cffe66a3d57123cdc5e447c7753d328", size = 4192568 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/b0/51c944ecd58b3ebc81eb03b50448127ff85fd9448063094524e0c6693c75/polars-1.16.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:072f5ff3b5fe05797c59890de0e464b34ede75a9735e7d7221622fa3a0616d8e", size = 34735038 }, + { url = "https://files.pythonhosted.org/packages/61/2f/d0b45007f2ae4b4926070b420c8525840b9757013cd96077bcde40807ecb/polars-1.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ebaf7a1ea114b042fa9f1cd17d49436279eb30545dd74361a2f5e3febeb867cd", size = 30577461 }, + { url = "https://files.pythonhosted.org/packages/31/9e/21e05959323883abcee799837d8cac08adf10a48c233432993757e41791a/polars-1.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e626d21dcd2566e1442dac414fe177bc70ebfc2f16620d59d778b1b774361018", size = 36006233 }, + { url = "https://files.pythonhosted.org/packages/25/80/da5c3cd248c7642d1feb896f0a27a0860c607f8cdde3e75457182e4c76c6/polars-1.16.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:53debcce55f68731ee2c7d6c787afdee26860ed6576f1ffa0cb9111b57f82857", size = 32348398 }, + { url = "https://files.pythonhosted.org/packages/08/0b/677c905f9dd5bc37708694e8f7367659c5382bd011f5dc1d564474032d0b/polars-1.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:17efcb550c42d51034ff79702612b9184d8eac0d500de1dd7fb98490459276d3", size = 35743314 }, +] + +[[package]] +name = "prometheus-client" +version = "0.21.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/62/14/7d0f567991f3a9af8d1cd4f619040c93b68f09a02b6d0b6ab1b2d1ded5fe/prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", size = 78551 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301", size = 54682 }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.48" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2d/4f/feb5e137aff82f7c7f3248267b97451da3644f6cdc218edfe549fb354127/prompt_toolkit-3.0.48.tar.gz", hash = "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", size = 424684 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/6a/fd08d94654f7e67c52ca30523a178b3f8ccc4237fce4be90d39c938a831a/prompt_toolkit-3.0.48-py3-none-any.whl", hash = "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e", size = 386595 }, +] + +[[package]] +name = "propcache" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/28/1d205fe49be8b1b4df4c50024e62480a442b1a7b818e734308bb0d17e7fb/propcache-0.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:081a430aa8d5e8876c6909b67bd2d937bfd531b0382d3fdedb82612c618bc41a", size = 79588 }, + { url = "https://files.pythonhosted.org/packages/21/ee/fc4d893f8d81cd4971affef2a6cb542b36617cd1d8ce56b406112cb80bf7/propcache-0.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2ccec9ac47cf4e04897619c0e0c1a48c54a71bdf045117d3a26f80d38ab1fb0", size = 45825 }, + { url = "https://files.pythonhosted.org/packages/4a/de/bbe712f94d088da1d237c35d735f675e494a816fd6f54e9db2f61ef4d03f/propcache-0.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:14d86fe14b7e04fa306e0c43cdbeebe6b2c2156a0c9ce56b815faacc193e320d", size = 45357 }, + { url = "https://files.pythonhosted.org/packages/7f/14/7ae06a6cf2a2f1cb382586d5a99efe66b0b3d0c6f9ac2f759e6f7af9d7cf/propcache-0.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:049324ee97bb67285b49632132db351b41e77833678432be52bdd0289c0e05e4", size = 241869 }, + { url = "https://files.pythonhosted.org/packages/cc/59/227a78be960b54a41124e639e2c39e8807ac0c751c735a900e21315f8c2b/propcache-0.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cd9a1d071158de1cc1c71a26014dcdfa7dd3d5f4f88c298c7f90ad6f27bb46d", size = 247884 }, + { url = "https://files.pythonhosted.org/packages/84/58/f62b4ffaedf88dc1b17f04d57d8536601e4e030feb26617228ef930c3279/propcache-0.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98110aa363f1bb4c073e8dcfaefd3a5cea0f0834c2aab23dda657e4dab2f53b5", size = 248486 }, + { url = "https://files.pythonhosted.org/packages/1c/07/ebe102777a830bca91bbb93e3479cd34c2ca5d0361b83be9dbd93104865e/propcache-0.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:647894f5ae99c4cf6bb82a1bb3a796f6e06af3caa3d32e26d2350d0e3e3faf24", size = 243649 }, + { url = "https://files.pythonhosted.org/packages/ed/bc/4f7aba7f08f520376c4bb6a20b9a981a581b7f2e385fa0ec9f789bb2d362/propcache-0.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfd3223c15bebe26518d58ccf9a39b93948d3dcb3e57a20480dfdd315356baff", size = 229103 }, + { url = "https://files.pythonhosted.org/packages/fe/d5/04ac9cd4e51a57a96f78795e03c5a0ddb8f23ec098b86f92de028d7f2a6b/propcache-0.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d71264a80f3fcf512eb4f18f59423fe82d6e346ee97b90625f283df56aee103f", size = 226607 }, + { url = "https://files.pythonhosted.org/packages/e3/f0/24060d959ea41d7a7cc7fdbf68b31852331aabda914a0c63bdb0e22e96d6/propcache-0.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e73091191e4280403bde6c9a52a6999d69cdfde498f1fdf629105247599b57ec", size = 221153 }, + { url = "https://files.pythonhosted.org/packages/77/a7/3ac76045a077b3e4de4859a0753010765e45749bdf53bd02bc4d372da1a0/propcache-0.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3935bfa5fede35fb202c4b569bb9c042f337ca4ff7bd540a0aa5e37131659348", size = 222151 }, + { url = "https://files.pythonhosted.org/packages/e7/af/5e29da6f80cebab3f5a4dcd2a3240e7f56f2c4abf51cbfcc99be34e17f0b/propcache-0.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f508b0491767bb1f2b87fdfacaba5f7eddc2f867740ec69ece6d1946d29029a6", size = 233812 }, + { url = "https://files.pythonhosted.org/packages/8c/89/ebe3ad52642cc5509eaa453e9f4b94b374d81bae3265c59d5c2d98efa1b4/propcache-0.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1672137af7c46662a1c2be1e8dc78cb6d224319aaa40271c9257d886be4363a6", size = 238829 }, + { url = "https://files.pythonhosted.org/packages/e9/2f/6b32f273fa02e978b7577159eae7471b3cfb88b48563b1c2578b2d7ca0bb/propcache-0.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b74c261802d3d2b85c9df2dfb2fa81b6f90deeef63c2db9f0e029a3cac50b518", size = 230704 }, + { url = "https://files.pythonhosted.org/packages/5c/2e/f40ae6ff5624a5f77edd7b8359b208b5455ea113f68309e2b00a2e1426b6/propcache-0.2.1-cp312-cp312-win32.whl", hash = "sha256:d09c333d36c1409d56a9d29b3a1b800a42c76a57a5a8907eacdbce3f18768246", size = 40050 }, + { url = "https://files.pythonhosted.org/packages/3b/77/a92c3ef994e47180862b9d7d11e37624fb1c00a16d61faf55115d970628b/propcache-0.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:c214999039d4f2a5b2073ac506bba279945233da8c786e490d411dfc30f855c1", size = 44117 }, + { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, +] + +[[package]] +name = "proto-plus" +version = "1.25.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/05/74417b2061e1bf1b82776037cad97094228fa1c1b6e82d08a78d3fb6ddb6/proto_plus-1.25.0.tar.gz", hash = "sha256:fbb17f57f7bd05a68b7707e745e26528b0b3c34e378db91eef93912c54982d91", size = 56124 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/25/0b7cc838ae3d76d46539020ec39fc92bfc9acc29367e58fe912702c2a79e/proto_plus-1.25.0-py3-none-any.whl", hash = "sha256:c91fc4a65074ade8e458e95ef8bac34d4008daa7cce4a12d6707066fca648961", size = 50126 }, +] + +[[package]] +name = "protobuf" +version = "5.29.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d2/4f/1639b7b1633d8fd55f216ba01e21bf2c43384ab25ef3ddb35d85a52033e8/protobuf-5.29.1.tar.gz", hash = "sha256:683be02ca21a6ffe80db6dd02c0b5b2892322c59ca57fd6c872d652cb80549cb", size = 424965 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/c7/28669b04691a376cf7d0617d612f126aa0fff763d57df0142f9bf474c5b8/protobuf-5.29.1-cp310-abi3-win32.whl", hash = "sha256:22c1f539024241ee545cbcb00ee160ad1877975690b16656ff87dde107b5f110", size = 422706 }, + { url = "https://files.pythonhosted.org/packages/e3/33/dc7a7712f457456b7e0b16420ab8ba1cc8686751d3f28392eb43d0029ab9/protobuf-5.29.1-cp310-abi3-win_amd64.whl", hash = "sha256:1fc55267f086dd4050d18ef839d7bd69300d0d08c2a53ca7df3920cc271a3c34", size = 434505 }, + { url = "https://files.pythonhosted.org/packages/e5/39/44239fb1c6ec557e1731d996a5de89a9eb1ada7a92491fcf9c5d714052ed/protobuf-5.29.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d473655e29c0c4bbf8b69e9a8fb54645bc289dead6d753b952e7aa660254ae18", size = 417822 }, + { url = "https://files.pythonhosted.org/packages/fb/4a/ec56f101d38d4bef2959a9750209809242d86cf8b897db00f2f98bfa360e/protobuf-5.29.1-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5ba1d0e4c8a40ae0496d0e2ecfdbb82e1776928a205106d14ad6985a09ec155", size = 319572 }, + { url = "https://files.pythonhosted.org/packages/04/52/c97c58a33b3d6c89a8138788576d372a90a6556f354799971c6b4d16d871/protobuf-5.29.1-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:8ee1461b3af56145aca2800e6a3e2f928108c749ba8feccc6f5dd0062c410c0d", size = 319671 }, + { url = "https://files.pythonhosted.org/packages/3b/24/c8c49df8f6587719e1d400109b16c10c6902d0c9adddc8fff82840146f99/protobuf-5.29.1-py3-none-any.whl", hash = "sha256:32600ddb9c2a53dedc25b8581ea0f1fd8ea04956373c0c07577ce58d312522e0", size = 172547 }, +] + +[[package]] +name = "psutil" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, +] + +[[package]] +name = "pulp" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/d5/7cb148b56f3603be3663498db3a63054d7d519eab32ef9c39f93faf6b7a9/pulp-2.9.0.tar.gz", hash = "sha256:2e30e6c0ef2c0edac185220e3e53faca62eb786a9bd68465208f05bc63e850f3", size = 17610175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/10/704c18b5960b3f9b10efcc859e11881ad90f1e44008e181d2b10cd305a63/PuLP-2.9.0-py3-none-any.whl", hash = "sha256:ad6a9b566d8458f4d05f4bfe2cea59e32885dd1da6929a361be579222107987c", size = 17678417 }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, +] + +[[package]] +name = "pyarrow" +version = "18.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7f/7b/640785a9062bb00314caa8a387abce547d2a420cf09bd6c715fe659ccffb/pyarrow-18.1.0.tar.gz", hash = "sha256:9386d3ca9c145b5539a1cfc75df07757dff870168c959b473a0bccbc3abc8c73", size = 1118671 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/50/12829e7111b932581e51dda51d5cb39207a056c30fe31ef43f14c63c4d7e/pyarrow-18.1.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f3a76670b263dc41d0ae877f09124ab96ce10e4e48f3e3e4257273cee61ad0d", size = 29514620 }, + { url = "https://files.pythonhosted.org/packages/d1/41/468c944eab157702e96abab3d07b48b8424927d4933541ab43788bb6964d/pyarrow-18.1.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:da31fbca07c435be88a0c321402c4e31a2ba61593ec7473630769de8346b54ee", size = 30856494 }, + { url = "https://files.pythonhosted.org/packages/68/f9/29fb659b390312a7345aeb858a9d9c157552a8852522f2c8bad437c29c0a/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:543ad8459bc438efc46d29a759e1079436290bd583141384c6f7a1068ed6f992", size = 39203624 }, + { url = "https://files.pythonhosted.org/packages/6e/f6/19360dae44200e35753c5c2889dc478154cd78e61b1f738514c9f131734d/pyarrow-18.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0743e503c55be0fdb5c08e7d44853da27f19dc854531c0570f9f394ec9671d54", size = 40139341 }, + { url = "https://files.pythonhosted.org/packages/bb/e6/9b3afbbcf10cc724312e824af94a2e993d8ace22994d823f5c35324cebf5/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d4b3d2a34780645bed6414e22dda55a92e0fcd1b8a637fba86800ad737057e33", size = 38618629 }, + { url = "https://files.pythonhosted.org/packages/3a/2e/3b99f8a3d9e0ccae0e961978a0d0089b25fb46ebbcfb5ebae3cca179a5b3/pyarrow-18.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c52f81aa6f6575058d8e2c782bf79d4f9fdc89887f16825ec3a66607a5dd8e30", size = 40078661 }, + { url = "https://files.pythonhosted.org/packages/76/52/f8da04195000099d394012b8d42c503d7041b79f778d854f410e5f05049a/pyarrow-18.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ad4892617e1a6c7a551cfc827e072a633eaff758fa09f21c4ee548c30bcaf99", size = 25092330 }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/67/6afbf0d507f73c32d21084a79946bfcfca5fbc62a72057e9c23797a737c9/pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c", size = 310028 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd", size = 181537 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + +[[package]] +name = "pymongo" +version = "4.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/35/b62a3139f908c68b69aac6a6a3f8cc146869de0a7929b994600e2c587c77/pymongo-4.10.1.tar.gz", hash = "sha256:a9de02be53b6bb98efe0b9eda84ffa1ec027fcb23a2de62c4f941d9a2f2f3330", size = 1903902 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/d1/60ad99fe3f64d45e6c71ac0e3078e88d9b64112b1bae571fc3707344d6d1/pymongo-4.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fbedc4617faa0edf423621bb0b3b8707836687161210d470e69a4184be9ca011", size = 943356 }, + { url = "https://files.pythonhosted.org/packages/ca/9b/21d4c6b4ee9c1fa9691c68dc2a52565e0acb644b9e95148569b4736a4ebd/pymongo-4.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7bd26b2aec8ceeb95a5d948d5cc0f62b0eb6d66f3f4230705c1e3d3d2c04ec76", size = 943142 }, + { url = "https://files.pythonhosted.org/packages/07/af/691b7454e219a8eb2d1641aecedd607e3a94b93650c2011ad8a8fd74ef9f/pymongo-4.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb104c3c2a78d9d85571c8ac90ec4f95bca9b297c6eee5ada71fabf1129e1674", size = 1909129 }, + { url = "https://files.pythonhosted.org/packages/0c/74/fd75d5ad4181d6e71ce0fca32404fb71b5046ac84d9a1a2f0862262dd032/pymongo-4.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4924355245a9c79f77b5cda2db36e0f75ece5faf9f84d16014c0a297f6d66786", size = 1987763 }, + { url = "https://files.pythonhosted.org/packages/8a/56/6d3d0ef63c6d8cb98c7c653a3a2e617675f77a95f3853851d17a7664876a/pymongo-4.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11280809e5dacaef4971113f0b4ff4696ee94cfdb720019ff4fa4f9635138252", size = 1950821 }, + { url = "https://files.pythonhosted.org/packages/70/ed/1603fa0c0e51444752c3fa91f16c3a97e6d92eb9fe5e553dae4f18df16f6/pymongo-4.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5d55f2a82e5eb23795f724991cac2bffbb1c0f219c0ba3bf73a835f97f1bb2e", size = 1912247 }, + { url = "https://files.pythonhosted.org/packages/c1/66/e98b2308971d45667cb8179d4d66deca47336c90663a7e0527589f1038b7/pymongo-4.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e974ab16a60be71a8dfad4e5afccf8dd05d41c758060f5d5bda9a758605d9a5d", size = 1862230 }, + { url = "https://files.pythonhosted.org/packages/6c/80/ba9b7ed212a5f8cf8ad7037ed5bbebc1c587fc09242108f153776e4a338b/pymongo-4.10.1-cp312-cp312-win32.whl", hash = "sha256:544890085d9641f271d4f7a47684450ed4a7344d6b72d5968bfae32203b1bb7c", size = 903045 }, + { url = "https://files.pythonhosted.org/packages/76/8b/5afce891d78159912c43726fab32641e3f9718f14be40f978c148ea8db48/pymongo-4.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:dcc07b1277e8b4bf4d7382ca133850e323b7ab048b8353af496d050671c7ac52", size = 926686 }, +] + +[[package]] +name = "pymunk" +version = "6.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/08/1513c868bc2a6bfa22d47acded27f5525c1db10bf1db4fdfa39160991616/pymunk-6.9.0.tar.gz", hash = "sha256:765f7c561a859a1b565bc517a47cc3992d6258e860f9174c533033c218af63c3", size = 3104088 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/96/d8505f4e9661c0e5343db5492895b90b2ada6ec4547fdc7a2df50eb0cdf2/pymunk-6.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02bb0fbbbce2b12c18a033e2cec747e6c4b0db93d2cb9a20f45e569b571ba184", size = 364703 }, + { url = "https://files.pythonhosted.org/packages/54/3e/610a2f2b0c6c14038168f6f862148cb245aef867b01906ce18704acafe1c/pymunk-6.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6aae4f93ac686d5e2ec60b01faa1b3722a8ab630464d0c127e16462e7bef6292", size = 347056 }, + { url = "https://files.pythonhosted.org/packages/4a/dd/4e12fb3671a6c4f2c0604420f0f15b5402b05c4964bba001088a3d92e3b9/pymunk-6.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7734d13e490e84665b1f03e616270b248d5279ed34e03859267f67868f1b94c", size = 1071014 }, + { url = "https://files.pythonhosted.org/packages/91/f8/0618a9204aff896da8b2a9df44179390b178bf00b189851affd4809b1f03/pymunk-6.9.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b05dbfa58d366dea860f7259ca48483922a83620ab6a19effaa74e85a4251966", size = 990358 }, + { url = "https://files.pythonhosted.org/packages/af/67/ea2ff4a26b66acad394e4f28e4e316fbe306d34909eca401baae211ca182/pymunk-6.9.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cb9520c52c043de4b2b1f83979f0d097929f6ff13c8a4059d9d211b98ae25887", size = 976300 }, + { url = "https://files.pythonhosted.org/packages/91/d9/a69b268712dceacf227cfff74401e2292b53050383661d456605a1928a84/pymunk-6.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:da0e153d321073cd07a48380cfc1b7bd8d40bf4ee1b14a7ede33d90a69ee0452", size = 1042511 }, + { url = "https://files.pythonhosted.org/packages/f0/40/21c2a08b027d99f351b75daa36f8a2e2385daba45098078d225811275ff8/pymunk-6.9.0-cp312-cp312-win32.whl", hash = "sha256:8325c9092345764876b1c3855126cb14450dc83dc5b141ff54983a7c77fbae52", size = 315339 }, + { url = "https://files.pythonhosted.org/packages/78/b4/0a18c632f96924f969924cc5903689afcaf474d4c472305805dab391b247/pymunk-6.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:13246a79b599c44d174f5619596c62b656d8539797f28bdb2797c4b700c90a33", size = 366671 }, +] + +[[package]] +name = "pyogrio" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "numpy" }, + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a5/8f/5a784595524a79c269f2b1c880f4fdb152867df700c97005dda51997da02/pyogrio-0.10.0.tar.gz", hash = "sha256:ec051cb568324de878828fae96379b71858933413e185148acb6c162851ab23c", size = 281950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/b5/3c5dfd0b50cbce6f3d4e42c0484647feb1809dbe20e225c4c6abd067e69f/pyogrio-0.10.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2d6558b180e020f71ab7aa7f82d592ed3305c9f698d98f6d0a4637ec7a84c4ce", size = 15079211 }, + { url = "https://files.pythonhosted.org/packages/b8/9a/1ba9c707a094976f343bd0177741eaba0e842fa05ecd8ab97192db4f2ec1/pyogrio-0.10.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:a99102037eead8ba491bc57825c1e395ee31c9956d7bff7b4a9e4fdbff3a13c2", size = 16442782 }, + { url = "https://files.pythonhosted.org/packages/5e/bb/b4250746c2c85fea5004cae93e9e25ad01516e9e94e04de780a2e78139da/pyogrio-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a4c373281d7cbf560c5b61f8f3c7442103ad7f1c7ac4ef3a84572ed7a5dd2f6", size = 23899832 }, + { url = "https://files.pythonhosted.org/packages/bd/4c/79e47e40a8e54e79a45133786a0a58209534f580591c933d40c5ed314fe7/pyogrio-0.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:19f18411bdf836d24cdc08b9337eb3ec415e4ac4086ba64516b36b73a2e88622", size = 23081469 }, + { url = "https://files.pythonhosted.org/packages/47/78/2b62c8a340bcb0ea56b9ddf2ef5fd3d1f101dc0e98816b9e6da87c5ac3b7/pyogrio-0.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:1abbcdd9876f30bebf1df8a0273f6cdeb29d03259290008275c7fddebe139f20", size = 24024758 }, + { url = "https://files.pythonhosted.org/packages/43/97/34605480f06b0ad9611bf58a174eccc6f3673275f3d519cf763391892881/pyogrio-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a3e09839590d71ff832aa95c4f23fa00a2c63c3de82c1fbd4fb8d265792acfc", size = 16160294 }, +] + +[[package]] +name = "pyparsing" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/d5/e5aeee5387091148a19e1145f63606619cb5f20b83fccb63efae6474e7b2/pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c", size = 920984 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/ec/2eb3cd785efd67806c46c13a17339708ddc346cbb684eade7a6e6f79536a/pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84", size = 106921 }, +] + +[[package]] +name = "pyproj" +version = "3.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/47/c2/0572c8e31aebf0270f15f3368adebd10fc473de9f09567a0743a3bc41c8d/pyproj-3.7.0.tar.gz", hash = "sha256:bf658f4aaf815d9d03c8121650b6f0b8067265c36e31bc6660b98ef144d81813", size = 225577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/19/be806b711e9ebfb80411c653054157db128fffdd7f8493e3064136c8d880/pyproj-3.7.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:8cbec92bdd6e9933ca08795c12717d1384e9b51cf4b1acf0d753db255a75c51e", size = 6261400 }, + { url = "https://files.pythonhosted.org/packages/99/3b/8497995e8cae0049d013679c6a7ac6c57b816d590c733a388748dafe5af5/pyproj-3.7.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8c4a8e4d3ba76c3adac3c087544cf92f7f9a19ea34946904a13fca48cc1c0106", size = 4637848 }, + { url = "https://files.pythonhosted.org/packages/ea/f7/2a5b46d6f8da913d58d44942ab06ca4803b5424b73259b15344cf90040f6/pyproj-3.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82624fb42aa31f6b1a860fbc0316babd07fd712642bc31022df4e9b4056bf463", size = 6324856 }, + { url = "https://files.pythonhosted.org/packages/36/83/c257771077bcf9da20d0e97abc834f9037c219986cc76d40183903a30464/pyproj-3.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34e1bbb3f89c68d4a6835c40b2da8b27680eec60e8cc7cdb08c09bcc725b2b62", size = 9525831 }, + { url = "https://files.pythonhosted.org/packages/d6/50/a635de79def69fe03cdef3a4bd3bec780c30987bce3a15dd7099afb2506f/pyproj-3.7.0-cp312-cp312-win32.whl", hash = "sha256:952515d5592167ad4436b355485f82acebed2a49b46722159e4584b75a763dd3", size = 5811864 }, + { url = "https://files.pythonhosted.org/packages/a1/8b/96bc8c8f3eca4eb7fa3758fde0b755d1df30a19f494376e3ee8de1ef4e79/pyproj-3.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0692f806224e8ed82fe4acfa57268ff444fdaf9f330689f24c0d96e59480cce1", size = 6224720 }, +] + +[[package]] +name = "pyqt5" +version = "5.15.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyqt5-qt5" }, + { name = "pyqt5-sip" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/07/c9ed0bd428df6f87183fca565a79fee19fa7c88c7f00a7f011ab4379e77a/PyQt5-5.15.11.tar.gz", hash = "sha256:fda45743ebb4a27b4b1a51c6d8ef455c4c1b5d610c90d2934c7802b5c1557c52", size = 3216775 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/64/42ec1b0bd72d87f87bde6ceb6869f444d91a2d601f2e67cd05febc0346a1/PyQt5-5.15.11-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c8b03dd9380bb13c804f0bdb0f4956067f281785b5e12303d529f0462f9afdc2", size = 6579776 }, + { url = "https://files.pythonhosted.org/packages/49/f5/3fb696f4683ea45d68b7e77302eff173493ac81e43d63adb60fa760b9f91/PyQt5-5.15.11-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:6cd75628f6e732b1ffcfe709ab833a0716c0445d7aec8046a48d5843352becb6", size = 7016415 }, + { url = "https://files.pythonhosted.org/packages/b4/8c/4065950f9d013c4b2e588fe33cf04e564c2322842d84dbcbce5ba1dc28b0/PyQt5-5.15.11-cp38-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:cd672a6738d1ae33ef7d9efa8e6cb0a1525ecf53ec86da80a9e1b6ec38c8d0f1", size = 8188103 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/ae5a5b4f9b826b29ea4be841b2f2d951bcf5ae1d802f3732b145b57c5355/PyQt5-5.15.11-cp38-abi3-win32.whl", hash = "sha256:76be0322ceda5deecd1708a8d628e698089a1cea80d1a49d242a6d579a40babd", size = 5433308 }, + { url = "https://files.pythonhosted.org/packages/56/d5/68eb9f3d19ce65df01b6c7b7a577ad3bbc9ab3a5dd3491a4756e71838ec9/PyQt5-5.15.11-cp38-abi3-win_amd64.whl", hash = "sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517", size = 6865864 }, +] + +[[package]] +name = "pyqt5-qt5" +version = "5.15.15" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/6e/a5789bac6310208756fc6a36fd7e01caa86ea6ae7abbb5922dcea003a215/PyQt5_Qt5-5.15.15-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:eb74072935958a830887115b1de1ff26341fc2d5881b28129de39612b10a260e", size = 39147807 }, + { url = "https://files.pythonhosted.org/packages/92/4c/c9026ca280f2cd4bef562cfb0a5050eb23f1e7fe1b85aa8455eb6ea437bf/PyQt5_Qt5-5.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f8b174725fbe29c1a22f8acce5798933a65c8a083f1d9833ff212479ec2b3c14", size = 36953104 }, + { url = "https://files.pythonhosted.org/packages/95/70/1ba9b828387f42e0812b496ed637a950bf57a5d59b844d034841e8f9fb4f/PyQt5_Qt5-5.15.15-py3-none-manylinux2014_x86_64.whl", hash = "sha256:611505d04ffb06a5e5bcf98f5ff0e4e15ba7785565ccbe7bd3b2e40642ea3bdd", size = 59827278 }, +] + +[[package]] +name = "pyqt5-sip" +version = "12.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/b8/8e2a30fc0e5222e8d86572d5c7c3611fea93ab8d2369927b6e42977c9a42/PyQt5_sip-12.16.0.tar.gz", hash = "sha256:8cfb0345b9438a18ec1dd3952054c2ac1508bd9e306092a96df99329382e3e25", size = 103977 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/3c/0713c459e95a2a1317d8955189dfd1ef300f70a1f1eeb3b0b65b24dbf8b7/PyQt5_sip-12.16.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:70ebd353ca0da7d7140fcab6718ee802157aa7794171fc80887b9251ebf44e6b", size = 124546 }, + { url = "https://files.pythonhosted.org/packages/f8/bf/b5675329f34182efe52205df26516e842670c57bd24b3d2eb9b97ac9c59e/PyQt5_sip-12.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9ec67e5f55df791c9139dc9c890530f243aac304d60e731846bd9302064dc727", size = 281638 }, + { url = "https://files.pythonhosted.org/packages/be/0f/4e0cd2c07981f51d5f58e68cf25586f7133f170a68ecbbd856f2412f19f6/PyQt5_sip-12.16.0-cp312-cp312-win32.whl", hash = "sha256:7a9260174aa875e24603cb0840fc76ced2f35d90af057ce2f6d79d282cf1bbdc", size = 49430 }, + { url = "https://files.pythonhosted.org/packages/eb/31/8610b8e0f53400dbfd3cfe2f838d725239650e0a27cdf6fc5d5dc1518b8a/PyQt5_sip-12.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:57135e6b1f309b20163aaf15515967bec01ee145c538f87f9f89d8afc8c570f1", size = 57957 }, +] + +[[package]] +name = "pysal" +version = "24.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "access" }, + { name = "beautifulsoup4" }, + { name = "esda" }, + { name = "geopandas" }, + { name = "giddy" }, + { name = "inequality" }, + { name = "libpysal" }, + { name = "mapclassify" }, + { name = "mgwr" }, + { name = "momepy" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "platformdirs" }, + { name = "pointpats" }, + { name = "requests" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "segregation" }, + { name = "shapely" }, + { name = "spaghetti" }, + { name = "spglm" }, + { name = "spint" }, + { name = "splot" }, + { name = "spopt" }, + { name = "spreg" }, + { name = "spvcm" }, + { name = "tobler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/8c/50b280aa50d7998441fbce7a7bfaaa9c85cf611cd6c5b66910c8ed39ff20/pysal-24.7.tar.gz", hash = "sha256:7cf9d520b21c3c5db15d08d0f670e6b1cc4f029df46a31b9ddaee2d4b1210c8b", size = 2073180 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d8/53/5597ffb9c9847b4e468d584445ad44cea1633429f01d20cc5f481e8d048a/pysal-24.7-py3-none-any.whl", hash = "sha256:86e02d7af7d3741120c0bcd8aefbe4203c1434a4df4b0f1b2d8cb15b1498f084", size = 17616 }, +] + +[[package]] +name = "pytest" +version = "8.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, +] + +[[package]] +name = "pytest-cov" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-json-logger" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", size = 10508 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 }, +] + +[[package]] +name = "pytz" +version = "2024.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 }, +] + +[[package]] +name = "pyviz-comms" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "param" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/21460c434d01fe94bd97b9a5b41726ae79b68024b634dcaf7d77f8254c6f/pyviz_comms-3.0.3.tar.gz", hash = "sha256:fde4a017c2213ecee63a9a6741431c845e42a5c7b1588e4a7ba2e4370c583728", size = 196501 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/3e/5a36494314e4780362b15a7e190095eec68366a0d512b5b532607c213a26/pyviz_comms-3.0.3-py3-none-any.whl", hash = "sha256:fd26951eebc7950106d481655d91ba06296d4cf352dffb1d03f88f959832448e", size = 83530 }, +] + +[[package]] +name = "pywin32" +version = "308" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, +] + +[[package]] +name = "pywinpty" +version = "2.0.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/82/90f8750423cba4b9b6c842df227609fb60704482d7abf6dd47e2babc055a/pywinpty-2.0.14.tar.gz", hash = "sha256:18bd9529e4a5daf2d9719aa17788ba6013e594ae94c5a0c27e83df3278b0660e", size = 27769 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/79/759ae767a3b78d340446efd54dd1fe4f7dafa4fc7be96ed757e44bcdba54/pywinpty-2.0.14-cp312-none-win_amd64.whl", hash = "sha256:55dad362ef3e9408ade68fd173e4f9032b3ce08f68cfe7eacb2c263ea1179737", size = 1397207 }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, +] + +[[package]] +name = "pyzmq" +version = "26.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/2f/78a766c8913ad62b28581777ac4ede50c6d9f249d39c2963e279524a1bbe/pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9", size = 1343105 }, + { url = "https://files.pythonhosted.org/packages/b7/9c/4b1e2d3d4065be715e007fe063ec7885978fad285f87eae1436e6c3201f4/pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52", size = 1008365 }, + { url = "https://files.pythonhosted.org/packages/4f/ef/5a23ec689ff36d7625b38d121ef15abfc3631a9aecb417baf7a4245e4124/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08", size = 665923 }, + { url = "https://files.pythonhosted.org/packages/ae/61/d436461a47437d63c6302c90724cf0981883ec57ceb6073873f32172d676/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5", size = 903400 }, + { url = "https://files.pythonhosted.org/packages/47/42/fc6d35ecefe1739a819afaf6f8e686f7f02a4dd241c78972d316f403474c/pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae", size = 860034 }, + { url = "https://files.pythonhosted.org/packages/07/3b/44ea6266a6761e9eefaa37d98fabefa112328808ac41aa87b4bbb668af30/pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711", size = 860579 }, + { url = "https://files.pythonhosted.org/packages/38/6f/4df2014ab553a6052b0e551b37da55166991510f9e1002c89cab7ce3b3f2/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6", size = 1196246 }, + { url = "https://files.pythonhosted.org/packages/38/9d/ee240fc0c9fe9817f0c9127a43238a3e28048795483c403cc10720ddef22/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3", size = 1507441 }, + { url = "https://files.pythonhosted.org/packages/85/4f/01711edaa58d535eac4a26c294c617c9a01f09857c0ce191fd574d06f359/pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b", size = 1406498 }, + { url = "https://files.pythonhosted.org/packages/07/18/907134c85c7152f679ed744e73e645b365f3ad571f38bdb62e36f347699a/pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7", size = 575533 }, + { url = "https://files.pythonhosted.org/packages/ce/2c/a6f4a20202a4d3c582ad93f95ee78d79bbdc26803495aec2912b17dbbb6c/pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a", size = 637768 }, + { url = "https://files.pythonhosted.org/packages/5f/0e/eb16ff731632d30554bf5af4dbba3ffcd04518219d82028aea4ae1b02ca5/pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b", size = 540675 }, +] + +[[package]] +name = "qdldl" +version = "0.1.7.post4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/ce/817c670dbf346281e7344d97fc37270e51eb54a67c944728928d3045a56c/qdldl-0.1.7.post4.tar.gz", hash = "sha256:0c163b9afb92c4b69d446387b1d4295094438b041ec4e8510271b6c4ff1f86fd", size = 73919 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/37/9ae52198cfd9070f72f4421656fbcc13bdb3391acd1741b00cb7fa1a59ff/qdldl-0.1.7.post4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2b9e92bb52d3bc49cfc9fd9a761adb692f049c46e68c0535ed07df2de8292f5", size = 102123 }, + { url = "https://files.pythonhosted.org/packages/3c/c3/e153b6181d0e275b5d370ae509ff288a9b46b35a2d8af73eb5e9bce82ce4/qdldl-0.1.7.post4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f6710b0c1013292697262803ddd549a81cdfdbdbbbcfa5b56aad04ac9cebbb4a", size = 98898 }, + { url = "https://files.pythonhosted.org/packages/30/9e/1ddf8b3903d2fd8bcb9f3d9d3b9e4390285608223790279ca8ca3f82e7ad/qdldl-0.1.7.post4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a40429f5c0d0edb28d22c4e52c2459fd9a64892ba7d8a39ba51a1a37b3581927", size = 1137897 }, + { url = "https://files.pythonhosted.org/packages/1e/f5/dc4c2a07d2e281df982533733ec6eeda507c605443ac351f5357259cdbbb/qdldl-0.1.7.post4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b85beb51096100dcdea575acedbafb5bac2b7f44485a1d7090bb68a47c8f9928", size = 1156526 }, + { url = "https://files.pythonhosted.org/packages/71/55/f9a26749a4019eb5a149b4304d8dfcac6a27450f2e605c298c8363ead9bc/qdldl-0.1.7.post4-cp312-cp312-win_amd64.whl", hash = "sha256:684306b37a2f06f72c18edd2d6fa45a832e99071ebd87b875d172719e09a322d", size = 87782 }, +] + +[[package]] +name = "quantecon" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numba" }, + { name = "numpy" }, + { name = "requests" }, + { name = "scipy" }, + { name = "sympy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/c2/1bd8e16607bacf69e73c1f688bd62e178265ed82f367d318e1de94f141b1/quantecon-0.7.2.tar.gz", hash = "sha256:a73bedde80d2452e096bbfa3472cf002b09f5061bcba1da94e57e8d59afcdccc", size = 173187 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/1b/75e44bd482abe2e87dcbead8cfd99b8fa6582fdc0906967c34f64abfdf13/quantecon-0.7.2-py3-none-any.whl", hash = "sha256:d1333ca7bc3046efe3655d9eeeefb299051b00870b8608cb5bc0b88e3bdb8b67", size = 215436 }, +] + +[[package]] +name = "rasterio" +version = "1.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "affine" }, + { name = "attrs" }, + { name = "certifi" }, + { name = "click" }, + { name = "click-plugins" }, + { name = "cligj" }, + { name = "numpy" }, + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/19/ab4326e419b543da623ce4191f68e3f36a4d9adc64f3df5c78f044d8d9ca/rasterio-1.4.3.tar.gz", hash = "sha256:201f05dbc7c4739dacb2c78a1cf4e09c0b7265b0a4d16ccbd1753ce4f2af350a", size = 442990 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/f2/b7417292ceace70d815760f7e41fe5b0244ebff78ede11b1ffa9ca01c370/rasterio-1.4.3-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:e703e4b2c74c678786d5d110a3f30e26f3acfd65f09ccf35f69683a532f7a772", size = 21514543 }, + { url = "https://files.pythonhosted.org/packages/b2/ea/e21010457847b26bb4aea3983e9b44afbcefef07defc5e9a3285a8fe2f0c/rasterio-1.4.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:38a126f8dbf405cd3450b5bd10c6cc493a2e1be4cf83442d26f5e4f412372d36", size = 18735924 }, + { url = "https://files.pythonhosted.org/packages/67/72/331727423b28fffdfd8bf18bdc55c18d374c0fefd2dde390cd833f8f4477/rasterio-1.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e90c2c300294265c16becc9822337ded0f01fb8664500b4d77890d633d8cd0e", size = 22251721 }, + { url = "https://files.pythonhosted.org/packages/be/cc/453816b489af94b9a243eda889865973d518989ba6923b2381f6d6722b43/rasterio-1.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:a962ad4c29feaf38b1d7a94389313127de3646a5b9b734fbf9a04e16051a27ff", size = 25430154 }, +] + +[[package]] +name = "rasterstats" +version = "0.20.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "affine" }, + { name = "click" }, + { name = "cligj" }, + { name = "fiona" }, + { name = "numpy" }, + { name = "rasterio" }, + { name = "shapely" }, + { name = "simplejson" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/3d/6a32a149e494b9b3f17edc4243843563a899b1ab4feb680f22bf688bd189/rasterstats-0.20.0.tar.gz", hash = "sha256:5b8ee775e815727767e0d359c03f3dd1c7840876d1d1d0c7a5a88ecf3e492938", size = 24017 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/0b/bd73621d2a5f87da97158c5c77a4bf31e27d60cf6bcc6ddea532043cc21d/rasterstats-0.20.0-py3-none-any.whl", hash = "sha256:a7015e99f42807842b8638d489157639ff0cbf8e35aac9647aa3e079982b18ee", size = 17280 }, +] + +[[package]] +name = "referencing" +version = "0.35.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/73ca1f8e72fff6fa52119dbd185f73a907b1989428917b24cff660129b6d/referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c", size = 62991 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de", size = 26684 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179 }, +] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, +] + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, +] + +[[package]] +name = "rpds-py" +version = "0.22.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/75/47/3383ee3bd787a2a5e65a9b9edc37ccf8505c0a00170e3a5e6ea5fbcd97f7/rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e", size = 352334 }, + { url = "https://files.pythonhosted.org/packages/40/14/aa6400fa8158b90a5a250a77f2077c0d0cd8a76fce31d9f2b289f04c6dec/rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56", size = 342111 }, + { url = "https://files.pythonhosted.org/packages/7d/06/395a13bfaa8a28b302fb433fb285a67ce0ea2004959a027aea8f9c52bad4/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45", size = 384286 }, + { url = "https://files.pythonhosted.org/packages/43/52/d8eeaffab047e6b7b7ef7f00d5ead074a07973968ffa2d5820fa131d7852/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e", size = 391739 }, + { url = "https://files.pythonhosted.org/packages/83/31/52dc4bde85c60b63719610ed6f6d61877effdb5113a72007679b786377b8/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d", size = 427306 }, + { url = "https://files.pythonhosted.org/packages/70/d5/1bab8e389c2261dba1764e9e793ed6830a63f830fdbec581a242c7c46bda/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38", size = 442717 }, + { url = "https://files.pythonhosted.org/packages/82/a1/a45f3e30835b553379b3a56ea6c4eb622cf11e72008229af840e4596a8ea/rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15", size = 385721 }, + { url = "https://files.pythonhosted.org/packages/a6/27/780c942de3120bdd4d0e69583f9c96e179dfff082f6ecbb46b8d6488841f/rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059", size = 415824 }, + { url = "https://files.pythonhosted.org/packages/94/0b/aa0542ca88ad20ea719b06520f925bae348ea5c1fdf201b7e7202d20871d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e", size = 561227 }, + { url = "https://files.pythonhosted.org/packages/0d/92/3ed77d215f82c8f844d7f98929d56cc321bb0bcfaf8f166559b8ec56e5f1/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61", size = 587424 }, + { url = "https://files.pythonhosted.org/packages/09/42/cacaeb047a22cab6241f107644f230e2935d4efecf6488859a7dd82fc47d/rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7", size = 555953 }, + { url = "https://files.pythonhosted.org/packages/e6/52/c921dc6d5f5d45b212a456c1f5b17df1a471127e8037eb0972379e39dff4/rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627", size = 221339 }, + { url = "https://files.pythonhosted.org/packages/f2/c7/f82b5be1e8456600395366f86104d1bd8d0faed3802ad511ef6d60c30d98/rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4", size = 235786 }, +] + +[[package]] +name = "rsa" +version = "4.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 }, +] + +[[package]] +name = "rtree" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/79/44fdc619e87bd7b5388f76418719bd8b99de5565475f74a2e0d82b401062/rtree-1.3.0.tar.gz", hash = "sha256:b36e9dd2dc60ffe3d02e367242d2c26f7281b00e1aaf0c39590442edaaadd916", size = 48190 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/cc/1b494bde9c99a5cf27e980bf36ef99e76abac6316736231007c04e3a7b28/Rtree-1.3.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:80879d9db282a2273ca3a0d896c84583940e9777477727a277624ebfd424c517", size = 475526 }, + { url = "https://files.pythonhosted.org/packages/dd/5b/085d6fad9d45c0cc2acbea5b78c3a2d7f1e7ccc7c05929633461a6a741d8/Rtree-1.3.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4328e9e421797c347e6eb08efbbade962fe3664ebd60c1dffe82c40911b1e125", size = 432890 }, + { url = "https://files.pythonhosted.org/packages/12/70/f0553ffb163c47a62c09e4bdc5e0c7fb3392a03cd5a3dbde965aa6a85052/Rtree-1.3.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:037130d3ce1fc029de81941ec416ba5546f66228380ba19bb41f2ea1294e8423", size = 500384 }, + { url = "https://files.pythonhosted.org/packages/4e/92/3c972e534ce0508214b9ed0cfeba03d1e26d193e8fa624131b5324b91b25/Rtree-1.3.0-py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:864a05d0c3b7ce6c5e34378b7ab630057603b79179368bc50624258bdf2ff631", size = 569246 }, + { url = "https://files.pythonhosted.org/packages/70/db/6c8bc20061572c33766ade296071d0127e7365d4d3ff54a6c2c075de637b/Rtree-1.3.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ec2ed6d1635753dab966e68f592a9c4896f3f4ec6ad2b09b776d592eacd883a9", size = 543195 }, + { url = "https://files.pythonhosted.org/packages/71/2c/5d04fa6010f2d4d4b38078efdc6f371430f499ef2cf7eeced3d18f57daaa/Rtree-1.3.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:b4485fb3e5c5e85b94a95f0a930a3848e040d2699cfb012940ba5b0130f1e09a", size = 1416562 }, + { url = "https://files.pythonhosted.org/packages/b6/63/0a2bee2940a8ba116d845ac8b360e49c315a57aeb4aa92ea12a4cb84eb4f/Rtree-1.3.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:7e2e9211f4fb404c06a08fd2cbebb03234214f73c51913bb371c3d9954e99cc9", size = 1630693 }, + { url = "https://files.pythonhosted.org/packages/10/8a/8a50fc8d58807ba5780485ecc502136aa814f6a08e1cce4f9c4f109ba2b4/Rtree-1.3.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:c021f4772b25cc24915da8073e553ded6fa8d0b317caa4202255ed26b2344c1c", size = 1506863 }, + { url = "https://files.pythonhosted.org/packages/85/d2/5bb7617faa3b23b51e2259f9d23e0b33f6ff0ed9811b0d05511e9b7ed84e/Rtree-1.3.0-py3-none-win_amd64.whl", hash = "sha256:97f835801d24c10bbf02381abe5e327345c8296ec711dde7658792376abafc66", size = 377458 }, +] + +[[package]] +name = "ruff" +version = "0.8.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/2b/01245f4f3a727d60bebeacd7ee6d22586c7f62380a2597ddb22c2f45d018/ruff-0.8.2.tar.gz", hash = "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5", size = 3349020 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/29/366be70216dba1731a00a41f2f030822b0c96c7c4f3b2c0cdce15cbace74/ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d", size = 10530649 }, + { url = "https://files.pythonhosted.org/packages/63/82/a733956540bb388f00df5a3e6a02467b16c0e529132625fe44ce4c5fb9c7/ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5", size = 10274069 }, + { url = "https://files.pythonhosted.org/packages/3d/12/0b3aa14d1d71546c988a28e1b412981c1b80c8a1072e977a2f30c595cc4a/ruff-0.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c", size = 9909400 }, + { url = "https://files.pythonhosted.org/packages/23/08/f9f08cefb7921784c891c4151cce6ed357ff49e84b84978440cffbc87408/ruff-0.8.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f", size = 10766782 }, + { url = "https://files.pythonhosted.org/packages/e4/71/bf50c321ec179aa420c8ec40adac5ae9cc408d4d37283a485b19a2331ceb/ruff-0.8.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897", size = 10286316 }, + { url = "https://files.pythonhosted.org/packages/f2/83/c82688a2a6117539aea0ce63fdf6c08e60fe0202779361223bcd7f40bd74/ruff-0.8.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58", size = 11338270 }, + { url = "https://files.pythonhosted.org/packages/7f/d7/bc6a45e5a22e627640388e703160afb1d77c572b1d0fda8b4349f334fc66/ruff-0.8.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29", size = 12058579 }, + { url = "https://files.pythonhosted.org/packages/da/3b/64150c93946ec851e6f1707ff586bb460ca671581380c919698d6a9267dc/ruff-0.8.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248", size = 11615172 }, + { url = "https://files.pythonhosted.org/packages/e4/9e/cf12b697ea83cfe92ec4509ae414dc4c9b38179cc681a497031f0d0d9a8e/ruff-0.8.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93", size = 12882398 }, + { url = "https://files.pythonhosted.org/packages/a9/27/96d10863accf76a9c97baceac30b0a52d917eb985a8ac058bd4636aeede0/ruff-0.8.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d", size = 11176094 }, + { url = "https://files.pythonhosted.org/packages/eb/10/cd2fd77d4a4e7f03c29351be0f53278a393186b540b99df68beb5304fddd/ruff-0.8.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0", size = 10771884 }, + { url = "https://files.pythonhosted.org/packages/71/5d/beabb2ff18870fc4add05fa3a69a4cb1b1d2d6f83f3cf3ae5ab0d52f455d/ruff-0.8.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa", size = 10382535 }, + { url = "https://files.pythonhosted.org/packages/ae/29/6b3fdf3ad3e35b28d87c25a9ff4c8222ad72485ab783936b2b267250d7a7/ruff-0.8.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f", size = 10886995 }, + { url = "https://files.pythonhosted.org/packages/e9/dc/859d889b4d9356a1a2cdbc1e4a0dda94052bc5b5300098647e51a58c430b/ruff-0.8.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22", size = 11220750 }, + { url = "https://files.pythonhosted.org/packages/0b/08/e8f519f61f1d624264bfd6b8829e4c5f31c3c61193bc3cff1f19dbe7626a/ruff-0.8.2-py3-none-win32.whl", hash = "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1", size = 8729396 }, + { url = "https://files.pythonhosted.org/packages/f8/d4/ba1c7ab72aba37a2b71fe48ab95b80546dbad7a7f35ea28cf66fc5cea5f6/ruff-0.8.2-py3-none-win_amd64.whl", hash = "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea", size = 9594729 }, + { url = "https://files.pythonhosted.org/packages/23/34/db20e12d3db11b8a2a8874258f0f6d96a9a4d631659d54575840557164c8/ruff-0.8.2-py3-none-win_arm64.whl", hash = "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8", size = 9035131 }, +] + +[[package]] +name = "scikit-image" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "imageio" }, + { name = "lazy-loader" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "scipy" }, + { name = "tifffile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/c5/bcd66bf5aae5587d3b4b69c74bee30889c46c9778e858942ce93a030e1f3/scikit_image-0.24.0.tar.gz", hash = "sha256:5d16efe95da8edbeb363e0c4157b99becbd650a60b77f6e3af5768b66cf007ab", size = 22693928 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/19/45ad3b8b8ab8d275a48a9d1016c4beb1c2801a7a13e384268861d01145c1/scikit_image-0.24.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6fccceb54c9574590abcddc8caf6cefa57c13b5b8b4260ab3ff88ad8f3c252b3", size = 14101823 }, + { url = "https://files.pythonhosted.org/packages/6e/75/db10ee1bc7936b411d285809b5fe62224bbb1b324a03dd703582132ce5ee/scikit_image-0.24.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ccc01e4760d655aab7601c1ba7aa4ddd8b46f494ac46ec9c268df6f33ccddf4c", size = 13420758 }, + { url = "https://files.pythonhosted.org/packages/87/fd/07a7396962abfe22a285a922a63d18e4d5ec48eb5dbb1c06e96fb8fb6528/scikit_image-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18836a18d3a7b6aca5376a2d805f0045826bc6c9fc85331659c33b4813e0b563", size = 14256813 }, + { url = "https://files.pythonhosted.org/packages/2c/24/4bcd94046b409ac4d63e2f92e46481f95f5006a43e68f6ab2b24f5d70ab4/scikit_image-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8579bda9c3f78cb3b3ed8b9425213c53a25fa7e994b7ac01f2440b395babf660", size = 15013039 }, + { url = "https://files.pythonhosted.org/packages/d9/17/b561823143eb931de0f82fed03ae128ef954a9641309602ea0901c357f95/scikit_image-0.24.0-cp312-cp312-win_amd64.whl", hash = "sha256:82ab903afa60b2da1da2e6f0c8c65e7c8868c60a869464c41971da929b3e82bc", size = 12949363 }, +] + +[[package]] +name = "scikit-learn" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/59/44985a2bdc95c74e34fef3d10cb5d93ce13b0e2a7baefffe1b53853b502d/scikit_learn-1.5.2.tar.gz", hash = "sha256:b4237ed7b3fdd0a4882792e68ef2545d5baa50aca3bb45aa7df468138ad8f94d", size = 7001680 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/db/b485c1ac54ff3bd9e7e6b39d3cc6609c4c76a65f52ab0a7b22b6c3ab0e9d/scikit_learn-1.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f932a02c3f4956dfb981391ab24bda1dbd90fe3d628e4b42caef3e041c67707a", size = 12110344 }, + { url = "https://files.pythonhosted.org/packages/54/1a/7deb52fa23aebb855431ad659b3c6a2e1709ece582cb3a63d66905e735fe/scikit_learn-1.5.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3b923d119d65b7bd555c73be5423bf06c0105678ce7e1f558cb4b40b0a5502b1", size = 11033502 }, + { url = "https://files.pythonhosted.org/packages/a1/32/4a7a205b14c11225609b75b28402c196e4396ac754dab6a81971b811781c/scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd", size = 12085794 }, + { url = "https://files.pythonhosted.org/packages/c6/29/044048c5e911373827c0e1d3051321b9183b2a4f8d4e2f11c08fcff83f13/scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6", size = 12945797 }, + { url = "https://files.pythonhosted.org/packages/aa/ce/c0b912f2f31aeb1b756a6ba56bcd84dd1f8a148470526a48515a3f4d48cd/scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1", size = 10985467 }, +] + +[[package]] +name = "scipy" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/11/4d44a1f274e002784e4dbdb81e0ea96d2de2d1045b2132d5af62cc31fd28/scipy-1.14.1.tar.gz", hash = "sha256:5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417", size = 58620554 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/04/2bdacc8ac6387b15db6faa40295f8bd25eccf33f1f13e68a72dc3c60a99e/scipy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:631f07b3734d34aced009aaf6fedfd0eb3498a97e581c3b1e5f14a04164a456d", size = 39128781 }, + { url = "https://files.pythonhosted.org/packages/c8/53/35b4d41f5fd42f5781dbd0dd6c05d35ba8aa75c84ecddc7d44756cd8da2e/scipy-1.14.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:af29a935803cc707ab2ed7791c44288a682f9c8107bc00f0eccc4f92c08d6e07", size = 29939542 }, + { url = "https://files.pythonhosted.org/packages/66/67/6ef192e0e4d77b20cc33a01e743b00bc9e68fb83b88e06e636d2619a8767/scipy-1.14.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:2843f2d527d9eebec9a43e6b406fb7266f3af25a751aa91d62ff416f54170bc5", size = 23148375 }, + { url = "https://files.pythonhosted.org/packages/f6/32/3a6dedd51d68eb7b8e7dc7947d5d841bcb699f1bf4463639554986f4d782/scipy-1.14.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:eb58ca0abd96911932f688528977858681a59d61a7ce908ffd355957f7025cfc", size = 25578573 }, + { url = "https://files.pythonhosted.org/packages/f0/5a/efa92a58dc3a2898705f1dc9dbaf390ca7d4fba26d6ab8cfffb0c72f656f/scipy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30ac8812c1d2aab7131a79ba62933a2a76f582d5dbbc695192453dae67ad6310", size = 35319299 }, + { url = "https://files.pythonhosted.org/packages/8e/ee/8a26858ca517e9c64f84b4c7734b89bda8e63bec85c3d2f432d225bb1886/scipy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f9ea80f2e65bdaa0b7627fb00cbeb2daf163caa015e59b7516395fe3bd1e066", size = 40849331 }, + { url = "https://files.pythonhosted.org/packages/a5/cd/06f72bc9187840f1c99e1a8750aad4216fc7dfdd7df46e6280add14b4822/scipy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:edaf02b82cd7639db00dbff629995ef185c8df4c3ffa71a5562a595765a06ce1", size = 42544049 }, + { url = "https://files.pythonhosted.org/packages/aa/7d/43ab67228ef98c6b5dd42ab386eae2d7877036970a0d7e3dd3eb47a0d530/scipy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:2ff38e22128e6c03ff73b6bb0f85f897d2362f8c052e3b8ad00532198fbdae3f", size = 44521212 }, +] + +[[package]] +name = "scs" +version = "3.2.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/54/2550a67de4d675ab7c733b6c61575995958d2beffdbb69c2287461eb9c3a/scs-3.2.7.tar.gz", hash = "sha256:e89d81752ef241d7e408f21d0b69cde9bb6ce196241482e17f763cba5a7d9497", size = 1600253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/d3/cc2ae520c7d6c6d6ae553bf9ae6661deea30b96f8d8fbf3dfc36363f6806/scs-3.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ae5f0b85c5970d5024343a8ade77a0b1d05e5b36aa2069067971ae6adcaa51e7", size = 105889 }, + { url = "https://files.pythonhosted.org/packages/8b/08/9b5d872ffab4aa938821419231ed56f3fbf262cdd8102ff80ba4ff7d2c11/scs-3.2.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab0678e6a678929fabc1f18c34ff9a2ad888d8e2f73a1a350770ecb62fb35724", size = 93472 }, + { url = "https://files.pythonhosted.org/packages/9f/87/0da6223183ca403b6478ab7f8ba87b83b8f2d6546dba2b929cf05b97d734/scs-3.2.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d91ab6d26b6aaf14905c1295c331cef2ed956a16b92228de2fa58723729f6d7", size = 10443056 }, + { url = "https://files.pythonhosted.org/packages/08/12/074f49ac609a6886f26bd42ef4e63da1d5e9108618eb2fe461d7a6908400/scs-3.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:ab42697c7b8deeb2bb800b4d7ff6ab6c313d2f235f0d031f85a38f986a29006e", size = 8444209 }, +] + +[[package]] +name = "seaborn" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, +] + +[[package]] +name = "segregation" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "deprecation" }, + { name = "geopandas" }, + { name = "joblib" }, + { name = "libpysal" }, + { name = "mapclassify" }, + { name = "matplotlib" }, + { name = "numba" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pyproj" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/c4/c6b882e9b071ab84eafae68225e24b182bc455eb3097c94e5e33584804c5/segregation-2.5.1.tar.gz", hash = "sha256:fedd0e16413a1ef111404d18f5af9652cf47ee4a7fdaf1ad15e932b5034e4042", size = 15930644 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/41/c1b92476668a67b1ac07283b4b9596e634fcf5940e45f5393b3c65e33cec/segregation-2.5.1-py3-none-any.whl", hash = "sha256:cc7493eaf8c4713f3bc3764616c830472ded9f4c9adb2f8df3116a7d17d17e04", size = 141314 }, +] + +[[package]] +name = "send2trash" +version = "1.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072 }, +] + +[[package]] +name = "setuptools" +version = "75.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/54/292f26c208734e9a7f067aea4a7e282c080750c4546559b58e2e45413ca0/setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6", size = 1337429 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/21/47d163f615df1d30c094f6c8bbb353619274edccf0327b185cc2493c2c33/setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d", size = 1224032 }, +] + +[[package]] +name = "shapely" +version = "2.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/89/0d20bac88016be35ff7d3c0c2ae64b477908f1b1dfa540c5d69ac7af07fe/shapely-2.0.6.tar.gz", hash = "sha256:997f6159b1484059ec239cacaa53467fd8b5564dabe186cd84ac2944663b0bf6", size = 282361 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/77/efd9f9d4b6a762f976f8b082f54c9be16f63050389500fb52e4f6cc07c1a/shapely-2.0.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cec9193519940e9d1b86a3b4f5af9eb6910197d24af02f247afbfb47bcb3fab0", size = 1450326 }, + { url = "https://files.pythonhosted.org/packages/68/53/5efa6e7a4036a94fe6276cf7bbb298afded51ca3396b03981ad680c8cc7d/shapely-2.0.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83b94a44ab04a90e88be69e7ddcc6f332da7c0a0ebb1156e1c4f568bbec983c3", size = 1298480 }, + { url = "https://files.pythonhosted.org/packages/88/a2/1be1db4fc262e536465a52d4f19d85834724fedf2299a1b9836bc82fe8fa/shapely-2.0.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:537c4b2716d22c92036d00b34aac9d3775e3691f80c7aa517c2c290351f42cd8", size = 2439311 }, + { url = "https://files.pythonhosted.org/packages/d5/7d/9a57e187cbf2fbbbdfd4044a4f9ce141c8d221f9963750d3b001f0ec080d/shapely-2.0.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fea108334be345c283ce74bf064fa00cfdd718048a8af7343c59eb40f59726", size = 2524835 }, + { url = "https://files.pythonhosted.org/packages/6d/0a/f407509ab56825f39bf8cfce1fb410238da96cf096809c3e404e5bc71ea1/shapely-2.0.6-cp312-cp312-win32.whl", hash = "sha256:42fd4cd4834747e4990227e4cbafb02242c0cffe9ce7ef9971f53ac52d80d55f", size = 1295613 }, + { url = "https://files.pythonhosted.org/packages/7b/b3/857afd9dfbfc554f10d683ac412eac6fa260d1f4cd2967ecb655c57e831a/shapely-2.0.6-cp312-cp312-win_amd64.whl", hash = "sha256:665990c84aece05efb68a21b3523a6b2057e84a1afbef426ad287f0796ef8a48", size = 1442539 }, +] + +[[package]] +name = "simplejson" +version = "3.19.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/29/085111f19717f865eceaf0d4397bf3e76b08d60428b076b64e2a1903706d/simplejson-3.19.3.tar.gz", hash = "sha256:8e086896c36210ab6050f2f9f095a5f1e03c83fa0e7f296d6cba425411364680", size = 85237 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/15/513fea93fafbdd4993eacfcb762965b2ff3d29e618c029e2956174d68c4b/simplejson-3.19.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:66a0399e21c2112acacfebf3d832ebe2884f823b1c7e6d1363f2944f1db31a99", size = 92921 }, + { url = "https://files.pythonhosted.org/packages/a4/4f/998a907ae1a6c104dc0ee48aa248c2478490152808d34d8e07af57f396c3/simplejson-3.19.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6ef9383c5e05f445be60f1735c1816163c874c0b1ede8bb4390aff2ced34f333", size = 75311 }, + { url = "https://files.pythonhosted.org/packages/db/44/acd6122201e927451869d45952b9ab1d3025cdb5e61548d286d08fbccc08/simplejson-3.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:42e5acf80d4d971238d4df97811286a044d720693092b20a56d5e56b7dcc5d09", size = 74964 }, + { url = "https://files.pythonhosted.org/packages/27/ca/d0a1e8f16e1bbdc0b8c6d88166f45f565ed7285f53928cfef3b6ce78f14d/simplejson-3.19.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0b0efc7279d768db7c74d3d07f0b5c81280d16ae3fb14e9081dc903e8360771", size = 150106 }, + { url = "https://files.pythonhosted.org/packages/63/59/0554b78cf26c98e2b9cae3f44723bd72c2394e2afec1a14eedc6211f7187/simplejson-3.19.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0552eb06e7234da892e1d02365cd2b7b2b1f8233aa5aabdb2981587b7cc92ea0", size = 158347 }, + { url = "https://files.pythonhosted.org/packages/b2/fe/9f30890352e431e8508cc569912d3322147d3e7e4f321e48c0adfcb4c97d/simplejson-3.19.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf6a3b9a7d7191471b464fe38f684df10eb491ec9ea454003edb45a011ab187", size = 148456 }, + { url = "https://files.pythonhosted.org/packages/37/e3/663a09542ee021d4131162f7a164cb2e7f04ef48433a67591738afbf12ea/simplejson-3.19.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7017329ca8d4dca94ad5e59f496e5fc77630aecfc39df381ffc1d37fb6b25832", size = 152190 }, + { url = "https://files.pythonhosted.org/packages/31/20/4e0c4d35e10ff6465003bec304316d822a559a1c38c66ef6892ca199c207/simplejson-3.19.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:67a20641afebf4cfbcff50061f07daad1eace6e7b31d7622b6fa2c40d43900ba", size = 149846 }, + { url = "https://files.pythonhosted.org/packages/08/7a/46e2e072cac3987cbb05946f25167f0ad2fe536748e7405953fd6661a486/simplejson-3.19.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:dd6a7dabcc4c32daf601bc45e01b79175dde4b52548becea4f9545b0a4428169", size = 151714 }, + { url = "https://files.pythonhosted.org/packages/7f/7d/dbeeac10eb61d5d8858d0bb51121a21050d281dc83af4c557f86da28746c/simplejson-3.19.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:08f9b443a94e72dd02c87098c96886d35790e79e46b24e67accafbf13b73d43b", size = 158777 }, + { url = "https://files.pythonhosted.org/packages/fc/8f/a98bdbb799c6a4a884b5823db31785a96ba895b4b0f4d8ac345d6fe98bbf/simplejson-3.19.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa97278ae6614346b5ca41a45a911f37a3261b57dbe4a00602048652c862c28b", size = 154230 }, + { url = "https://files.pythonhosted.org/packages/b1/db/852eebceb85f969ae40e06babed1a93d3bacb536f187d7a80ff5823a5979/simplejson-3.19.3-cp312-cp312-win32.whl", hash = "sha256:ef28c3b328d29b5e2756903aed888960bc5df39b4c2eab157ae212f70ed5bf74", size = 74002 }, + { url = "https://files.pythonhosted.org/packages/fe/68/9f0e5df0651cb79ef83cba1378765a00ee8038e6201cc82b8e7178a7778e/simplejson-3.19.3-cp312-cp312-win_amd64.whl", hash = "sha256:1e662336db50ad665777e6548b5076329a94a0c3d4a0472971c588b3ef27de3a", size = 75596 }, + { url = "https://files.pythonhosted.org/packages/0d/e7/f9fafbd4f39793a20cc52e77bbd766f7384312526d402c382928dc7667f6/simplejson-3.19.3-py3-none-any.whl", hash = "sha256:49cc4c7b940d43bd12bf87ec63f28cbc4964fc4e12c031cc8cd01650f43eb94e", size = 57004 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + +[[package]] +name = "spaghetti" +version = "1.7.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "esda" }, + { name = "geopandas" }, + { name = "libpysal" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "rtree" }, + { name = "scipy" }, + { name = "shapely" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/eb/55d382ef7c0b1459ccd419e19d46aa9f64effaf99e3651a8f6919964efcb/spaghetti-1.7.6.tar.gz", hash = "sha256:c9beddbb3bf285e88745d36aee886c78ac6e6a416f0f9b1a441265c8c08f923d", size = 22156350 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/04/8f6b281e28cc090f368f5eee126d8fd72f60ed9a318893a54989918b048b/spaghetti-1.7.6-py3-none-any.whl", hash = "sha256:184ececfac6006843c22ca5d2de31621983606e7a611c0107fe5ae4ead33396e", size = 53884 }, +] + +[[package]] +name = "spglm" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "spreg" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/87/5e8ba8b386cdf0289190ae4b1a8aecfeb061c84b4bade081641021a9d257/spglm-1.1.0.tar.gz", hash = "sha256:20519dc38be9d660a28109bb1b89d1068454e79f6413bab2e3987db5bf959327", size = 616651 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/14/fac87dce2abbd7ee3b3bb3250cc2980388802f8cded9234d8ecb09801534/spglm-1.1.0-py3-none-any.whl", hash = "sha256:98240e3889c6672405ca90d9f9e7bd59bc86f8ecb69c03a14b87c38d8e6cf1c4", size = 41391 }, +] + +[[package]] +name = "spint" +version = "1.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "spglm" }, + { name = "spreg" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/c5/e4862ab3f745a1886135b07e498e77504c14e468d0a6b89f7270f5def979/spint-1.0.7.tar.gz", hash = "sha256:7ee6bfc725f8b507abd43f3d397bde8eaf6d85b8052f9ecb0c69f613bfeac4ca", size = 28536 } + +[[package]] +name = "splot" +version = "1.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "esda" }, + { name = "geopandas" }, + { name = "giddy" }, + { name = "libpysal" }, + { name = "mapclassify" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "seaborn" }, + { name = "spreg" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/04/f3897dc9a5a4f1926afa17805101ecc1857d27a00fc3a9dba897d9992208/splot-1.1.7.tar.gz", hash = "sha256:6edcaee24cd417965c378c5bc87414d02806915950c138c1f6e40f1a1de5286b", size = 53201 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/c7/bc840c32ee973c4609465c1d8722f3e433653edf6aab65ba341cd59fcf34/splot-1.1.7-py3-none-any.whl", hash = "sha256:6d5e7d9835d6af65f1ab7de45c8291702d8ac8cb43c60f5bb2af83694584278a", size = 39557 }, +] + +[[package]] +name = "spopt" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "libpysal" }, + { name = "mapclassify" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pointpats" }, + { name = "pulp" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "shapely" }, + { name = "spaghetti" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/57/0a/a4e5a26d650a54da009f772a9cd57c03300285130d52bbb640bf26611dcb/spopt-0.6.1.tar.gz", hash = "sha256:22fd867543cd04325d11d7d75a68dcdf8fba4c2c2fe959ba60ccef13dc54acf7", size = 30537353 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/59/08e1796f4dda22a780254ad24c525dd4641daee86a3f5212c807b4a55c4a/spopt-0.6.1-py3-none-any.whl", hash = "sha256:1e05fa545a78fca501556e3f6921ada3f95f6319df7d99bb24ce635fff3d1be8", size = 243143 }, +] + +[[package]] +name = "spreg" +version = "1.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scikit-learn" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/20/507022928b70f7f46b6c971c8dd3ebc5023da57595d99c6c8b1786a42256/spreg-1.8.1.tar.gz", hash = "sha256:771ec6020f03db0cd9659e922e7df30242c0106cbefa65463715e64e23411de7", size = 593020 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/71/6a4d517e9613b965dfa02d42de95417a049e1607b21ff9e4ce628c80cfab/spreg-1.8.1-py3-none-any.whl", hash = "sha256:b48f0a020fcd825c8812e0cdd452c4704ce6375845bba71b7781cb5c8c4cd4d9", size = 379945 }, +] + +[[package]] +name = "spvcm" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "libpysal" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "spreg" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b4/c9/43fb98bc60728b76fceee175119a1ff7e5033ed9012d07570e34a2a19a8f/spvcm-0.3.0.tar.gz", hash = "sha256:ce331bd5d6bcb64a07c4393093f3978763cfc8764ad0737e1866f3905e6cceae", size = 5724408 } + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, +] + +[[package]] +name = "statsmodels" +version = "0.14.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "patsy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1f/3b/963a015dd8ea17e10c7b0e2f14d7c4daec903baf60a017e756b57953a4bf/statsmodels-0.14.4.tar.gz", hash = "sha256:5d69e0f39060dc72c067f9bb6e8033b6dccdb0bae101d76a7ef0bcc94e898b67", size = 20354802 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/99/654fd41a9024643ee70b239e5ebc987bf98ce9fc2693bd550bee58136564/statsmodels-0.14.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5221dba7424cf4f2561b22e9081de85f5bb871228581124a0d1b572708545199", size = 10220508 }, + { url = "https://files.pythonhosted.org/packages/67/d8/ac30cf4cf97adaa48548be57e7cf02e894f31b45fd55bf9213358d9781c9/statsmodels-0.14.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:17672b30c6b98afe2b095591e32d1d66d4372f2651428e433f16a3667f19eabb", size = 9912317 }, + { url = "https://files.pythonhosted.org/packages/e0/77/2440d551eaf27f9c1d3650e13b3821a35ad5b21d3a19f62fb302af9203e8/statsmodels-0.14.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ab5e6312213b8cfb9dca93dd46a0f4dccb856541f91d3306227c3d92f7659245", size = 10301662 }, + { url = "https://files.pythonhosted.org/packages/fa/e1/60a652f18996a40a7410aeb7eb476c18da8a39792c7effe67f06883e9852/statsmodels-0.14.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbb150620b53133d6cd1c5d14c28a4f85701e6c781d9b689b53681effaa655f", size = 10741763 }, + { url = "https://files.pythonhosted.org/packages/81/0c/2453eec3ac25e300847d9ed97f41156de145e507391ecb5ac989e111e525/statsmodels-0.14.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb695c2025d122a101c2aca66d2b78813c321b60d3a7c86bb8ec4467bb53b0f9", size = 10879534 }, + { url = "https://files.pythonhosted.org/packages/59/9a/e466a1b887a1441141e52dbcc98152f013d85076576da6eed2357f2016ae/statsmodels-0.14.4-cp312-cp312-win_amd64.whl", hash = "sha256:7f7917a51766b4e074da283c507a25048ad29a18e527207883d73535e0dc6184", size = 9823866 }, +] + +[[package]] +name = "stochastic-arrow" +version = "1.1.0" +source = { git = "https://github.com/CovertLab/arrow?rev=numpy2#3589de18424953375a05a9e4416d8077168d9393" } +dependencies = [ + { name = "numpy" }, + { name = "six" }, +] + +[[package]] +name = "swiglpk" +version = "5.0.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/6c/9150c5b248eed3a491e5c58642182635956c33b6e03974fcf122f2b0c562/swiglpk-5.0.12.tar.gz", hash = "sha256:86d1be00f24ad59b9e179d3d5132f270535d57be7f209f70f8a6a8b001a65c98", size = 39615 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/5f/e8a7e24f7bdad510e43a2fcbb231fd7e96f48d0ab6980bc09416d34ba3fe/swiglpk-5.0.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7bd6565a5b75e8648fa232c1ee23f8597da75475691f097d7399ef40de14b482", size = 779114 }, + { url = "https://files.pythonhosted.org/packages/86/fb/d4e079319d5c46f0482f77d38281b8f2420083b2058e879b2b69bb2c22d9/swiglpk-5.0.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:18773487af5fc92b3063b5c777a3a139518a94201c35572996a6ffef4d710e40", size = 766290 }, + { url = "https://files.pythonhosted.org/packages/60/3f/e3c725010a116f193072e1618592174ac965547aaa606620a09cca2852ba/swiglpk-5.0.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da0318776acf3892933dfcf6a75b2fe4b26b0334c5513ed6ca7176c0d1b82420", size = 2257547 }, + { url = "https://files.pythonhosted.org/packages/03/84/635b666e61dc70a73618665246a9c0f42332a138a9dab041d9f1523b3344/swiglpk-5.0.12-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e60202c809104a07263d0b9c734ca37f644430907a66d7f3155024d83de00b78", size = 2117627 }, + { url = "https://files.pythonhosted.org/packages/70/7a/a45aa0a006f4861966dbdbad7cd4c7eef45ee9057929934b7fd5fa30f02a/swiglpk-5.0.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:436f8cc5f3d638a7304ea8397236465017c7b9c4abf668f7c83286609585baaa", size = 2335846 }, + { url = "https://files.pythonhosted.org/packages/4a/bb/6955f4a5993427d715e8b021ba4b15c1a9eeb915776addde26703d14da1c/swiglpk-5.0.12-cp312-cp312-win32.whl", hash = "sha256:c541683a0f12e715affde7b1ef766328f2610ac0523f8fee208bb95cb3e774b5", size = 468500 }, + { url = "https://files.pythonhosted.org/packages/a7/ef/d864ad0ee5d32bb004018358486f34883d727f0ea5dc4ecfa692188ae81f/swiglpk-5.0.12-cp312-cp312-win_amd64.whl", hash = "sha256:78d0b6e74ad18033c59b3c3e7d6aa058dd28f25e39e71ce54e7a51b04b32e418", size = 584971 }, +] + +[[package]] +name = "sympy" +version = "1.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/8a/5a7fd6284fa8caac23a26c9ddf9c30485a48169344b4bd3b0f02fef1890f/sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9", size = 7533196 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/ff/c87e0622b1dadea79d2fb0b25ade9ed98954c9033722eb707053d310d4f3/sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73", size = 6189483 }, +] + +[[package]] +name = "terminado" +version = "0.18.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess", marker = "os_name != 'nt'" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, +] + +[[package]] +name = "threadpoolctl" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b5148dcbf72f5cde221f8bfe3b6a540da7aa1842f6b491ad979a6c8b84af/threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107", size = 41936 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467", size = 18414 }, +] + +[[package]] +name = "tifffile" +version = "2024.9.20" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f2/14/6fe362c483166b3a44521ac5c92c98f096bd7fb05512e8730d0e23e152c9/tifffile-2024.9.20.tar.gz", hash = "sha256:3fbf3be2f995a7051a8ae05a4be70c96fc0789f22ed6f1c4104c973cf68a640b", size = 367207 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl", hash = "sha256:c54dc85bc1065d972cb8a6ffb3181389d597876aa80177933459733e4ed243dd", size = 228191 }, +] + +[[package]] +name = "tinycss2" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, +] + +[[package]] +name = "tobler" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "geopandas" }, + { name = "joblib" }, + { name = "libpysal" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "rasterio" }, + { name = "rasterstats" }, + { name = "scipy" }, + { name = "statsmodels" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/86/20b91751d249037dd130e0ec053d8faa0874fd4ff8c24a5c3e63d4eaec3a/tobler-0.12.0.tar.gz", hash = "sha256:8d612d6930e963d8bdd18b8b39d104f0b6b514062e491dca72f0d1e274dde1c0", size = 13606339 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/fb/6f37e3795ed805193fe8552fe1820c9310efee041c41b47e38a1c7053d26/tobler-0.12.0-py3-none-any.whl", hash = "sha256:ec5c70c0b3e7a8dfd696517c77beb9084f67072d49ad9696cf8b8c784508c6a6", size = 28393 }, +] + +[[package]] +name = "tornado" +version = "6.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299 }, + { url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253 }, + { url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602 }, + { url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972 }, + { url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173 }, + { url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892 }, + { url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334 }, + { url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261 }, + { url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463 }, + { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907 }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, +] + +[[package]] +name = "types-python-dateutil" +version = "2.9.0.20241206" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "tzdata" +version = "2024.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/34/943888654477a574a86a98e9896bae89c7aa15078ec29f490fef2f1e5384/tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", size = 193282 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 }, +] + +[[package]] +name = "uc-micro-py" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 }, +] + +[[package]] +name = "unum" +version = "4.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/a7/0d0685be80d222f1dcd32d687960e9dba1a2b7f77ea2d6dfc79290de4892/Unum-4.2.1.tar.gz", hash = "sha256:96591615235eb1ef08434c8221fb042c6999a519b0a7d4f57d49cd2d39ef21e5", size = 25656 } + +[[package]] +name = "uri-template" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, +] + +[[package]] +name = "vecoli" +version = "1.1.0" +source = { editable = "." } +dependencies = [ + { name = "altair" }, + { name = "biopython" }, + { name = "cvxpy" }, + { name = "cython" }, + { name = "dill" }, + { name = "duckdb" }, + { name = "ecos" }, + { name = "ete3" }, + { name = "gcsfs" }, + { name = "hvplot" }, + { name = "ipdb" }, + { name = "ipython" }, + { name = "iteround" }, + { name = "jax" }, + { name = "jupyter" }, + { name = "line-profiler" }, + { name = "matplotlib" }, + { name = "nbclassic" }, + { name = "numba" }, + { name = "numpy" }, + { name = "opencv-python-headless" }, + { name = "orjson" }, + { name = "ortools" }, + { name = "pandas" }, + { name = "polars" }, + { name = "pyarrow" }, + { name = "pymunk" }, + { name = "pyqt5" }, + { name = "pysal" }, + { name = "scikit-image" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "statsmodels" }, + { name = "stochastic-arrow" }, + { name = "swiglpk" }, + { name = "sympy" }, + { name = "tqdm" }, + { name = "unum" }, + { name = "vivarium-core" }, + { name = "wheel" }, +] + +[package.optional-dependencies] +dev = [ + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "altair" }, + { name = "biopython" }, + { name = "cvxpy" }, + { name = "cython" }, + { name = "dill" }, + { name = "duckdb" }, + { name = "ecos" }, + { name = "ete3" }, + { name = "gcsfs" }, + { name = "hvplot" }, + { name = "ipdb" }, + { name = "ipython" }, + { name = "iteround" }, + { name = "jax" }, + { name = "jupyter" }, + { name = "line-profiler" }, + { name = "matplotlib" }, + { name = "mypy", marker = "extra == 'dev'" }, + { name = "nbclassic" }, + { name = "numba" }, + { name = "numpy" }, + { name = "opencv-python-headless" }, + { name = "orjson" }, + { name = "ortools", specifier = "<=9.9.3963" }, + { name = "pandas" }, + { name = "polars" }, + { name = "pyarrow" }, + { name = "pymunk" }, + { name = "pyqt5" }, + { name = "pysal" }, + { name = "pytest", marker = "extra == 'dev'" }, + { name = "pytest-cov", marker = "extra == 'dev'" }, + { name = "ruff", marker = "extra == 'dev'" }, + { name = "scikit-image" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "seaborn" }, + { name = "statsmodels" }, + { name = "stochastic-arrow", git = "https://github.com/CovertLab/arrow?rev=numpy2" }, + { name = "swiglpk" }, + { name = "sympy" }, + { name = "tqdm" }, + { name = "unum" }, + { name = "vivarium-core" }, + { name = "wheel" }, +] + +[[package]] +name = "vivarium-core" +version = "1.6.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "orjson" }, + { name = "pint" }, + { name = "pymongo" }, + { name = "pytest" }, + { name = "scipy" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/87/794e0b4c5dccbca3036152fe5df56860a57e70f3e68ac0198dbd7df60fcb/vivarium-core-1.6.5.tar.gz", hash = "sha256:1d83faa60005304b548f623447ab8675a06bb7ed8f6b7c0bd25b4aaa3381fccb", size = 136102 } + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +] + +[[package]] +name = "webcolors" +version = "24.11.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934 }, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 }, +] + +[[package]] +name = "wheel" +version = "0.45.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494 }, +] + +[[package]] +name = "widgetsnbextension" +version = "4.0.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/fc/238c424fd7f4ebb25f8b1da9a934a3ad7c848286732ae04263661eb0fc03/widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6", size = 1164730 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/02/88b65cc394961a60c43c70517066b6b679738caf78506a5da7b88ffcb643/widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71", size = 2335872 }, +] + +[[package]] +name = "xyzservices" +version = "2024.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/16/ae87cbd2d6bfc40a419077521c35aadf5121725b7bee3d7c51b56f50958b/xyzservices-2024.9.0.tar.gz", hash = "sha256:68fb8353c9dbba4f1ff6c0f2e5e4e596bb9e1db7f94f4f7dfbcb26e25aa66fde", size = 1131900 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/d3/e07ce413d16ef64e885bea37551eac4c5ca3ddd440933f9c94594273d0d9/xyzservices-2024.9.0-py3-none-any.whl", hash = "sha256:776ae82b78d6e5ca63dd6a94abb054df8130887a4a308473b54a6bd364de8644", size = 85130 }, +] + +[[package]] +name = "yarl" +version = "1.18.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/85/bd2e2729752ff4c77338e0102914897512e92496375e079ce0150a6dc306/yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50", size = 142644 }, + { url = "https://files.pythonhosted.org/packages/ff/74/1178322cc0f10288d7eefa6e4a85d8d2e28187ccab13d5b844e8b5d7c88d/yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576", size = 94962 }, + { url = "https://files.pythonhosted.org/packages/be/75/79c6acc0261e2c2ae8a1c41cf12265e91628c8c58ae91f5ff59e29c0787f/yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640", size = 92795 }, + { url = "https://files.pythonhosted.org/packages/6b/32/927b2d67a412c31199e83fefdce6e645247b4fb164aa1ecb35a0f9eb2058/yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2", size = 332368 }, + { url = "https://files.pythonhosted.org/packages/19/e5/859fca07169d6eceeaa4fde1997c91d8abde4e9a7c018e371640c2da2b71/yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75", size = 342314 }, + { url = "https://files.pythonhosted.org/packages/08/75/76b63ccd91c9e03ab213ef27ae6add2e3400e77e5cdddf8ed2dbc36e3f21/yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512", size = 341987 }, + { url = "https://files.pythonhosted.org/packages/1a/e1/a097d5755d3ea8479a42856f51d97eeff7a3a7160593332d98f2709b3580/yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba", size = 336914 }, + { url = "https://files.pythonhosted.org/packages/0b/42/e1b4d0e396b7987feceebe565286c27bc085bf07d61a59508cdaf2d45e63/yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb", size = 325765 }, + { url = "https://files.pythonhosted.org/packages/7e/18/03a5834ccc9177f97ca1bbb245b93c13e58e8225276f01eedc4cc98ab820/yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272", size = 344444 }, + { url = "https://files.pythonhosted.org/packages/c8/03/a713633bdde0640b0472aa197b5b86e90fbc4c5bc05b727b714cd8a40e6d/yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6", size = 340760 }, + { url = "https://files.pythonhosted.org/packages/eb/99/f6567e3f3bbad8fd101886ea0276c68ecb86a2b58be0f64077396cd4b95e/yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e", size = 346484 }, + { url = "https://files.pythonhosted.org/packages/8e/a9/84717c896b2fc6cb15bd4eecd64e34a2f0a9fd6669e69170c73a8b46795a/yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb", size = 359864 }, + { url = "https://files.pythonhosted.org/packages/1e/2e/d0f5f1bef7ee93ed17e739ec8dbcb47794af891f7d165fa6014517b48169/yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393", size = 364537 }, + { url = "https://files.pythonhosted.org/packages/97/8a/568d07c5d4964da5b02621a517532adb8ec5ba181ad1687191fffeda0ab6/yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285", size = 357861 }, + { url = "https://files.pythonhosted.org/packages/7d/e3/924c3f64b6b3077889df9a1ece1ed8947e7b61b0a933f2ec93041990a677/yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2", size = 84097 }, + { url = "https://files.pythonhosted.org/packages/34/45/0e055320daaabfc169b21ff6174567b2c910c45617b0d79c68d7ab349b02/yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477", size = 90399 }, + { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, +] From 26e3179285f1a691cfea91faea8ed0dfb1ad6460 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 00:20:01 -0800 Subject: [PATCH 13/54] Use uv everywhere, including docs --- .env | 2 + .github/workflows/docs_deploy.yml | 15 +- .github/workflows/docs_test.yml | 15 +- .github/workflows/pr_tests.yml | 63 ++---- .github/workflows/pytest.yml | 68 ++----- .gitignore | 1 - Makefile | 21 -- README.md | 66 +++--- doc/conf.py | 48 ++--- doc/docs.rst | 14 +- doc/experiments.rst | 2 +- doc/gcloud.rst | 4 +- doc/requirements.txt | 105 ---------- ecoli/composites/ecoli_master.py | 2 +- ecoli/composites/ecoli_master_tests.py | 4 +- ecoli/composites/environment/lattice.py | 2 +- ecoli/experiments/antibiotics_tests.py | 2 +- ecoli/library/schema.py | 2 +- ecoli/processes/engine_process.py | 4 +- .../processes/environment/diffusion_field.py | 2 +- ecoli/processes/environment/lysis.py | 2 +- .../environment/multibody_physics.py | 2 +- .../environment/reaction_diffusion_field.py | 2 +- ecoli/processes/enzyme_kinetics.py | 2 +- ecoli/processes/listeners/monomer_counts.py | 2 +- ecoli/processes/transcript_initiation.py | 4 +- pyproject.toml | 5 + runscripts/container/wholecell/Dockerfile | 6 +- uv.lock | 188 +++++++++++++++++- wholecell/tests/utils/test_memory_debug.py | 2 +- 30 files changed, 297 insertions(+), 360 deletions(-) create mode 100644 .env delete mode 100644 Makefile delete mode 100644 doc/requirements.txt diff --git a/.env b/.env new file mode 100644 index 000000000..7bea7fc51 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +# Greatly improves performance and reproducibility +OMP_NUM_THREADS=1 diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index 4afb0c7fa..183741916 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -9,19 +9,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: "3.11" - - name: Install dependencies + - name: Install Pandoc and uv run: | sudo apt-get install pandoc - python -m pip install --upgrade pip wheel - pip install numpy==1.26.4 - pip install -r doc/requirements.txt - - name: Compile Cython components - run: | - make compile + curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index 9ae1c794f..f2daec8b9 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -11,19 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Python - uses: actions/setup-python@v2 - with: - python-version: "3.11" - - name: Install dependencies + - name: Install Pandoc and uv run: | sudo apt-get install pandoc - python -m pip install --upgrade pip wheel - pip install numpy==1.26.4 - pip install -r doc/requirements.txt - - name: Compile Cython components - run: | - make compile + curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index 7d4b0297a..76e483dcc 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -2,11 +2,6 @@ name: Workflow -# Improves reproducibility and speed -env: - OPENBLAS_NUM_THREADS: 1 - OMP_NUM_THREADS: 1 - on: push: branches: [master] @@ -16,72 +11,44 @@ on: jobs: Reproducibility: runs-on: macos-latest - strategy: - matrix: - python-version: ["3.11"] steps: - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --upgrade pip wheel - pip install numpy==1.26.4 - pip install -r requirements.txt - - name: Compile Cython components - run: | - make clean compile - - name: Set PYTHONPATH - run: | - echo "PYTHONPATH=." >> $GITHUB_ENV + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync - name: Test ParCa reproducibility run: | - python runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ + uv run runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ -c 3 -o out/parca_1 - python runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ + uv run runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ -c 3 -o out/parca_2 - python runscripts/debug/compare_pickles.py out/parca_1/kb out/parca_2/kb + uv run runscripts/debug/compare_pickles.py out/parca_1/kb out/parca_2/kb - name: Test simulation reproducibility run: | - python ecoli/experiments/ecoli_master_sim.py \ + uv run ecoli/experiments/ecoli_master_sim.py \ --generations 1 --emitter parquet --emitter_arg out_dir='out' \ --experiment_id "parca_1" --daughter_outdir "out/parca_1" \ --sim_data_path "out/parca_1/kb/simData.cPickle" --fail_at_total_time & - python ecoli/experiments/ecoli_master_sim.py \ + uv run ecoli/experiments/ecoli_master_sim.py \ --generations 1 --emitter parquet --emitter_arg out_dir='out' \ --experiment_id "parca_2" --daughter_outdir "out/parca_2" \ --sim_data_path "out/parca_2/kb/simData.cPickle" --fail_at_total_time - python runscripts/debug/diff_simouts.py -o "out" "parca_1*" "parca_2*" + uv run runscripts/debug/diff_simouts.py -o "out" "parca_1*" "parca_2*" Two-gens: runs-on: macos-latest - strategy: - matrix: - python-version: ["3.11"] steps: - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --upgrade pip wheel - pip install numpy==1.26.4 mypy - pip install -r requirements.txt + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync - name: Install nextflow edge run: | curl -s https://get.nextflow.io | bash chmod +x nextflow echo "PATH=.:$PATH" >> $GITHUB_ENV NXF_EDGE=1 ./nextflow self-update - - name: Compile Cython components - run: | - make clean compile - - name: Set PYTHONPATH - run: | - echo "PYTHONPATH=." >> $GITHUB_ENV - name: Two generations run: | - python runscripts/workflow.py --config ecoli/composites/ecoli_configs/two_generations.json + uv run runscripts/workflow.py --config ecoli/composites/ecoli_configs/two_generations.json diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 2713dad91..e08b8590f 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -2,11 +2,6 @@ name: QA -# Improves reproducibility and speed -env: - OPENBLAS_NUM_THREADS: 1 - OMP_NUM_THREADS: 1 - on: push: branches: [master] @@ -16,26 +11,15 @@ on: jobs: Pytest: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.11"] steps: - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --upgrade pip wheel - pip install numpy==1.26.4 - pip install -r requirements.txt - - name: Compile Cython components - run: | - make clean compile + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync - name: Test with pytest run: | - python -m pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 + uv run pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 - name: Code Coverage Report uses: irongut/CodeCoverageSummary@v1.3.0 with: @@ -51,45 +35,23 @@ jobs: path: code-coverage-results.md Mypy: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.11"] steps: - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --upgrade pip wheel - pip install numpy==1.26.4 mypy - pip install -r requirements.txt - - name: Compile Cython components - run: | - make clean compile + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync - name: Mypy run: | - mypy + uv run mypy Lint: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.11"] steps: - uses: actions/checkout@v2 - - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --upgrade pip wheel - pip install numpy==1.26.4 ruff - pip install -r requirements.txt - - name: Compile Cython components - run: | - make clean compile + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install model + run: uv sync - name: Ruff run: | - ruff check doc ecoli migration wholecell runscripts validation reconstruction + uv run ruff check doc ecoli migration wholecell runscripts validation reconstruction diff --git a/.gitignore b/.gitignore index d6cbc365b..c1453707c 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ __pycache__ # VS Code files # ################# /.vscode -/.env # Generated Files # ################### diff --git a/Makefile b/Makefile deleted file mode 100644 index 1cad6b662..000000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -.PHONY: compile, clean, recompile - -compile: - python setup.py build_ext --inplace - rm -fr build - -# The reconstruction/ecoli/dataclasses/process/*.py files were generated by -# write_ode_file.py in Parca code. -clean: - rm -fr fixtures cache - (cd reconstruction/ecoli/dataclasses/process && rm -f equilibrium_odes.py two_component_system_odes*.py) - find . -name "*.pyc" -exec rm -rf {} + - find . -name "*.o" -exec rm -fr {} + - find . -name "*.so" -exec rm -fr {} + - rm -fr build - -# Delete just the *.so libraries then (re)compile them. -# This is useful when switching to a different Python virtualenv. -recompile: - find . -name "*.so" -delete - make compile diff --git a/README.md b/README.md index 4384ad337..5ed09708e 100644 --- a/README.md +++ b/README.md @@ -24,62 +24,60 @@ model parameters (e.g. transcription probabilities). These parameters are used t [processes](ecoli/processes) that are linked together into a [complete simulation](ecoli/experiments/ecoli_master_sim.py). -## Installation +## Setup -> **Note:** The following instructions assume a Linux or MacOS system. Windows users can -> attempt to follow the same instructions after setting up -> [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/install). - -> **Note:** Refer to the following pages for non-local setups: +> **Note:** The following instructions assume a local Linux or MacOS system. Windows users can +> attempt to follow the same steps after setting up +> [Windows Subsystem for Linux](https://learn.microsoft.com/en-us/windows/wsl/install). Refer to the following pages for non-local setups: > [Sherlock](https://covertlab.github.io/vEcoli/workflows.html#sherlock), > [other HPC cluster](https://covertlab.github.io/vEcoli/workflows.html#other-hpc-clusters), > [Google Cloud](https://covertlab.github.io/vEcoli/gcloud.html). -pyenv lets you install and switch between multiple Python releases and multiple "virtual -environments", each with its own pip packages. Using pyenv, create a virtual environment -and install Python 3.11.10. For a tutorial on how to install pyenv and other dependencies, -follow the instructions [here](https://github.com/CovertLab/wcEcoli/blob/master/docs/dev-tools.md). -Then, run the following command in your terminal: +### Prerequisites + +Your system must have git, curl (or wget), and a C compiler. - pyenv virtualenv 3.11.10 vEcoli && pyenv local vEcoli +On Ubuntu/Debian: -Update `pip`, `setuptools` and `wheel` to avoid issues with these: + sudo -s eval 'apt update && apt install git curl clang' - pip install --upgrade pip setuptools==73.0.1 wheel +On MacOS: -Now, install numpy (check `requirements.txt` for the exact version): + xcode-select --install - pip install numpy==1.26.4 +### Installation -Then install the remaining requirements: +Clone the repository: - pip install -r requirements.txt + git clone https://github.com/CovertLab/vEcoli.git -And build the Cython components: +[Follow these instructions](https://docs.astral.sh/uv/getting-started/installation/) +to install `uv`, our Python package and project manager of choice. - make clean compile +Navigate into the cloned repository and use `uv` to install the model: -Install `nextflow` following the instructions [here](https://www.nextflow.io/docs/latest/install.html). -After installing Java with SDKMAN!, close and reopen your terminal, then run -the following commands and compare their output to ensure that the Java compiler -and JVM were properly installed and the same version. + cd vEcoli + uv sync - javac -version - java -version +> **Note:** If your C compiler is not `clang`, run `CC={your compiler} uv sync` +> instead to work around [this limitation](https://github.com/astral-sh/uv/issues/8429). +> For example, `CC=gcc uv sync` for `gcc`. -After verifying your Java installation, you can proceed with installing Nextflow, -starting with `curl -s https://get.nextflow.io | bash`. If this fails, try -prepending `export CAPSULE_LOG=verbose` and re-run, checking for failed downloads. -If any downloads failed, re-run this command until it succeeds. +Finally, install `nextflow` [following these instructions](https://www.nextflow.io/docs/latest/install.html). +If you choose to install Java with SDKMAN!, after the Java installation +finishes, close and reopen your terminal before continuing with the +`nextflow` installation steps. + +> **Tip:** If any step in the `nextflow` installation fails, +> try rerunning a few times to see if that fixes the issue. ## Test Installation To test your installation, from the top-level of the cloned repository, invoke: - # Must set PYTHONPATH and OMP_NUM_THREADS for every new shell (can add to .bashrc/.zshrc) - export PYTHONPATH=. - export OMP_NUM_THREADS=1 - python runscripts/workflow.py --config ecoli/composites/ecoli_configs/test_installation.json + uv run runscripts/workflow.py --config ecoli/composites/ecoli_configs/test_installation.json + +> **Note:** Prefix all of your commands to run scripts with `uv run`. This will run the following basic simulation workflow: diff --git a/doc/conf.py b/doc/conf.py index ec59f590f..3ebdea6ac 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -45,6 +45,8 @@ "sphinx.ext.napoleon", "sphinx.ext.intersphinx", "sphinx.ext.viewcode", + "sphinx.ext.autosummary", + "matplotlib.sphinxext.roles", "nbsphinx", ] @@ -54,7 +56,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "venv"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "venv", ".venv"] # Causes warnings to be thrown for all unresolvable references. This # will help avoid broken links. @@ -68,6 +70,7 @@ ("py:class", "any valid matplotlib color"), # Silence warning in ecoli.analysis.single.blame.SignNormalize ("py:class", "default: False"), + # Numpy, DuckDB, PyArrow, Polars, and Pandas types fail to resolve ("py:class", "numpy.float64"), ("py:class", "numpy.int64"), ("py:class", "numpy.int32"), @@ -79,7 +82,8 @@ ("py:class", "pyarrow.lib.Array"), ("py:class", "pyarrow.lib.NativeFile"), ("py:class", "pyarrow.lib.Table"), - ("py:class", "polars.Series"), + ("py:class", "pandas.core.frame.DataFrame"), + ("py:class", "polars.series.series.Series"), # Silence warning in ecoli.processes.environment.field_timeline.FieldTimeline ("py:class", "vivarium.processes.timeline.TimelineProcess"), ] @@ -92,7 +96,7 @@ # html_theme = "sphinx_rtd_theme" html_theme_options = { - "display_version": True, + "version_selector": True, } # Add any paths that contain custom static files (such as style sheets) here, @@ -118,6 +122,8 @@ "numpy": ("https://numpy.org/doc/stable", None), "matplotlib": ("https://matplotlib.org/stable/", None), "pandas": ("http://pandas.pydata.org/pandas-docs/dev", None), + "polars": ("https://docs.pola.rs/api/python/stable", None), + "sympy": ("https://docs.sympy.org/latest", None), } @@ -125,38 +131,12 @@ autodoc_inherit_docstrings = False # The Python dependencies aren't really required for building the docs autodoc_mock_imports = [ - "stochastic_arrow", - "numba", - "line-profiler", - "iteround", - "pandas", # Runs code on import and fails due to missing solvers. "wholecell.utils.modular_fba", # Runs code on import and fails due to missing packages "ecoli.library.parameters", # Needs to be run with kernprof "wholecell.tests.utils.profile_polymerize", - "sympy", - "cv2", - "Bio", - "tqdm", - "cvxpy", - "pymunk", - "skimage", - "dill", - "Equation", - "swiglpk", - "seaborn", - "statsmodels", - "ete3", - "esda", - "hvplot", - "line_profiler", - "fsspec", - "sklearn", - "libpysal", - "splot", - "polars", ] # Move typehints from signature into description autodoc_typehints = "description" @@ -271,9 +251,15 @@ def object_description_handler(_, domain, objtype, contentnode): return for child in contentnode.children: if child.astext().startswith("defaults: Dict["): - name = contentnode.source.split()[-1] + ".defaults" + if contentnode.source is None: + continue + else: + name = contentnode.source.split()[-1] + ".defaults" elif child.astext().startswith("topology"): - name = contentnode.source.split()[-1] + ".topology" + if contentnode.source is None: + continue + else: + name = contentnode.source.split()[-1] + ".topology" else: continue diff --git a/doc/docs.rst b/doc/docs.rst index c30638c04..745401103 100644 --- a/doc/docs.rst +++ b/doc/docs.rst @@ -496,23 +496,13 @@ Building the Documentation To build the documentation, we will use Sphinx to generate HTML files from plain text. Here are stepwise instructions: -#. (optional) Create a virtual environment for the - documentation-building packages. You might want this to be separate - from the environment you use for the rest of Vivarium *E. coli*. -#. Setup *Vivarium E. coli*. We need it to be setup so that we can - import its Cython code. -#. Install dependencies: - - .. code-block:: console - - $ pip install -r doc/requirements.txt - +#. Run ``uv sync --extra docs`` to install the necessary dependencies. #. Build the HTML! .. code-block:: console $ cd doc - $ make html + $ uv run make html Your HTML will now be in ``doc/_build/html``. To view it, open ``doc/_build/html/index.html`` in a web browser. diff --git a/doc/experiments.rst b/doc/experiments.rst index 59630efb3..035912a29 100644 --- a/doc/experiments.rst +++ b/doc/experiments.rst @@ -65,7 +65,7 @@ with options loaded later on overriding those from earlier sources: In most cases, configuration options that appear in more than one of the above sources are successively overriden in their entirety. The sole exceptions are configuration options listed in -:py:attr:`~ecoli.experiments.ecoli_master_sim.LIST_KEYS_TO_MERGE`. These +:py:attr:`~runscripts.workflow.LIST_KEYS_TO_MERGE`. These options hold lists of values that are concatenated with one another instead of being wholly overriden. diff --git a/doc/gcloud.rst b/doc/gcloud.rst index 880268351..717b0d70a 100644 --- a/doc/gcloud.rst +++ b/doc/gcloud.rst @@ -260,8 +260,8 @@ Interactive Containers .. warning:: Install - :ref:`Docker ` and - :ref:`Google Cloud Storage FUSE ` + `Docker `_ and + `Google Cloud Storage FUSE `_ on your VM before continuing. Since all steps of the workflow are run inside Docker containers, it can be diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 15dd8e61a..000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,105 +0,0 @@ -alabaster==0.7.16 -appdirs==1.4.4 -appnope==0.1.4 -asttokens==2.4.1 -attrs==23.2.0 -Babel==2.15.0 -backcall==0.2.0 -beautifulsoup4==4.12.3 -bleach==6.1.0 -certifi==2024.7.4 -charset-normalizer==3.3.2 -contourpy==1.2.1 -cycler==0.12.1 -Cython==3.0.10 -decorator==5.1.1 -defusedxml==0.7.1 -dnspython==2.6.1 -docutils==0.20.1 -duckdb==1.0.0 -entrypoints==0.4 -executing==2.0.1 -fastjsonschema==2.20.0 -flexcache==0.3 -flexparser==0.3.1 -fonttools==4.53.1 -idna==3.7 -imagesize==1.4.1 -importlib_metadata==8.0.0 -importlib_resources==6.4.0 -iniconfig==2.0.0 -ipython==8.26.0 -jedi==0.19.1 -Jinja2==3.1.4 -jsonschema==4.23.0 -jsonschema-specifications==2023.12.1 -jupyter_client==8.6.2 -jupyter_core==5.7.2 -jupyterlab_pygments==0.3.0 -kiwisolver==1.4.5 -lxml==5.2.2 -lz4==4.3.3 -MarkupSafe==2.1.5 -matplotlib==3.9.1 -matplotlib-inline==0.1.7 -mistune==3.0.2 -nbclient==0.10.0 -nbconvert==7.16.4 -nbformat==5.10.4 -nbsphinx==0.9.4 -nest-asyncio==1.6.0 -networkx==3.3 -numpy==1.26.4 -orjson==3.10.6 -packaging==24.1 -pandocfilters==1.5.1 -parso==0.8.4 -pexpect==4.9.0 -pickleshare==0.7.5 -pillow==10.4.0 -Pint==0.24.1 -pkgutil_resolve_name==1.3.10 -platformdirs==4.2.2 -pluggy==1.5.0 -polars==1.1.0 -prompt_toolkit==3.0.47 -ptyprocess==0.7.0 -pure-eval==0.2.2 -pyarrow==16.1.0 -Pygments==2.18.0 -pymongo==4.8.0 -pyparsing==3.1.2 -pyrsistent==0.20.0 -pytest==8.2.2 -python-dateutil==2.9.0.post0 -pytz==2024.1 -pyzmq==26.0.3 -referencing==0.35.1 -requests==2.32.3 -rpds-py==0.19.0 -scipy==1.14.0 -six==1.16.0 -snowballstemmer==2.2.0 -soupsieve==2.5 -Sphinx==7.3.7 -sphinx-rtd-theme==2.0.0 -sphinxcontrib-applehelp==1.0.8 -sphinxcontrib-devhelp==1.0.6 -sphinxcontrib-htmlhelp==2.0.5 -sphinxcontrib-jquery==4.1 -sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.7 -sphinxcontrib-serializinghtml==1.1.10 -stack-data==0.6.3 -tinycss2==1.3.0 -tornado==6.4.1 -traitlets==5.14.3 -typing_extensions==4.12.2 -tzdata==2024.1 -Unum==4.2.1 -urllib3==2.2.2 -vivarium-core==1.6.4 -wcwidth==0.2.13 -webencodings==0.5.1 -zipp==3.19.2 -zstandard==0.22.0 diff --git a/ecoli/composites/ecoli_master.py b/ecoli/composites/ecoli_master.py index 07d6dd623..ea2c7bbf8 100644 --- a/ecoli/composites/ecoli_master.py +++ b/ecoli/composites/ecoli_master.py @@ -857,6 +857,6 @@ def ecoli_topology_plot(config=None): } # run experiments in test_library from the command line with: -# python ecoli/composites/ecoli_master.py -n [experiment id] +# uv run ecoli/composites/ecoli_master.py -n [experiment id] if __name__ == "__main__": run_library_cli(test_library) diff --git a/ecoli/composites/ecoli_master_tests.py b/ecoli/composites/ecoli_master_tests.py index 664e8776c..4ed2c3e5e 100644 --- a/ecoli/composites/ecoli_master_tests.py +++ b/ecoli/composites/ecoli_master_tests.py @@ -217,7 +217,7 @@ def test_lattice_lysis(plot=False): """ Run plots: ''' - > python ecoli/composites/ecoli_master_tests.py -n 4 -o plot=True + > uv run ecoli/composites/ecoli_master_tests.py -n 4 -o plot=True ''' ANTIBIOTIC_KEY = 'nitrocefin' @@ -287,6 +287,6 @@ def plot_spatial_snapshots(data, sim, experiment_dir="ecoli_test"): } # run experiments in test_library from the command line with: -# python ecoli/composites/ecoli_master_tests.py -n [experiment id] +# uv run ecoli/composites/ecoli_master_tests.py -n [experiment id] if __name__ == "__main__": run_library_cli(test_library) diff --git a/ecoli/composites/environment/lattice.py b/ecoli/composites/environment/lattice.py index e2d053b5f..eda0bf947 100644 --- a/ecoli/composites/environment/lattice.py +++ b/ecoli/composites/environment/lattice.py @@ -281,6 +281,6 @@ def main(): ) -# python ecoli/composites/environment/lattice.py [-e if exchanges on] +# uv run ecoli/composites/environment/lattice.py [-e if exchanges on] if __name__ == "__main__": main() diff --git a/ecoli/experiments/antibiotics_tests.py b/ecoli/experiments/antibiotics_tests.py index 96e3e3e8e..eafacfd68 100644 --- a/ecoli/experiments/antibiotics_tests.py +++ b/ecoli/experiments/antibiotics_tests.py @@ -126,6 +126,6 @@ def test_lysis_rxn_dff_environment(total_time=10): "2": test_lysis_rxn_dff_environment, } -# python ecoli/experiments/antibiotics_tests.py -n library_id +# uv run ecoli/experiments/antibiotics_tests.py -n library_id if __name__ == "__main__": run_library_cli(library) diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index a86b53200..997019943 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -146,7 +146,7 @@ def array_from(d: dict) -> np.ndarray: return np.array(list(d.values())) -def create_unique_indexes( +def create_unique_indices( n_indexes: int, unique_molecules: MetadataArray ) -> np.ndarray: """We strongly recommend letting diff --git a/ecoli/processes/engine_process.py b/ecoli/processes/engine_process.py index 3674f6844..882f5b512 100644 --- a/ecoli/processes/engine_process.py +++ b/ecoli/processes/engine_process.py @@ -235,7 +235,7 @@ def __init__(self, parameters=None): access to. :py:class:`~ecoli.experiments.ecoli_engine_process.EcoliEngineProcess` has a custom :py:meth:`~vivarium.core.composer.Composer.generate_topology` method to ensure that each port name is wired to a user-specified store - in the outer simulation. Then, every time the :py:meth:`~.EngineProcess` + in the outer simulation. Then, every time the :py:class:`~.EngineProcess` is run, the value from the outer simulation store is copied to the store located at the path in the inner simulation, the inner simulation is incremented, and the final value of the store in the inner simulation @@ -244,7 +244,7 @@ def __init__(self, parameters=None): value of stores in the inner simulation. - ``stub_schemas``: a mapping from process names to a mapping from paths in the inner simulation to the schema to use for the store at that - path. See :py:class:`~.StubSchemas` for more details. + path. See :py:class:`~.SchemaStub` for more details. - ``tunnel_out_schemas``: a mapping from names of ports for tunnels out to schemas to use for the stores that those ports point to. Helpful for ensuring consistency in schemas specified for these stores. diff --git a/ecoli/processes/environment/diffusion_field.py b/ecoli/processes/environment/diffusion_field.py index 4eb88acb4..c3d12d682 100644 --- a/ecoli/processes/environment/diffusion_field.py +++ b/ecoli/processes/environment/diffusion_field.py @@ -336,7 +336,7 @@ def run_diffusion_field(config=None, total_time=100, filename="snapshots"): ) -# python ecoli/processes/environment/diffusion_field.py +# uv run ecoli/processes/environment/diffusion_field.py if __name__ == "__main__": # test_all() diff --git a/ecoli/processes/environment/lysis.py b/ecoli/processes/environment/lysis.py index 9765bae4e..77c208389 100644 --- a/ecoli/processes/environment/lysis.py +++ b/ecoli/processes/environment/lysis.py @@ -423,6 +423,6 @@ def main(): ) -# python ecoli/processes/environment/lysis.py +# uv run ecoli/processes/environment/lysis.py if __name__ == "__main__": main() diff --git a/ecoli/processes/environment/multibody_physics.py b/ecoli/processes/environment/multibody_physics.py index 799c2cea6..5afd1285a 100644 --- a/ecoli/processes/environment/multibody_physics.py +++ b/ecoli/processes/environment/multibody_physics.py @@ -103,7 +103,7 @@ class Multibody(Process): .. code-block:: console - $ MPLBACKEND=TKAgg python vivarium/processes/snapshots.py + $ MPLBACKEND=TKAgg uv run vivarium/processes/snapshots.py Notes: * rotational diffusion in liquid medium with viscosity = 1 mPa.s: :math:`Dr = 3.5 \\pm0.3 rad^{2}/s` diff --git a/ecoli/processes/environment/reaction_diffusion_field.py b/ecoli/processes/environment/reaction_diffusion_field.py index 32ce067f2..a8708d128 100644 --- a/ecoli/processes/environment/reaction_diffusion_field.py +++ b/ecoli/processes/environment/reaction_diffusion_field.py @@ -410,6 +410,6 @@ def main(): ) -# python ecoli/processes/environment/reaction_diffusion_field.py +# uv run ecoli/processes/environment/reaction_diffusion_field.py if __name__ == "__main__": main() diff --git a/ecoli/processes/enzyme_kinetics.py b/ecoli/processes/enzyme_kinetics.py index 7ffc27c3b..b61dcdbb8 100644 --- a/ecoli/processes/enzyme_kinetics.py +++ b/ecoli/processes/enzyme_kinetics.py @@ -173,6 +173,6 @@ def test_enzyme_kinetics(end_time=100): return data is not None -# run module with python ecoli/processes/enzyme_kinetics.py +# run module with uv run ecoli/processes/enzyme_kinetics.py if __name__ == "__main__": test_enzyme_kinetics() diff --git a/ecoli/processes/listeners/monomer_counts.py b/ecoli/processes/listeners/monomer_counts.py index 844420953..1980f3b7c 100644 --- a/ecoli/processes/listeners/monomer_counts.py +++ b/ecoli/processes/listeners/monomer_counts.py @@ -239,6 +239,6 @@ def test_monomer_counts_listener(): assert isinstance(listeners["monomer_counts"][1], list) -# python ecoli/processes/listeners/monomer_counts.py +# uv run ecoli/processes/listeners/monomer_counts.py if __name__ == "__main__": test_monomer_counts_listener() diff --git a/ecoli/processes/transcript_initiation.py b/ecoli/processes/transcript_initiation.py index 3ab05ca25..3bd99c0c1 100644 --- a/ecoli/processes/transcript_initiation.py +++ b/ecoli/processes/transcript_initiation.py @@ -23,7 +23,7 @@ from vivarium.core.composition import simulate_process from ecoli.library.schema import ( - create_unique_indexes, + create_unique_indices, listener_schema, numpy_schema, counts, @@ -539,7 +539,7 @@ def evolve_state(self, timestep, states): is_forward = self.transcription_direction[TU_index_partial_RNAs] # new RNAPs - RNAP_indexes = create_unique_indexes(n_RNAPs_to_activate, states["RNAs"]) + RNAP_indexes = create_unique_indices(n_RNAPs_to_activate, states["RNAs"]) update["active_RNAPs"].update( { "add": { diff --git a/pyproject.toml b/pyproject.toml index 2df0c4fc2..b858aa8cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,11 @@ dev = [ "mypy", "ruff" ] +docs = [ + "Sphinx", + "sphinx-rtd-theme", + "nbsphinx" +] [tool.setuptools] packages = [ diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index 7a684838e..03c7a586a 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -16,7 +16,7 @@ # # > docker run --name wholecelltest -it --rm ${USER}-wcm-code # -# or if you used build.sh or build-wcm.sh to build using Cloud Build: +# or if you used build-wcm.sh to build using Cloud Build: # # > PROJECT="$(gcloud config get-value core/project)" # > TAG="gcr.io/${PROJECT}/${USER}-wcm-code" @@ -24,11 +24,11 @@ # # It will start a shell where you can execute commands: # -# # pytest +# uv run pytest # # If this succeeds you can start running WCM code in the container, e.g.: # -# # python runscripts/manual/runParca.py +# uv run runscripts/manual/runParca.py ARG from=wcm-runtime:latest FROM ${from} diff --git a/uv.lock b/uv.lock index b128f72a9..3e50dc9f2 100644 --- a/uv.lock +++ b/uv.lock @@ -92,6 +92,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] +[[package]] +name = "alabaster" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 }, +] + [[package]] name = "altair" version = "5.5.0" @@ -101,7 +110,7 @@ dependencies = [ { name = "jsonschema" }, { name = "narwhals" }, { name = "packaging" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/16/b1/f2969c7bdb8ad8bbdda031687defdce2c19afba2aa2c8e1d2a17f78376d8/altair-5.5.0.tar.gz", hash = "sha256:d960ebe6178c56de3855a68c47b516be38640b73fb3b5111c2a9ca90546dd73d", size = 705305 } wheels = [ @@ -115,7 +124,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 } wheels = [ @@ -569,6 +578,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, ] +[[package]] +name = "docutils" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, +] + [[package]] name = "duckdb" version = "1.1.3" @@ -1001,6 +1019,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/f9/f78e7f5ac8077c481bf6b43b8bc736605363034b3d5eb3ce8eb79f53f5f1/imageio-2.36.1-py3-none-any.whl", hash = "sha256:20abd2cae58e55ca1af8a8dcf43293336a59adf0391f1917bf8518633cfc2cdf", size = 315435 }, ] +[[package]] +name = "imagesize" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, +] + [[package]] name = "immutabledict" version = "4.2.1" @@ -1038,8 +1065,8 @@ name = "ipdb" version = "0.13.13" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "decorator" }, - { name = "ipython" }, + { name = "decorator", marker = "python_full_version == '3.12.8'" }, + { name = "ipython", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042 } wheels = [ @@ -1142,9 +1169,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jaxlib" }, { name = "ml-dtypes" }, - { name = "numpy" }, + { name = "numpy", marker = "python_full_version == '3.12.8'" }, { name = "opt-einsum" }, - { name = "scipy" }, + { name = "scipy", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/df/79/b8033b443d15671725ef4aef7f756c8b0026a7add3e807981d4d7c6abba7/jax-0.4.36.tar.gz", hash = "sha256:088bff0575d01fc82682a9af4eb07433d60de7e5164686bd2cea3439492e608a", size = 1915594 } wheels = [ @@ -1158,7 +1185,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ml-dtypes" }, { name = "numpy" }, - { name = "scipy" }, + { name = "scipy", marker = "python_full_version == '3.12.8'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/e3/0e/3b4a99c09431ee5820624d4dcf4efa7becd3c83b56ff0f09a078f4c421a2/jaxlib-0.4.36-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:5972aa85f6d771ecc8cc72148c1fa64250ca33cbdf2bf24407cdee8a5299d25d", size = 98718357 }, @@ -1698,7 +1725,7 @@ name = "ml-dtypes" version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/15/76f86faa0902836cc133939732f7611ace68cf54148487a99c539c272dc8/ml_dtypes-0.4.1.tar.gz", hash = "sha256:fad5f2de464fd09127e49b7fd1252b9006fb43d2edc1ff112d390c324af5ca7a", size = 692594 } wheels = [ @@ -1866,6 +1893,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, ] +[[package]] +name = "nbsphinx" +version = "0.9.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "jinja2" }, + { name = "nbconvert" }, + { name = "nbformat" }, + { name = "sphinx" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/af/49/a6b1ed510bcc7734daa20372222804d6109d3087ced82f65c8720da90ef4/nbsphinx-0.9.5.tar.gz", hash = "sha256:736916e7b0dab28fc904f4a9ae3b53a9a50c29fccc6329c052fcc7485abcf2b7", size = 179599 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/8a/5a1e56efa95e2038de5646e2bc5c0abe18678ae5d167e267c0fbaa17a372/nbsphinx-0.9.5-py3-none-any.whl", hash = "sha256:d82f71084425db1f48e72515f15c25b4de8652ceaab513ee462ac05f1b8eae0a", size = 31349 }, +] + [[package]] name = "nest-asyncio" version = "1.6.0" @@ -1961,7 +2005,7 @@ name = "opencv-python-headless" version = "4.10.0.84" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_full_version == '3.12.8'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } wheels = [ @@ -2063,7 +2107,7 @@ name = "pandas" version = "2.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, + { name = "numpy", marker = "python_full_version == '3.12.8'" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, @@ -3098,6 +3142,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] +[[package]] +name = "snowballstemmer" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, +] + [[package]] name = "soupsieve" version = "2.6" @@ -3141,6 +3194,113 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/14/fac87dce2abbd7ee3b3bb3250cc2980388802f8cded9234d8ecb09801534/spglm-1.1.0-py3-none-any.whl", hash = "sha256:98240e3889c6672405ca90d9f9e7bd59bc86f8ecb69c03a14b87c38d8e6cf1c4", size = 41391 }, ] +[[package]] +name = "sphinx" +version = "8.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125 }, +] + +[[package]] +name = "sphinx-rtd-theme" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "docutils" }, + { name = "sphinx" }, + { name = "sphinxcontrib-jquery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561 }, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, +] + +[[package]] +name = "sphinxcontrib-jquery" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 }, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, +] + [[package]] name = "spint" version = "1.0.7" @@ -3522,6 +3682,11 @@ dev = [ { name = "pytest-cov" }, { name = "ruff" }, ] +docs = [ + { name = "nbsphinx" }, + { name = "sphinx" }, + { name = "sphinx-rtd-theme" }, +] [package.metadata] requires-dist = [ @@ -3544,6 +3709,7 @@ requires-dist = [ { name = "matplotlib" }, { name = "mypy", marker = "extra == 'dev'" }, { name = "nbclassic" }, + { name = "nbsphinx", marker = "extra == 'docs'" }, { name = "numba" }, { name = "numpy" }, { name = "opencv-python-headless" }, @@ -3562,6 +3728,8 @@ requires-dist = [ { name = "scikit-learn" }, { name = "scipy" }, { name = "seaborn" }, + { name = "sphinx", marker = "extra == 'docs'" }, + { name = "sphinx-rtd-theme", marker = "extra == 'docs'" }, { name = "statsmodels" }, { name = "stochastic-arrow", git = "https://github.com/CovertLab/arrow?rev=numpy2" }, { name = "swiglpk" }, diff --git a/wholecell/tests/utils/test_memory_debug.py b/wholecell/tests/utils/test_memory_debug.py index 40c937900..5f0b18b11 100644 --- a/wholecell/tests/utils/test_memory_debug.py +++ b/wholecell/tests/utils/test_memory_debug.py @@ -1,7 +1,7 @@ """Test the memory_debug utility. Running it this way reveals the stdout messages about MemoryDebugNode IDs: - python -m wholecell.tests.utils.test_memory_debug + uv run python -m wholecell.tests.utils.test_memory_debug In any case, you should see GC messages like: gc: uncollectable From b72411375a0eb69b8c1819f6c9857a6439791fa4 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 03:31:46 -0800 Subject: [PATCH 14/54] Use uv for container images and remove hvplot dependency --- .github/workflows/docs_deploy.yml | 2 +- .github/workflows/docs_test.yml | 2 +- .github/workflows/pr_tests.yml | 18 +- .github/workflows/pytest.yml | 12 +- README.md | 12 +- doc/docs.rst | 4 +- doc/tutorial.rst | 40 ++-- .../multigeneration/new_gene_counts.py | 16 +- .../analysis/single/mass_fraction_summary.py | 41 ++-- ecoli/composites/ecoli_master.py | 2 +- ecoli/composites/ecoli_master_tests.py | 4 +- ecoli/composites/environment/lattice.py | 2 +- ecoli/experiments/antibiotics_tests.py | 2 +- .../processes/environment/diffusion_field.py | 2 +- ecoli/processes/environment/lysis.py | 2 +- .../environment/multibody_physics.py | 2 +- .../environment/reaction_diffusion_field.py | 2 +- ecoli/processes/enzyme_kinetics.py | 2 +- ecoli/processes/listeners/monomer_counts.py | 2 +- pyproject.toml | 1 - runscripts/container/build-runtime.sh | 8 +- runscripts/container/runtime/Dockerfile | 34 ++-- runscripts/container/wholecell/Dockerfile | 8 +- runscripts/nextflow/config.template | 3 +- runscripts/workflow.py | 11 +- uv.lock | 192 +----------------- wholecell/tests/utils/test_memory_debug.py | 2 +- 27 files changed, 136 insertions(+), 292 deletions(-) diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index 183741916..d0565e0a1 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -14,7 +14,7 @@ jobs: sudo apt-get install pandoc curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --extra docs + run: uv sync --frozen --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index f2daec8b9..7348ad61e 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -16,7 +16,7 @@ jobs: sudo apt-get install pandoc curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --extra docs + run: uv sync --frozen --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index 76e483dcc..fd78e421c 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -16,25 +16,25 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync + run: uv sync --frozen - name: Test ParCa reproducibility run: | - uv run runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ + uv run --env-file .env runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ -c 3 -o out/parca_1 - uv run runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ + uv run --env-file .env runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ -c 3 -o out/parca_2 - uv run runscripts/debug/compare_pickles.py out/parca_1/kb out/parca_2/kb + uv run --env-file .env runscripts/debug/compare_pickles.py out/parca_1/kb out/parca_2/kb - name: Test simulation reproducibility run: | - uv run ecoli/experiments/ecoli_master_sim.py \ + uv run --env-file .env ecoli/experiments/ecoli_master_sim.py \ --generations 1 --emitter parquet --emitter_arg out_dir='out' \ --experiment_id "parca_1" --daughter_outdir "out/parca_1" \ --sim_data_path "out/parca_1/kb/simData.cPickle" --fail_at_total_time & - uv run ecoli/experiments/ecoli_master_sim.py \ + uv run --env-file .env ecoli/experiments/ecoli_master_sim.py \ --generations 1 --emitter parquet --emitter_arg out_dir='out' \ --experiment_id "parca_2" --daughter_outdir "out/parca_2" \ --sim_data_path "out/parca_2/kb/simData.cPickle" --fail_at_total_time - uv run runscripts/debug/diff_simouts.py -o "out" "parca_1*" "parca_2*" + uv run --env-file .env runscripts/debug/diff_simouts.py -o "out" "parca_1*" "parca_2*" Two-gens: runs-on: macos-latest steps: @@ -42,7 +42,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync + run: uv sync --frozen - name: Install nextflow edge run: | curl -s https://get.nextflow.io | bash @@ -51,4 +51,4 @@ jobs: NXF_EDGE=1 ./nextflow self-update - name: Two generations run: | - uv run runscripts/workflow.py --config ecoli/composites/ecoli_configs/two_generations.json + uv run --env-file .env runscripts/workflow.py --config ecoli/composites/ecoli_configs/two_generations.json diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index e08b8590f..20bbe4d55 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,10 +16,10 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync + run: uv sync --frozen - name: Test with pytest run: | - uv run pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 + uv run --env-file .env pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 - name: Code Coverage Report uses: irongut/CodeCoverageSummary@v1.3.0 with: @@ -40,10 +40,10 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync + run: uv sync --frozen - name: Mypy run: | - uv run mypy + uv run --env-file .env mypy Lint: runs-on: ubuntu-latest steps: @@ -51,7 +51,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync + run: uv sync --frozen - name: Ruff run: | - uv run ruff check doc ecoli migration wholecell runscripts validation reconstruction + uv run --env-file .env ruff check doc ecoli migration wholecell runscripts validation reconstruction diff --git a/README.md b/README.md index 5ed09708e..9ddb70997 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,11 @@ to install `uv`, our Python package and project manager of choice. Navigate into the cloned repository and use `uv` to install the model: cd vEcoli - uv sync + uv sync --frozen -> **Note:** If your C compiler is not `clang`, run `CC={your compiler} uv sync` +> **Note:** If your C compiler is not `clang`, run `CC={your compiler} uv sync --frozen` > instead to work around [this limitation](https://github.com/astral-sh/uv/issues/8429). -> For example, `CC=gcc uv sync` for `gcc`. +> For example, `CC=gcc uv sync --frozen` for `gcc`. Finally, install `nextflow` [following these instructions](https://www.nextflow.io/docs/latest/install.html). If you choose to install Java with SDKMAN!, after the Java installation @@ -75,9 +75,11 @@ finishes, close and reopen your terminal before continuing with the To test your installation, from the top-level of the cloned repository, invoke: - uv run runscripts/workflow.py --config ecoli/composites/ecoli_configs/test_installation.json + uv run --env-file .env runscripts/workflow.py --config ecoli/composites/ecoli_configs/test_installation.json -> **Note:** Prefix all of your commands to run scripts with `uv run`. +> **Note:** Start all of your commands to run scripts with `uv run --env-file .env`. +> You can create an alias by appending `alias uvrun="uv run --env-file .env"` +> to your `~/.zshrc` or `~/.bashrc`. Then, you can start commands with `uvrun`. This will run the following basic simulation workflow: diff --git a/doc/docs.rst b/doc/docs.rst index 745401103..d4b4e2d5c 100644 --- a/doc/docs.rst +++ b/doc/docs.rst @@ -496,13 +496,13 @@ Building the Documentation To build the documentation, we will use Sphinx to generate HTML files from plain text. Here are stepwise instructions: -#. Run ``uv sync --extra docs`` to install the necessary dependencies. +#. Run ``uv sync --frozen --extra docs`` to install the necessary dependencies. #. Build the HTML! .. code-block:: console $ cd doc - $ uv run make html + $ uv run --env-file .env make html Your HTML will now be in ``doc/_build/html``. To view it, open ``doc/_build/html/index.html`` in a web browser. diff --git a/doc/tutorial.rst b/doc/tutorial.rst index d370b790a..c634ee3df 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -238,9 +238,8 @@ annotated example of an analysis script: if TYPE_CHECKING: from duckdb import DuckDBPyConnection # Can use polars to perform calculations on tabular data - # returned by DuckDB. Also has hvplot interface for plotting. + # returned by DuckDB. import polars as pl - import hvplot.polars # Import helper functions to read data (see "Output" documentation). from ecoli.library.parquet_emitter import num_cells, read_stacked_columns @@ -288,21 +287,32 @@ annotated example of an analysis script: for k, v in mass_columns.items() } new_columns = { - "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, - **{ - f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] - for k, v in mass_columns.items() - }, + f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] + for k, v in mass_columns.items() } - mass_fold_change = pl.DataFrame(new_columns) - # Easily create and save interactive plot from Polars DataFrame with hvplot - plotted_data = mass_fold_change.plot.line( - x="Time (min)", - ylabel="Mass (normalized by t = 0 min)", - title="Biomass components (average fraction of total dry mass in parentheses)", - color=COLORS, + mass_fold_change = pl.DataFrame( + { + "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, + **new_columns, + } ) - hvplot.save(plotted_data, os.path.join(outdir, "mass_fraction_summary.html")) + # Use Altair to create interactive visualizations + plotted_data = ( + alt.Chart(mass_fold_change) + .transform_fold( + list(new_columns.keys()), + as_=["mass_type", "Mass (normalized by t = 0 min)"], + ) + .mark_line() + .encode( + x="Time (min)", + y=alt.Y("Mass (normalized by t = 0 min)"), + color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), + title="Biomass components (average fraction of total dry mass in parentheses)", + ) + ) + plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) + To add a new analysis script: diff --git a/ecoli/analysis/multigeneration/new_gene_counts.py b/ecoli/analysis/multigeneration/new_gene_counts.py index 90e3ec32d..424cf6457 100644 --- a/ecoli/analysis/multigeneration/new_gene_counts.py +++ b/ecoli/analysis/multigeneration/new_gene_counts.py @@ -1,10 +1,10 @@ +import altair as alt import os from typing import Any, cast from duckdb import DuckDBPyConnection import pickle import polars as pl -import hvplot.polars from ecoli.library.parquet_emitter import ( get_field_metadata, @@ -94,20 +94,18 @@ def plot( ) # mRNA counts - mrna_plot = new_gene_data.hvplot.line( # type: ignore[attr-defined] + mrna_plot = new_gene_data.plot.line( x="Time (min)", - y=new_gene_mRNA_ids, - ylabel="mRNA Counts", + y=alt.Y(new_gene_mRNA_ids).title("mRNA Counts"), title="New Gene mRNA Counts", ) # Protein counts - protein_plot = new_gene_data.hvplot.line( # type: ignore[attr-defined] + protein_plot = new_gene_data.plot.line( x="Time (min)", - y=new_gene_monomer_ids, - ylabel="Protein Counts", + y=alt.Y(new_gene_monomer_ids).title("Protein Counts"), title="New Gene Protein Counts", ) - combined_plot = (mrna_plot + protein_plot).cols(1) - hvplot.save(combined_plot, os.path.join(outdir, "new_gene_counts.html")) + combined_plot = alt.vconcat(mrna_plot, protein_plot) + combined_plot.save(os.path.join(outdir, "new_gene_counts.html")) diff --git a/ecoli/analysis/single/mass_fraction_summary.py b/ecoli/analysis/single/mass_fraction_summary.py index eea59ec43..b81184538 100644 --- a/ecoli/analysis/single/mass_fraction_summary.py +++ b/ecoli/analysis/single/mass_fraction_summary.py @@ -3,12 +3,10 @@ from duckdb import DuckDBPyConnection import polars as pl -import hvplot.polars +import altair as alt from ecoli.library.parquet_emitter import num_cells, read_stacked_columns -hvplot.extension("matplotlib") - COLORS_256 = [ # From colorbrewer2.org, qualitative 8-class set 1 [228, 26, 28], [55, 126, 184], @@ -56,20 +54,27 @@ def plot( for k, v in mass_columns.items() } new_columns = { - "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, - **{ - f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] - for k, v in mass_columns.items() - }, + f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] + for k, v in mass_columns.items() } - mass_fold_change = pl.DataFrame(new_columns) - plot_namespace = mass_fold_change.hvplot # type: ignore[attr-defined] - # hvplot.output(backend='matplotlib') - plotted_data = plot_namespace.line( - x="Time (min)", - ylabel="Mass (normalized by t = 0 min)", - title="Biomass components (average fraction of total dry mass in parentheses)", - color=COLORS, + mass_fold_change = pl.DataFrame( + { + "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, + **new_columns, + } + ) + plotted_data = ( + alt.Chart(mass_fold_change) + .transform_fold( + list(new_columns.keys()), + as_=["mass_type", "Mass (normalized by t = 0 min)"], + ) + .mark_line() + .encode( + x="Time (min)", + y=alt.Y("Mass (normalized by t = 0 min)"), + color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), + title="Biomass components (average fraction of total dry mass in parentheses)", + ) ) - hvplot.save(plotted_data, os.path.join(outdir, "mass_fraction_summary.html")) - # hvplot.save(plotted_data, 'mass_fraction_summary.png', dpi=300) + plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) diff --git a/ecoli/composites/ecoli_master.py b/ecoli/composites/ecoli_master.py index ea2c7bbf8..c312fdf47 100644 --- a/ecoli/composites/ecoli_master.py +++ b/ecoli/composites/ecoli_master.py @@ -857,6 +857,6 @@ def ecoli_topology_plot(config=None): } # run experiments in test_library from the command line with: -# uv run ecoli/composites/ecoli_master.py -n [experiment id] +# uv run --env-file .env ecoli/composites/ecoli_master.py -n [experiment id] if __name__ == "__main__": run_library_cli(test_library) diff --git a/ecoli/composites/ecoli_master_tests.py b/ecoli/composites/ecoli_master_tests.py index 4ed2c3e5e..c1bdc983e 100644 --- a/ecoli/composites/ecoli_master_tests.py +++ b/ecoli/composites/ecoli_master_tests.py @@ -217,7 +217,7 @@ def test_lattice_lysis(plot=False): """ Run plots: ''' - > uv run ecoli/composites/ecoli_master_tests.py -n 4 -o plot=True + > uv run --env-file .env ecoli/composites/ecoli_master_tests.py -n 4 -o plot=True ''' ANTIBIOTIC_KEY = 'nitrocefin' @@ -287,6 +287,6 @@ def plot_spatial_snapshots(data, sim, experiment_dir="ecoli_test"): } # run experiments in test_library from the command line with: -# uv run ecoli/composites/ecoli_master_tests.py -n [experiment id] +# uv run --env-file .env ecoli/composites/ecoli_master_tests.py -n [experiment id] if __name__ == "__main__": run_library_cli(test_library) diff --git a/ecoli/composites/environment/lattice.py b/ecoli/composites/environment/lattice.py index eda0bf947..4aa86a492 100644 --- a/ecoli/composites/environment/lattice.py +++ b/ecoli/composites/environment/lattice.py @@ -281,6 +281,6 @@ def main(): ) -# uv run ecoli/composites/environment/lattice.py [-e if exchanges on] +# uv run --env-file .env ecoli/composites/environment/lattice.py [-e if exchanges on] if __name__ == "__main__": main() diff --git a/ecoli/experiments/antibiotics_tests.py b/ecoli/experiments/antibiotics_tests.py index eafacfd68..c889fe93a 100644 --- a/ecoli/experiments/antibiotics_tests.py +++ b/ecoli/experiments/antibiotics_tests.py @@ -126,6 +126,6 @@ def test_lysis_rxn_dff_environment(total_time=10): "2": test_lysis_rxn_dff_environment, } -# uv run ecoli/experiments/antibiotics_tests.py -n library_id +# uv run --env-file .env ecoli/experiments/antibiotics_tests.py -n library_id if __name__ == "__main__": run_library_cli(library) diff --git a/ecoli/processes/environment/diffusion_field.py b/ecoli/processes/environment/diffusion_field.py index c3d12d682..dce0730dc 100644 --- a/ecoli/processes/environment/diffusion_field.py +++ b/ecoli/processes/environment/diffusion_field.py @@ -336,7 +336,7 @@ def run_diffusion_field(config=None, total_time=100, filename="snapshots"): ) -# uv run ecoli/processes/environment/diffusion_field.py +# uv run --env-file .env ecoli/processes/environment/diffusion_field.py if __name__ == "__main__": # test_all() diff --git a/ecoli/processes/environment/lysis.py b/ecoli/processes/environment/lysis.py index 77c208389..0ff2591cb 100644 --- a/ecoli/processes/environment/lysis.py +++ b/ecoli/processes/environment/lysis.py @@ -423,6 +423,6 @@ def main(): ) -# uv run ecoli/processes/environment/lysis.py +# uv run --env-file .env ecoli/processes/environment/lysis.py if __name__ == "__main__": main() diff --git a/ecoli/processes/environment/multibody_physics.py b/ecoli/processes/environment/multibody_physics.py index 5afd1285a..bdd90bfd6 100644 --- a/ecoli/processes/environment/multibody_physics.py +++ b/ecoli/processes/environment/multibody_physics.py @@ -103,7 +103,7 @@ class Multibody(Process): .. code-block:: console - $ MPLBACKEND=TKAgg uv run vivarium/processes/snapshots.py + $ MPLBACKEND=TKAgg uv run --env-file .env vivarium/processes/snapshots.py Notes: * rotational diffusion in liquid medium with viscosity = 1 mPa.s: :math:`Dr = 3.5 \\pm0.3 rad^{2}/s` diff --git a/ecoli/processes/environment/reaction_diffusion_field.py b/ecoli/processes/environment/reaction_diffusion_field.py index a8708d128..5e4a0217d 100644 --- a/ecoli/processes/environment/reaction_diffusion_field.py +++ b/ecoli/processes/environment/reaction_diffusion_field.py @@ -410,6 +410,6 @@ def main(): ) -# uv run ecoli/processes/environment/reaction_diffusion_field.py +# uv run --env-file .env ecoli/processes/environment/reaction_diffusion_field.py if __name__ == "__main__": main() diff --git a/ecoli/processes/enzyme_kinetics.py b/ecoli/processes/enzyme_kinetics.py index b61dcdbb8..6158ec082 100644 --- a/ecoli/processes/enzyme_kinetics.py +++ b/ecoli/processes/enzyme_kinetics.py @@ -173,6 +173,6 @@ def test_enzyme_kinetics(end_time=100): return data is not None -# run module with uv run ecoli/processes/enzyme_kinetics.py +# run module with uv run --env-file .env ecoli/processes/enzyme_kinetics.py if __name__ == "__main__": test_enzyme_kinetics() diff --git a/ecoli/processes/listeners/monomer_counts.py b/ecoli/processes/listeners/monomer_counts.py index 1980f3b7c..195eea94f 100644 --- a/ecoli/processes/listeners/monomer_counts.py +++ b/ecoli/processes/listeners/monomer_counts.py @@ -239,6 +239,6 @@ def test_monomer_counts_listener(): assert isinstance(listeners["monomer_counts"][1], list) -# uv run ecoli/processes/listeners/monomer_counts.py +# uv run --env-file .env ecoli/processes/listeners/monomer_counts.py if __name__ == "__main__": test_monomer_counts_listener() diff --git a/pyproject.toml b/pyproject.toml index b858aa8cf..08c101a38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ dependencies = [ "ete3", "gcsfs", "pyarrow", - "hvplot", "ipdb", "ipython", "jupyter", diff --git a/runscripts/container/build-runtime.sh b/runscripts/container/build-runtime.sh index c45719a01..8af57faaf 100755 --- a/runscripts/container/build-runtime.sh +++ b/runscripts/container/build-runtime.sh @@ -31,9 +31,10 @@ while getopts 'r:al' flag; do esac done -# This needs only one payload file so copy it in rather than using a config at +# Copy required payload files so rather than using a config at # the project root which would upload the entire project. -cp requirements.txt runscripts/container/runtime/ +cp pyproject.toml runscripts/container/runtime/ +cp uv.lock runscripts/container/runtime/ if (( $RUN_LOCAL )); then echo "=== Locally building WCM runtime Docker Image: ${RUNTIME_IMAGE} ===" @@ -56,4 +57,5 @@ else runscripts/container/runtime/ fi -rm runscripts/container/runtime/requirements.txt +rm runscripts/container/runtime/pyproject.toml +rm runscripts/container/runtime/uv.lock diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index c5ba0a12f..d2d0ad2ac 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -14,25 +14,35 @@ ARG from=python:3.11.10@sha256:15f10b142547000e2429615b3d314474ae7d6ac062a8dd2c9246adcee7068e55 FROM ${from} +# Install uv +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ + RUN echo "alias ls='ls --color=auto'" >> ~/.bashrc \ && echo "alias ll='ls -l'" >> ~/.bashrc \ && cp ~/.bashrc / # Update and install in the same layer so it won't install from old updates. -RUN apt-get update \ - && apt-get install -y swig=4.1.0-0.2 gfortran=4:12.2.0-3 \ - llvm=1:14.0-55.7~deb12u1 cmake=3.25.1-1 nano=7.2-1+deb12u1 \ - libopenblas-dev=0.3.21+ds-4 +RUN apt-get update && apt-get install git curl gcc + +# Install the project into `/vEcoli` +WORKDIR /vEcoli -# This gets more consistent results from openblas. +# This gets better performance and more reproducible results ENV OPENBLAS_NUM_THREADS=1 -# Install all the pips within one Docker layer, don't cache the downloads. -COPY requirements.txt / -RUN (b1="" \ - && echo "Installing pips with '$b1'" \ - && pip install --no-cache-dir --upgrade pip setuptools==73.0.1 wheel \ - && pip install --no-cache-dir numpy==1.26.4 $b1 \ - && pip install --no-cache-dir -r requirements.txt $b1) +# Enable bytecode compilation +ENV UV_COMPILE_BYTECODE=1 + +# Copy from the cache instead of linking since it's a mounted volume +ENV UV_LINK_MODE=copy + +# Install the project's dependencies using the lockfile and settings +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --frozen --no-install-project --no-dev + +# Place executables in the environment at the front of the path +ENV PATH="/vEcoli/.venv/bin:$PATH" CMD ["/bin/bash"] diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index 03c7a586a..743d35a72 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -24,11 +24,11 @@ # # It will start a shell where you can execute commands: # -# uv run pytest +# uv run --env-file .env pytest # # If this succeeds you can start running WCM code in the container, e.g.: # -# uv run runscripts/manual/runParca.py +# uv run --env-file .env runscripts/manual/runParca.py ARG from=wcm-runtime:latest FROM ${from} @@ -51,8 +51,8 @@ LABEL application="Whole Cell Model of Escherichia coli" \ COPY . /vEcoli WORKDIR /vEcoli -RUN make clean compile -ENV PYTHONPATH=/vEcoli +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen # Since this build runs as root, set permissions so running the container as # another user will work: Parca writes into /vEcoli/cache/. diff --git a/runscripts/nextflow/config.template b/runscripts/nextflow/config.template index 72581b7ef..992fe4dd6 100644 --- a/runscripts/nextflow/config.template +++ b/runscripts/nextflow/config.template @@ -79,6 +79,7 @@ profiles { memory = params.parca_cpus * 2.GB } container = params.container_image + containerOptions = "-B ${PUBLISH_DIR}:${PUBLISH_DIR} -B ${launchDir}:/vEcoli" queue = 'mcovert,owners,dev,normal' executor = 'slurm' // Single core sims are slightly slower but can have shorter @@ -108,7 +109,7 @@ profiles { maxRetries = 3 } apptainer.enabled = true - params.projectRoot = "${launchDir}" + params.projectRoot = "/vEcoli" // Avoid getting queue status too frequently (can cause job status mixups) executor.queueStatInterval = '2 min' // Check for terminated jobs and submit new ones fairly frequently diff --git a/runscripts/workflow.py b/runscripts/workflow.py index 18287843a..d8eaa23a4 100644 --- a/runscripts/workflow.py +++ b/runscripts/workflow.py @@ -431,13 +431,16 @@ def main(): [ "apptainer", "exec", + "-B", + f"{repo_dir}:/vEcoli", "--cwd", - os.path.dirname(os.path.dirname(__file__)), + repo_dir, "-e", runtime_image_name, - "make", - "clean", - "compile", + "uv", + "sync", + "--frozen", + "--no-cache" ] ) if sherlock_config.get("jenkins", False): diff --git a/uv.lock b/uv.lock index 3e50dc9f2..20f50708e 100644 --- a/uv.lock +++ b/uv.lock @@ -263,26 +263,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, ] -[[package]] -name = "bokeh" -version = "3.6.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "contourpy" }, - { name = "jinja2" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "pillow" }, - { name = "pyyaml" }, - { name = "tornado" }, - { name = "xyzservices" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/9d/cc9c561e1db8cbecc5cfad972159020700fff2339bdaa316498ace1cb04c/bokeh-3.6.2.tar.gz", hash = "sha256:2f3043d9ecb3d5dc2e8c0ebf8ad55727617188d4e534f3e7208b36357e352396", size = 6247610 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/12/2c266a0dc57379c60b4e73a2f93e71343db4170bf26c5a76a74e7d8bce2a/bokeh-3.6.2-py3-none-any.whl", hash = "sha256:fddc4b91f8b40178c0e3e83dfcc33886d7803a3a1f041a840834255e435a18c2", size = 6866799 }, -] - [[package]] name = "cachetools" version = "5.5.0" @@ -411,15 +391,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] -[[package]] -name = "colorcet" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5f/c3/ae78e10b7139d6b7ce080d2e81d822715763336aa4229720f49cb3b3e15b/colorcet-3.1.0.tar.gz", hash = "sha256:2921b3cd81a2288aaf2d63dbc0ce3c26dcd882e8c389cc505d6886bf7aa9a4eb", size = 2183107 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/c6/9963d588cc3d75d766c819e0377a168ef83cf3316a92769971527a1ad1de/colorcet-3.1.0-py3-none-any.whl", hash = "sha256:2a7d59cc8d0f7938eeedd08aad3152b5319b4ba3bcb7a612398cc17a384cb296", size = 260286 }, -] - [[package]] name = "comm" version = "0.2.2" @@ -931,25 +902,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, ] -[[package]] -name = "holoviews" -version = "1.20.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bokeh" }, - { name = "colorcet" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "panel" }, - { name = "param" }, - { name = "pyviz-comms" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9b/6d/460e318557121a3d22fa1dd60db44cac7357cf83a2890b2f781a91b5be25/holoviews-1.20.0.tar.gz", hash = "sha256:29d183045fafa3d846deda999d9687b99b8abdc1a8c06712e54afa576bb02b3e", size = 4590760 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/89/8df4efa78df8b129847c8a7c0e492376cca62ab68453e5a20375a1c6291b/holoviews-1.20.0-py3-none-any.whl", hash = "sha256:dc810b6790e1dd2c90f16406b292e08db10efa377b2554e46755a130e12044c5", size = 5016222 }, -] - [[package]] name = "httpcore" version = "1.0.7" @@ -978,25 +930,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] -[[package]] -name = "hvplot" -version = "0.11.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bokeh" }, - { name = "colorcet" }, - { name = "holoviews" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "panel" }, - { name = "param" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/09/e5fe45bf64fefadd4e4dd9cc64c9c9757e28562c88d5db94b9e560820e5f/hvplot-0.11.1.tar.gz", hash = "sha256:989ed0389189adc47edcd2601d2eab18bf366e74b07f5e2873e021323c4a14bb", size = 6979548 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/57/7c/9342dfd03f2bdad4d1e6f2532631d346557286ce254c40f7bd5e66abecc2/hvplot-0.11.1-py3-none-any.whl", hash = "sha256:1cef5bf1ab4157c50b5ee265da760a8034b8dbb7fc81867d6050962a2eab9b35", size = 161240 }, -] - [[package]] name = "idna" version = "3.10" @@ -1169,7 +1102,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jaxlib" }, { name = "ml-dtypes" }, - { name = "numpy", marker = "python_full_version == '3.12.8'" }, + { name = "numpy" }, { name = "opt-einsum" }, { name = "scipy", marker = "python_full_version == '3.12.8'" }, ] @@ -1185,7 +1118,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ml-dtypes" }, { name = "numpy" }, - { name = "scipy", marker = "python_full_version == '3.12.8'" }, + { name = "scipy" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/e3/0e/3b4a99c09431ee5820624d4dcf4efa7becd3c83b56ff0f09a078f4c421a2/jaxlib-0.4.36-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:5972aa85f6d771ecc8cc72148c1fa64250ca33cbdf2bf24407cdee8a5299d25d", size = 98718357 }, @@ -1557,18 +1490,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/aa/b7c02db2668bfd8de7b84f3d13dc36e4aca7dc8dba978b34f9e56dd0f103/line_profiler-4.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a85ff57d4ef9d899ca12d6b0883c3cab1786388b29d2fb5f30f909e70bb9a691", size = 128330 }, ] -[[package]] -name = "linkify-it-py" -version = "2.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "uc-micro-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 }, -] - [[package]] name = "llvmlite" version = "0.43.0" @@ -1598,27 +1519,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/e9/d7531a07454927788642373ae253ad6dd8714fec375a789031418ecebf2d/mapclassify-2.8.1-py3-none-any.whl", hash = "sha256:c79ba6ba9e51c16a5c209e824a47c76aa2b6df5773ec8a56a2f3871590d92fb6", size = 59085 }, ] -[[package]] -name = "markdown" -version = "3.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - [[package]] name = "markupsafe" version = "3.0.2" @@ -1674,27 +1574,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, ] -[[package]] -name = "mdit-py-plugins" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - [[package]] name = "mgwr" version = "2.2.1" @@ -1725,7 +1604,7 @@ name = "ml-dtypes" version = "0.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", marker = "python_full_version == '3.12.8'" }, + { name = "numpy" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fd/15/76f86faa0902836cc133939732f7611ace68cf54148487a99c539c272dc8/ml_dtypes-0.4.1.tar.gz", hash = "sha256:fad5f2de464fd09127e49b7fd1252b9006fb43d2edc1ff112d390c324af5ca7a", size = 692594 } wheels = [ @@ -2132,39 +2011,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, ] -[[package]] -name = "panel" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bleach" }, - { name = "bokeh" }, - { name = "linkify-it-py" }, - { name = "markdown" }, - { name = "markdown-it-py" }, - { name = "mdit-py-plugins" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "param" }, - { name = "pyviz-comms" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/66/7f13691d577c3096d8605c307cfc6f662014896086a0c53778cf6e5828ea/panel-1.5.4.tar.gz", hash = "sha256:7644e87afe9b94c32b4fca939d645c5b958d671691bd841d3391e31941090092", size = 29378323 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/9e/6bdbdc6c5ce7d0ba901d8599f6338cd8d945f425348629cd53560d8c05c1/panel-1.5.4-py3-none-any.whl", hash = "sha256:98521ff61dfe2ef684181213842521674d2db95f692c7942ab9103a2c0e882b9", size = 63137025 }, -] - -[[package]] -name = "param" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/39/75203d36ddd59f3819ef930451d4436e60248a674fb1136d9cf126cb9859/param-2.1.1.tar.gz", hash = "sha256:3b1da14abafa75bfd908572378a58696826b3719a723bc31b40ffff2e9a5c852", size = 174619 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/7b/5593a40fcd0981bda85274bb3e622ac433a94ae1e11ef8639de362cfa7de/param-2.1.1-py3-none-any.whl", hash = "sha256:81066d040526fbaa44b6419f3e92348fa8856ea44c8d3915e9245937ddabe2d6", size = 116757 }, -] - [[package]] name = "parso" version = "0.8.4" @@ -2669,18 +2515,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 }, ] -[[package]] -name = "pyviz-comms" -version = "3.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "param" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/d6/21460c434d01fe94bd97b9a5b41726ae79b68024b634dcaf7d77f8254c6f/pyviz_comms-3.0.3.tar.gz", hash = "sha256:fde4a017c2213ecee63a9a6741431c845e42a5c7b1588e4a7ba2e4370c583728", size = 196501 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/81/3e/5a36494314e4780362b15a7e190095eec68366a0d512b5b532607c213a26/pyviz_comms-3.0.3-py3-none-any.whl", hash = "sha256:fd26951eebc7950106d481655d91ba06296d4cf352dffb1d03f88f959832448e", size = 83530 }, -] - [[package]] name = "pywin32" version = "308" @@ -3594,15 +3428,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 }, ] -[[package]] -name = "uc-micro-py" -version = "1.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 }, -] - [[package]] name = "unum" version = "4.2.1" @@ -3641,7 +3466,6 @@ dependencies = [ { name = "ecos" }, { name = "ete3" }, { name = "gcsfs" }, - { name = "hvplot" }, { name = "ipdb" }, { name = "ipython" }, { name = "iteround" }, @@ -3699,7 +3523,6 @@ requires-dist = [ { name = "ecos" }, { name = "ete3" }, { name = "gcsfs" }, - { name = "hvplot" }, { name = "ipdb" }, { name = "ipython" }, { name = "iteround" }, @@ -3811,15 +3634,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/21/02/88b65cc394961a60c43c70517066b6b679738caf78506a5da7b88ffcb643/widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71", size = 2335872 }, ] -[[package]] -name = "xyzservices" -version = "2024.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a0/16/ae87cbd2d6bfc40a419077521c35aadf5121725b7bee3d7c51b56f50958b/xyzservices-2024.9.0.tar.gz", hash = "sha256:68fb8353c9dbba4f1ff6c0f2e5e4e596bb9e1db7f94f4f7dfbcb26e25aa66fde", size = 1131900 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/d3/e07ce413d16ef64e885bea37551eac4c5ca3ddd440933f9c94594273d0d9/xyzservices-2024.9.0-py3-none-any.whl", hash = "sha256:776ae82b78d6e5ca63dd6a94abb054df8130887a4a308473b54a6bd364de8644", size = 85130 }, -] - [[package]] name = "yarl" version = "1.18.3" diff --git a/wholecell/tests/utils/test_memory_debug.py b/wholecell/tests/utils/test_memory_debug.py index 5f0b18b11..a223a423a 100644 --- a/wholecell/tests/utils/test_memory_debug.py +++ b/wholecell/tests/utils/test_memory_debug.py @@ -1,7 +1,7 @@ """Test the memory_debug utility. Running it this way reveals the stdout messages about MemoryDebugNode IDs: - uv run python -m wholecell.tests.utils.test_memory_debug + uv run --env-file .env python -m wholecell.tests.utils.test_memory_debug In any case, you should see GC messages like: gc: uncollectable From 9c786d6d14267988c3c98475058224b0e4a40c84 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 03:35:48 -0800 Subject: [PATCH 15/54] Replace Jax with lightweight Autograd --- pyproject.toml | 4 +- .../ecoli/dataclasses/process/rna_decay.py | 18 ++--- uv.lock | 73 ++++--------------- 3 files changed, 24 insertions(+), 71 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 08c101a38..bdc5e29fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ dependencies = [ "sympy", "tqdm", "unum", - "jax", "vivarium-core", "pysal", "opencv-python-headless", @@ -54,7 +53,8 @@ dependencies = [ "iteround", "wheel", # Can change to regular stochastic-arrow once PR merged - "stochastic-arrow @ git+https://github.com/CovertLab/arrow@numpy2" + "stochastic-arrow @ git+https://github.com/CovertLab/arrow@numpy2", + "autograd", ] [project.optional-dependencies] diff --git a/reconstruction/ecoli/dataclasses/process/rna_decay.py b/reconstruction/ecoli/dataclasses/process/rna_decay.py index db5c8ce89..207207ee5 100644 --- a/reconstruction/ecoli/dataclasses/process/rna_decay.py +++ b/reconstruction/ecoli/dataclasses/process/rna_decay.py @@ -4,12 +4,10 @@ from wholecell.utils import units -from jax import config, jacfwd -import jax.numpy as jnp +import autograd.numpy as anp +from autograd import jacobian import numpy as np -config.update("jax_enable_x64", True) - class RnaDecay(object): """RnaDecay""" @@ -74,7 +72,7 @@ def km_loss_function(self, vMax, rnaConc, kDeg, isEndoRnase, alpha): are positive, the loss function accepts as input the logarithm of the final Km values and exponentiates them before calculating the residuals. - The third-party package Jax uses autodiff to calculate Jacobians for our loss + The third-party package Autograd uses autodiff to calculate Jacobians for our loss function that can be used during minimization. Parameters @@ -96,20 +94,20 @@ def km_loss_function(self, vMax, rnaConc, kDeg, isEndoRnase, alpha): """ def residual_f(km): - return vMax / km / kDeg / (1 + jnp.sum(rnaConc / km)) - 1 + return vMax / km / kDeg / (1 + anp.sum(rnaConc / km)) - 1 def residual_aux_f(km): - return vMax * rnaConc / km / (1 + jnp.sum(rnaConc / km)) - kDeg * rnaConc + return vMax * rnaConc / km / (1 + anp.sum(rnaConc / km)) - kDeg * rnaConc def L(log_km): - km = jnp.exp(log_km) + km = anp.exp(log_km) residual_squared = residual_f(km) ** 2 # Loss function - return jnp.sum(residual_squared) + return anp.sum(residual_squared) def Lp(km): - return jacfwd(L)(km) + return jacobian(L)(km) return ( L, diff --git a/uv.lock b/uv.lock index 20f50708e..6d2b92ad4 100644 --- a/uv.lock +++ b/uv.lock @@ -213,6 +213,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, ] +[[package]] +name = "autograd" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/ed/67975d75c0fe71220c8df2370c6c1390805790a641359b502f39c042c0c1/autograd-1.7.0.tar.gz", hash = "sha256:de743fd368d6df523cd37305dcd171861a9752a144493677d2c9f5a56983ff2f", size = 2564855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/90/d13cf396989052cadd8511c1878b0913bbce28eeef5feb95710a92e03076/autograd-1.7.0-py3-none-any.whl", hash = "sha256:49680300f842f3a8722b060ac0d3ed7aca071d1ad4d3d38c9fdadafdcc73c30b", size = 52522 }, +] + [[package]] name = "babel" version = "2.16.0" @@ -1095,39 +1107,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/c7/68d920f791cd99919d82dd6db9fc0aca3790dc8d67c69b559a447ca2a914/iteround-1.0.4-py3-none-any.whl", hash = "sha256:17947dd5479177e6fb186b0a3d5d594b55eedea14dc722c6da7e84bbed45f5b2", size = 7333 }, ] -[[package]] -name = "jax" -version = "0.4.36" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jaxlib" }, - { name = "ml-dtypes" }, - { name = "numpy" }, - { name = "opt-einsum" }, - { name = "scipy", marker = "python_full_version == '3.12.8'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/79/b8033b443d15671725ef4aef7f756c8b0026a7add3e807981d4d7c6abba7/jax-0.4.36.tar.gz", hash = "sha256:088bff0575d01fc82682a9af4eb07433d60de7e5164686bd2cea3439492e608a", size = 1915594 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/d5/1240192a0bc7b284bca9f753e69e92645afb82a6b2c3e1138520698938f4/jax-0.4.36-py3-none-any.whl", hash = "sha256:4d86a99fab7c25ea0deda2672b429ef650e5eac819884e74d35c32c6e86a5856", size = 2221127 }, -] - -[[package]] -name = "jaxlib" -version = "0.4.36" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "ml-dtypes" }, - { name = "numpy" }, - { name = "scipy" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/0e/3b4a99c09431ee5820624d4dcf4efa7becd3c83b56ff0f09a078f4c421a2/jaxlib-0.4.36-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:5972aa85f6d771ecc8cc72148c1fa64250ca33cbdf2bf24407cdee8a5299d25d", size = 98718357 }, - { url = "https://files.pythonhosted.org/packages/d3/46/05e70a1236ec3782333b3e9469f971c9d45af2aa0aebf602acd9d76292eb/jaxlib-0.4.36-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5597908cd10418c0b42e9af807fc8112036703533cf501a5255a8fbf4011867e", size = 78596060 }, - { url = "https://files.pythonhosted.org/packages/8e/76/6b969cbf197b8c53c84c2642069722e84a3a260af084a8acbbf90ca444ea/jaxlib-0.4.36-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:fbbabaa287378a78a3cf9cbe4de30a1f6f19a99116feb4bd687ff256415cd442", size = 84053202 }, - { url = "https://files.pythonhosted.org/packages/fe/f2/7624a304426daa7b135b85caf1b8eccf879e7cb10bc074656ce628309cb0/jaxlib-0.4.36-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:be295abc209c980817db0488f21f1fbc0644f87326522895e2b9b64729106357", size = 100325610 }, - { url = "https://files.pythonhosted.org/packages/bb/8b/ded8420cd9198eb677869ffd557d9880af5833c7bf39e604e80b56550e09/jaxlib-0.4.36-cp312-cp312-win_amd64.whl", hash = "sha256:d4bbb5d2970628dcd3dabc28a5b97a1125ad3e06a1be822d340fd9f06f7449b3", size = 63338518 }, -] - [[package]] name = "jedi" version = "0.19.2" @@ -1599,21 +1578,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205", size = 47958 }, ] -[[package]] -name = "ml-dtypes" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fd/15/76f86faa0902836cc133939732f7611ace68cf54148487a99c539c272dc8/ml_dtypes-0.4.1.tar.gz", hash = "sha256:fad5f2de464fd09127e49b7fd1252b9006fb43d2edc1ff112d390c324af5ca7a", size = 692594 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/1a/99e924f12e4b62139fbac87419698c65f956d58de0dbfa7c028fa5b096aa/ml_dtypes-0.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:827d3ca2097085cf0355f8fdf092b888890bb1b1455f52801a2d7756f056f54b", size = 405077 }, - { url = "https://files.pythonhosted.org/packages/8f/8c/7b610bd500617854c8cc6ed7c8cfb9d48d6a5c21a1437a36a4b9bc8a3598/ml_dtypes-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772426b08a6172a891274d581ce58ea2789cc8abc1c002a27223f314aaf894e7", size = 2181554 }, - { url = "https://files.pythonhosted.org/packages/c7/c6/f89620cecc0581dc1839e218c4315171312e46c62a62da6ace204bda91c0/ml_dtypes-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126e7d679b8676d1a958f2651949fbfa182832c3cd08020d8facd94e4114f3e9", size = 2160488 }, - { url = "https://files.pythonhosted.org/packages/ae/11/a742d3c31b2cc8557a48efdde53427fd5f9caa2fa3c9c27d826e78a66f51/ml_dtypes-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:df0fb650d5c582a9e72bb5bd96cfebb2cdb889d89daff621c8fbc60295eba66c", size = 127462 }, -] - [[package]] name = "momepy" version = "0.9.1" @@ -1896,15 +1860,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/d0/22f68eb23eea053a31655960f133c0be9726c6a881547e6e9e7e2a946c4f/opencv_python_headless-4.10.0.84-cp37-abi3-win_amd64.whl", hash = "sha256:afcf28bd1209dd58810d33defb622b325d3cbe49dcd7a43a902982c33e5fad05", size = 38754031 }, ] -[[package]] -name = "opt-einsum" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932 }, -] - [[package]] name = "orjson" version = "3.10.12" @@ -3458,6 +3413,7 @@ version = "1.1.0" source = { editable = "." } dependencies = [ { name = "altair" }, + { name = "autograd" }, { name = "biopython" }, { name = "cvxpy" }, { name = "cython" }, @@ -3469,7 +3425,6 @@ dependencies = [ { name = "ipdb" }, { name = "ipython" }, { name = "iteround" }, - { name = "jax" }, { name = "jupyter" }, { name = "line-profiler" }, { name = "matplotlib" }, @@ -3515,6 +3470,7 @@ docs = [ [package.metadata] requires-dist = [ { name = "altair" }, + { name = "autograd", specifier = ">=1.7.0" }, { name = "biopython" }, { name = "cvxpy" }, { name = "cython" }, @@ -3526,7 +3482,6 @@ requires-dist = [ { name = "ipdb" }, { name = "ipython" }, { name = "iteround" }, - { name = "jax" }, { name = "jupyter" }, { name = "line-profiler" }, { name = "matplotlib" }, From a6ffd1ca6360e97011e921e8233c458c9c143c01 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 03:58:58 -0800 Subject: [PATCH 16/54] Try Debian image with uv --- runscripts/container/runtime/Dockerfile | 7 ++----- runscripts/container/runtime/Singularity | 14 +++++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index d2d0ad2ac..a5497bb45 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -11,18 +11,15 @@ # Add option `--build-arg from=ABC` to build from a different base image "ABC" # but DO NOT USE an alpine base since the simulation math comes out different! # See https://pythonspeed.com/articles/alpine-docker-python/ for more reasons. -ARG from=python:3.11.10@sha256:15f10b142547000e2429615b3d314474ae7d6ac062a8dd2c9246adcee7068e55 +ARG from=ghcr.io/astral-sh/uv:bookworm-slim@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b3575f48a4ae4c1e4efadd FROM ${from} -# Install uv -COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ - RUN echo "alias ls='ls --color=auto'" >> ~/.bashrc \ && echo "alias ll='ls -l'" >> ~/.bashrc \ && cp ~/.bashrc / # Update and install in the same layer so it won't install from old updates. -RUN apt-get update && apt-get install git curl gcc +RUN apt-get update && apt-get install -y clang # Install the project into `/vEcoli` WORKDIR /vEcoli diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index 1c5038dd2..91a11ac7a 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -1,5 +1,5 @@ Bootstrap: docker -From: python@sha256:15f10b142547000e2429615b3d314474ae7d6ac062a8dd2c9246adcee7068e55 +From: ghcr.io/astral-sh/uv@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b3575f48a4ae4c1e4efadd %environment export OPENBLAS_NUM_THREADS=1 @@ -12,7 +12,8 @@ From: python@sha256:15f10b142547000e2429615b3d314474ae7d6ac062a8dd2c9246adcee706 website "https://www.covert.stanford.edu/" %files - requirements.txt /requirements.txt + uv.lock /vEcoli/uv.lock + pyproject.toml /vEcoli/pyproject.toml %post echo "Setting up runtime environment..." @@ -21,14 +22,9 @@ From: python@sha256:15f10b142547000e2429615b3d314474ae7d6ac062a8dd2c9246adcee706 echo "alias ll='ls -l'" >> ~/.bashrc cp ~/.bashrc / - apt-get update \ - && apt-get install -y swig=4.1.0-0.2 gfortran=4:12.2.0-3 \ - llvm=1:14.0-55.7~deb12u1 cmake=3.25.1-1 nano=7.2-1+deb12u1 \ - libopenblas-dev=0.3.21+ds-4 + apt-get update && apt-get install -y clang - pip install --no-cache-dir --upgrade pip setuptools==73.0.1 wheel - pip install --no-cache-dir numpy==1.26.4 - pip install --no-cache-dir -r /requirements.txt + uv sync --frozen --no-install-project --no-dev %runscript # This defines the default behavior when the container is executed. From f9962a06400bf76c8178493b45820ee8cf2b401f Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:03:18 -0800 Subject: [PATCH 17/54] Add project dir for Singularity image --- runscripts/container/runtime/Singularity | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index 91a11ac7a..bf3ed568e 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -24,7 +24,7 @@ From: ghcr.io/astral-sh/uv@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b357 apt-get update && apt-get install -y clang - uv sync --frozen --no-install-project --no-dev + uv sync --frozen --no-install-project --no-dev --project vEcoli %runscript # This defines the default behavior when the container is executed. From 17dcd9189fcb8e7ce9fdd866ab908c4b05aa4816 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:05:08 -0800 Subject: [PATCH 18/54] Install git and use gcc --- runscripts/container/runtime/Dockerfile | 4 ++-- runscripts/container/runtime/Singularity | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index a5497bb45..06dad30e5 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -19,7 +19,7 @@ RUN echo "alias ls='ls --color=auto'" >> ~/.bashrc \ && cp ~/.bashrc / # Update and install in the same layer so it won't install from old updates. -RUN apt-get update && apt-get install -y clang +RUN apt-get update && apt-get install -y git gcc # Install the project into `/vEcoli` WORKDIR /vEcoli @@ -37,7 +37,7 @@ ENV UV_LINK_MODE=copy RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - uv sync --frozen --no-install-project --no-dev + CC=gcc uv sync --frozen --no-install-project --no-dev # Place executables in the environment at the front of the path ENV PATH="/vEcoli/.venv/bin:$PATH" diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index bf3ed568e..b423029d5 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -22,9 +22,9 @@ From: ghcr.io/astral-sh/uv@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b357 echo "alias ll='ls -l'" >> ~/.bashrc cp ~/.bashrc / - apt-get update && apt-get install -y clang + apt-get update && apt-get install -y git gcc - uv sync --frozen --no-install-project --no-dev --project vEcoli + CC=gcc uv sync --frozen --no-install-project --no-dev --project vEcoli %runscript # This defines the default behavior when the container is executed. From 4265a8aea18e223421341cfb4e48849bf554dd3b Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:07:03 -0800 Subject: [PATCH 19/54] Add temporary flag while waiting for stochastic-arrow 1.1.0 --- runscripts/container/runtime/Dockerfile | 2 +- runscripts/container/runtime/Singularity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index 06dad30e5..d8a017fbb 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -37,7 +37,7 @@ ENV UV_LINK_MODE=copy RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - CC=gcc uv sync --frozen --no-install-project --no-dev + USE_CYTHON=1 CC=gcc uv sync --frozen --no-install-project --no-dev # Place executables in the environment at the front of the path ENV PATH="/vEcoli/.venv/bin:$PATH" diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index b423029d5..61f396537 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -24,7 +24,7 @@ From: ghcr.io/astral-sh/uv@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b357 apt-get update && apt-get install -y git gcc - CC=gcc uv sync --frozen --no-install-project --no-dev --project vEcoli + USE_CYTHON=1 CC=gcc uv sync --frozen --no-install-project --no-dev --project vEcoli %runscript # This defines the default behavior when the container is executed. From 1cbe75a81d1b845aa4c7216de8c33e0d6d5e6bd7 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:14:01 -0800 Subject: [PATCH 20/54] No persistent cache on Cloud Build --- runscripts/container/runtime/Dockerfile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index d8a017fbb..ee0c6ecd8 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -30,14 +30,9 @@ ENV OPENBLAS_NUM_THREADS=1 # Enable bytecode compilation ENV UV_COMPILE_BYTECODE=1 -# Copy from the cache instead of linking since it's a mounted volume -ENV UV_LINK_MODE=copy - +COPY uv.lock pyproject.toml /vEcoli/ # Install the project's dependencies using the lockfile and settings -RUN --mount=type=cache,target=/root/.cache/uv \ - --mount=type=bind,source=uv.lock,target=uv.lock \ - --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - USE_CYTHON=1 CC=gcc uv sync --frozen --no-install-project --no-dev +RUN USE_CYTHON=1 CC=gcc uv sync --frozen --no-install-project --no-dev # Place executables in the environment at the front of the path ENV PATH="/vEcoli/.venv/bin:$PATH" From 7cbf34ee7a24f1a8852c246d0b69c0d65b954a4a Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:32:42 -0800 Subject: [PATCH 21/54] Clarify ortools constraint --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bdc5e29fd..2540681f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ dependencies = [ "altair", "numba", "orjson", - # Can be removed once cvxpy supports newer ortools + # Constraint can be removed once cvxpy supports newer ortools "ortools<=9.9.3963", "pandas", "polars", diff --git a/uv.lock b/uv.lock index 6d2b92ad4..68ed23541 100644 --- a/uv.lock +++ b/uv.lock @@ -3470,7 +3470,7 @@ docs = [ [package.metadata] requires-dist = [ { name = "altair" }, - { name = "autograd", specifier = ">=1.7.0" }, + { name = "autograd" }, { name = "biopython" }, { name = "cvxpy" }, { name = "cython" }, From cc0dfd4c306901207ac37f2ac3d9e42cbe4aeba9 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 04:34:07 -0800 Subject: [PATCH 22/54] No cache for WCM Docker build --- runscripts/container/wholecell/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index 743d35a72..bf0c7658a 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -51,8 +51,7 @@ LABEL application="Whole Cell Model of Escherichia coli" \ COPY . /vEcoli WORKDIR /vEcoli -RUN --mount=type=cache,target=/root/.cache/uv \ - uv sync --frozen +RUN uv sync --frozen # Since this build runs as root, set permissions so running the container as # another user will work: Parca writes into /vEcoli/cache/. From ae08c461bb078e6b19faaf7d3787f1b0f0dd4385 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 05:21:26 -0800 Subject: [PATCH 23/54] Use gcc for WCM image --- runscripts/container/wholecell/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index bf0c7658a..c090bfb3c 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -51,7 +51,7 @@ LABEL application="Whole Cell Model of Escherichia coli" \ COPY . /vEcoli WORKDIR /vEcoli -RUN uv sync --frozen +RUN CC=gcc uv sync --frozen # Since this build runs as root, set permissions so running the container as # another user will work: Parca writes into /vEcoli/cache/. From 5b7365ce11a177e3dc07eb8eaed1ac1faf7fcdb7 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 05:39:59 -0800 Subject: [PATCH 24/54] Fix Altair plot syntax --- doc/tutorial.rst | 4 +++- ecoli/analysis/multigeneration/new_gene_counts.py | 6 ++---- ecoli/analysis/single/mass_fraction_summary.py | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index c634ee3df..b64d7fa8b 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -308,7 +308,9 @@ annotated example of an analysis script: x="Time (min)", y=alt.Y("Mass (normalized by t = 0 min)"), color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), - title="Biomass components (average fraction of total dry mass in parentheses)", + ) + .properties( + title="Biomass components (average fraction of total dry mass in parentheses)" ) ) plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) diff --git a/ecoli/analysis/multigeneration/new_gene_counts.py b/ecoli/analysis/multigeneration/new_gene_counts.py index 424cf6457..a89abb1f7 100644 --- a/ecoli/analysis/multigeneration/new_gene_counts.py +++ b/ecoli/analysis/multigeneration/new_gene_counts.py @@ -97,15 +97,13 @@ def plot( mrna_plot = new_gene_data.plot.line( x="Time (min)", y=alt.Y(new_gene_mRNA_ids).title("mRNA Counts"), - title="New Gene mRNA Counts", - ) + ).properties(title="New Gene mRNA Counts") # Protein counts protein_plot = new_gene_data.plot.line( x="Time (min)", y=alt.Y(new_gene_monomer_ids).title("Protein Counts"), - title="New Gene Protein Counts", - ) + ).properties(title="New Gene Protein Counts") combined_plot = alt.vconcat(mrna_plot, protein_plot) combined_plot.save(os.path.join(outdir, "new_gene_counts.html")) diff --git a/ecoli/analysis/single/mass_fraction_summary.py b/ecoli/analysis/single/mass_fraction_summary.py index b81184538..ea281f9f8 100644 --- a/ecoli/analysis/single/mass_fraction_summary.py +++ b/ecoli/analysis/single/mass_fraction_summary.py @@ -74,7 +74,9 @@ def plot( x="Time (min)", y=alt.Y("Mass (normalized by t = 0 min)"), color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), - title="Biomass components (average fraction of total dry mass in parentheses)", + ) + .properties( + title="Biomass components (average fraction of total dry mass in parentheses)" ) ) plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) From 60987a41bf955ddbb4eb82e16ea36a425ee32682 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 06:38:44 -0800 Subject: [PATCH 25/54] Fix fold change plot --- doc/tutorial.rst | 40 ++++++++--------- .../analysis/single/mass_fraction_summary.py | 44 ++++++++++--------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/doc/tutorial.rst b/doc/tutorial.rst index b64d7fa8b..112e53a0f 100644 --- a/doc/tutorial.rst +++ b/doc/tutorial.rst @@ -280,40 +280,40 @@ annotated example of an analysis script: mass_data = read_stacked_columns( history_sql, list(mass_columns.values()), conn=conn ) - # Convert Polars DataFrame to use their API - mass_data = pl.DataFrame(mass_data) fractions = { k: (mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean() for k, v in mass_columns.items() } new_columns = { - f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] - for k, v in mass_columns.items() + "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, + **{ + f"{k} ({fractions[k]:.3f})": mass_data[v] / mass_data[v][0] + for k, v in mass_columns.items() + }, } - mass_fold_change = pl.DataFrame( - { - "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, - **new_columns, - } + # Convert Polars DataFrame to use their API + mass_fold_change_df = pl.DataFrame(new_columns) + + # Altair requires long form data (also no periods in column names) + melted_df = mass_fold_change_df.melt( + id_vars="Time (min)", + variable_name="Submass", + value_name="Mass (normalized by t = 0 min)", ) - # Use Altair to create interactive visualizations - plotted_data = ( - alt.Chart(mass_fold_change) - .transform_fold( - list(new_columns.keys()), - as_=["mass_type", "Mass (normalized by t = 0 min)"], - ) + + chart = ( + alt.Chart(melted_df) .mark_line() .encode( - x="Time (min)", - y=alt.Y("Mass (normalized by t = 0 min)"), - color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), + x=alt.X("Time (min):Q", title="Time (min)"), + y=alt.Y("Mass (normalized by t = 0 min):Q"), + color=alt.Color("Submass:N", scale=alt.Scale(range=COLORS)), ) .properties( title="Biomass components (average fraction of total dry mass in parentheses)" ) ) - plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) + chart.save(os.path.join(outdir, "mass_fraction_summary.html")) To add a new analysis script: diff --git a/ecoli/analysis/single/mass_fraction_summary.py b/ecoli/analysis/single/mass_fraction_summary.py index ea281f9f8..5d26b1c10 100644 --- a/ecoli/analysis/single/mass_fraction_summary.py +++ b/ecoli/analysis/single/mass_fraction_summary.py @@ -42,41 +42,43 @@ def plot( "rRNA": "listeners__mass__rRna_mass", "mRNA": "listeners__mass__mRna_mass", "DNA": "listeners__mass__dna_mass", - "Small Mol.s": "listeners__mass__smallMolecule_mass", + "Small Mol": "listeners__mass__smallMolecule_mass", "Dry": "listeners__mass__dry_mass", } - mass_data = read_stacked_columns( - history_sql, list(mass_columns.values()), conn=conn + mass_data = pl.DataFrame( + read_stacked_columns(history_sql, list(mass_columns.values()), conn=conn) ) - mass_data = pl.DataFrame(mass_data) + fractions = { k: (mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean() for k, v in mass_columns.items() } new_columns = { - f"{k} ({cast(float, fractions[k]):.3f})": mass_data[v] / mass_data[v][0] - for k, v in mass_columns.items() + "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, + **{ + f"{k} ({fractions[k]:.3f})": mass_data[v] / mass_data[v][0] + for k, v in mass_columns.items() + }, } - mass_fold_change = pl.DataFrame( - { - "Time (min)": (mass_data["time"] - mass_data["time"].min()) / 60, - **new_columns, - } + mass_fold_change_df = pl.DataFrame(new_columns) + + # Altair requires long form data (also no periods in column names) + melted_df = mass_fold_change_df.melt( + id_vars="Time (min)", + variable_name="Submass", + value_name="Mass (normalized by t = 0 min)", ) - plotted_data = ( - alt.Chart(mass_fold_change) - .transform_fold( - list(new_columns.keys()), - as_=["mass_type", "Mass (normalized by t = 0 min)"], - ) + + chart = ( + alt.Chart(melted_df) .mark_line() .encode( - x="Time (min)", - y=alt.Y("Mass (normalized by t = 0 min)"), - color=alt.Color("mass_type", scale=alt.Scale(range=COLORS)), + x=alt.X("Time (min):Q", title="Time (min)"), + y=alt.Y("Mass (normalized by t = 0 min):Q"), + color=alt.Color("Submass:N", scale=alt.Scale(range=COLORS)), ) .properties( title="Biomass components (average fraction of total dry mass in parentheses)" ) ) - plotted_data.save(os.path.join(outdir, "mass_fraction_summary.html")) + chart.save(os.path.join(outdir, "mass_fraction_summary.html")) From 1d7ecc555ad9321b0df8dc4fe9f066b6fc127f23 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 06:48:23 -0800 Subject: [PATCH 26/54] WCM image should use non-editable install --- runscripts/container/wholecell/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index c090bfb3c..b8a4da6a2 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -51,7 +51,7 @@ LABEL application="Whole Cell Model of Escherichia coli" \ COPY . /vEcoli WORKDIR /vEcoli -RUN CC=gcc uv sync --frozen +RUN CC=gcc uv sync --frozen --no-editable # Since this build runs as root, set permissions so running the container as # another user will work: Parca writes into /vEcoli/cache/. From 8586f58db629fe6c848d6353fcadc13e1d7fcf0a Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 06:57:02 -0800 Subject: [PATCH 27/54] Make container build scripts sh compliant Also auto-delete temp files if error --- runscripts/container/build-runtime.sh | 41 ++++++++++++++++++++------- runscripts/container/build-wcm.sh | 15 +++++----- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/runscripts/container/build-runtime.sh b/runscripts/container/build-runtime.sh index 8af57faaf..366617265 100755 --- a/runscripts/container/build-runtime.sh +++ b/runscripts/container/build-runtime.sh @@ -6,6 +6,7 @@ # ASSUMES: The current working dir is the vEcoli/ project root. set -eu +trap 'rm -f runscripts/container/runtime/pyproject.toml runscripts/container/runtime/uv.lock' EXIT RUNTIME_IMAGE="${USER}-wcm-runtime" RUN_LOCAL=0 @@ -18,16 +19,34 @@ for the wcm-runtime image to build; defaults to ${USER}-wcm-runtime\n\ -l: Build image locally.\n" print_usage() { - printf "$usage_str" + printf "%s" "$usage_str" } while getopts 'r:al' flag; do case "${flag}" in - r) RUNTIME_IMAGE="${OPTARG}" ;; - a) (( $RUN_LOCAL )) && print_usage && exit 1 || BUILD_APPTAINER=1 ;; - l) (( $BUILD_APPTAINER )) && print_usage && exit 1 || RUN_LOCAL=1 ;; - *) print_usage - exit 1 ;; + r) + RUNTIME_IMAGE="${OPTARG}" + ;; + a) + if [ "$RUN_LOCAL" -ne 0 ]; then + print_usage + exit 1 + else + BUILD_APPTAINER=1 + fi + ;; + l) + if [ "$BUILD_APPTAINER" -ne 0 ]; then + print_usage + exit 1 + else + RUN_LOCAL=1 + fi + ;; + *) + print_usage + exit 1 + ;; esac done @@ -36,12 +55,12 @@ done cp pyproject.toml runscripts/container/runtime/ cp uv.lock runscripts/container/runtime/ -if (( $RUN_LOCAL )); then +if [ "$RUN_LOCAL" -ne 0 ]; then echo "=== Locally building WCM runtime Docker Image: ${RUNTIME_IMAGE} ===" docker build -f runscripts/container/runtime/Dockerfile -t "${RUNTIME_IMAGE}" . -elif (( $BUILD_APPTAINER )); then +elif [ "$BUILD_APPTAINER" -ne 0 ]; then echo "=== Building WCM runtime Apptainer Image: ${RUNTIME_IMAGE} ===" - apptainer build --force ${RUNTIME_IMAGE} runscripts/container/runtime/Singularity + apptainer build --force "${RUNTIME_IMAGE}" runscripts/container/runtime/Singularity else echo "=== Cloud-building WCM runtime Docker Image: ${RUNTIME_IMAGE} ===" # For this script to work on a Compute Engine VM, you must @@ -52,8 +71,8 @@ else REGION=$(gcloud config get compute/region) # This needs a config file to identify the project files to upload and the # Dockerfile to run. - gcloud builds submit --timeout=3h --region=$REGION --tag \ - '${LOCATION}-docker.pkg.dev/${PROJECT_ID}/vecoli/'${RUNTIME_IMAGE} \ + gcloud builds submit --timeout=3h --region="$REGION" --tag \ + "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/vecoli/${RUNTIME_IMAGE}" \ runscripts/container/runtime/ fi diff --git a/runscripts/container/build-wcm.sh b/runscripts/container/build-wcm.sh index 41ff101b6..27283c71a 100755 --- a/runscripts/container/build-wcm.sh +++ b/runscripts/container/build-wcm.sh @@ -6,23 +6,24 @@ # ASSUMES: The current working dir is the vEcoli/ project root. set -eu +trap 'rm -f source-info/git_diff.txt' EXIT RUNTIME_IMAGE="${USER}-wcm-runtime" WCM_IMAGE="${USER}-wcm-code" RUN_LOCAL=0 usage_str="Usage: build-wcm.sh [-r RUNTIME_IMAGE] \ -[-w WCM_IMAGE] [-a] [-b BIND_PATH] [-l]\n\ +[-w WCM_IMAGE] [-l]\n\ -r: Docker tag of wcm-runtime image to build from; defaults to \ -"$USER-wcm-runtime" (must exist in Artifact Registry).\n\ - -w: Docker tag of wcm-code image to build; defaults to "$USER-wcm-code".\n\ +\"$USER-wcm-runtime\" (must exist in Artifact Registry).\n\ + -w: Docker tag of wcm-code image to build; defaults to \"$USER-wcm-code\".\n\ -l: Build image locally.\n" print_usage() { - printf "$usage_str" + printf "%s" "$usage_str" } -while getopts 'r:w:abl:' flag; do +while getopts 'r:w:l' flag; do case "${flag}" in r) RUNTIME_IMAGE="${OPTARG}" ;; w) WCM_IMAGE="${OPTARG}" ;; @@ -38,7 +39,7 @@ TIMESTAMP=$(date '+%Y%m%d.%H%M%S') mkdir -p source-info git diff HEAD > source-info/git_diff.txt -if (( $RUN_LOCAL )); then +if [ "$RUN_LOCAL" -ne 0 ]; then echo "=== Locally building WCM code Docker Image ${WCM_IMAGE} on ${RUNTIME_IMAGE} ===" echo "=== git hash ${GIT_HASH}, git branch ${GIT_BRANCH} ===" docker build -f runscripts/container/wholecell/Dockerfile -t "${WCM_IMAGE}" \ @@ -57,7 +58,7 @@ else REGION=$(gcloud config get compute/region) # This needs a config file to identify the project files to upload and the # Dockerfile to run. - gcloud builds submit --timeout=15m --region=$REGION \ + gcloud builds submit --timeout=15m --region="$REGION" \ --config runscripts/container/cloud_build.json \ --substitutions="_WCM_RUNTIME=${RUNTIME_IMAGE},\ _WCM_CODE=${WCM_IMAGE},_GIT_HASH=${GIT_HASH},_GIT_BRANCH=${GIT_BRANCH},\ From a7bb125f068bbb45c7fd35a5b960c74a321b64eb Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 06:58:04 -0800 Subject: [PATCH 28/54] Remove requirements.txt now that we use uv --- .gitignore | 1 + requirements.txt | 255 ----------------------------------------------- 2 files changed, 1 insertion(+), 255 deletions(-) delete mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore index c1453707c..33ca16075 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,4 @@ cache/ ################## .nextflow* nextflow_temp +trace-* diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 47bb7c8cf..000000000 --- a/requirements.txt +++ /dev/null @@ -1,255 +0,0 @@ -# Note: Core required packages are numpy, scipy, biopython, cvxpy, cython, dill, -# duckdb, ete3, gcsfs, pyarrow, hvplot, ipdb, ipython, jupyter, line-profiler, altair, -# numba, orjson, ortools, pandas, polars, pymunk, pytest, pytest-cov, scikit-image, -# scikit-learn, seaborn, swiglpk, sympy, tqdm, unum, jax, vivarium-core, pysal, mypy, -# opencv-python-headless, statsmodels, ruff, ecos, nbclassic, stochastic-arrow, -# matplotlib, pyqt5, and iteround. Other packages are dependencies of the above. - -absl-py==2.1.0 -access==1.1.9 -affine==2.4.0 -aiohappyeyeballs==2.4.4 -aiohttp==3.11.8 -aiosignal==1.3.1 -altair==5.5.0 -anyio==4.6.2.post1 -appnope==0.1.4 -argon2-cffi==23.1.0 -argon2-cffi-bindings==21.2.0 -arrow==1.3.0 -asttokens==3.0.0 -async-lru==2.0.4 -attrs==24.2.0 -babel==2.16.0 -beautifulsoup4==4.12.3 -biopython==1.84 -bleach==6.2.0 -bokeh==3.6.1 -cachetools==5.5.0 -certifi==2024.8.30 -cffi==1.17.1 -charset-normalizer==3.4.0 -clarabel==0.9.0 -click==8.1.7 -click-plugins==1.1.1 -cligj==0.7.2 -colorcet==3.1.0 -comm==0.2.2 -contourpy==1.3.1 -coverage==7.6.8 -cvxpy==1.6.0 -cycler==0.12.1 -Cython==3.0.11 -debugpy==1.8.9 -decorator==5.1.1 -defusedxml==0.7.1 -deprecation==2.1.0 -dill==0.3.9 -dnspython==2.7.0 -duckdb==1.1.3 -ecos==2.0.14 -esda==2.6.0 -ete3==3.1.3 -executing==2.1.0 -fastjsonschema==2.21.0 -fiona==1.10.1 -flexcache==0.3 -flexparser==0.4 -fonttools==4.55.0 -fqdn==1.5.1 -frozenlist==1.5.0 -fsspec==2024.10.0 -gcsfs==2024.10.0 -geopandas==1.0.1 -giddy==2.3.5 -google-api-core==2.23.0 -google-auth==2.36.0 -google-auth-oauthlib==1.2.1 -google-cloud-core==2.4.1 -google-cloud-storage==2.18.2 -google-crc32c==1.6.0 -google-resumable-media==2.7.2 -googleapis-common-protos==1.66.0 -h11==0.14.0 -holoviews==1.20.0 -httpcore==1.0.7 -httpx==0.28.0 -hvplot==0.11.1 -idna==3.10 -imageio==2.36.1 -immutabledict==4.2.1 -inequality==1.0.1 -iniconfig==2.0.0 -ipdb==0.13.13 -ipykernel==6.29.5 -ipython==8.30.0 -ipython-genutils==0.2.0 -ipywidgets==8.1.5 -isoduration==20.11.0 -iteround==1.0.4 -jax==0.4.35 -jaxlib==0.4.35 -jedi==0.19.2 -Jinja2==3.1.4 -joblib==1.4.2 -json5==0.10.0 -jsonpointer==3.0.0 -jsonschema==4.23.0 -jsonschema-specifications==2024.10.1 -jupyter==1.1.1 -jupyter-console==6.6.3 -jupyter-events==0.10.0 -jupyter-lsp==2.2.5 -jupyter_client==8.6.3 -jupyter_core==5.7.2 -jupyter_server==2.14.2 -jupyter_server_terminals==0.5.3 -jupyterlab==4.2.6 -jupyterlab_pygments==0.3.0 -jupyterlab_server==2.27.3 -jupyterlab_widgets==3.0.13 -kiwisolver==1.4.7 -lazy_loader==0.4 -libpysal==4.12.1 -line_profiler==4.1.3 -linkify-it-py==2.0.3 -llvmlite==0.43.0 -mapclassify==2.8.1 -Markdown==3.7 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -matplotlib==3.9.3 -matplotlib-inline==0.1.7 -mdit-py-plugins==0.4.2 -mdurl==0.1.2 -mgwr==2.2.1 -mistune==3.0.2 -ml_dtypes==0.5.0 -momepy==0.9.1 -mpmath==1.3.0 -multidict==6.1.0 -mypy==1.13.0 -mypy-extensions==1.0.0 -narwhals==1.15.1 -nbclassic==1.1.0 -nbclient==0.10.1 -nbconvert==7.16.4 -nbformat==5.10.4 -nest-asyncio==1.6.0 -networkx==3.4.2 -notebook==7.2.2 -notebook_shim==0.2.4 -numba==0.60.0 -numpy==1.26.4 -oauthlib==3.2.2 -opencv-python-headless==4.10.0.84 -opt_einsum==3.4.0 -orjson==3.10.12 -ortools==9.9.3963 -osqp==0.6.7.post3 -overrides==7.7.0 -packaging==24.2 -pandas==2.2.3 -pandocfilters==1.5.1 -panel==1.5.4 -param==2.1.1 -parso==0.8.4 -patsy==1.0.1 -pexpect==4.9.0 -pillow==11.0.0 -Pint==0.24.4 -platformdirs==4.3.6 -pluggy==1.5.0 -pointpats==2.5.1 -polars==1.16.0 -prometheus_client==0.21.0 -prompt_toolkit==3.0.48 -propcache==0.2.0 -proto-plus==1.25.0 -protobuf==5.29.0 -psutil==6.1.0 -ptyprocess==0.7.0 -PuLP==2.9.0 -pure_eval==0.2.3 -pyarrow==18.1.0 -pyasn1==0.6.1 -pyasn1_modules==0.4.1 -pycparser==2.22 -Pygments==2.18.0 -pymongo==4.10.1 -pymunk==6.9.0 -pyogrio==0.10.0 -pyparsing==3.2.0 -pyproj==3.7.0 -PyQt5==5.15.11 -PyQt5-Qt5==5.15.15 -PyQt5_sip==12.15.0 -pysal==24.7 -pytest==8.3.4 -pytest-cov==6.0.0 -python-dateutil==2.9.0.post0 -python-json-logger==2.0.7 -pytz==2024.2 -pyviz_comms==3.0.3 -PyYAML==6.0.2 -pyzmq==26.2.0 -qdldl==0.1.7.post4 -quantecon==0.7.2 -rasterio==1.4.2 -rasterstats==0.20.0 -referencing==0.35.1 -requests==2.32.3 -requests-oauthlib==2.0.0 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 -rpds-py==0.21.0 -rsa==4.9 -Rtree==1.3.0 -ruff==0.8.1 -scikit-image==0.24.0 -scikit-learn==1.5.2 -scipy==1.14.1 -scs==3.2.7 -seaborn==0.13.2 -segregation==2.5.1 -Send2Trash==1.8.3 -shapely==2.0.6 -simplejson==3.19.3 -six==1.16.0 -sniffio==1.3.1 -soupsieve==2.6 -spaghetti==1.7.6 -spglm==1.1.0 -spint==1.0.7 -splot==1.1.7 -spopt==0.6.1 -spreg==1.8 -spvcm==0.3.0 -stack-data==0.6.3 -statsmodels==0.14.4 -stochastic-arrow==1.0.0 -swiglpk==5.0.12 -sympy==1.13.3 -terminado==0.18.1 -threadpoolctl==3.5.0 -tifffile==2024.9.20 -tinycss2==1.4.0 -tobler==0.12.0 -tornado==6.4.2 -tqdm==4.67.1 -traitlets==5.14.3 -types-python-dateutil==2.9.0.20241003 -typing_extensions==4.12.2 -tzdata==2024.2 -uc-micro-py==1.0.3 -Unum==4.2.1 -uri-template==1.3.0 -urllib3==2.2.3 -vivarium-core==1.6.4 -wcwidth==0.2.13 -webcolors==24.11.1 -webencodings==0.5.1 -websocket-client==1.8.0 -widgetsnbextension==4.0.13 -xyzservices==2024.9.0 -yarl==1.18.0 From d098ed024608a5ad2e64323687617cb786c3a736 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:08:15 -0800 Subject: [PATCH 29/54] Use Python 3.12 Debian slim base image --- runscripts/container/runtime/Dockerfile | 2 +- runscripts/container/runtime/Singularity | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index ee0c6ecd8..4bbfd9178 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -11,7 +11,7 @@ # Add option `--build-arg from=ABC` to build from a different base image "ABC" # but DO NOT USE an alpine base since the simulation math comes out different! # See https://pythonspeed.com/articles/alpine-docker-python/ for more reasons. -ARG from=ghcr.io/astral-sh/uv:bookworm-slim@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b3575f48a4ae4c1e4efadd +ARG from=ghcr.io/astral-sh/uv:0.5.7-python3.12-bookworm-slim@sha256:444d948934bdb22e3204317842be6e1ad454cfa85103287a2ed18e471ede1f5b FROM ${from} RUN echo "alias ls='ls --color=auto'" >> ~/.bashrc \ diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index 61f396537..c86182f67 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -1,5 +1,5 @@ Bootstrap: docker -From: ghcr.io/astral-sh/uv@sha256:9e963fcd233dcc215cb0b6899a95a5f8c5cf9f51f3b3575f48a4ae4c1e4efadd +From: ghcr.io/astral-sh/uv@sha256:444d948934bdb22e3204317842be6e1ad454cfa85103287a2ed18e471ede1f5b %environment export OPENBLAS_NUM_THREADS=1 From ada3416060471d76ed7c2ec0809c9077a0b31843 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:10:02 -0800 Subject: [PATCH 30/54] Fix publish dir substitution --- runscripts/nextflow/config.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/nextflow/config.template b/runscripts/nextflow/config.template index 992fe4dd6..465529989 100644 --- a/runscripts/nextflow/config.template +++ b/runscripts/nextflow/config.template @@ -79,7 +79,7 @@ profiles { memory = params.parca_cpus * 2.GB } container = params.container_image - containerOptions = "-B ${PUBLISH_DIR}:${PUBLISH_DIR} -B ${launchDir}:/vEcoli" + containerOptions = "-B ${publishDir}:${publishDir} -B ${launchDir}:/vEcoli" queue = 'mcovert,owners,dev,normal' executor = 'slurm' // Single core sims are slightly slower but can have shorter From 6274a3cff021eba7bd25075a6b41aa6a1ef12989 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:31:21 -0800 Subject: [PATCH 31/54] Strip container image of unnecessary files --- .gcloudignore | 8 ++++++++ .gitignore | 7 +++++++ 2 files changed, 15 insertions(+) create mode 100644 .gcloudignore diff --git a/.gcloudignore b/.gcloudignore new file mode 100644 index 000000000..4aa378771 --- /dev/null +++ b/.gcloudignore @@ -0,0 +1,8 @@ +#!include:.gitignore +notebooks +data +reconstruction/sim_data +reconstruction/ecoli/scripts +.git +.github +doc diff --git a/.gitignore b/.gitignore index 33ca16075..94268a359 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,8 @@ __pycache__ ._* .python-version .pytest_cache +.mypy_cache/ +.ruff_cache/ # VS Code files # ################# @@ -55,3 +57,8 @@ cache/ .nextflow* nextflow_temp trace-* + +# Virtual environment # +####################### +.venv/ + From 289ab2e28f9a6a8f0813fbb545eb3ad23ea1970c Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:33:45 -0800 Subject: [PATCH 32/54] Add procps to container images --- runscripts/container/runtime/Dockerfile | 3 ++- runscripts/container/runtime/Singularity | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/runscripts/container/runtime/Dockerfile b/runscripts/container/runtime/Dockerfile index 4bbfd9178..63d12a18c 100644 --- a/runscripts/container/runtime/Dockerfile +++ b/runscripts/container/runtime/Dockerfile @@ -19,7 +19,8 @@ RUN echo "alias ls='ls --color=auto'" >> ~/.bashrc \ && cp ~/.bashrc / # Update and install in the same layer so it won't install from old updates. -RUN apt-get update && apt-get install -y git gcc +# procps necessary for `ps` command used by Nextflow to track processes. +RUN apt-get update && apt-get install -y git gcc procps # Install the project into `/vEcoli` WORKDIR /vEcoli diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index c86182f67..712004e5d 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -22,7 +22,7 @@ From: ghcr.io/astral-sh/uv@sha256:444d948934bdb22e3204317842be6e1ad454cfa8510328 echo "alias ll='ls -l'" >> ~/.bashrc cp ~/.bashrc / - apt-get update && apt-get install -y git gcc + apt-get update && apt-get install -y git gcc procps USE_CYTHON=1 CC=gcc uv sync --frozen --no-install-project --no-dev --project vEcoli From 62e4b58b9aaac28523112ee159acab2f0569363e Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:36:15 -0800 Subject: [PATCH 33/54] Fix gcloud build substitution --- runscripts/container/build-runtime.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/container/build-runtime.sh b/runscripts/container/build-runtime.sh index 366617265..4a1625f9e 100755 --- a/runscripts/container/build-runtime.sh +++ b/runscripts/container/build-runtime.sh @@ -72,7 +72,7 @@ else # This needs a config file to identify the project files to upload and the # Dockerfile to run. gcloud builds submit --timeout=3h --region="$REGION" --tag \ - "${LOCATION}-docker.pkg.dev/${PROJECT_ID}/vecoli/${RUNTIME_IMAGE}" \ + '${LOCATION}-docker.pkg.dev/${PROJECT_ID}/vecoli/'${RUNTIME_IMAGE} \ runscripts/container/runtime/ fi From f527fc5157fef7737f272dfa6de037db16e72dc8 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:40:50 -0800 Subject: [PATCH 34/54] Try Kaniko cache --- runscripts/container/build-runtime.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runscripts/container/build-runtime.sh b/runscripts/container/build-runtime.sh index 4a1625f9e..49f482bf3 100755 --- a/runscripts/container/build-runtime.sh +++ b/runscripts/container/build-runtime.sh @@ -69,6 +69,8 @@ else # creating VM # - Run gcloud init in VM REGION=$(gcloud config get compute/region) + # Enable Kaniko cache to speed up build times + gcloud config set builds/use_kaniko True # This needs a config file to identify the project files to upload and the # Dockerfile to run. gcloud builds submit --timeout=3h --region="$REGION" --tag \ From e79bc23f63041aa0cadfa9bd3efa3a7e7596fa6f Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 07:45:53 -0800 Subject: [PATCH 35/54] Remove data dir from package installation --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2540681f3..f516cc694 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,7 +72,6 @@ docs = [ [tool.setuptools] packages = [ - "data", "ecoli", "migration", "reconstruction", From 6e809a2a53a30bbbe89114ebe2ca83633a80a74c Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 08:04:06 -0800 Subject: [PATCH 36/54] Move murein strand length distribution to flat files --- ecoli/library/cell_wall/lattice.py | 4 +- ecoli/library/parameters.py | 3 +- .../murein_strand_length_distribution.csv | 63 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv diff --git a/ecoli/library/cell_wall/lattice.py b/ecoli/library/cell_wall/lattice.py index e2f383f68..7079f704d 100644 --- a/ecoli/library/cell_wall/lattice.py +++ b/ecoli/library/cell_wall/lattice.py @@ -104,7 +104,9 @@ def get_length_distributions(lattice): def plot_strand_length_distribution(lengths): # Plot experimental data first - df = pd.read_csv("data/cell_wall/murein_strand_length_distribution.csv") + df = pd.read_csv( + "reconsruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv" + ) fig, ax = plt.subplots() X = np.arange(1, 32, 1) diff --git a/ecoli/library/parameters.py b/ecoli/library/parameters.py index 484c603e0..f13629abe 100644 --- a/ecoli/library/parameters.py +++ b/ecoli/library/parameters.py @@ -264,7 +264,8 @@ def derive_parameters(self, derivation_rules): "cell_wall": { "strand_length_data": Parameter( os.path.join( - ROOT_PATH, "data/cell_wall/murein_strand_length_distribution.csv" + ROOT_PATH, + "reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv", ), "Obermann, W., & Höltje, J. (1994).", ), diff --git a/reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv b/reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv new file mode 100644 index 000000000..77d9a533a --- /dev/null +++ b/reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv @@ -0,0 +1,63 @@ +"Strain","Length","Percent" +"P678-54","1",8.22355289421158 +"P678-54","2",9.18163672654691 +"P678-54","3",8.18363273453094 +"P678-54","4",7.34530938123753 +"P678-54","5",6.62674650698603 +"P678-54","7",5.26946107784431 +"P678-54","8",4.59081836327345 +"P678-54","9",4.11177644710579 +"P678-54","10",3.35329341317366 +"P678-54","11",3.1936127744511 +"P678-54","12",2.71457085828344 +"P678-54","13",2.55489021956088 +"P678-54","14",2.35528942115769 +"P678-54","15",2.19560878243513 +"P678-54","16",1.91616766467066 +"P678-54","17",1.67664670658683 +"P678-54","18",1.51696606786427 +"P678-54","19",1.43712574850299 +"P678-54","20",1.27744510978044 +"P678-54","21",1.07784431137725 +"P678-54","22",1.11776447105789 +"P678-54","23",0.998003992015967 +"P678-54","24",0.758483033932137 +"P678-54","25",0.758483033932137 +"P678-54","26",0.798403193612774 +"P678-54","27",0.678642714570859 +"P678-54","28",0.558882235528941 +"P678-54","29",0.518962075848304 +"P678-54","30",0.479041916167663 +"P678-54",">30",12.814371257485 +"P678-54","6",5.53155566040573 +"MC4100","1",8.46686696132648 +"MC4100","2",6.2959596450205 +"MC4100","3",6.54056892009723 +"MC4100","4",6.87690667332774 +"MC4100","5",6.50999276071264 +"MC4100","6",6.23480732625132 +"MC4100","7",5.40925102286736 +"MC4100","8",5.07291326963686 +"MC4100","9",4.64484703825258 +"MC4100","10",4.27793312563748 +"MC4100","11",3.42180066286893 +"MC4100","12",3.05488675025384 +"MC4100","13",2.8408536345617 +"MC4100","14",2.50451588133119 +"MC4100","15",2.41278740317742 +"MC4100","16",1.92356885302396 +"MC4100","17",1.64838341856264 +"MC4100","18",1.55665494040887 +"MC4100","19",1.31204566533214 +"MC4100","20",1.28146950594755 +"MC4100","21",1.22031718717837 +"MC4100","22",0.975707912101637 +"MC4100","23",0.975707912101637 +"MC4100","24",0.822827115178683 +"MC4100","25",0.792250955794088 +"MC4100","26",0.700522477640316 +"MC4100","27",0.700522477640316 +"MC4100","28",0.547641680717362 +"MC4100","29",0.547641680717362 +"MC4100","30",0.455913202563583 +"MC4100",">30",14.8878604320906 From 3621487f8f811e6ebe5aa9a7212f6b79edb2d4ce Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 08:20:17 -0800 Subject: [PATCH 37/54] Try editable install to fix cython modules --- runscripts/container/wholecell/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runscripts/container/wholecell/Dockerfile b/runscripts/container/wholecell/Dockerfile index b8a4da6a2..c090bfb3c 100644 --- a/runscripts/container/wholecell/Dockerfile +++ b/runscripts/container/wholecell/Dockerfile @@ -51,7 +51,7 @@ LABEL application="Whole Cell Model of Escherichia coli" \ COPY . /vEcoli WORKDIR /vEcoli -RUN CC=gcc uv sync --frozen --no-editable +RUN CC=gcc uv sync --frozen # Since this build runs as root, set permissions so running the container as # another user will work: Parca writes into /vEcoli/cache/. From c476fa1bacb3ff78aaaf1e052448b06bd6504ab6 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 08:31:14 -0800 Subject: [PATCH 38/54] Move tetracycline gene FC to flat --- data/marA_binding/get_TU_ID.py | 4 ++-- ecoli/analysis/antibiotics_colony/__init__.py | 2 +- .../ecoli/flat/tetracycline/gene_fc.csv | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename data/marA_binding/model_degenes.csv => reconstruction/ecoli/flat/tetracycline/gene_fc.csv (100%) diff --git a/data/marA_binding/get_TU_ID.py b/data/marA_binding/get_TU_ID.py index 0098a523d..2b4afbd6c 100644 --- a/data/marA_binding/get_TU_ID.py +++ b/data/marA_binding/get_TU_ID.py @@ -5,7 +5,7 @@ This file contains functions to compile important metadata for genes that are designed to be regulated by marA when the `mar_regulon` option is enabled. -For each gene, the output `model_degenes.csv` file contains the fold change, +For each gene, the output `gene_fc.csv` file contains the fold change, monomer ID, gene ID, TU index, bulk ID, and IDs of complexes containing that monomer as well as the number of monomers incorporated into each complex. @@ -150,7 +150,7 @@ def get_IDs(monomer_id): ].to_numpy()[0] marR_monomers_used.append(-2) - de_genes.to_csv("data/marA_binding/model_degenes.csv", index=False) + de_genes.to_csv("reconstruction/ecoli/flat/tetracycline/gene_fc.csv", index=False) if __name__ == "__main__": diff --git a/ecoli/analysis/antibiotics_colony/__init__.py b/ecoli/analysis/antibiotics_colony/__init__.py index 1377b1259..4b32b95c9 100644 --- a/ecoli/analysis/antibiotics_colony/__init__.py +++ b/ecoli/analysis/antibiotics_colony/__init__.py @@ -7,7 +7,7 @@ plt.rcParams["svg.fonttype"] = "none" plt.rcParams["font.family"] = "Arial" -DE_GENES = pd.read_csv(os.path.join(ROOT_PATH, "data/marA_binding/model_degenes.csv")) +DE_GENES = pd.read_csv(os.path.join(ROOT_PATH, "reconstruction/ecoli/flat/tetracycline/gene_fc.csv")) SPLIT_TIME = 11550 MAX_TIME = 26000 COUNTS_PER_FL_TO_NANOMOLAR = 1 / (1e-15) / N_A * (1e9) diff --git a/data/marA_binding/model_degenes.csv b/reconstruction/ecoli/flat/tetracycline/gene_fc.csv similarity index 100% rename from data/marA_binding/model_degenes.csv rename to reconstruction/ecoli/flat/tetracycline/gene_fc.csv From ff6db2ea00869c8989c4caf1613a8899ba5690e0 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 09:25:59 -0800 Subject: [PATCH 39/54] Fix publishDir substitution --- runscripts/nextflow/config.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runscripts/nextflow/config.template b/runscripts/nextflow/config.template index 465529989..2b232abba 100644 --- a/runscripts/nextflow/config.template +++ b/runscripts/nextflow/config.template @@ -79,7 +79,7 @@ profiles { memory = params.parca_cpus * 2.GB } container = params.container_image - containerOptions = "-B ${publishDir}:${publishDir} -B ${launchDir}:/vEcoli" + containerOptions = "-B ${params.publishDir}:${params.publishDir} -B ${launchDir}:${launchDir}" queue = 'mcovert,owners,dev,normal' executor = 'slurm' // Single core sims are slightly slower but can have shorter @@ -109,7 +109,7 @@ profiles { maxRetries = 3 } apptainer.enabled = true - params.projectRoot = "/vEcoli" + params.projectRoot = "${launchDir}" // Avoid getting queue status too frequently (can cause job status mixups) executor.queueStatInterval = '2 min' // Check for terminated jobs and submit new ones fairly frequently From 9426bc81a4d1004e00bf68dbd5988ddc1fd175cb Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 09:26:14 -0800 Subject: [PATCH 40/54] Activate Python virtual environment in Singularity containers --- runscripts/container/runtime/Singularity | 1 + runscripts/workflow.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index 712004e5d..9beebbb24 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -3,6 +3,7 @@ From: ghcr.io/astral-sh/uv@sha256:444d948934bdb22e3204317842be6e1ad454cfa8510328 %environment export OPENBLAS_NUM_THREADS=1 + export PATH="/vEcoli/.venv/bin:$PATH" %labels application "Whole Cell Model Runtime Environment" diff --git a/runscripts/workflow.py b/runscripts/workflow.py index d8eaa23a4..ffdf2974d 100644 --- a/runscripts/workflow.py +++ b/runscripts/workflow.py @@ -437,10 +437,10 @@ def main(): repo_dir, "-e", runtime_image_name, - "uv", - "sync", - "--frozen", - "--no-cache" + "pip", + "install", + "-e", + ".", ] ) if sherlock_config.get("jenkins", False): From 19ea32b564839405acf2950c5b97fffe0c6d1200 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 10:39:28 -0800 Subject: [PATCH 41/54] Clarify C compilers --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9ddb70997..21f5a06f7 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ model parameters (e.g. transcription probabilities). These parameters are used t Your system must have git, curl (or wget), and a C compiler. -On Ubuntu/Debian: +On Ubuntu/Debian, apt can be used to install all three prerequisites: sudo -s eval 'apt update && apt install git curl clang' -On MacOS: +On MacOS, curl is preinstalled and git and clang come with the Xcode Command Line Tools: xcode-select --install From c268a2357d8a9afe5331f5ca426a9c6c44b75959 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 10:39:47 -0800 Subject: [PATCH 42/54] Force uv to install in container venv --- runscripts/container/runtime/Singularity | 2 ++ runscripts/workflow.py | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/runscripts/container/runtime/Singularity b/runscripts/container/runtime/Singularity index 9beebbb24..05a93f6c3 100644 --- a/runscripts/container/runtime/Singularity +++ b/runscripts/container/runtime/Singularity @@ -4,6 +4,8 @@ From: ghcr.io/astral-sh/uv@sha256:444d948934bdb22e3204317842be6e1ad454cfa8510328 %environment export OPENBLAS_NUM_THREADS=1 export PATH="/vEcoli/.venv/bin:$PATH" + export UV_PROJECT_ENVIRONMENT="/vEcoli/.venv" + export CC=gcc %labels application "Whole Cell Model Runtime Environment" diff --git a/runscripts/workflow.py b/runscripts/workflow.py index ffdf2974d..30bb9e39d 100644 --- a/runscripts/workflow.py +++ b/runscripts/workflow.py @@ -432,15 +432,15 @@ def main(): "apptainer", "exec", "-B", - f"{repo_dir}:/vEcoli", + f"{repo_dir}:{repo_dir}", "--cwd", repo_dir, "-e", runtime_image_name, - "pip", - "install", - "-e", - ".", + "uv", + "sync", + "--frozen", + "--no-cache", ] ) if sherlock_config.get("jenkins", False): From b766b204071a0d4fe23dbf480cce202daddf3c14 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 20:58:39 -0800 Subject: [PATCH 43/54] Unique indices should be unique between molecule types as well --- ecoli/analysis/antibiotics_colony/__init__.py | 4 +++- ecoli/library/initial_conditions.py | 11 ++++++++--- ecoli/library/json_state.py | 3 ++- ecoli/library/schema.py | 5 ++++- ecoli/processes/chromosome_structure.py | 2 -- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ecoli/analysis/antibiotics_colony/__init__.py b/ecoli/analysis/antibiotics_colony/__init__.py index 4b32b95c9..330d29190 100644 --- a/ecoli/analysis/antibiotics_colony/__init__.py +++ b/ecoli/analysis/antibiotics_colony/__init__.py @@ -7,7 +7,9 @@ plt.rcParams["svg.fonttype"] = "none" plt.rcParams["font.family"] = "Arial" -DE_GENES = pd.read_csv(os.path.join(ROOT_PATH, "reconstruction/ecoli/flat/tetracycline/gene_fc.csv")) +DE_GENES = pd.read_csv( + os.path.join(ROOT_PATH, "reconstruction/ecoli/flat/tetracycline/gene_fc.csv") +) SPLIT_TIME = 11550 MAX_TIME = 26000 COUNTS_PER_FL_TO_NANOMOLAR = 1 / (1e-15) / N_A * (1e9) diff --git a/ecoli/library/initial_conditions.py b/ecoli/library/initial_conditions.py index 181c8f2f8..f7da9f45d 100644 --- a/ecoli/library/initial_conditions.py +++ b/ecoli/library/initial_conditions.py @@ -230,9 +230,14 @@ def create_new_unique_molecules(name, n_mols, sim_data, random_state, **attrs): unique_mols = np.zeros(n_mols, dtype=dtypes) for attr_name, attr_value in attrs.items(): unique_mols[attr_name] = attr_value - unique_mols["unique_index"] = np.arange(n_mols) + # Each unique molecule has unique prefix for indices to prevent conflicts + unique_mol_names = list( + sim_data.internal_state.unique_molecule.unique_molecule_definitions.keys() + ) + unique_prefix = unique_mol_names.index(name) << 59 + unique_mols["unique_index"] = np.arange(unique_prefix, unique_prefix + n_mols) unique_mols["_entryState"] = 1 - unique_mols = MetadataArray(unique_mols, n_mols) + unique_mols = MetadataArray(unique_mols, unique_prefix + n_mols) return unique_mols @@ -1235,7 +1240,7 @@ def initialize_transcription( unique_molecules["RNA"] = np.concatenate((partial_rnas, full_rnas)) unique_molecules["RNA"] = MetadataArray( unique_molecules["RNA"], - unique_molecules["RNA"]["unique_index"].size, + unique_molecules["RNA"]["unique_index"].max() + 1, ) # Reset counts of bulk mRNAs to zero diff --git a/ecoli/library/json_state.py b/ecoli/library/json_state.py index b99dcacfc..7500e13f9 100644 --- a/ecoli/library/json_state.py +++ b/ecoli/library/json_state.py @@ -32,7 +32,8 @@ def numpy_molecules(states): unique_arr = np.array(unique_tuples, dtype=dtypes) unique_arr.flags.writeable = False states["unique"][key] = MetadataArray( - unique_arr, unique_arr["unique_index"].max() + unique_arr, + unique_arr["unique_index"].max() + 1, ) if "environment" in states: if "exchange_data" in states["environment"]: diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index 997019943..fb927332a 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -163,8 +163,11 @@ def create_unique_indices( List of unique indexes for new unique molecules. """ next_unique_index = unique_molecules.metadata + unique_indices = np.arange( + next_unique_index, int(next_unique_index + n_indexes), dtype=int + ) unique_molecules.metadata += n_indexes - return np.arange(next_unique_index, next_unique_index + n_indexes) + return unique_indices def not_a_process(value): diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index 5df0a32ca..8e84d97d2 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -401,7 +401,6 @@ def get_removed_molecules_mask(domain_indexes, coordinates): boundary_coordinates, segment_domain_indexes, linking_numbers, - chromosomal_segment_indexes, ) = attrs( states["chromosomal_segments"], [ @@ -409,7 +408,6 @@ def get_removed_molecules_mask(domain_indexes, coordinates): "boundary_coordinates", "domain_index", "linking_number", - "unique_index", ], ) From 2b95c004dbe42400352665e78f70356c7a87e1cc Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 21:31:09 -0800 Subject: [PATCH 44/54] Add temporary flag to GHA jobs while waiting for stochastic-arrow release --- .github/workflows/docs_deploy.yml | 2 +- .github/workflows/docs_test.yml | 2 +- .github/workflows/pr_tests.yml | 2 +- .github/workflows/pytest.yml | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index d0565e0a1..ffa402958 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -14,7 +14,7 @@ jobs: sudo apt-get install pandoc curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen --extra docs + run: USE_CYTHON=1 uv sync --frozen --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index 7348ad61e..2818280df 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -16,7 +16,7 @@ jobs: sudo apt-get install pandoc curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen --extra docs + run: USE_CYTHON=1 uv sync --frozen --extra docs - name: Build documentation run: | cd doc diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index fd78e421c..1b9c1639d 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -42,7 +42,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen - name: Install nextflow edge run: | curl -s https://get.nextflow.io | bash diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 20bbe4d55..dae15662b 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,7 +16,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen - name: Test with pytest run: | uv run --env-file .env pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 @@ -40,7 +40,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen - name: Mypy run: | uv run --env-file .env mypy @@ -51,7 +51,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen - name: Ruff run: | uv run --env-file .env ruff check doc ecoli migration wholecell runscripts validation reconstruction From 5226b8bee24423342d41cec61da411f16d2f14e1 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 21:32:51 -0800 Subject: [PATCH 45/54] Add dev dependencies for QA tests --- .github/workflows/pytest.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index dae15662b..1fe372ecf 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,7 +16,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: USE_CYTHON=1 uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Test with pytest run: | uv run --env-file .env pytest --cov-report xml:cov.xml --cov=ecoli --cov=reconstruction --cov=wholecell --cov=runscripts --durations=0 @@ -40,7 +40,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: USE_CYTHON=1 uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Mypy run: | uv run --env-file .env mypy @@ -51,7 +51,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: USE_CYTHON=1 uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Ruff run: | uv run --env-file .env ruff check doc ecoli migration wholecell runscripts validation reconstruction From 2308bdf26f860ebc39b662c00915803ce75e2d1c Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 21:33:41 -0800 Subject: [PATCH 46/54] Remove redundant data --- .../murein_strand_length_distribution.csv | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 data/cell_wall/murein_strand_length_distribution.csv diff --git a/data/cell_wall/murein_strand_length_distribution.csv b/data/cell_wall/murein_strand_length_distribution.csv deleted file mode 100644 index 77d9a533a..000000000 --- a/data/cell_wall/murein_strand_length_distribution.csv +++ /dev/null @@ -1,63 +0,0 @@ -"Strain","Length","Percent" -"P678-54","1",8.22355289421158 -"P678-54","2",9.18163672654691 -"P678-54","3",8.18363273453094 -"P678-54","4",7.34530938123753 -"P678-54","5",6.62674650698603 -"P678-54","7",5.26946107784431 -"P678-54","8",4.59081836327345 -"P678-54","9",4.11177644710579 -"P678-54","10",3.35329341317366 -"P678-54","11",3.1936127744511 -"P678-54","12",2.71457085828344 -"P678-54","13",2.55489021956088 -"P678-54","14",2.35528942115769 -"P678-54","15",2.19560878243513 -"P678-54","16",1.91616766467066 -"P678-54","17",1.67664670658683 -"P678-54","18",1.51696606786427 -"P678-54","19",1.43712574850299 -"P678-54","20",1.27744510978044 -"P678-54","21",1.07784431137725 -"P678-54","22",1.11776447105789 -"P678-54","23",0.998003992015967 -"P678-54","24",0.758483033932137 -"P678-54","25",0.758483033932137 -"P678-54","26",0.798403193612774 -"P678-54","27",0.678642714570859 -"P678-54","28",0.558882235528941 -"P678-54","29",0.518962075848304 -"P678-54","30",0.479041916167663 -"P678-54",">30",12.814371257485 -"P678-54","6",5.53155566040573 -"MC4100","1",8.46686696132648 -"MC4100","2",6.2959596450205 -"MC4100","3",6.54056892009723 -"MC4100","4",6.87690667332774 -"MC4100","5",6.50999276071264 -"MC4100","6",6.23480732625132 -"MC4100","7",5.40925102286736 -"MC4100","8",5.07291326963686 -"MC4100","9",4.64484703825258 -"MC4100","10",4.27793312563748 -"MC4100","11",3.42180066286893 -"MC4100","12",3.05488675025384 -"MC4100","13",2.8408536345617 -"MC4100","14",2.50451588133119 -"MC4100","15",2.41278740317742 -"MC4100","16",1.92356885302396 -"MC4100","17",1.64838341856264 -"MC4100","18",1.55665494040887 -"MC4100","19",1.31204566533214 -"MC4100","20",1.28146950594755 -"MC4100","21",1.22031718717837 -"MC4100","22",0.975707912101637 -"MC4100","23",0.975707912101637 -"MC4100","24",0.822827115178683 -"MC4100","25",0.792250955794088 -"MC4100","26",0.700522477640316 -"MC4100","27",0.700522477640316 -"MC4100","28",0.547641680717362 -"MC4100","29",0.547641680717362 -"MC4100","30",0.455913202563583 -"MC4100",">30",14.8878604320906 From e28883a7cba750d65c12a6fbd1527465ae70dee1 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 21:37:28 -0800 Subject: [PATCH 47/54] Fix CI tests --- .github/workflows/docs_deploy.yml | 2 +- .github/workflows/docs_test.yml | 2 +- .github/workflows/pr_tests.yml | 2 +- ecoli/analysis/single/mass_fraction_summary.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index ffa402958..85c853c0c 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -18,7 +18,7 @@ jobs: - name: Build documentation run: | cd doc - make html + uv run make html - name: Deploy documentation to GitHub pages run: | cd doc/_build/html diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index 2818280df..aef9765a9 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -20,4 +20,4 @@ jobs: - name: Build documentation run: | cd doc - make html + uv run make html diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index 1b9c1639d..856954072 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -16,7 +16,7 @@ jobs: - name: Install uv run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install model - run: uv sync --frozen + run: USE_CYTHON=1 uv sync --frozen - name: Test ParCa reproducibility run: | uv run --env-file .env runscripts/parca.py --config ecoli/composites/ecoli_configs/run_parca.json \ diff --git a/ecoli/analysis/single/mass_fraction_summary.py b/ecoli/analysis/single/mass_fraction_summary.py index 5d26b1c10..159d201cf 100644 --- a/ecoli/analysis/single/mass_fraction_summary.py +++ b/ecoli/analysis/single/mass_fraction_summary.py @@ -1,5 +1,5 @@ import os -from typing import Any, cast +from typing import Any from duckdb import DuckDBPyConnection import polars as pl @@ -50,7 +50,7 @@ def plot( ) fractions = { - k: (mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean() + k: float((mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean()) for k, v in mass_columns.items() } new_columns = { From 053d03cb19c2db22bbb3fff72f089fde29979f4c Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 21:39:43 -0800 Subject: [PATCH 48/54] Use cast to fix type check --- ecoli/analysis/single/mass_fraction_summary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecoli/analysis/single/mass_fraction_summary.py b/ecoli/analysis/single/mass_fraction_summary.py index 159d201cf..e4fb410e1 100644 --- a/ecoli/analysis/single/mass_fraction_summary.py +++ b/ecoli/analysis/single/mass_fraction_summary.py @@ -1,5 +1,5 @@ import os -from typing import Any +from typing import Any, cast from duckdb import DuckDBPyConnection import polars as pl @@ -50,7 +50,7 @@ def plot( ) fractions = { - k: float((mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean()) + k: cast(float, (mass_data[v] / mass_data["listeners__mass__dry_mass"]).mean()) for k, v in mass_columns.items() } new_columns = { From 7c2ff81c2fd3cebbc849d8168f4287e3e96ce379 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 22:01:33 -0800 Subject: [PATCH 49/54] Set writable flag after converting to MetadataArray --- ecoli/library/json_state.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecoli/library/json_state.py b/ecoli/library/json_state.py index 7500e13f9..ad6a4d4ed 100644 --- a/ecoli/library/json_state.py +++ b/ecoli/library/json_state.py @@ -30,11 +30,11 @@ def numpy_molecules(states): dtypes = ast.literal_eval(dtypes) unique_tuples = [tuple(mol) for mol in states["unique"][key]] unique_arr = np.array(unique_tuples, dtype=dtypes) - unique_arr.flags.writeable = False states["unique"][key] = MetadataArray( unique_arr, unique_arr["unique_index"].max() + 1, ) + states["unique"][key].flags.writeable = False if "environment" in states: if "exchange_data" in states["environment"]: states["environment"]["exchange_data"]["constrained"] = { From e759f3d28ad28889584eaa51d71898c546ef1976 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sat, 7 Dec 2024 22:38:28 -0800 Subject: [PATCH 50/54] Handle unique molecules with zero count --- ecoli/library/initial_conditions.py | 6 +++++- ecoli/library/json_state.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/ecoli/library/initial_conditions.py b/ecoli/library/initial_conditions.py index f7da9f45d..7530c3a09 100644 --- a/ecoli/library/initial_conditions.py +++ b/ecoli/library/initial_conditions.py @@ -1238,9 +1238,13 @@ def initialize_transcription( massDiff_mRNA=rna_masses[TU_index_full_mRNAs], ) unique_molecules["RNA"] = np.concatenate((partial_rnas, full_rnas)) + if len(unique_molecules["RNA"]) > 0: + next_unique_index = unique_molecules["RNA"]["unique_index"].max() + 1 + else: + next_unique_index = 0 unique_molecules["RNA"] = MetadataArray( unique_molecules["RNA"], - unique_molecules["RNA"]["unique_index"].max() + 1, + next_unique_index, ) # Reset counts of bulk mRNAs to zero diff --git a/ecoli/library/json_state.py b/ecoli/library/json_state.py index ad6a4d4ed..6fb3c255b 100644 --- a/ecoli/library/json_state.py +++ b/ecoli/library/json_state.py @@ -30,9 +30,13 @@ def numpy_molecules(states): dtypes = ast.literal_eval(dtypes) unique_tuples = [tuple(mol) for mol in states["unique"][key]] unique_arr = np.array(unique_tuples, dtype=dtypes) + if len(unique_arr) == 0: + next_unique_index = 0 + else: + next_unique_index = unique_arr["unique_index"].max() + 1 states["unique"][key] = MetadataArray( unique_arr, - unique_arr["unique_index"].max() + 1, + next_unique_index, ) states["unique"][key].flags.writeable = False if "environment" in states: From daf8283a55bd406e5a5e85316953e86e07e13b66 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sun, 8 Dec 2024 01:44:58 -0800 Subject: [PATCH 51/54] Use official uv GitHub action --- .github/workflows/docs_deploy.yml | 11 +++++++---- .github/workflows/docs_test.yml | 11 +++++++---- .github/workflows/pr_tests.yml | 10 ++++++++-- .github/workflows/pytest.yml | 15 ++++++++++++--- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/.github/workflows/docs_deploy.yml b/.github/workflows/docs_deploy.yml index 85c853c0c..48c61c6fc 100644 --- a/.github/workflows/docs_deploy.yml +++ b/.github/workflows/docs_deploy.yml @@ -9,10 +9,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Install Pandoc and uv - run: | - sudo apt-get install pandoc - curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" + - name: Install Pandoc + run: sudo apt-get install pandoc - name: Install model run: USE_CYTHON=1 uv sync --frozen --extra docs - name: Build documentation diff --git a/.github/workflows/docs_test.yml b/.github/workflows/docs_test.yml index aef9765a9..3718b95ab 100644 --- a/.github/workflows/docs_test.yml +++ b/.github/workflows/docs_test.yml @@ -11,10 +11,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Install Pandoc and uv - run: | - sudo apt-get install pandoc - curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install uv + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" + - name: Install Pandoc + run: sudo apt-get install pandoc - name: Install model run: USE_CYTHON=1 uv sync --frozen --extra docs - name: Build documentation diff --git a/.github/workflows/pr_tests.yml b/.github/workflows/pr_tests.yml index 856954072..190440445 100644 --- a/.github/workflows/pr_tests.yml +++ b/.github/workflows/pr_tests.yml @@ -14,7 +14,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install uv - run: curl -LsSf https://astral.sh/uv/install.sh | sh + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" - name: Install model run: USE_CYTHON=1 uv sync --frozen - name: Test ParCa reproducibility @@ -40,7 +43,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install uv - run: curl -LsSf https://astral.sh/uv/install.sh | sh + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" - name: Install model run: USE_CYTHON=1 uv sync --frozen - name: Install nextflow edge diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 1fe372ecf..db88d769c 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -14,7 +14,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install uv - run: curl -LsSf https://astral.sh/uv/install.sh | sh + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" - name: Install model run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Test with pytest @@ -38,7 +41,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install uv - run: curl -LsSf https://astral.sh/uv/install.sh | sh + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" - name: Install model run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Mypy @@ -49,7 +55,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install uv - run: curl -LsSf https://astral.sh/uv/install.sh | sh + uses: astral-sh/setup-uv@v4 + with: + enable-cache: true + version: "0.5.7" - name: Install model run: USE_CYTHON=1 uv sync --frozen --extra dev - name: Ruff From 01d36206d0aa19b1df8b32564ff83478134e5c5f Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sun, 8 Dec 2024 16:09:08 -0800 Subject: [PATCH 52/54] Fix pytests --- ecoli/library/cell_wall/lattice.py | 2 +- ecoli/library/schema.py | 6 +++- ecoli/processes/transcript_initiation.py | 37 +++++++++++++++--------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/ecoli/library/cell_wall/lattice.py b/ecoli/library/cell_wall/lattice.py index 7079f704d..89b3f4e2c 100644 --- a/ecoli/library/cell_wall/lattice.py +++ b/ecoli/library/cell_wall/lattice.py @@ -105,7 +105,7 @@ def get_length_distributions(lattice): def plot_strand_length_distribution(lengths): # Plot experimental data first df = pd.read_csv( - "reconsruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv" + "reconstruction/ecoli/flat/cell_wall/murein_strand_length_distribution.csv" ) fig, ax = plt.subplots() diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index fb927332a..433ebb51a 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -463,12 +463,16 @@ def updater(self, current: MetadataArray, update: Dict[str, Any]) -> MetadataArr ) elif update_type == "delete": if isinstance(update_val, list): - if isinstance(update_val[0], list) or isinstance( + if len(update_val) == 0: + continue + elif isinstance(update_val[0], list) or isinstance( update_val[0], np.ndarray ): self.delete_updates.extend(update_val) elif isinstance(update_val[0], int): self.delete_updates.append(update_val) + elif isinstance(update_val[0], np.integer): + self.delete_updates.append(update_val) else: raise ValueError( "Delete updates must be lists/arrays of integers " diff --git a/ecoli/processes/transcript_initiation.py b/ecoli/processes/transcript_initiation.py index 3bd99c0c1..ec6b85754 100644 --- a/ecoli/processes/transcript_initiation.py +++ b/ecoli/processes/transcript_initiation.py @@ -29,6 +29,7 @@ counts, attrs, bulk_name_to_idx, + MetadataArray, ) from wholecell.utils import units @@ -990,22 +991,30 @@ def make_elongation_rates(random, base, time_step, variable_elongation=False): "listeners": {"mass": {"cell_mass": 1000, "dry_mass": 350}}, } unique_state = { - "full_chromosome": np.array( - [ - (1, 0, 0, 0, False, 0) + (0,) * 9, - ], - dtype=chromosome_dtypes + submass_dtypes, + "full_chromosome": MetadataArray( + np.array( + [ + (1, 0, 0, 0, False, 0) + (0,) * 9, + ], + dtype=chromosome_dtypes + submass_dtypes, + ), + 1, ), - "promoter": np.array( - [ - (i, 1, i, [False] * 4, subdata["replication_coordinate"], 0, i) - + (0,) * 9 - for i, subdata in enumerate(rna_data) - ], - dtype=promoter_dtypes + submass_dtypes, + "promoter": MetadataArray( + np.array( + [ + (i, 1, i, [False] * 4, subdata["replication_coordinate"], 0, i) + + (0,) * 9 + for i, subdata in enumerate(rna_data) + ], + dtype=promoter_dtypes + submass_dtypes, + ), + len(rna_data), + ), + "RNA": MetadataArray(np.array([], dtype=rna_dtypes + submass_dtypes), 0), + "active_RNAP": MetadataArray( + np.array([], dtype=active_rnap_dtypes + submass_dtypes), 0 ), - "RNA": np.array([], dtype=rna_dtypes + submass_dtypes), - "active_RNAP": np.array([], dtype=active_rnap_dtypes + submass_dtypes), } initial_state["unique"] = unique_state From 158711a240f1490daf6f19652b38ee64f4f9c494 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Sun, 8 Dec 2024 17:18:42 -0800 Subject: [PATCH 53/54] Regenerate unique indices after merging partial and full mRNA arrays --- ecoli/library/initial_conditions.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ecoli/library/initial_conditions.py b/ecoli/library/initial_conditions.py index 7530c3a09..4c94c61dc 100644 --- a/ecoli/library/initial_conditions.py +++ b/ecoli/library/initial_conditions.py @@ -1238,13 +1238,18 @@ def initialize_transcription( massDiff_mRNA=rna_masses[TU_index_full_mRNAs], ) unique_molecules["RNA"] = np.concatenate((partial_rnas, full_rnas)) - if len(unique_molecules["RNA"]) > 0: - next_unique_index = unique_molecules["RNA"]["unique_index"].max() + 1 - else: - next_unique_index = 0 + # Have to recreate unique indices or else there will be conflicts between + # full and partial RNAs + unique_mol_names = list( + sim_data.internal_state.unique_molecule.unique_molecule_definitions.keys() + ) + unique_prefix = unique_mol_names.index("RNA") << 59 + unique_molecules["RNA"]["unique_index"] = np.arange( + unique_prefix, unique_prefix + len(unique_molecules["RNA"]) + ) unique_molecules["RNA"] = MetadataArray( unique_molecules["RNA"], - next_unique_index, + unique_prefix + len(unique_molecules["RNA"]), ) # Reset counts of bulk mRNAs to zero From 563235cc90be1616417f16ebbe7f6f5656060f37 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Wed, 11 Dec 2024 17:21:33 -0800 Subject: [PATCH 54/54] Update to latest stochastic-arrow --- pyproject.toml | 3 +-- uv.lock | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f516cc694..e67ad7b10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,8 +52,7 @@ dependencies = [ "pyqt5", "iteround", "wheel", - # Can change to regular stochastic-arrow once PR merged - "stochastic-arrow @ git+https://github.com/CovertLab/arrow@numpy2", + "stochastic-arrow", "autograd", ] diff --git a/uv.lock b/uv.lock index 68ed23541..a501589ef 100644 --- a/uv.lock +++ b/uv.lock @@ -3216,11 +3216,18 @@ wheels = [ [[package]] name = "stochastic-arrow" version = "1.1.0" -source = { git = "https://github.com/CovertLab/arrow?rev=numpy2#3589de18424953375a05a9e4416d8077168d9393" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "six" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/74/9f/ff40066fb2795eb8ede816d35e274f3e14e8e0f6eb5cfe8a36e7371dd735/stochastic_arrow-1.1.0.tar.gz", hash = "sha256:4b8b21ac2873673a97442439b4681963917230b54110b88282a7cff4d4a9dd8c", size = 22018 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/22/897f62ad220c5e7c67d5cd17798231a90965d714f5e5651adef309fb0ebf/stochastic_arrow-1.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc02ae5216008ca88c5b15b0c1ae9912ea5c450927de804f67c9295874057791", size = 99359 }, + { url = "https://files.pythonhosted.org/packages/4f/87/be7b45e55562e32432ac67ebc324f53b6a06f6f31fb284ffea991dc147ae/stochastic_arrow-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:097da7d5cfc54209ab74b735c80c5ae5b9c296949e2564feb9647619d142365f", size = 93773 }, + { url = "https://files.pythonhosted.org/packages/83/3c/eec2529c87dd022e3cf537dfabd32ea0084f8029eb2e560930c78ee7b805/stochastic_arrow-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2886367f77e796589d2c0d91c4efe50af1006dc8e6f2a885aa9befe609e9e381", size = 513892 }, + { url = "https://files.pythonhosted.org/packages/2a/f5/0534ec782efec47cf575b944a378065ed7890e8ea670f807d311694a53aa/stochastic_arrow-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:f07ae6ffeee5c2a330778a1a8bdbf41b7a73235b3bc02a0fe6f265ebcaf1d63c", size = 90487 }, +] [[package]] name = "swiglpk" @@ -3509,7 +3516,7 @@ requires-dist = [ { name = "sphinx", marker = "extra == 'docs'" }, { name = "sphinx-rtd-theme", marker = "extra == 'docs'" }, { name = "statsmodels" }, - { name = "stochastic-arrow", git = "https://github.com/CovertLab/arrow?rev=numpy2" }, + { name = "stochastic-arrow" }, { name = "swiglpk" }, { name = "sympy" }, { name = "tqdm" },