napistu 0.3.6__py3-none-any.whl → 0.3.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,7 @@ import os
5
5
  import numpy as np
6
6
  import pandas as pd
7
7
  import pytest
8
+ from napistu import identifiers
8
9
  from napistu import sbml_dfs_core
9
10
  from napistu.source import Source
10
11
  from napistu.ingestion import sbml
@@ -25,11 +26,13 @@ from unittest.mock import patch
25
26
  def test_data():
26
27
  """Create test data for SBML integration tests."""
27
28
 
29
+ blank_id = identifiers.Identifiers([])
30
+
28
31
  # Test compartments
29
32
  compartments_df = pd.DataFrame(
30
33
  [
31
- {"c_name": "nucleus", "c_Identifiers": None},
32
- {"c_name": "cytoplasm", "c_Identifiers": None},
34
+ {SBML_DFS.C_NAME: "nucleus", SBML_DFS.C_IDENTIFIERS: blank_id},
35
+ {SBML_DFS.C_NAME: "cytoplasm", SBML_DFS.C_IDENTIFIERS: blank_id},
33
36
  ]
34
37
  )
35
38
 
@@ -37,14 +40,18 @@ def test_data():
37
40
  species_df = pd.DataFrame(
38
41
  [
39
42
  {
40
- "s_name": "TP53",
41
- "s_Identifiers": None,
43
+ SBML_DFS.S_NAME: "TP53",
44
+ SBML_DFS.S_IDENTIFIERS: blank_id,
42
45
  "gene_type": "tumor_suppressor",
43
46
  },
44
- {"s_name": "MDM2", "s_Identifiers": None, "gene_type": "oncogene"},
45
47
  {
46
- "s_name": "CDKN1A",
47
- "s_Identifiers": None,
48
+ SBML_DFS.S_NAME: "MDM2",
49
+ SBML_DFS.S_IDENTIFIERS: blank_id,
50
+ "gene_type": "oncogene",
51
+ },
52
+ {
53
+ SBML_DFS.S_NAME: "CDKN1A",
54
+ SBML_DFS.S_IDENTIFIERS: blank_id,
48
55
  "gene_type": "cell_cycle",
49
56
  },
50
57
  ]
@@ -58,10 +65,10 @@ def test_data():
58
65
  "downstream_name": "CDKN1A",
59
66
  "upstream_compartment": "nucleus",
60
67
  "downstream_compartment": "nucleus",
61
- "r_name": "TP53_activates_CDKN1A",
62
- "sbo_term": "SBO:0000459",
63
- "r_Identifiers": None,
64
- "r_isreversible": False,
68
+ SBML_DFS.R_NAME: "TP53_activates_CDKN1A",
69
+ SBML_DFS.SBO_TERM: "SBO:0000459",
70
+ SBML_DFS.R_IDENTIFIERS: blank_id,
71
+ SBML_DFS.R_ISREVERSIBLE: False,
65
72
  "confidence": 0.95,
66
73
  },
67
74
  {
@@ -69,10 +76,10 @@ def test_data():
69
76
  "downstream_name": "TP53",
70
77
  "upstream_compartment": "cytoplasm",
71
78
  "downstream_compartment": "nucleus",
72
- "r_name": "MDM2_inhibits_TP53",
73
- "sbo_term": "SBO:0000020",
74
- "r_Identifiers": None,
75
- "r_isreversible": False,
79
+ SBML_DFS.R_NAME: "MDM2_inhibits_TP53",
80
+ SBML_DFS.SBO_TERM: "SBO:0000020",
81
+ SBML_DFS.R_IDENTIFIERS: blank_id,
82
+ SBML_DFS.R_ISREVERSIBLE: False,
76
83
  "confidence": 0.87,
77
84
  },
78
85
  ]
@@ -611,3 +618,146 @@ def test_sbml_custom_stoichiometry(test_data):
611
618
  stoichiometries = result.reaction_species["stoichiometry"].unique()
612
619
  assert 2 in stoichiometries # upstream
