From b13ba46120b7ab656aa1527f249869f1cd95920b Mon Sep 17 00:00:00 2001 From: thalassemia Date: Mon, 16 Dec 2024 12:43:34 -0800 Subject: [PATCH 1/8] Fix workflow resumption with suffix_time --- doc/workflows.rst | 3 ++- runscripts/workflow.py | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/doc/workflows.rst b/doc/workflows.rst index 02f9fb68b..023250b78 100644 --- a/doc/workflows.rst +++ b/doc/workflows.rst @@ -679,7 +679,8 @@ is a list workflow behaviors enabled in our model to handle unexpected errors. - If you realize that a code issue is the cause of job failure(s), stop the workflow run if it is not already (e.g. ``control + c``, ``scancel``, etc.), make the necessary code fixes, and rerun :py:mod:`runscripts.workflow` - with the same configuration JSON and the ``--resume`` command-line argument. + with the same configuration JSON and the ``--resume`` command-line argument, + supplying the experiment ID (with time suffix if using ``suffix_time`` option). Nextflow will intelligently resume workflow execution from the last successful job in each chain of job dependencies (e.g. generation 7 of a cell lineage depends on generation 6, :py:mod:`runscripts.create_variants` depends on diff --git a/runscripts/workflow.py b/runscripts/workflow.py index 91fb4140f..53235266a 100644 --- a/runscripts/workflow.py +++ b/runscripts/workflow.py @@ -311,9 +311,11 @@ def main(): ) parser.add_argument( "--resume", - action="store_true", - default=False, - help="Resume last run workflow.", + type=str, + default=None, + help="Resume workflow with given experiment ID. The experiment ID must " + "match the supplied configuration file and if suffix_time was used, must " + "contain the full time suffix (suffix_time will not be applied again).", ) args = parser.parse_args() with open(config_file, "r") as f: @@ -335,11 +337,14 @@ def main(): experiment_id = config["experiment_id"] if experiment_id is None: raise RuntimeError("No experiment ID was provided.") - if config["suffix_time"]: + if args.resume is not None: + experiment_id = args.resume + config["experiment_id"] = args.resume + elif config["suffix_time"]: current_time = datetime.now().strftime("%Y%m%d-%H%M%S") experiment_id = experiment_id + "_" + current_time config["experiment_id"] = experiment_id - config["suffix_time"] = False + config["suffix_time"] = False # Special characters are messy so do not allow them if experiment_id != parse.quote_plus(experiment_id): raise TypeError( @@ -370,7 +375,7 @@ def main(): final_config_uri = os.path.join(out_uri, "workflow_config.json") with open(temp_config_path, "w") as f: json.dump(config, f) - if not args.resume: + if args.resume is None: copy_to_filesystem(temp_config_path, final_config_path, filesystem) nf_config = os.path.join(os.path.dirname(__file__), "nextflow", "config.template") @@ -471,7 +476,7 @@ def main(): workflow_path = os.path.join(out_uri, "main.nf") config_path = os.path.join(out_uri, "nextflow.config") - if not args.resume: + if args.resume is None: copy_to_filesystem(local_workflow, os.path.join(outdir, "main.nf"), filesystem) copy_to_filesystem( local_config, os.path.join(outdir, "nextflow.config"), filesystem @@ -497,7 +502,7 @@ def main(): report_path, "-work-dir", workdir, - "-resume" if args.resume else "", + "-resume" if args.resume is not None else "", ], check=True, ) @@ -511,7 +516,7 @@ def main(): #SBATCH --mem=4GB #SBATCH --partition=mcovert nextflow -C {config_path} run {workflow_path} -profile {nf_profile} \ - -with-report {report_path} -work-dir {workdir} {"-resume" if args.resume else ""} + -with-report {report_path} -work-dir {workdir} {"-resume" if args.resume is not None else ""} """) copy_to_filesystem( batch_script, os.path.join(outdir, "nextflow_job.sh"), filesystem From 2e26c55a33b6743e90dfa91522ea9033b8ca92bc Mon Sep 17 00:00:00 2001 From: thalassemia Date: Mon, 16 Dec 2024 14:25:59 -0800 Subject: [PATCH 2/8] Copy publish mode allows task caching when resuming workflow --- runscripts/nextflow/analysis.nf | 10 +++++----- runscripts/nextflow/template.nf | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/runscripts/nextflow/analysis.nf b/runscripts/nextflow/analysis.nf index 6c5735d7b..93479424a 100644 --- a/runscripts/nextflow/analysis.nf +++ b/runscripts/nextflow/analysis.nf @@ -1,5 +1,5 @@ process analysisSingle { - publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}/agent_id=${agent_id}", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}/agent_id=${agent_id}", mode: "copy" tag "variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}/agent_id=${agent_id}" @@ -49,7 +49,7 @@ process analysisSingle { } process analysisMultiDaughter { - publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}", mode: "copy" tag "variant=${variant}/lineage_seed=${lineage_seed}/generation=${generation}" @@ -97,7 +97,7 @@ process analysisMultiDaughter { } process analysisMultiGeneration { - publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}/lineage_seed=${lineage_seed}", mode: "copy" tag "variant=${variant}/lineage_seed=${lineage_seed}" @@ -143,7 +143,7 @@ process analysisMultiGeneration { } process analysisMultiSeed { - publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/analyses/variant=${variant}", mode: "copy" tag "variant=${variant}" @@ -187,7 +187,7 @@ process analysisMultiSeed { } process analysisMultiVariant { - publishDir "${params.publishDir}/${params.experimentId}/analyses", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/analyses", mode: "copy" label "short" diff --git a/runscripts/nextflow/template.nf b/runscripts/nextflow/template.nf index 7118ba0d0..4eb48db4f 100644 --- a/runscripts/nextflow/template.nf +++ b/runscripts/nextflow/template.nf @@ -26,7 +26,7 @@ process runParca { } process analysisParca { - publishDir "${params.publishDir}/${params.experimentId}/parca/analysis", mode: "move" + publishDir "${params.publishDir}/${params.experimentId}/parca/analysis", mode: "copy" label "short" From 0629fb38406a313ce937254d8d23f4aca081a2ca Mon Sep 17 00:00:00 2001 From: thalassemia Date: Mon, 16 Dec 2024 14:26:44 -0800 Subject: [PATCH 3/8] Handle replisome removal in superhelical density --- ecoli/processes/chromosome_structure.py | 564 ++++++++++++++++++++---- migration/migration_utils.py | 9 +- 2 files changed, 489 insertions(+), 84 deletions(-) diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index 4b41e52dc..217371f88 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -99,6 +99,7 @@ class ChromosomeStructure(Step): "mature_rna_end_positions": [], "mature_rna_nt_counts": [], "unprocessed_rna_index_mapping": {}, + "removed_replisome_index": -2, "time_step": 1.0, } @@ -119,6 +120,7 @@ def __init__(self, parameters=None): "relaxed_DNA_base_pairs_per_turn" ] self.terC_index = self.parameters["terC_index"] + self.removed_replisome_index = self.parameters["removed_replisome_index"] self.n_mature_rnas = self.parameters["n_mature_rnas"] self.mature_rna_ids = self.parameters["mature_rna_ids"] @@ -164,6 +166,8 @@ def ports_schema(self): np.zeros(self.n_TUs, np.int64), self.rna_ids, ), + "n_empty_fork_collisions": 0, + "empty_fork_collision_coordinates": [], } ) }, @@ -334,14 +338,14 @@ def get_removed_molecules_mask(domain_indexes, coordinates): # Domain has no active replisomes else: - # Domain has child domains (has finished replicating) - if ( - child_domains[all_chromosome_domain_indexes == domain_index, 0] - != self.no_child_place_holder - ): + children_of_domain = child_domains[ + all_chromosome_domain_indexes == domain_index + ] + # Child domains are full chromosomes (domain has finished replicating) + if np.all(np.isin(children_of_domain, mother_domain_indexes)): # Remove all molecules on this domain domain_mask = domain_indexes == domain_index - # Domain has not started replication + # Domain has not started replication or replication was interrupted else: continue @@ -363,12 +367,6 @@ def get_removed_molecules_mask(domain_indexes, coordinates): DnaA_box_domain_indexes, DnaA_box_coordinates ) - # Get attribute arrays of remaining RNAPs - remaining_RNAPs_mask = np.logical_not(removed_RNAPs_mask) - remaining_RNAP_domain_indexes = RNAP_domain_indexes[remaining_RNAPs_mask] - remaining_RNAP_coordinates = RNAP_coordinates[remaining_RNAPs_mask] - remaining_RNAP_unique_indexes = RNAP_unique_indexes[remaining_RNAPs_mask] - # Build masks for head-on and co-directional collisions between RNAPs # and replication forks RNAP_headon_collision_mask = np.logical_and( @@ -434,6 +432,9 @@ def get_removed_molecules_mask(domain_indexes, coordinates): all_new_segment_domain_indexes = np.array([], dtype=np.int32) all_new_linking_numbers = np.array([], dtype=np.float64) + # Iteratively tally RNAPs that were removed due to collisions with + # replication forks with or without replisomes on each domain + removed_RNAP_masks_all_domains = np.full_like(removed_RNAPs_mask, False) for domain_index in np.unique(all_chromosome_domain_indexes): # Skip domains that have completed replication if np.all(domain_index < mother_domain_indexes): @@ -442,11 +443,14 @@ def get_removed_molecules_mask(domain_indexes, coordinates): domain_spans_oriC = domain_index in origin_domain_indexes domain_spans_terC = domain_index in mother_domain_indexes - # Get masks for segments and RNAPs in this domain - segments_domain_mask = segment_domain_indexes == domain_index - RNAP_domain_mask = remaining_RNAP_domain_indexes == domain_index + # Parse attributes of remaining RNAPs in this domain + RNAPs_domain_mask = RNAP_domain_indexes == domain_index + RNAP_coordinates_this_domain = RNAP_coordinates[RNAPs_domain_mask] + RNAP_unique_indexes_this_domain = RNAP_unique_indexes[RNAPs_domain_mask] + domain_remaining_RNAPs_mask = ~removed_RNAPs_mask[RNAPs_domain_mask] # Parse attributes of segments in this domain + segments_domain_mask = segment_domain_indexes == domain_index boundary_molecule_indexes_this_domain = boundary_molecule_indexes[ segments_domain_mask, : ] @@ -455,29 +459,59 @@ def get_removed_molecules_mask(domain_indexes, coordinates): ] linking_numbers_this_domain = linking_numbers[segments_domain_mask] - # Parse attributes of remaining RNAPs in this domain - new_molecule_coordinates_this_domain = remaining_RNAP_coordinates[ - RNAP_domain_mask - ] - new_molecule_indexes_this_domain = remaining_RNAP_unique_indexes[ - RNAP_domain_mask - ] - + new_molecule_coordinates_this_domain = np.array([], dtype=np.int64) + new_molecule_indexes_this_domain = np.array([], dtype=np.int64) # Append coordinates and indexes of replisomes on this domain, # if any if not domain_spans_oriC: replisome_domain_mask = replisome_domain_indexes == domain_index + replisome_coordinates_this_domain = replisome_coordinates[ + replisome_domain_mask + ] + replisome_molecule_indexes_this_domain = replisome_unique_indexes[ + replisome_domain_mask + ] + + # If one or more replisomes was removed in the last time step, + # use the last known location and molecule index. + if len(replisome_molecule_indexes_this_domain) != 2: + assert len(replisome_molecule_indexes_this_domain) < 2 + ( + replisome_coordinates_this_domain, + replisome_molecule_indexes_this_domain, + ) = get_last_known_replisome_data( + boundary_coordinates_this_domain, + boundary_molecule_indexes_this_domain, + replisome_coordinates_this_domain, + replisome_molecule_indexes_this_domain, + ) + # Assume that RNAPs that run into a replication fork + # are removed even if there is no replisome + RNAPs_on_forks = np.isin( + RNAP_coordinates_this_domain, + replisome_coordinates_this_domain, + ) + domain_remaining_RNAPs_mask = np.logical_and( + domain_remaining_RNAPs_mask, ~RNAPs_on_forks + ) + full_removed_RNAPs_mask = np.full_like( + removed_RNAPs_mask, False + ) + full_removed_RNAPs_mask[RNAPs_domain_mask] = RNAPs_on_forks + removed_RNAP_masks_all_domains = np.logical_or( + removed_RNAP_masks_all_domains, full_removed_RNAPs_mask + ) new_molecule_coordinates_this_domain = np.concatenate( ( new_molecule_coordinates_this_domain, - replisome_coordinates[replisome_domain_mask], + replisome_coordinates_this_domain, ) ) new_molecule_indexes_this_domain = np.concatenate( ( new_molecule_indexes_this_domain, - replisome_unique_indexes[replisome_domain_mask], + replisome_molecule_indexes_this_domain, ) ) @@ -490,20 +524,81 @@ def get_removed_molecules_mask(domain_indexes, coordinates): replisome_parent_domain_mask = ( replisome_domain_indexes == parent_domain_index ) + replisome_coordinates_parent_domain = replisome_coordinates[ + replisome_parent_domain_mask + ] + replisome_molecule_indexes_parent_domain = replisome_unique_indexes[ + replisome_parent_domain_mask + ] + + # If one or more replisomes was removed in the last time step, + # use the last known location and molecule index. + if len(replisome_molecule_indexes_parent_domain) != 2: + assert len(replisome_molecule_indexes_parent_domain) < 2 + # Parse attributes of segments in parent domain + parent_segments_domain_mask = ( + segment_domain_indexes == parent_domain_index + ) + boundary_molecule_indexes_parent_domain = ( + boundary_molecule_indexes[parent_segments_domain_mask, :] + ) + boundary_coordinates_parent_domain = boundary_coordinates[ + parent_segments_domain_mask, : + ] + ( + replisome_coordinates_parent_domain, + replisome_molecule_indexes_parent_domain, + ) = get_last_known_replisome_data( + boundary_coordinates_parent_domain, + boundary_molecule_indexes_parent_domain, + replisome_coordinates_parent_domain, + replisome_molecule_indexes_parent_domain, + ) + # Assume that RNAPs that run into a replication fork + # are removed even if there is no replisome + RNAPs_on_forks = np.isin( + RNAP_coordinates_this_domain, + replisome_coordinates_parent_domain, + ) + domain_remaining_RNAPs_mask = np.logical_and( + domain_remaining_RNAPs_mask, ~RNAPs_on_forks + ) + full_removed_RNAPs_mask = np.full_like( + removed_RNAPs_mask, False + ) + full_removed_RNAPs_mask[RNAPs_domain_mask] = RNAPs_on_forks + removed_RNAP_masks_all_domains = np.logical_or( + removed_RNAP_masks_all_domains, full_removed_RNAPs_mask + ) new_molecule_coordinates_this_domain = np.concatenate( ( new_molecule_coordinates_this_domain, - replisome_coordinates[replisome_parent_domain_mask], + replisome_coordinates_parent_domain, ) ) new_molecule_indexes_this_domain = np.concatenate( ( new_molecule_indexes_this_domain, - replisome_unique_indexes[replisome_parent_domain_mask], + replisome_molecule_indexes_parent_domain, ) ) + # Add remaining RNAPs in this domain after accounting for removals + # due to collisions with replication forks + new_molecule_coordinates_this_domain = np.concatenate( + ( + new_molecule_coordinates_this_domain, + RNAP_coordinates_this_domain[domain_remaining_RNAPs_mask], + ) + ) + new_molecule_indexes_this_domain = np.concatenate( + ( + new_molecule_indexes_this_domain, + RNAP_unique_indexes_this_domain[domain_remaining_RNAPs_mask], + ) + ) + # If there are no molecules left on this domain, continue if len(new_molecule_indexes_this_domain) == 0: continue @@ -564,6 +659,25 @@ def get_removed_molecules_mask(domain_indexes, coordinates): } ) + # Figure out if any additional RNAPs were removed due to collisions with + # replication forks where there were no replisomes + empty_fork_RNAP_collision_mask = np.logical_and( + removed_RNAP_masks_all_domains, + np.logical_not( + np.logical_or( + RNAP_headon_collision_mask, RNAP_codirectional_collision_mask + ) + ), + ) + update["listeners"]["rnap_data"].update( + { + "n_empty_fork_collisions": empty_fork_RNAP_collision_mask.sum(), + "empty_fork_collision_coordinates": RNAP_coordinates[ + empty_fork_RNAP_collision_mask + ], + } + ) + # Get mask for RNAs that are transcribed from removed RNAPs removed_RNAs_mask = np.isin( RNA_RNAP_indexes, RNAP_unique_indexes[removed_RNAPs_mask] @@ -1128,10 +1242,73 @@ def _compute_new_segment_attributes( } -def test_superhelical_bug(): +def get_last_known_replisome_data( + boundary_coordinates, + boundary_molecule_indexes, + replisome_coordinates, + replisome_molecule_indexes, +): + # Sort old boundary coordinates and molecule indexes to find first index + # where left boundary is non-negative + boundary_coordinates_argsort = np.argsort(boundary_coordinates[:, 0]) + boundary_coordinates_sorted = boundary_coordinates[boundary_coordinates_argsort] + boundary_molecule_indexes_sorted = boundary_molecule_indexes[ + boundary_coordinates_argsort + ] + replisome_index = np.argmax(boundary_coordinates_sorted[:, 0] >= 0) + # If positive coordinate replisome still exists, add + # last known info on negative coordinate replisome. + if np.any(replisome_coordinates > 0): + replisome_coordinates = np.insert( + replisome_coordinates, + 0, + boundary_coordinates_sorted[replisome_index - 1, 1], + ) + replisome_molecule_indexes = np.insert( + replisome_molecule_indexes, + 0, + boundary_molecule_indexes_sorted[replisome_index - 1, 1], + ) + # If negative coordinate replisome still exists, add + # last known info on positive coordinate replisome. + elif np.any(replisome_coordinates < 0): + replisome_coordinates = np.insert( + replisome_coordinates, 0, boundary_coordinates_sorted[replisome_index, 0] + ) + replisome_molecule_indexes = np.insert( + replisome_molecule_indexes, + 0, + boundary_molecule_indexes_sorted[replisome_index, 0], + ) + # If neither replisomes exist, use last known info on both. + else: + replisome_coordinates = np.array( + [ + boundary_coordinates_sorted[replisome_index - 1, 1], + boundary_coordinates_sorted[replisome_index, 0], + ] + ) + replisome_molecule_indexes = np.array( + [ + boundary_molecule_indexes_sorted[replisome_index - 1, 1], + boundary_molecule_indexes_sorted[replisome_index, 0], + ] + ) + + return replisome_coordinates, replisome_molecule_indexes + + +def test_superhelical_removal_sim(): """ - Test that ChromosomeStructure correctly handles edge case where RNAP and replisome - share the same genomic coordinates. + Run a single time step simulation of :py:class:`~.ChromosomeStructure` + that tests some edge cases in superhelical density calculations. Start with + a chromosome that has four active replication forks for a total of 4 replisomes + and 5 chromosome domains. There are 4 RNAPs per domain and 1 to 2 of those + will be intentionally placed at the same coordinates as a replisome per domain. + They should be removed, causing some segment boundaries to be redefined. + Additionally, 3 of the replisomes will be removed. This should be detected + and superhelical density calculations should still work using the last known + information for the removed replisomes. """ # Get topology for UniqueUpdate Steps unique_topology = TOPOLOGY.copy() @@ -1158,7 +1335,7 @@ def generate_processes(self, config): "water": "WATER[c]", "mature_rna_ids": ["alaT-tRNA[c]"], "fragmentBases": ["polymerized_ATP[c]"], - "replichore_lengths": [2000, 2000], + "replichore_lengths": [100000, 100000], "calculate_superhelical_densities": True, } ), @@ -1168,10 +1345,6 @@ def generate_processes(self, config): def generate_topology(self, config): return { - "rnap_remover": { - "active_RNAPs": ("unique", "active_RNAP"), - "global_time": ("global_time",), - }, "chromosome_structure": TOPOLOGY, "unique_update": unique_topology, "global_clock": { @@ -1193,46 +1366,158 @@ def generate_flow(self, config): unique_mol.flags.writeable = True unique_mol["_entryState"] = 0 unique_mol.flags.writeable = False - # Set up chromosome domain 1 + # Set up a single full chromosome full_chromosomes = template_initial_state["unique"]["full_chromosome"] full_chromosomes.flags.writeable = True full_chromosomes["_entryState"][0] = 1 - full_chromosomes["domain_index"][0] = 1 + full_chromosomes["domain_index"][0] = 0 full_chromosomes.flags.writeable = False - chromosome_domains = template_initial_state["unique"]["chromosome_domain"] + # Set up chromosome domains + chromosome_domains, replisome_idx = get_free_indices( + template_initial_state["unique"]["chromosome_domain"], 5 + ) chromosome_domains.flags.writeable = True - chromosome_domains["_entryState"][0] = 1 - chromosome_domains["domain_index"][0] = 1 - chromosome_domains["child_domains"][0] = [-1, -1] + chromosome_domains["_entryState"][replisome_idx] = 1 + chromosome_domains["domain_index"][replisome_idx] = np.arange(5) + chromosome_domains["child_domains"][replisome_idx] = [ + [1, 2], + [3, 4], + [-1, -1], + [-1, -1], + [-1, -1], + ] chromosome_domains.flags.writeable = False - # Add two replisomes at -1000 and 1000 - active_replisomes = template_initial_state["unique"]["active_replisome"] + template_initial_state["unique"]["chromosome_domain"] = chromosome_domains + # Set up 1 oriC per domain that is not actively replicating + oriCs, oriC_idx = get_free_indices(template_initial_state["unique"]["oriC"], 3) + oriCs.flags.writeable = True + oriCs["_entryState"][oriC_idx] = 1 + oriCs["domain_index"][oriC_idx] = [2, 3, 4] + oriCs.flags.writeable = False + template_initial_state["unique"]["oriC"] = oriCs + # Set up replisome for actively replicating domain + # Notice that the replisomes previously at 45000, 20000, and -20000 + # when the chromosomal segment data below was tabulated are removed + active_replisomes, replisome_idx = get_free_indices( + template_initial_state["unique"]["active_replisome"], 1 + ) active_replisomes.flags.writeable = True - active_replisomes["_entryState"][:2] = 1 - active_replisomes["domain_index"][:2] = 1 - active_replisomes["coordinates"][:2] = [-1000, 1000] - active_replisomes["unique_index"][:2] = [1, 2] + active_replisomes["_entryState"][replisome_idx] = 1 + active_replisomes["domain_index"][replisome_idx] = 0 + active_replisomes["coordinates"][replisome_idx] = -50000 + active_replisomes["unique_index"][replisome_idx] = 0 active_replisomes.flags.writeable = False - # Add four RNAPs: two that coincide with replisomes, two that do not + template_initial_state["unique"]["active_replisome"] = active_replisomes + # Set up 4 RNAPs per domain, some of which will intentionally have + # the same coordinates as replisomes (either active or removed) active_RNAP = template_initial_state["unique"]["active_RNAP"] active_RNAP.flags.writeable = True - active_RNAP["_entryState"][:4] = 1 - active_RNAP["domain_index"][:4] = 1 - active_RNAP["coordinates"][:4] = [-1500, -1000, 1000, 1500] - active_RNAP["is_forward"][:4] = [True, True, True, True] - active_RNAP["unique_index"][:4] = [3, 4, 5, 6] + coordinates_per_domain = [ + [-65000, -50000, 60000, 75000], + [-40000, -26000, 25000, 35000], + [-30000, -10000, 20000, 40000], + [-20000, -15000, 10000, 15000], + ] + for i in range(4): + active_RNAP["_entryState"][i * 4 : (i + 1) * 4] = 1 + active_RNAP["domain_index"][i * 4 : (i + 1) * 4] = i + active_RNAP["is_forward"][i * 4 : (i + 1) * 4] = True + active_RNAP["coordinates"][i * 4 : (i + 1) * 4] = coordinates_per_domain[i] + active_RNAP["unique_index"][i * 4 : (i + 1) * 4] = np.arange( + 4 + i * 4, 4 + (i + 1) * 4 + ) + # Special domain 4 that will be left with no molecules + active_RNAP["_entryState"][16:18] = 1 + active_RNAP["domain_index"][16:18] = 4 + active_RNAP["is_forward"][16:18] = True + active_RNAP["coordinates"][16:18] = [-20000, 20000] + active_RNAP["unique_index"][16:18] = np.arange(20, 22) active_RNAP.flags.writeable = False - # Add chromosomal segments between replisome and RNAPs on either side - # of origin of replication (coordinates offset from current timestep) - chromosomal_segments, _ = get_free_indices( - template_initial_state["unique"]["chromosomal_segment"], 2 + # Construct chromosomal segments by domain + # Assume that RNAPs have advanced 1000 bp from their initial coordinates + # and replisomes have advanced 5000 bp + boundary_coordinates = [] + boundary_molecule_indexes = [] + domain_index = [] + linking_number = [] + # Segments for domain 0 + # - Includes replisome at 45000 (index 1) that will be removed + # - Includes RNAP (index 5) that will conflict with replisome at -50000 (index 0) + boundary_coordinates.extend( + [[-64000, -49000], [-49000, -45000], [45000, 59000], [59000, 74000]] + ) + boundary_molecule_indexes.extend([[4, 5], [5, 0], [1, 6], [6, 7]]) + domain_index.extend([0, 0, 0, 0]) + linking_number.extend([1, 1, 1, 1]) + # Segments for domain 1 + # - Includes replisome at 20000 (index 2) that will be removed + # - Includes replisome at -20000 (index 3) that will be removed + # - Parent domain replisome at 45000 (index 1) will be removed + boundary_coordinates.extend( + [ + [-45000, -39000], + [-39000, -25000], + [-25000, -20000], + [20000, 24000], + [24000, 34000], + [34000, 45000], + ] + ) + boundary_molecule_indexes.extend( + [[0, 8], [8, 9], [9, 3], [2, 10], [10, 11], [11, 1]] + ) + domain_index.extend([1, 1, 1, 1, 1, 1]) + linking_number.extend([1, 1, 1, 1, 1, 1]) + # Segments for domain 2 + # - Parent domain replisome at 45000 (index 1) will be removed + boundary_coordinates.extend( + [ + [-45000, -29000], + [-29000, -9000], + [-9000, 19000], + [19000, 39000], + [39000, 45000], + ] + ) + boundary_molecule_indexes.extend([[0, 12], [12, 13], [13, 14], [14, 15], [15, 1]]) + domain_index.extend([2, 2, 2, 2, 2]) + linking_number.extend([1, 1, 1, 1, 1]) + # Segments for domain 3 + # - Includes RNAP (index 16) that will conflict with replisome that will + # be removed at -20000 (index 3) + # - Includes replisome at 20000 (index 2) that will be removed + boundary_coordinates.extend( + [ + [-20000, -19000], + [-19000, -14000], + [-14000, 9000], + [9000, 14000], + [14000, 20000], + ] + ) + boundary_molecule_indexes.extend([[3, 16], [16, 17], [17, 18], [18, 19], [19, 2]]) + domain_index.extend([3, 3, 3, 3, 3]) + linking_number.extend([1, 1, 1, 1, 1]) + # Segments for domain 4 + # - Includes RNAP (index 20) that will conflict with replisome that will + # be removed at -20000 (index 3) + # - Includes RNAP (index 23) that will conflict with replisome that will + # be removed at 20000 (index 2) + boundary_coordinates.extend([[-20000, -19000], [-19000, 19000], [19000, 20000]]) + boundary_molecule_indexes.extend([[3, 20], [20, 21], [21, 2]]) + domain_index.extend([4, 4, 4]) + linking_number.extend([1, 1, 1]) + chromosomal_segments, segment_idx = get_free_indices( + template_initial_state["unique"]["chromosomal_segment"], len(linking_number) ) chromosomal_segments.flags.writeable = True - chromosomal_segments["_entryState"][:2] = 1 - chromosomal_segments["boundary_coordinates"][:2] = [[-1400, -800], [800, 1400]] - chromosomal_segments["boundary_molecule_indexes"][:2] = [[3, 1], [2, 6]] - chromosomal_segments["domain_index"][:2] = 1 - chromosomal_segments["linking_number"][:2] = 1 + chromosomal_segments["_entryState"][segment_idx] = 1 + chromosomal_segments["boundary_coordinates"][segment_idx] = boundary_coordinates + chromosomal_segments["boundary_molecule_indexes"][segment_idx] = ( + boundary_molecule_indexes + ) + chromosomal_segments["domain_index"][segment_idx] = domain_index + chromosomal_segments["linking_number"][segment_idx] = linking_number chromosomal_segments.flags.writeable = False template_initial_state["unique"]["chromosomal_segment"] = chromosomal_segments # Since unique numpy updater is an class method, internal @@ -1250,30 +1535,145 @@ def generate_flow(self, config): ) engine.update(1) state = engine.state.get_value() - # Check that conflicting RNAPs were removed - active_RNAPs = state["unique"]["active_RNAP"][ - state["unique"]["active_RNAP"]["_entryState"].view(np.bool_) - ] - assert len(active_RNAPs) == 2 - assert np.all(active_RNAPs["domain_index"] == 1) - assert np.all(active_RNAPs["coordinates"] == np.array([-1500, 1500])) - assert np.all(active_RNAPs["unique_index"] == np.array([3, 6])) - # Check that chromosomal segments were added for the span between - # each replisome and terC in addition to the existing ones between - # replisomes and non-conflicting RNAPs - active_chromosome_segments = state["unique"]["chromosomal_segment"][ + # Check that right number of collisions happened at right coordinates + rnap_data = state["listeners"]["rnap_data"] + assert rnap_data["n_total_collisions"] == 1 + assert rnap_data["n_headon_collisions"] == 1 + assert rnap_data["n_codirectional_collisions"] == 0 + assert np.array_equal( + rnap_data["headon_collision_coordinates"], np.array([-50000], dtype=int) + ) + assert rnap_data["n_empty_fork_collisions"] == 3 + assert np.array_equal( + rnap_data["empty_fork_collision_coordinates"], + np.array([-20000, -20000, 20000], dtype=int), + ) + # Check chromosomal segments + chromosomal_segments = state["unique"]["chromosomal_segment"][ state["unique"]["chromosomal_segment"]["_entryState"].view(np.bool_) ] - assert len(active_chromosome_segments) == 4 - assert np.all( - active_chromosome_segments["boundary_coordinates"] - == np.array([[-2000, -1500], [-1500, -1000], [1000, 1500], [1500, 2000]]) + assert np.array_equal( + chromosomal_segments["boundary_coordinates"], + np.array( + [ + # Domain 0 + [-100000, -65000], + [-65000, -50000], + [45000, 60000], + [60000, 75000], + [75000, 100000], + # Domain 1 + [-50000, -40000], + [-40000, -26000], + [-26000, -20000], + [20000, 25000], + [25000, 35000], + [35000, 45000], + # Domain 2 + [-50000, -30000], + [-30000, -10000], + [-10000, 20000], + [20000, 40000], + [40000, 45000], + # Domain 3 + [-20000, -15000], + [-15000, 10000], + [10000, 15000], + [15000, 20000], + # Domain 4 + [-20000, 20000], + ], + dtype=int, + ), + ) + assert np.array_equal( + chromosomal_segments["boundary_molecule_indexes"], + np.array( + [ + # Domain 0: index 5 is gone due to conflict with replisome, + # segments were added flanking terC (-1 placeholder index), + # index 1 replisome is gone but still exists as placeholder + # for replication fork in our superhelical density calculations + [-1, 4], + [4, 0], + [1, 6], + [6, 7], + [7, -1], + # Domain 1: index 1, 2, and 3 replisomes are removed but still exist + # here as placeholders + [0, 8], + [8, 9], + [9, 3], + [2, 10], + [10, 11], + [11, 1], + # Domain 2: index 1 replisome was removed but still exists here + # as a placeholder + [0, 12], + [12, 13], + [13, 14], + [14, 15], + [15, 1], + # Domain 3: index 2 and 3 replisomes are removed but still exist + # here as placeholders, index 16 RNAP was removed due to conflict + # with replisome placeholder index 3 + [3, 17], + [17, 18], + [18, 19], + [19, 2], + # Domain 4: index 2 and 3 replisomes were removed but still exist + # here as placeholders, index 20 and 21 RNAPs were removed due to + # conflicts with replisome placeholders + [3, 2], + ], + dtype=int, + ), + ) + assert np.array_equal( + chromosomal_segments["domain_index"], + np.array( + [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4], dtype=int + ), ) - assert np.all( - active_chromosome_segments["boundary_molecule_indexes"] - == np.array([[-1, 3], [3, 1], [2, 6], [6, -1]]) + assert np.array_equal( + chromosomal_segments["linking_number"], + np.array( + [ + # Domain 0: terC segments have 0 linking number, second segment + # combines two original segments due to removed RNAP index 5 + 0, + 2, + 1, + 1, + 0, + # Domain 1: No molecule boundaries were changed + 1, + 1, + 1, + 1, + 1, + 1, + # Domain 2: No molecule boundaries were changed + 1, + 1, + 1, + 1, + 1, + # Domain 3: First segment combines two original segments due to + # removed RNAP index 16 + 2, + 1, + 1, + 1, + # Domain 4: Sole segment combines all three original segments + # due to removed RNAP index 20 and 21, leaving only a single + # segment between two unoccupied replication forks + 3, + ], + dtype=float, + ), ) if __name__ == "__main__": - test_superhelical_bug() + test_superhelical_removal_sim() diff --git a/migration/migration_utils.py b/migration/migration_utils.py index ba8d25e26..ac8be2aaa 100644 --- a/migration/migration_utils.py +++ b/migration/migration_utils.py @@ -345,12 +345,17 @@ def run_and_compare( if "mRNA_counts" in actual_listeners: actual_listeners = {"mrna_counts": actual_listeners} # Gene copy number determined by listener after everything updates in wcEcoli - # TODO: Move this out of TfBinding process + # Empty fork collisions are a new concept in vEcoli assert recursive_compare( actual_listeners, wc_listeners, check_keys_strict=False, - ignore_keys={"growth", "gene_copy_number"}, + ignore_keys={ + "growth", + "gene_copy_number", + "n_empty_fork_collisions", + "empty_fork_collision_coordinates", + }, ) From 159c0171983128eea51157395ef205d09393534b Mon Sep 17 00:00:00 2001 From: thalassemia Date: Mon, 16 Dec 2024 22:50:01 -0800 Subject: [PATCH 4/8] Upgrade all packages --- uv.lock | 221 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 111 insertions(+), 110 deletions(-) diff --git a/uv.lock b/uv.lock index a501589ef..ca9246837 100644 --- a/uv.lock +++ b/uv.lock @@ -82,14 +82,14 @@ wheels = [ [[package]] name = "aiosignal" -version = "1.3.1" +version = "1.3.2" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, + { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, ] [[package]] @@ -110,7 +110,7 @@ dependencies = [ { name = "jsonschema" }, { name = "narwhals" }, { name = "packaging" }, - { name = "typing-extensions", marker = "python_full_version == '3.12.8'" }, + { 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 = [ @@ -124,7 +124,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version == '3.12.8'" }, + { 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 = [ @@ -206,11 +206,11 @@ wheels = [ [[package]] name = "attrs" -version = "24.2.0" +version = "24.3.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 } +sdist = { url = "https://files.pythonhosted.org/packages/48/c8/6260f8ccc11f0917360fc0da435c5c9c7504e3db174d5a12a1494887b045/attrs-24.3.0.tar.gz", hash = "sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff", size = 805984 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, + { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 }, ] [[package]] @@ -286,11 +286,11 @@ wheels = [ [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, + { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, ] [[package]] @@ -502,15 +502,15 @@ wheels = [ [[package]] name = "debugpy" -version = "1.8.9" +version = "1.8.11" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/e7/666f4c9b0e24796af50aadc28d36d21c2e01e831a934535f956e09b3650c/debugpy-1.8.11.tar.gz", hash = "sha256:6ad2688b69235c43b020e04fecccdf6a96c8943ca9c2fb340b8adc103c655e57", size = 1640124 } 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 }, + { url = "https://files.pythonhosted.org/packages/c6/ae/2cf26f3111e9d94384d9c01e9d6170188b0aeda15b60a4ac6457f7c8a26f/debugpy-1.8.11-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:84e511a7545d11683d32cdb8f809ef63fc17ea2a00455cc62d0a4dbb4ed1c308", size = 2498756 }, + { url = "https://files.pythonhosted.org/packages/b0/16/ec551789d547541a46831a19aa15c147741133da188e7e6acf77510545a7/debugpy-1.8.11-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce291a5aca4985d82875d6779f61375e959208cdf09fcec40001e65fb0a54768", size = 4219136 }, + { url = "https://files.pythonhosted.org/packages/72/6f/b2b3ce673c55f882d27a6eb04a5f0c68bcad6b742ac08a86d8392ae58030/debugpy-1.8.11-cp312-cp312-win32.whl", hash = "sha256:28e45b3f827d3bf2592f3cf7ae63282e859f3259db44ed2b129093ca0ac7940b", size = 5224440 }, + { url = "https://files.pythonhosted.org/packages/77/09/b1f05be802c1caef5b3efc042fc6a7cadd13d8118b072afd04a9b9e91e06/debugpy-1.8.11-cp312-cp312-win_amd64.whl", hash = "sha256:44b1b8e6253bceada11f714acf4309ffb98bfa9ac55e4fce14f9e5d4484287a1", size = 5264578 }, + { url = "https://files.pythonhosted.org/packages/77/0a/d29a5aacf47b4383ed569b8478c02d59ee3a01ad91224d2cff8562410e43/debugpy-1.8.11-py2.py3-none-any.whl", hash = "sha256:0e22f846f4211383e6a416d04b4c13ed174d24cc5d43f5fd52e7821d0ebc8920", size = 5226874 }, ] [[package]] @@ -688,19 +688,19 @@ wheels = [ [[package]] name = "fonttools" -version = "4.55.2" +version = "4.55.3" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/76/61/a300d1574dc381393424047c0396a0e213db212e28361123af9830d71a8d/fonttools-4.55.3.tar.gz", hash = "sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45", size = 3498155 } 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 }, + { url = "https://files.pythonhosted.org/packages/89/58/fbcf5dff7e3ea844bb00c4d806ca1e339e1f2dce5529633bf4842c0c9a1f/fonttools-4.55.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35", size = 2765380 }, + { url = "https://files.pythonhosted.org/packages/81/dd/da6e329e51919b4f421c8738f3497e2ab08c168e76aaef7b6d5351862bdf/fonttools-4.55.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c", size = 2297940 }, + { url = "https://files.pythonhosted.org/packages/00/44/f5ee560858425c99ef07e04919e736db09d6416408e5a8d3bbfb4a6623fd/fonttools-4.55.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7", size = 4793327 }, + { url = "https://files.pythonhosted.org/packages/24/da/0a001926d791c55e29ac3c52964957a20dbc1963615446b568b7432891c3/fonttools-4.55.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314", size = 4865624 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/1edd8b13a427a9fb6418373437caa586c0caa57f260af8e0548f4d11e340/fonttools-4.55.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427", size = 4774166 }, + { url = "https://files.pythonhosted.org/packages/9c/ec/ade054097976c3d6debc9032e09a351505a0196aa5493edf021be376f75e/fonttools-4.55.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a", size = 5001832 }, + { url = "https://files.pythonhosted.org/packages/e2/cd/233f0e31ad799bb91fc78099c8b4e5ec43b85a131688519640d6bae46f6a/fonttools-4.55.3-cp312-cp312-win32.whl", hash = "sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07", size = 2162228 }, + { url = "https://files.pythonhosted.org/packages/46/45/a498b5291f6c0d91b2394b1ed7447442a57d1c9b9cf8f439aee3c316a56e/fonttools-4.55.3-cp312-cp312-win_amd64.whl", hash = "sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54", size = 2209118 }, + { url = "https://files.pythonhosted.org/packages/99/3b/406d17b1f63e04a82aa621936e6e1c53a8c05458abd66300ac85ea7f9ae9/fonttools-4.55.3-py3-none-any.whl", hash = "sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977", size = 1111638 }, ] [[package]] @@ -782,22 +782,23 @@ wheels = [ [[package]] name = "giddy" -version = "2.3.5" +version = "2.3.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "esda" }, { name = "libpysal" }, + { name = "mapclassify" }, { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/49/dc/a5c110d76dbdd99bd1804956c0bb83a43ca5f9decd666190ca2e2527e711/giddy-2.3.6.tar.gz", hash = "sha256:004ec587eb7b75d9f717efd9b018a9f95f55d30d9768e2bb9cdb86ae7bdb7592", size = 11166266 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/19/9125c0ec03be4e4345b95c8a8490d4552fb224cb86ed27e0ef2d37d09e06/giddy-2.3.5-py3-none-any.whl", hash = "sha256:42730e5cbfbdce004470d8fb17b5319c5221476fe5f49d41430a059bd92ec824", size = 61087 }, + { url = "https://files.pythonhosted.org/packages/3b/d2/e6b32499fd212ac7f6d2a5db8343460c790a394d9742d96e88f4cca90173/giddy-2.3.6-py3-none-any.whl", hash = "sha256:fbc5fde6798d5e1a4a527a2d80d0856cb24a2be71243cc586c15328868b55d8b", size = 61336 }, ] [[package]] name = "google-api-core" -version = "2.23.0" +version = "2.24.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-auth" }, @@ -806,23 +807,23 @@ dependencies = [ { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/81/56/d70d66ed1b5ab5f6c27bf80ec889585ad8f865ff32acbafd3b2ef0bfb5d0/google_api_core-2.24.0.tar.gz", hash = "sha256:e255640547a597a4da010876d333208ddac417d60add22b6851a0c66a831fcaf", size = 162647 } 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 }, + { url = "https://files.pythonhosted.org/packages/a1/76/65b8b94e74bf1b6d1cc38d916089670c4da5029d25762441d8c5c19e51dd/google_api_core-2.24.0-py3-none-any.whl", hash = "sha256:10d82ac0fca69c82a25b3efdeefccf6f28e02ebb97925a8cce8edbfe379929d9", size = 158576 }, ] [[package]] name = "google-auth" -version = "2.36.0" +version = "2.37.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 } +sdist = { url = "https://files.pythonhosted.org/packages/46/af/b25763b9d35dfc2c6f9c3ec34d8d3f1ba760af3a7b7e8d5c5f0579522c45/google_auth-2.37.0.tar.gz", hash = "sha256:0054623abf1f9c83492c63d3f47e77f0a544caa3d40b2d98e099a611c2dd5d00", size = 268878 } 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 }, + { url = "https://files.pythonhosted.org/packages/8d/8d/4d5d5f9f500499f7bd4c93903b43e8d6976f3fc6f064637ded1a85d09b07/google_auth-2.37.0-py2.py3-none-any.whl", hash = "sha256:42664f18290a6be591be5329a96fe30184be1a1badb7292a7f686a9659de9ca0", size = 209829 }, ] [[package]] @@ -1010,8 +1011,8 @@ name = "ipdb" version = "0.13.13" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "decorator", marker = "python_full_version == '3.12.8'" }, - { name = "ipython", marker = "python_full_version == '3.12.8'" }, + { 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 = [ @@ -1338,7 +1339,7 @@ wheels = [ [[package]] name = "jupyterlab" -version = "4.3.2" +version = "4.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -1355,9 +1356,9 @@ dependencies = [ { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/ca/b80ea37f800b7d0b96088dec04d59b4575eb33e59ca1ca19d23885fb6fe6/jupyterlab-4.3.3.tar.gz", hash = "sha256:76fa39e548fdac94dc1204af5956c556f54c785f70ee26aa47ea08eda4d5bbcd", size = 21797278 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/fc/f12dbf6e3f44d8f95645c9142e40e7e7de1e7af284b286f35acf88df5b87/jupyterlab-4.3.2-py3-none-any.whl", hash = "sha256:e87100cbab8b886ff7a4f325c856100ba6fdfe916162a85409daf0e707e19d1d", size = 11664945 }, + { url = "https://files.pythonhosted.org/packages/c1/ce/6731e54aacbe91daa439ae895763fe9d91952ce96cd0e3f94d8d13229717/jupyterlab-4.3.3-py3-none-any.whl", hash = "sha256:32a8fd30677e734ffcc3916a4758b9dab21b02015b668c60eb36f84357b7d4b1", size = 11665394 }, ] [[package]] @@ -1518,7 +1519,7 @@ wheels = [ [[package]] name = "matplotlib" -version = "3.9.3" +version = "3.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -1531,14 +1532,14 @@ dependencies = [ { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418 } 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 }, + { url = "https://files.pythonhosted.org/packages/44/c7/6b2d8cb7cc251d53c976799cacd3200add56351c175ba89ab9cbd7c1e68a/matplotlib-3.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4659665bc7c9b58f8c00317c3c2a299f7f258eeae5a5d56b4c64226fca2f7c59", size = 8172465 }, + { url = "https://files.pythonhosted.org/packages/42/2a/6d66d0fba41e13e9ca6512a0a51170f43e7e7ed3a8dfa036324100775612/matplotlib-3.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d44cb942af1693cced2604c33a9abcef6205601c445f6d0dc531d813af8a2f5a", size = 8043300 }, + { url = "https://files.pythonhosted.org/packages/90/60/2a60342b27b90a16bada939a85e29589902b41073f59668b904b15ea666c/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a994f29e968ca002b50982b27168addfd65f0105610b6be7fa515ca4b5307c95", size = 8448936 }, + { url = "https://files.pythonhosted.org/packages/a7/b2/d872fc3d753516870d520595ddd8ce4dd44fa797a240999f125f58521ad7/matplotlib-3.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0558bae37f154fffda54d779a592bc97ca8b4701f1c710055b609a3bac44c8", size = 8594151 }, + { url = "https://files.pythonhosted.org/packages/f4/bd/b2f60cf7f57d014ab33e4f74602a2b5bdc657976db8196bbc022185f6f9c/matplotlib-3.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:503feb23bd8c8acc75541548a1d709c059b7184cde26314896e10a9f14df5f12", size = 9400347 }, + { url = "https://files.pythonhosted.org/packages/9f/6e/264673e64001b99d747aff5a288eca82826c024437a3694e19aed1decf46/matplotlib-3.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:c40ba2eb08b3f5de88152c2333c58cee7edcead0a2a0d60fcafa116b17117adc", size = 8039144 }, ] [[package]] @@ -1658,11 +1659,11 @@ wheels = [ [[package]] name = "narwhals" -version = "1.15.2" +version = "1.18.4" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/fa/cf/f428738e49584498d3ea8765b3d5a068827955c0d8d704c259b03e8c635f/narwhals-1.18.4.tar.gz", hash = "sha256:b1da4e2e4ab185824781760319ac1ec8ee2944a929795064c3a64ffff16b00c4", size = 213705 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/e7/fe3d69098e628e81cf317e860474e5df02a5a681b031acbf2aaf192cef3f/narwhals-1.15.2-py3-none-any.whl", hash = "sha256:00d16ed1c4466b43ba37ef6799142340981e4ac7dcd7686e461d4955abcd921d", size = 233774 }, + { url = "https://files.pythonhosted.org/packages/fd/ae/23fffe1efc750298e5e568cede71a9979c68ae8dcf08bf6d8ecd177a7bde/narwhals-1.18.4-py3-none-any.whl", hash = "sha256:c6bb6b6fba59caeab28a7d6ec1e79ab0040c75baef2e4152199ad1a9c266ef96", size = 251273 }, ] [[package]] @@ -1848,7 +1849,7 @@ name = "opencv-python-headless" version = "4.10.0.84" 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/2f/7e/d20f68a5f1487adf19d74378d349932a386b1ece3be9be9915e5986db468/opencv-python-headless-4.10.0.84.tar.gz", hash = "sha256:f2017c6101d7c2ef8d7bc3b414c37ff7f54d64413a1847d89970b6b7069b4e1a", size = 95117755 } wheels = [ @@ -1941,7 +1942,7 @@ name = "pandas" version = "2.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy", marker = "python_full_version == '3.12.8'" }, + { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, { name = "tzdata" }, @@ -2071,15 +2072,15 @@ wheels = [ [[package]] name = "polars" -version = "1.16.0" +version = "1.17.1" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/32/3b/40b42c6b0e54b001fbaaa55d3d769283e0d54541be783783e08da6a9c54a/polars-1.17.1.tar.gz", hash = "sha256:5a3dac3cb7cbe174d1fa898cba9afbede0c08e8728feeeab515554d762127019", size = 4220337 } 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 }, + { url = "https://files.pythonhosted.org/packages/5b/24/a7d97fb8988a3ccf9e285311fe9b04e8cec95657fc2b9f9a8ebedbcdd06f/polars-1.17.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:d3a2172f7cf332010f0b034345111e9c86d59b5a5b0fc5aa0509121f40d9e43c", size = 32993574 }, + { url = "https://files.pythonhosted.org/packages/84/4f/b892993474850e85ac05ffa6d0f312c207dcbb1e4a55dc6383f826d5a87d/polars-1.17.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:82e98c69197df0d8ddc341a6175008508ceaea88f723f32044027810bcdb43fa", size = 28773084 }, + { url = "https://files.pythonhosted.org/packages/29/08/54fe197c9d5f951cf85944ff9cfe0a706dc9d2230e98814a125eda8a1d09/polars-1.17.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59abdab015ed2ecfa0c63862b960816c35096e1f4df057dde3c44cd973af5029", size = 36360758 }, + { url = "https://files.pythonhosted.org/packages/9b/0c/f5a100da6184f11838520a423a5830dabe194a0812c9fdbef419f2276a92/polars-1.17.1-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:6d2f922c403b8900b3ae3c23a27b2cae3a2db40ad790cc4fc368402b92629b11", size = 32685903 }, + { url = "https://files.pythonhosted.org/packages/4b/59/cf2e88bebdffb7efb7e4f65f4ec9e293040c313d37e3628db87e4f64dca4/polars-1.17.1-cp39-abi3-win_amd64.whl", hash = "sha256:d38156c8259554cbcb17874d91e6dfa9c404335f08a3307496aadfdee46baa31", size = 35931768 }, ] [[package]] @@ -2363,14 +2364,14 @@ wheels = [ [[package]] name = "pyqt5-sip" -version = "12.16.0" +version = "12.16.1" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/3c/cd/f6f957107447bc53e398f6149f55a7f335c434f201e77dcfb8a3c20dc42c/pyqt5_sip-12.16.1.tar.gz", hash = "sha256:8c831f8b619811a32369d72339faa50ae53a963f5fdfa4d71f845c63e9673125", size = 103975 } 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 }, + { url = "https://files.pythonhosted.org/packages/7f/3d/8dc6b2ef0132ab1cc534485905b594e6f4176176924e54e35a3f6a0fb164/PyQt5_sip-12.16.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f6724c590de3d556c730ebda8b8f906b38373934472209e94d99357b52b56f5f", size = 124549 }, + { url = "https://files.pythonhosted.org/packages/45/eb/fa72094f2ca861941d38a4df49d0a34bd024972cd458f516ef3c65d128e3/PyQt5_sip-12.16.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:633cba509a98bd626def951bb948d4e736635acbd0b7fabd7be55a3a096a8a0b", size = 281640 }, + { url = "https://files.pythonhosted.org/packages/12/a5/9439567dbf513bfc0fd71a5bb3797fae649338715749e89571ad86b4b3e3/PyQt5_sip-12.16.1-cp312-cp312-win32.whl", hash = "sha256:2b35ff92caa569e540675ffcd79ffbf3e7092cccf7166f89e2a8b388db80aa1c", size = 49428 }, + { url = "https://files.pythonhosted.org/packages/a7/33/d91e003b85ff7ab227d0fff236d48c18ada2f0cd49d5e35cb514867ba609/PyQt5_sip-12.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:a0f83f554727f43dfe92afbf3a8c51e83bb8b78c5f160b635d4359fad681cebe", size = 57957 }, ] [[package]] @@ -2454,11 +2455,11 @@ wheels = [ [[package]] name = "python-json-logger" -version = "2.0.7" +version = "3.2.1" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/e3/c4/358cd13daa1d912ef795010897a483ab2f0b41c9ea1b35235a8b2f7d15a7/python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008", size = 16287 } 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 }, + { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924 }, ] [[package]] @@ -2717,32 +2718,32 @@ wheels = [ [[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 }, +version = "0.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/5e/683c7ef7a696923223e7d95ca06755d6e2acbc5fd8382b2912a28008137c/ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3", size = 3378522 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/c4/bfdbb8b9c419ff3b52479af8581026eeaac3764946fdb463dec043441b7d/ruff-0.8.3-py3-none-linux_armv6l.whl", hash = "sha256:8d5d273ffffff0acd3db5bf626d4b131aa5a5ada1276126231c4174543ce20d6", size = 10535860 }, + { url = "https://files.pythonhosted.org/packages/ef/c5/0aabdc9314b4b6f051168ac45227e2aa8e1c6d82718a547455e40c9c9faa/ruff-0.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e4d66a21de39f15c9757d00c50c8cdd20ac84f55684ca56def7891a025d7e939", size = 10346327 }, + { url = "https://files.pythonhosted.org/packages/1a/78/4843a59e7e7b398d6019cf91ab06502fd95397b99b2b858798fbab9151f5/ruff-0.8.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c356e770811858bd20832af696ff6c7e884701115094f427b64b25093d6d932d", size = 9942585 }, + { url = "https://files.pythonhosted.org/packages/91/5a/642ed8f1ba23ffc2dd347697e01eef3c42fad6ac76603be4a8c3a9d6311e/ruff-0.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c0a60a825e3e177116c84009d5ebaa90cf40dfab56e1358d1df4e29a9a14b13", size = 10797597 }, + { url = "https://files.pythonhosted.org/packages/30/25/2e654bc7226da09a49730a1a2ea6e89f843b362db80b4b2a7a4f948ac986/ruff-0.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fb782f4db39501210ac093c79c3de581d306624575eddd7e4e13747e61ba18", size = 10307244 }, + { url = "https://files.pythonhosted.org/packages/c0/2d/a224d56bcd4383583db53c2b8f410ebf1200866984aa6eb9b5a70f04e71f/ruff-0.8.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f26bc76a133ecb09a38b7868737eded6941b70a6d34ef53a4027e83913b6502", size = 11362439 }, + { url = "https://files.pythonhosted.org/packages/82/01/03e2857f9c371b8767d3e909f06a33bbdac880df17f17f93d6f6951c3381/ruff-0.8.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:01b14b2f72a37390c1b13477c1c02d53184f728be2f3ffc3ace5b44e9e87b90d", size = 12078538 }, + { url = "https://files.pythonhosted.org/packages/af/ae/ff7f97b355da16d748ceec50e1604a8215d3659b36b38025a922e0612e9b/ruff-0.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53babd6e63e31f4e96ec95ea0d962298f9f0d9cc5990a1bbb023a6baf2503a82", size = 11616172 }, + { url = "https://files.pythonhosted.org/packages/6a/d0/6156d4d1e53ebd17747049afe801c5d7e3014d9b2f398b9236fe36ba4320/ruff-0.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ae441ce4cf925b7f363d33cd6570c51435972d697e3e58928973994e56e1452", size = 12919886 }, + { url = "https://files.pythonhosted.org/packages/4e/84/affcb30bacb94f6036a128ad5de0e29f543d3f67ee42b490b17d68e44b8a/ruff-0.8.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c65bc0cadce32255e93c57d57ecc2cca23149edd52714c0c5d6fa11ec328cd", size = 11212599 }, + { url = "https://files.pythonhosted.org/packages/60/b9/5694716bdefd8f73df7c0104334156c38fb0f77673d2966a5a1345bab94d/ruff-0.8.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5be450bb18f23f0edc5a4e5585c17a56ba88920d598f04a06bd9fd76d324cb20", size = 10784637 }, + { url = "https://files.pythonhosted.org/packages/24/7e/0e8f835103ac7da81c3663eedf79dec8359e9ae9a3b0d704bae50be59176/ruff-0.8.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8faeae3827eaa77f5721f09b9472a18c749139c891dbc17f45e72d8f2ca1f8fc", size = 10390591 }, + { url = "https://files.pythonhosted.org/packages/27/da/180ec771fc01c004045962ce017ca419a0281f4bfaf867ed0020f555b56e/ruff-0.8.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:db503486e1cf074b9808403991663e4277f5c664d3fe237ee0d994d1305bb060", size = 10894298 }, + { url = "https://files.pythonhosted.org/packages/6d/f8/29f241742ed3954eb2222314b02db29f531a15cab3238d1295e8657c5f18/ruff-0.8.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6567be9fb62fbd7a099209257fef4ad2c3153b60579818b31a23c886ed4147ea", size = 11275965 }, + { url = "https://files.pythonhosted.org/packages/79/e9/5b81dc9afc8a80884405b230b9429efeef76d04caead904bd213f453b973/ruff-0.8.3-py3-none-win32.whl", hash = "sha256:19048f2f878f3ee4583fc6cb23fb636e48c2635e30fb2022b3a1cd293402f964", size = 8807651 }, + { url = "https://files.pythonhosted.org/packages/ea/67/7291461066007617b59a707887b90e319b6a043c79b4d19979f86b7a20e7/ruff-0.8.3-py3-none-win_amd64.whl", hash = "sha256:f7df94f57d7418fa7c3ffb650757e0c2b96cf2501a0b192c18e4fb5571dfada9", size = 9625289 }, + { url = "https://files.pythonhosted.org/packages/03/8f/e4fa95288b81233356d9a9dcaed057e5b0adc6399aa8fd0f6d784041c9c3/ruff-0.8.3-py3-none-win_arm64.whl", hash = "sha256:fe2756edf68ea79707c8d68b78ca9a58ed9af22e430430491ee03e718b5e4936", size = 9078754 }, ] [[package]] name = "scikit-image" -version = "0.24.0" +version = "0.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "imageio" }, @@ -2754,18 +2755,18 @@ dependencies = [ { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/e6/8d/383e5438c807804b66d68ed2c09202d185ea781b6022aa8b9fac3851137f/scikit_image-0.25.0.tar.gz", hash = "sha256:58d94fea11b6b3306b3770417dc1cbca7fa9bcbd6a13945d7910399c88c2018c", size = 22696477 } 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 }, + { url = "https://files.pythonhosted.org/packages/21/6a/a8df6953a85042a8a219c97e1758486b997c9dd319e1c474362229406e57/scikit_image-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7e63f18b10f9b74590d2ca62cbc4147e696a5e72cfcbcd4af52395fd94fcdc6e", size = 13981411 }, + { url = "https://files.pythonhosted.org/packages/dd/4c/e40a77c57a6b90dda710bc64ed761c93e7b3dd1cef3815675a2bc6807755/scikit_image-0.25.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bad4af5edf58775607c153af5bc3f193c2b67261ea9817b62362c746e439d094", size = 13230600 }, + { url = "https://files.pythonhosted.org/packages/63/3f/fac8e1eefbe4a885fa1c9a384db8e11e47c19ab5558b25f370ade3901868/scikit_image-0.25.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44f7681ff99eed2c33d993bc4bfc17b62e6cadbca1081c7fdbb3607ce89b15e6", size = 14173033 }, + { url = "https://files.pythonhosted.org/packages/47/fe/f09efbf54782996a7f1d3db0e33cb9097f3cc6033392fb53459d7254fa7c/scikit_image-0.25.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:758f55d858aa796114a4275051ca4bb41d8b40c53eb78cb60f0b1ed235d4144b", size = 15002211 }, + { url = "https://files.pythonhosted.org/packages/89/30/4f95a7462411def5563c01d56674bd122bd6db55ae1e8c31ad68586e2d27/scikit_image-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:4f7178c6fb6163710571522847326ad936a603646255b22d3d76b6ba58153890", size = 12894520 }, ] [[package]] name = "scikit-learn" -version = "1.5.2" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "joblib" }, @@ -2773,13 +2774,13 @@ dependencies = [ { 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 } +sdist = { url = "https://files.pythonhosted.org/packages/fa/19/5aa2002044afc297ecaf1e3517ed07bba4aece3b5613b5160c1212995fc8/scikit_learn-1.6.0.tar.gz", hash = "sha256:9d58481f9f7499dff4196927aedd4285a0baec8caa3790efbe205f13de37dd6e", size = 7074944 } 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 }, + { url = "https://files.pythonhosted.org/packages/18/0c/a5de627aa57b028aea7026cb3bbeaf63be3158adc118212d6cc7843d939a/scikit_learn-1.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:04a5ba45c12a5ff81518aa4f1604e826a45d20e53da47b15871526cda4ff5174", size = 12096999 }, + { url = "https://files.pythonhosted.org/packages/a3/7d/02a96e6fb28ddb213e84b1b4a44148d26ec96fc9db9c74e050277e009892/scikit_learn-1.6.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:21fadfc2ad7a1ce8bd1d90f23d17875b84ec765eecbbfc924ff11fb73db582ce", size = 11160579 }, + { url = "https://files.pythonhosted.org/packages/70/28/77b071f541d75247e6c3403f19aaa634371e972691f6aa1838ca9fd4cc52/scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30f34bb5fde90e020653bb84dcb38b6c83f90c70680dbd8c38bd9becbad7a127", size = 12246543 }, + { url = "https://files.pythonhosted.org/packages/17/0e/e6bb84074f1081245a165c0ee775ecef24beae9d2f2e24bcac0c9f155f13/scikit_learn-1.6.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dad624cffe3062276a0881d4e441bc9e3b19d02d17757cd6ae79a9d192a0027", size = 13140402 }, + { url = "https://files.pythonhosted.org/packages/21/1d/3df58df8bd425f425df9f90b316618ace62b7f1f838ac1580191025cc735/scikit_learn-1.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:2fce7950a3fad85e0a61dc403df0f9345b53432ac0e47c50da210d22c60b6d85", size = 11103596 }, ] [[package]] @@ -3281,14 +3282,14 @@ wheels = [ [[package]] name = "tifffile" -version = "2024.9.20" +version = "2024.12.12" 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 } +sdist = { url = "https://files.pythonhosted.org/packages/37/c9/fc4e490c5b0ccad68c98ea1d6e0f409bd7d50e2e8fc30a0725594d3104ff/tifffile-2024.12.12.tar.gz", hash = "sha256:c38e929bf74c04b6c8708d87f16b32c85c6d7c2514b99559ea3db8003ba4edda", size = 365416 } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/0a/435d5d7ec64d1c8b422ac9ebe42d2f3b2ac0b3f8a56f5c04dd0f3b7ba83c/tifffile-2024.9.20-py3-none-any.whl", hash = "sha256:c54dc85bc1065d972cb8a6ffb3181389d597876aa80177933459733e4ed243dd", size = 228191 }, + { url = "https://files.pythonhosted.org/packages/d8/1e/76cbc758f6865a9da18001ac70d1a4154603b71e233f704401fc7d62493e/tifffile-2024.12.12-py3-none-any.whl", hash = "sha256:6ff0f196a46a75c8c0661c70995e06ea4d08a81fe343193e69f1673f4807d508", size = 227538 }, ] [[package]] From 5074a9640e47bb3b464229acabc0a63ae07ea90a Mon Sep 17 00:00:00 2001 From: thalassemia Date: Mon, 16 Dec 2024 23:40:05 -0800 Subject: [PATCH 5/8] Cleanup and document new function --- ecoli/processes/chromosome_structure.py | 34 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index 217371f88..3f8439e2b 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -99,7 +99,6 @@ class ChromosomeStructure(Step): "mature_rna_end_positions": [], "mature_rna_nt_counts": [], "unprocessed_rna_index_mapping": {}, - "removed_replisome_index": -2, "time_step": 1.0, } @@ -120,7 +119,6 @@ def __init__(self, parameters=None): "relaxed_DNA_base_pairs_per_turn" ] self.terC_index = self.parameters["terC_index"] - self.removed_replisome_index = self.parameters["removed_replisome_index"] self.n_mature_rnas = self.parameters["n_mature_rnas"] self.mature_rna_ids = self.parameters["mature_rna_ids"] @@ -1243,11 +1241,33 @@ def _compute_new_segment_attributes( def get_last_known_replisome_data( - boundary_coordinates, - boundary_molecule_indexes, - replisome_coordinates, - replisome_molecule_indexes, -): + boundary_coordinates: np.ndarray, + boundary_molecule_indexes: np.ndarray, + replisome_coordinates: np.ndarray, + replisome_molecule_indexes: np.ndarray, +) -> tuple[np.ndarray, np.ndarray]: + """ + Gets the last known coordinates and molecule indexes of both replisomes + for a chromosome domain. + + Args: + boundary_coordinates: (N, 2) array of chromosomal coordinates of + all boundary molecules in the domain during the last time step. + boundary_molecule_indexes: (N, 2) array of unique indexes of all + boundary molecules in the domain during the last time step. + replisome_coordinates: (1,) or (0,) array of chromosomal coordinates of + the replisomes in the domain in the current time step. + replisome_molecule_indexes: (1,) or (0,) array of unique indexes of the + replisomes in the domain in the current time step. + + Returns: + Tuple of the following format:: + + ( + (2,) array of last known replisome coordinates in domain, + (2,) array of last known replisome molecule indexes in domain + ) + """ # Sort old boundary coordinates and molecule indexes to find first index # where left boundary is non-negative boundary_coordinates_argsort = np.argsort(boundary_coordinates[:, 0]) From 340f97e931cef105f96c7864aff64c082aa75ebf Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 17 Dec 2024 01:00:03 -0800 Subject: [PATCH 6/8] Ensure uniqueness of unique_indices field --- ecoli/library/initial_conditions.py | 5 +---- ecoli/library/schema.py | 12 ++++++++++++ ecoli/processes/chromosome_structure.py | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ecoli/library/initial_conditions.py b/ecoli/library/initial_conditions.py index 4c94c61dc..6608db23c 100644 --- a/ecoli/library/initial_conditions.py +++ b/ecoli/library/initial_conditions.py @@ -1240,10 +1240,7 @@ def initialize_transcription( unique_molecules["RNA"] = np.concatenate((partial_rnas, full_rnas)) # 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_prefix = np.min(unique_molecules["RNA"]["unique_index"]) unique_molecules["RNA"]["unique_index"] = np.arange( unique_prefix, unique_prefix + len(unique_molecules["RNA"]) ) diff --git a/ecoli/library/schema.py b/ecoli/library/schema.py index 0a3a7ecfc..9b6cbd1f3 100644 --- a/ecoli/library/schema.py +++ b/ecoli/library/schema.py @@ -116,6 +116,18 @@ class MetadataArray(np.ndarray): def __new__(cls, input_array, metadata=None): # Input array should be an array instance obj = np.asarray(input_array).view(cls) + # Ensure unique_index field exists and is unique + if "unique_index" in obj.dtype.names: + if "_entryState" in obj.dtype.names: + unique_indices = obj["unique_index"][obj["_entryState"].view(np.bool_)] + if len(unique_indices) != len(set(unique_indices)): + raise ValueError( + "All elements in the 'unique_index' field must be unique." + ) + else: + raise ValueError("Input array must have an '_entryState' field.") + else: + raise ValueError("Input array must have a 'unique_index' field.") obj.metadata = metadata return obj diff --git a/ecoli/processes/chromosome_structure.py b/ecoli/processes/chromosome_structure.py index 3f8439e2b..fa56bcc34 100644 --- a/ecoli/processes/chromosome_structure.py +++ b/ecoli/processes/chromosome_structure.py @@ -1391,6 +1391,7 @@ def generate_flow(self, config): full_chromosomes.flags.writeable = True full_chromosomes["_entryState"][0] = 1 full_chromosomes["domain_index"][0] = 0 + full_chromosomes["unique_index"][0] = 0 full_chromosomes.flags.writeable = False # Set up chromosome domains chromosome_domains, replisome_idx = get_free_indices( @@ -1399,6 +1400,7 @@ def generate_flow(self, config): chromosome_domains.flags.writeable = True chromosome_domains["_entryState"][replisome_idx] = 1 chromosome_domains["domain_index"][replisome_idx] = np.arange(5) + chromosome_domains["unique_index"][replisome_idx] = np.arange(5) chromosome_domains["child_domains"][replisome_idx] = [ [1, 2], [3, 4], @@ -1413,6 +1415,7 @@ def generate_flow(self, config): oriCs.flags.writeable = True oriCs["_entryState"][oriC_idx] = 1 oriCs["domain_index"][oriC_idx] = [2, 3, 4] + oriCs["unique_index"][oriC_idx] = np.arange(3) oriCs.flags.writeable = False template_initial_state["unique"]["oriC"] = oriCs # Set up replisome for actively replicating domain @@ -1538,6 +1541,7 @@ def generate_flow(self, config): ) chromosomal_segments["domain_index"][segment_idx] = domain_index chromosomal_segments["linking_number"][segment_idx] = linking_number + chromosomal_segments["unique_index"][segment_idx] = np.arange(len(linking_number)) chromosomal_segments.flags.writeable = False template_initial_state["unique"]["chromosomal_segment"] = chromosomal_segments # Since unique numpy updater is an class method, internal From 04ba75d0ca21f719714d832a4f72ca47a7104997 Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 17 Dec 2024 03:02:10 -0800 Subject: [PATCH 7/8] Document unique molecule MetadataArray --- doc/stores.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/stores.rst b/doc/stores.rst index b9f8e2dd1..899127af1 100644 --- a/doc/stores.rst +++ b/doc/stores.rst @@ -336,9 +336,7 @@ molecule). All unique molecules will have the following named fields: 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.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. + Note that unique indices are only unique within a single cell. 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 @@ -352,6 +350,17 @@ molecule). All unique molecules will have the following named fields: changing protein mass of the polypeptide associated with an actively translating ribosome. +.. note:: + Unique molecules are instances of :py:class:`~ecoli.library.schema.MetadataArray`, + a subclass of Numpy arrays that adds a ``metadata`` attribute. This attribute + is used to store the next unique index to be assigned to a new unique molecule. + If you wish to add a custom unique molecule type, after you have + created a structured Numpy array with at least the above attributes, + create a :py:class:`~ecoli.library.schema.MetadataArray` instance from it using + ``MetadataArray(array, next_unique_index)``, where ``array`` is your structured + Numpy array and ``next_unique_index`` is the next unique index to be assigned. + + Initialization ============== See :ref:`initialization`. From 2c56c09b1f9c9fa499375785f62929b765e9d76a Mon Sep 17 00:00:00 2001 From: thalassemia Date: Tue, 17 Dec 2024 03:08:28 -0800 Subject: [PATCH 8/8] Add pre-commit --- .pre-commit-config.yaml | 12 ++++++ README.md | 13 ++++++ pyproject.toml | 3 +- uv.lock | 93 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..9a4ed56d0 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,12 @@ +repos: +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.8.3 + hooks: + # Run the linter. + - id: ruff + types_or: [ python, pyi ] + args: [ --fix ] + # Run the formatter. + - id: ruff-format + types_or: [ python, pyi ] diff --git a/README.md b/README.md index 21f5a06f7..b02c3ab11 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,19 @@ finishes, close and reopen your terminal before continuing with the > **Tip:** If any step in the `nextflow` installation fails, > try rerunning a few times to see if that fixes the issue. +If you are installing the model for active development, we strongly +recommend that you also install the development dependencies using: + + uv sync --frozen --extra dev + +After that, you can run ``uv run pre-commit install`` to install +a pre-commit hook that will run the ``ruff`` linter and formatter +before all of your commits. + +The development dependencies also include ``pytest``, which lets +you run the test suite, and ``mypy``, which can be invoked to +perform static type checking. + ## Test Installation To test your installation, from the top-level of the cloned repository, invoke: diff --git a/pyproject.toml b/pyproject.toml index e67ad7b10..2d48bf796 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,8 @@ dev = [ "pytest", "pytest-cov", "mypy", - "ruff" + "ruff", + "pre-commit", ] docs = [ "Sphinx", diff --git a/uv.lock b/uv.lock index ca9246837..61f3ff1a5 100644 --- a/uv.lock +++ b/uv.lock @@ -3,7 +3,7 @@ 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')", + "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')", ] [[package]] @@ -315,6 +315,15 @@ wheels = [ { 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 = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, +] + [[package]] name = "charset-normalizer" version = "3.4.0" @@ -552,6 +561,15 @@ 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 = "distlib" +version = "0.3.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, +] + [[package]] name = "dnspython" version = "2.7.0" @@ -643,6 +661,15 @@ 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 = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, +] + [[package]] name = "fiona" version = "1.10.1" @@ -943,6 +970,15 @@ 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 = "identify" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/5f/05f0d167be94585d502b4adf8c7af31f1dc0b1c7e14f9938a88fdbbcf4a7/identify-2.6.3.tar.gz", hash = "sha256:62f5dae9b5fef52c84cc188514e9ea4f3f636b1d8799ab5ebc475471f9e47a02", size = 99179 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c9/f5/09644a3ad803fae9eca8efa17e1f2aef380c7f0b02f7ec4e8d446e51d64a/identify-2.6.3-py2.py3-none-any.whl", hash = "sha256:9edba65473324c2ea9684b1f944fe3191db3345e50b6d04571d10ed164f8d7bd", size = 99049 }, +] + [[package]] name = "idna" version = "3.10" @@ -1048,7 +1084,7 @@ name = "ipython" version = "8.30.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "decorator" }, { name = "jedi" }, { name = "matplotlib-inline" }, @@ -1256,7 +1292,7 @@ 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 = "pywin32", marker = "(platform_machine != 'aarch64' and platform_python_implementation != 'PyPy' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_python_implementation != 'PyPy' and platform_system != 'Darwin' and platform_system != 'Linux' 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 } @@ -1311,7 +1347,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1329,7 +1365,7 @@ name = "jupyter-server-terminals" version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { 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 } @@ -1772,6 +1808,15 @@ 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 = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, +] + [[package]] name = "notebook" version = "7.3.1" @@ -2083,6 +2128,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4b/59/cf2e88bebdffb7efb7e4f65f4ec9e293040c313d37e3628db87e4f64dca4/polars-1.17.1-cp39-abi3-win_amd64.whl", hash = "sha256:d38156c8259554cbcb17874d91e6dfa9c404335f08a3307496aadfdee46baa31", size = 35931768 }, ] +[[package]] +name = "pre-commit" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713 }, +] + [[package]] name = "prometheus-client" version = "0.21.1" @@ -2418,7 +2479,7 @@ name = "pytest" version = "8.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "iniconfig" }, { name = "packaging" }, { name = "pluggy" }, @@ -2991,7 +3052,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, { name = "babel" }, - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "docutils" }, { name = "imagesize" }, { name = "jinja2" }, @@ -3263,7 +3324,7 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { name = "tornado" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } @@ -3465,6 +3526,7 @@ dependencies = [ [package.optional-dependencies] dev = [ { name = "mypy" }, + { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "ruff" }, @@ -3503,6 +3565,7 @@ requires-dist = [ { name = "ortools", specifier = "<=9.9.3963" }, { name = "pandas" }, { name = "polars" }, + { name = "pre-commit", marker = "extra == 'dev'" }, { name = "pyarrow" }, { name = "pymunk" }, { name = "pyqt5" }, @@ -3526,6 +3589,20 @@ requires-dist = [ { name = "wheel" }, ] +[[package]] +name = "virtualenv" +version = "20.28.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/75/53316a5a8050069228a2f6d11f32046cfa94fbb6cc3f08703f59b873de2e/virtualenv-20.28.0.tar.gz", hash = "sha256:2c9c3262bb8e7b87ea801d715fae4495e6032450c71d2309be9550e7364049aa", size = 7650368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/f9/0919cf6f1432a8c4baa62511f8f8da8225432d22e83e3476f5be1a1edc6e/virtualenv-20.28.0-py3-none-any.whl", hash = "sha256:23eae1b4516ecd610481eda647f3a7c09aea295055337331bb4e6892ecce47b0", size = 4276702 }, +] + [[package]] name = "vivarium-core" version = "1.6.5"