613
620
  assert 3 in stoichiometries # downstream
621
+
622
+
623
+ def test_validate_schema_missing(minimal_valid_sbml_dfs):
624
+ """Test validation fails when schema is missing."""
625
+ delattr(minimal_valid_sbml_dfs, "schema")
626
+ with pytest.raises(ValueError, match="No schema found"):
627
+ minimal_valid_sbml_dfs.validate()
628
+
629
+
630
+ def test_validate_table(minimal_valid_sbml_dfs):
631
+ """Test _validate_table fails for various table structure issues."""
632
+ # Wrong index name
633
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
634
+ sbml_dfs.species.index.name = "wrong_name"
635
+ with pytest.raises(ValueError, match="the index name for species was not the pk"):
636
+ sbml_dfs.validate()
637
+
638
+ # Duplicate primary keys
639
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
640
+ duplicate_species = pd.DataFrame(
641
+ {
642
+ SBML_DFS.S_NAME: ["ATP", "ADP"],
643
+ SBML_DFS.S_IDENTIFIERS: [
644
+ identifiers.Identifiers([]),
645
+ identifiers.Identifiers([]),
646
+ ],
647
+ SBML_DFS.S_SOURCE: [Source(init=True), Source(init=True)],
648
+ },
649
+ index=pd.Index(["S00001", "S00001"], name=SBML_DFS.S_ID),
650
+ )
651
+ sbml_dfs.species = duplicate_species
652
+ with pytest.raises(ValueError, match="primary keys were duplicated"):
653
+ sbml_dfs.validate()
654
+
655
+ # Missing required variables
656
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
657
+ sbml_dfs.species = sbml_dfs.species.drop(columns=[SBML_DFS.S_NAME])
658
+ with pytest.raises(ValueError, match="Missing .+ required variables for species"):
659
+ sbml_dfs.validate()
660
+
661
+ # Empty table
662
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
663
+ sbml_dfs.species = pd.DataFrame(
664
+ {
665
+ SBML_DFS.S_NAME: [],
666
+ SBML_DFS.S_IDENTIFIERS: [],
667
+ SBML_DFS.S_SOURCE: [],
668
+ },
669
+ index=pd.Index([], name=SBML_DFS.S_ID),
670
+ )
671
+ with pytest.raises(ValueError, match="species contained no entries"):
672
+ sbml_dfs.validate()
673
+
674
+
675
+ def test_check_pk_fk_correspondence(minimal_valid_sbml_dfs):
676
+ """Test _check_pk_fk_correspondence fails for various foreign key issues."""
677
+ # Missing species reference
678
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
679
+ sbml_dfs.compartmentalized_species[SBML_DFS.S_ID] = ["S99999"]
680
+ with pytest.raises(
681
+ ValueError,
682
+ match="s_id values were found in compartmentalized_species but missing from species",
683
+ ):
684
+ sbml_dfs.validate()
685
+
686
+ # Missing compartment reference
687
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
688
+ sbml_dfs.compartmentalized_species[SBML_DFS.C_ID] = ["C99999"]
689
+ with pytest.raises(
690
+ ValueError,
691
+ match="c_id values were found in compartmentalized_species but missing from compartments",
692
+ ):
693
+ sbml_dfs.validate()
694
+
695
+ # Null foreign keys
696
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
697
+ sbml_dfs.compartmentalized_species[SBML_DFS.S_ID] = [None]
698
+ with pytest.raises(
699
+ ValueError, match="compartmentalized_species included missing s_id values"
700
+ ):
701
+ sbml_dfs.validate()
702
+
703
+
704
+ def test_validate_reaction_species(minimal_valid_sbml_dfs):
705
+ """Test _validate_reaction_species fails for various reaction species issues."""
706
+ # Null stoichiometry
707
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
708
+ sbml_dfs.reaction_species[SBML_DFS.STOICHIOMETRY] = [None]
709
+ with pytest.raises(ValueError, match="All reaction_species.* must be not null"):
710
+ sbml_dfs.validate()
711
+
712
+ # Null SBO terms
713
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
714
+ sbml_dfs.reaction_species[SBML_DFS.SBO_TERM] = [None]
715
+ with pytest.raises(
716
+ ValueError, match="sbo_terms were None; all terms should be defined"
717
+ ):
718
+ sbml_dfs.validate()
719
+
720
+ # Invalid SBO terms
721
+ sbml_dfs = minimal_valid_sbml_dfs.copy()
722
+ sbml_dfs.reaction_species[SBML_DFS.SBO_TERM] = ["INVALID_SBO_TERM"]
723
+ with pytest.raises(ValueError, match="sbo_terms were not defined"):
724
+ sbml_dfs.validate()
725
+
726
+
727
+ def test_validate_identifiers(minimal_valid_sbml_dfs):
728
+ """Test _validate_identifiers fails when identifiers are missing."""
729
+ minimal_valid_sbml_dfs.species[SBML_DFS.S_IDENTIFIERS] = [None]
730
+ with pytest.raises(ValueError, match="species has .+ missing ids"):
731
+ minimal_valid_sbml_dfs.validate()
732
+
733
+
734
+ def test_validate_sources(minimal_valid_sbml_dfs):
735
+ """Test _validate_sources fails when sources are missing."""
736
+ minimal_valid_sbml_dfs.species[SBML_DFS.S_SOURCE] = [None]
737
+ with pytest.raises(ValueError, match="species has .+ missing sources"):
738
+ minimal_valid_sbml_dfs.validate()
739
+
740
+
741
+ def test_validate_species_data(minimal_valid_sbml_dfs):
742
+ """Test _validate_species_data fails when species_data has invalid structure."""
743
+ invalid_data = pd.DataFrame(
744
+ {"extra_info": ["test"]}, index=pd.Index(["S99999"], name=SBML_DFS.S_ID)
745
+ ) # Non-existent species
746
+ minimal_valid_sbml_dfs.species_data["invalid"] = invalid_data
747
+ with pytest.raises(ValueError, match="species data invalid was invalid"):
748
+ minimal_valid_sbml_dfs.validate()
749
+
750
+
751
+ def test_validate_reactions_data(minimal_valid_sbml_dfs):
752
+ """Test _validate_reactions_data fails when reactions_data has invalid structure."""
753
+ invalid_data = pd.DataFrame(
754
+ {"extra_info": ["test"]}, index=pd.Index(["R99999"], name=SBML_DFS.R_ID)
755
+ ) # Non-existent reaction
756
+ minimal_valid_sbml_dfs.reactions_data["invalid"] = invalid_data
757
+ with pytest.raises(ValueError, match="reactions data invalid was invalid"):
758
+ minimal_valid_sbml_dfs.validate()
759
+
760
+
761
+ def test_validate_passes_with_valid_data(minimal_valid_sbml_dfs):
762
+ """Test that validation passes with completely valid data."""
763
+ minimal_valid_sbml_dfs.validate() # Should not raise any exceptions
tests/test_utils.py CHANGED
@@ -686,3 +686,22 @@ def test_safe_fill():
686
686
  "a_very_long\nstringggg",
687
687
  "",
688
688
  ]
689
+
690
+
691
+ def test_update_pathological_names():
692
+
693
+ # All numeric
694
+ s = pd.Series(["1", "2", "3"])
695
+ out = utils.update_pathological_names(s, "prefix_")
696
+ assert all(x.startswith("prefix_") for x in out)
697
+ assert list(out) == ["prefix_1", "prefix_2", "prefix_3"]
698
+
699
+ # Mixed numeric and non-numeric
700
+ s2 = pd.Series(["1", "foo", "3"])
701
+ out2 = utils.update_pathological_names(s2, "prefix_")
702
+ assert list(out2) == ["1", "foo", "3"]
703
+
704
+ # All non-numeric
705
+ s3 = pd.Series(["foo", "bar", "baz"])
706
+ out3 = utils.update_pathological_names(s3, "prefix_")
707
+ assert list(out3) == ["foo", "bar", "baz"]