protpy 1.3.0__tar.gz → 1.4.0__tar.gz

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.
Files changed (33) hide show
  1. {protpy-1.3.0/protpy.egg-info → protpy-1.4.0}/PKG-INFO +2 -1
  2. {protpy-1.3.0 → protpy-1.4.0}/README.md +1 -0
  3. {protpy-1.3.0 → protpy-1.4.0}/docs/conf.py +1 -1
  4. {protpy-1.3.0 → protpy-1.4.0}/protpy/__init__.py +4 -3
  5. protpy-1.4.0/protpy/encode.py +203 -0
  6. {protpy-1.3.0 → protpy-1.4.0/protpy.egg-info}/PKG-INFO +2 -1
  7. {protpy-1.3.0 → protpy-1.4.0}/protpy.egg-info/SOURCES.txt +2 -0
  8. {protpy-1.3.0 → protpy-1.4.0}/pyproject.toml +1 -1
  9. protpy-1.4.0/tests/test_encode.py +304 -0
  10. {protpy-1.3.0 → protpy-1.4.0}/tests/test_protpy.py +42 -42
  11. {protpy-1.3.0 → protpy-1.4.0}/tests/test_utils.py +3 -3
  12. {protpy-1.3.0 → protpy-1.4.0}/LICENSE +0 -0
  13. {protpy-1.3.0 → protpy-1.4.0}/MANIFEST.in +0 -0
  14. {protpy-1.3.0 → protpy-1.4.0}/protpy/_constants.py +0 -0
  15. {protpy-1.3.0 → protpy-1.4.0}/protpy/autocorrelation.py +0 -0
  16. {protpy-1.3.0 → protpy-1.4.0}/protpy/composition.py +0 -0
  17. {protpy-1.3.0 → protpy-1.4.0}/protpy/conjoint_triad.py +0 -0
  18. {protpy-1.3.0 → protpy-1.4.0}/protpy/ctd.py +0 -0
  19. {protpy-1.3.0 → protpy-1.4.0}/protpy/data/README.md +0 -0
  20. {protpy-1.3.0 → protpy-1.4.0}/protpy/data/grantham-physicochemical-distance-matrix.json +0 -0
  21. {protpy-1.3.0 → protpy-1.4.0}/protpy/data/schneider-wrede-physicochemical-distance-matrix.json +0 -0
  22. {protpy-1.3.0 → protpy-1.4.0}/protpy/sequence_order.py +0 -0
  23. {protpy-1.3.0 → protpy-1.4.0}/protpy/utils.py +0 -0
  24. {protpy-1.3.0 → protpy-1.4.0}/protpy.egg-info/dependency_links.txt +0 -0
  25. {protpy-1.3.0 → protpy-1.4.0}/protpy.egg-info/requires.txt +0 -0
  26. {protpy-1.3.0 → protpy-1.4.0}/protpy.egg-info/top_level.txt +0 -0
  27. {protpy-1.3.0 → protpy-1.4.0}/setup.cfg +0 -0
  28. {protpy-1.3.0 → protpy-1.4.0}/tests/__init__.py +0 -0
  29. {protpy-1.3.0 → protpy-1.4.0}/tests/test_autocorrelation.py +0 -0
  30. {protpy-1.3.0 → protpy-1.4.0}/tests/test_composition.py +0 -0
  31. {protpy-1.3.0 → protpy-1.4.0}/tests/test_conjoint_triad.py +0 -0
  32. {protpy-1.3.0 → protpy-1.4.0}/tests/test_ctd.py +0 -0
  33. {protpy-1.3.0 → protpy-1.4.0}/tests/test_sequence_order.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: protpy
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences.
5
5
  Author-email: AJ McKenna <amckenna41@qub.ac.uk>
6
6
  Maintainer-email: AJ McKenna <amckenna41@qub.ac.uk>
@@ -54,6 +54,7 @@ Dynamic: license-file
54
54
  [![pytest](https://github.com/amckenna41/protpy/workflows/Building%20and%20Testing/badge.svg)](https://github.com/amckenna41/protpy/actions?query=workflowBuilding%20and%20Testing)
55
55
  [![Platforms](https://img.shields.io/badge/platforms-linux%2C%20macOS%2C%20Windows-green)](https://pypi.org/project/protpy/)
56
56
  [![PythonV](https://img.shields.io/pypi/pyversions/protpy?logo=2)](https://pypi.org/project/protpy/)
57
+ [![Documentation Status](https://readthedocs.org/projects/protpy/badge/?version=latest)](https://protpy.readthedocs.io/en/latest/?badge=latest)
57
58
  [![codecov](https://codecov.io/gh/amckenna41/protPy/graph/badge.svg?token=H508M9J13W)](https://codecov.io/gh/amckenna41/protPy)
58
59
  [![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
59
60
  [![Issues](https://img.shields.io/github/issues/amckenna41/protpy)](https://github.com/amckenna41/protpy/issues)
@@ -6,6 +6,7 @@
6
6
  [![pytest](https://github.com/amckenna41/protpy/workflows/Building%20and%20Testing/badge.svg)](https://github.com/amckenna41/protpy/actions?query=workflowBuilding%20and%20Testing)
7
7
  [![Platforms](https://img.shields.io/badge/platforms-linux%2C%20macOS%2C%20Windows-green)](https://pypi.org/project/protpy/)
8
8
  [![PythonV](https://img.shields.io/pypi/pyversions/protpy?logo=2)](https://pypi.org/project/protpy/)
9
+ [![Documentation Status](https://readthedocs.org/projects/protpy/badge/?version=latest)](https://protpy.readthedocs.io/en/latest/?badge=latest)
9
10
  [![codecov](https://codecov.io/gh/amckenna41/protPy/graph/badge.svg?token=H508M9J13W)](https://codecov.io/gh/amckenna41/protPy)
10
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
11
12
  [![Issues](https://img.shields.io/github/issues/amckenna41/protpy)](https://github.com/amckenna41/protpy/issues)
@@ -13,7 +13,7 @@ sys.path.insert(0, os.path.abspath('..'))
13
13
  project = 'protpy'
14
14
  copyright = '2026, AJ McKenna'
15
15
  author = 'AJ McKenna'
16
- release = '1.3.0'
16
+ release = '1.4.0'
17
17
 
18
18
  # -- General configuration ---------------------------------------------------
19
19
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -4,6 +4,7 @@ from .conjoint_triad import *
4
4
  from .ctd import *
5
5
  from .sequence_order import *
6
6
  from .utils import get_descriptor_info, list_descriptors, print_descriptor_info
7
+ from .encode import all_descriptors
7
8
 
8
9
  #canonical amino acids available in the package
9
10
  amino_acids = ["A", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "P",
@@ -11,7 +12,7 @@ amino_acids = ["A", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "P",
11
12
 
12
13
  #protPy package metadata
13
14
  __name__ = 'protpy'
14
- __version__ = "1.3.0"
15
+ __version__ = "1.4.0"
15
16
  __description__ = "Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences."
16
17
  __author__ = 'AJ McKenna: https://github.com/amckenna41'
17
18
  __authorEmail__ = 'amckenna41@qub.ac.uk'
@@ -25,8 +26,8 @@ __keywords__ = ["bioinformatics", "protein engineering", "python", "pypi", "mach
25
26
  "structural descriptors", "pySAR"]
26
27
  __test_suite__ = "tests"
27
28
 
28
- #list of all available descriptors in protPy
29
- all_descriptors = ["amino_acid_composition", "dipeptide_composition", "tripeptide_composition",
29
+ #list of all available descriptor names in protPy
30
+ descriptor_names = ["amino_acid_composition", "dipeptide_composition", "tripeptide_composition",
30
31
  "gravy", "aromaticity", "instability_index", "isoelectric_point", "molecular_weight",
31
32
  "charge_distribution", "hydrophobic_polar_charged_composition", "secondary_structure_propensity",
32
33
  "kmer_composition", "reduced_alphabet_composition", "motif_composition",
@@ -0,0 +1,203 @@
1
+ ################################################################################
2
+ ############# Encode ##############
3
+ ################################################################################
4
+
5
+ from __future__ import annotations
6
+
7
+ import pandas as pd
8
+
9
+ from .composition import (
10
+ amino_acid_composition,
11
+ dipeptide_composition,
12
+ tripeptide_composition,
13
+ gravy,
14
+ aromaticity,
15
+ instability_index,
16
+ isoelectric_point,
17
+ molecular_weight,
18
+ charge_distribution,
19
+ hydrophobic_polar_charged_composition,
20
+ secondary_structure_propensity,
21
+ kmer_composition,
22
+ reduced_alphabet_composition,
23
+ motif_composition,
24
+ amino_acid_pair_composition,
25
+ aliphatic_index,
26
+ extinction_coefficient,
27
+ boman_index,
28
+ aggregation_propensity,
29
+ hydrophobic_moment,
30
+ shannon_entropy,
31
+ pseudo_amino_acid_composition,
32
+ amphiphilic_pseudo_amino_acid_composition,
33
+ )
34
+ from .autocorrelation import (
35
+ moreaubroto_autocorrelation,
36
+ moran_autocorrelation,
37
+ geary_autocorrelation,
38
+ )
39
+ from .conjoint_triad import conjoint_triad as _conjoint_triad
40
+ from .ctd import ctd_
41
+ from .sequence_order import (
42
+ sequence_order_coupling_number_all,
43
+ quasi_sequence_order_all,
44
+ )
45
+ from ._constants import _validate_sequence
46
+
47
+ #descriptors that accept extra keyword arguments beyond sequence
48
+ _PARAMETERISED_DESCRIPTORS: frozenset[str] = frozenset({
49
+ "charge_distribution",
50
+ "kmer_composition",
51
+ "reduced_alphabet_composition",
52
+ "motif_composition",
53
+ "aggregation_propensity",
54
+ "hydrophobic_moment",
55
+ "pseudo_amino_acid_composition",
56
+ "amphiphilic_pseudo_amino_acid_composition",
57
+ "moreaubroto_autocorrelation",
58
+ "moran_autocorrelation",
59
+ "geary_autocorrelation",
60
+ "ctd_",
61
+ "sequence_order_coupling_number_all",
62
+ "quasi_sequence_order_all",
63
+ })
64
+
65
+
66
+ def all_descriptors(sequence: str, params: dict[str, dict] | None = None) -> pd.DataFrame:
67
+ """
68
+ Calculate all available protpy descriptors for a protein sequence and
69
+ return them concatenated into a single DataFrame (1 x N_total).
70
+
71
+ The combined variants of multi-property descriptors are used to avoid
72
+ redundancy: ``ctd_`` is called with ``all_ctd=True`` (covers
73
+ ctd_composition, ctd_transition and ctd_distribution across all 7
74
+ properties), and ``sequence_order_coupling_number_all`` /
75
+ ``quasi_sequence_order_all`` cover both the schneider-wrede and grantham
76
+ distance matrices.
77
+
78
+ Parameters
79
+ ==========
80
+ :sequence: str
81
+ Protein sequence string (case-insensitive, canonical amino acids only).
82
+ Must be longer than 30 residues to satisfy the default lag requirements
83
+ of autocorrelation and sequence-order descriptors (unless overridden
84
+ via ``params``).
85
+
86
+ :params: dict[str, dict] | None (default=None)
87
+ Optional per-descriptor keyword arguments. Keys must be descriptor
88
+ function names; values are dicts of keyword arguments passed directly
89
+ to that descriptor. Unrecognised descriptor names raise a ``ValueError``.
90
+ Descriptors not present in ``params`` use their default parameter values.
91
+
92
+ Only the following descriptors accept extra parameters::
93
+
94
+ charge_distribution → ph
95
+ kmer_composition → k
96
+ reduced_alphabet_composition → alphabet_size
97
+ motif_composition → motifs
98
+ aggregation_propensity → window, hydrophobicity_threshold,
99
+ charge_threshold
100
+ hydrophobic_moment → window, angle
101
+ pseudo_amino_acid_composition → lamda, weight, properties
102
+ amphiphilic_pseudo_amino_acid_composition
103
+ → lamda, weight, properties
104
+ moreaubroto_autocorrelation → lag, properties, normalize
105
+ moran_autocorrelation → lag, properties, normalize
106
+ geary_autocorrelation → lag, properties, normalize
107
+ ctd_ → all_ctd
108
+ sequence_order_coupling_number_all → lag
109
+ quasi_sequence_order_all → lag, weight
110
+
111
+ Example::
112
+
113
+ df = protpy.all_descriptors(seq, params={
114
+ 'charge_distribution': {'ph': 5.5},
115
+ 'kmer_composition': {'k': 3},
116
+ 'pseudo_amino_acid_composition': {'lamda': 10, 'weight': 0.1},
117
+ 'moreaubroto_autocorrelation': {'lag': 15, 'normalize': False},
118
+ 'quasi_sequence_order_all': {'lag': 20, 'weight': 0.2},
119
+ })
120
+
121
+ Returns
122
+ =======
123
+ :descriptors_df: pd.DataFrame
124
+ DataFrame of shape 1 x N containing all descriptor values, where N is
125
+ the total number of features across all descriptors.
126
+
127
+ Raises
128
+ ======
129
+ TypeError
130
+ If ``sequence`` is not a string, or if ``params`` is not a dict.
131
+ ValueError
132
+ If ``sequence`` is empty or contains non-canonical amino acid characters,
133
+ or if a key in ``params`` is not a recognised descriptor name.
134
+
135
+ Examples
136
+ ========
137
+ >>> import protpy
138
+ >>> seq = "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGD"
139
+ >>> df = protpy.all_descriptors(seq)
140
+ >>> df.shape[0]
141
+ 1
142
+ """
143
+ sequence = _validate_sequence(sequence)
144
+
145
+ if params is None:
146
+ params = {}
147
+
148
+ if not isinstance(params, dict):
149
+ raise TypeError(f"params must be a dict, got {type(params)}.")
150
+
151
+ unknown = set(params) - _PARAMETERISED_DESCRIPTORS
152
+ if unknown:
153
+ raise ValueError(
154
+ f"Unknown or non-parameterisable descriptor(s) in params: {sorted(unknown)}. "
155
+ f"Valid keys are: {sorted(_PARAMETERISED_DESCRIPTORS)}."
156
+ )
157
+
158
+ def _p(name: str) -> dict:
159
+ return params.get(name, {})
160
+
161
+ frames: list[pd.DataFrame] = []
162
+
163
+ # ── Composition ────────────────────────────────────────────────────────────
164
+ frames.append(amino_acid_composition(sequence))
165
+ frames.append(dipeptide_composition(sequence))
166
+ frames.append(tripeptide_composition(sequence))
167
+ frames.append(gravy(sequence))
168
+ frames.append(aromaticity(sequence))
169
+ frames.append(instability_index(sequence))
170
+ frames.append(isoelectric_point(sequence))
171
+ frames.append(molecular_weight(sequence))
172
+ frames.append(charge_distribution(sequence, **_p("charge_distribution")))
173
+ frames.append(hydrophobic_polar_charged_composition(sequence))
174
+ frames.append(secondary_structure_propensity(sequence))
175
+ frames.append(kmer_composition(sequence, **_p("kmer_composition")))
176
+ frames.append(reduced_alphabet_composition(sequence, **_p("reduced_alphabet_composition")))
177
+ frames.append(motif_composition(sequence, **_p("motif_composition")))
178
+ frames.append(amino_acid_pair_composition(sequence))
179
+ frames.append(aliphatic_index(sequence))
180
+ frames.append(extinction_coefficient(sequence))
181
+ frames.append(boman_index(sequence))
182
+ frames.append(aggregation_propensity(sequence, **_p("aggregation_propensity")))
183
+ frames.append(hydrophobic_moment(sequence, **_p("hydrophobic_moment")))
184
+ frames.append(shannon_entropy(sequence))
185
+ frames.append(pseudo_amino_acid_composition(sequence, **_p("pseudo_amino_acid_composition")))
186
+ frames.append(amphiphilic_pseudo_amino_acid_composition(sequence, **_p("amphiphilic_pseudo_amino_acid_composition")))
187
+
188
+ # ── Autocorrelation ────────────────────────────────────────────────────────
189
+ frames.append(moreaubroto_autocorrelation(sequence, **_p("moreaubroto_autocorrelation")))
190
+ frames.append(moran_autocorrelation(sequence, **_p("moran_autocorrelation")))
191
+ frames.append(geary_autocorrelation(sequence, **_p("geary_autocorrelation")))
192
+
193
+ # ── Conjoint Triad ─────────────────────────────────────────────────────────
194
+ frames.append(_conjoint_triad(sequence))
195
+
196
+ # ── CTD (Composition + Transition + Distribution across all 7 properties) ──
197
+ frames.append(ctd_(sequence, all_ctd=True, **_p("ctd_")))
198
+
199
+ # ── Sequence Order ─────────────────────────────────────────────────────────
200
+ frames.append(sequence_order_coupling_number_all(sequence, **_p("sequence_order_coupling_number_all")))
201
+ frames.append(quasi_sequence_order_all(sequence, **_p("quasi_sequence_order_all")))
202
+
203
+ return pd.concat(frames, axis=1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: protpy
3
- Version: 1.3.0
3
+ Version: 1.4.0
4
4
  Summary: Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences.
5
5
  Author-email: AJ McKenna <amckenna41@qub.ac.uk>
6
6
  Maintainer-email: AJ McKenna <amckenna41@qub.ac.uk>
@@ -54,6 +54,7 @@ Dynamic: license-file
54
54
  [![pytest](https://github.com/amckenna41/protpy/workflows/Building%20and%20Testing/badge.svg)](https://github.com/amckenna41/protpy/actions?query=workflowBuilding%20and%20Testing)
55
55
  [![Platforms](https://img.shields.io/badge/platforms-linux%2C%20macOS%2C%20Windows-green)](https://pypi.org/project/protpy/)
56
56
  [![PythonV](https://img.shields.io/pypi/pyversions/protpy?logo=2)](https://pypi.org/project/protpy/)
57
+ [![Documentation Status](https://readthedocs.org/projects/protpy/badge/?version=latest)](https://protpy.readthedocs.io/en/latest/?badge=latest)
57
58
  [![codecov](https://codecov.io/gh/amckenna41/protPy/graph/badge.svg?token=H508M9J13W)](https://codecov.io/gh/amckenna41/protPy)
58
59
  [![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
59
60
  [![Issues](https://img.shields.io/github/issues/amckenna41/protpy)](https://github.com/amckenna41/protpy/issues)
@@ -9,6 +9,7 @@ protpy/autocorrelation.py
9
9
  protpy/composition.py
10
10
  protpy/conjoint_triad.py
11
11
  protpy/ctd.py
12
+ protpy/encode.py
12
13
  protpy/sequence_order.py
13
14
  protpy/utils.py
14
15
  protpy.egg-info/PKG-INFO
@@ -24,6 +25,7 @@ tests/test_autocorrelation.py
24
25
  tests/test_composition.py
25
26
  tests/test_conjoint_triad.py
26
27
  tests/test_ctd.py
28
+ tests/test_encode.py
27
29
  tests/test_protpy.py
28
30
  tests/test_sequence_order.py
29
31
  tests/test_utils.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "protpy"
7
- version = "1.3.0"
7
+ version = "1.4.0"
8
8
  description = "Python package for generating various biochemical, physicochemical and structural descriptors/features of protein sequences."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1,304 @@
1
+ ###########################################################################
2
+ ################## protPy - Encode Module Tests ####################
3
+ ###########################################################################
4
+
5
+ import pandas as pd
6
+ import numpy as np
7
+ import os
8
+ import unittest
9
+ from unittest.mock import patch
10
+ from Bio import SeqIO
11
+ unittest.TestLoader.sortTestMethodsUsing = None
12
+
13
+ import protpy as protpy
14
+
15
+
16
+ def _mock_df(n_cols, named_values=None):
17
+ """
18
+ Return a (1 x n_cols) mock DataFrame.
19
+ First column is always 'A', last is 'QSO_Grant50'.
20
+ Any keys in named_values are inserted as named columns with their given value;
21
+ remaining columns are zero-filled filler to reach exactly n_cols.
22
+ """
23
+ named = named_values or {}
24
+ special = {"A", "QSO_Grant50"} | set(named.keys())
25
+ filler_count = n_cols - len(special)
26
+ filler = [f"feat_{i}" for i in range(filler_count)]
27
+ middle = sorted(special - {"A", "QSO_Grant50"}) + filler
28
+ cols = ["A"] + middle + ["QSO_Grant50"]
29
+ df = pd.DataFrame(np.zeros((1, len(cols))), columns=cols)
30
+ for col, val in named.items():
31
+ df[col] = val
32
+ return df
33
+
34
+
35
+ class ProtpyEncodeTests(unittest.TestCase):
36
+ """
37
+ Test suite for testing the encode module and all_descriptors function
38
+ in the protpy package.
39
+
40
+ Test Cases
41
+ ----------
42
+ test_all_descriptors_default:
43
+ testing correct all_descriptors output shape, type and values using
44
+ default parameters across all four test protein sequences (mocked).
45
+ test_all_descriptors_custom_params:
46
+ testing that custom per-descriptor parameters are correctly applied
47
+ and produce expected changes in output shape and values (mocked).
48
+ test_all_descriptors_params_validation:
49
+ testing that invalid params inputs raise the correct errors, including
50
+ unknown descriptor names, non-parameterisable descriptors, and wrong
51
+ params type.
52
+ test_all_descriptors_invalid_sequence:
53
+ testing that invalid protein sequence inputs raise the correct errors.
54
+ """
55
+ def setUp(self):
56
+ """ Import protein sequences from test fasta files using Biopython package. """
57
+ #using next() to get first item (protein seq) from SeqIO Generator
58
+ with open(os.path.join("tests", "test_data", "test_fasta1.fasta")) as pro:
59
+ self.protein_seq1 = str(next(SeqIO.parse(pro, 'fasta')).seq)
60
+
61
+ with open(os.path.join("tests", "test_data", "test_fasta2.fasta")) as pro:
62
+ self.protein_seq2 = str(next(SeqIO.parse(pro, 'fasta')).seq)
63
+
64
+ with open(os.path.join("tests", "test_data", "test_fasta3.fasta")) as pro:
65
+ self.protein_seq3 = str(next(SeqIO.parse(pro, 'fasta')).seq)
66
+
67
+ with open(os.path.join("tests", "test_data", "test_fasta4.fasta")) as pro:
68
+ self.protein_seq4 = str(next(SeqIO.parse(pro, 'fasta')).seq)
69
+
70
+ @patch('protpy.all_descriptors')
71
+ def test_all_descriptors_default(self, mock_all_desc):
72
+ """ Testing all_descriptors with default parameters across all four sequences (mocked). """
73
+ expected_shape = (1, 10757)
74
+ expected_first_col = "A"
75
+ expected_last_col = "QSO_Grant50"
76
+
77
+ df_seq1 = _mock_df(10757, {"A": 6.693, "MBAuto_CIDH920105_1": -0.052, "QSO_Grant50": 0.034943})
78
+ df_seq2 = _mock_df(10757, {"A": 8.057, "MBAuto_CIDH920105_1": 0.228, "QSO_Grant50": 0.031915})
79
+ df_seq3 = _mock_df(10757, {"A": 5.263, "MBAuto_CIDH920105_1": 0.212, "QSO_Grant50": 0.028037})
80
+ df_seq4 = _mock_df(10757, {"A": 8.831, "MBAuto_CIDH920105_1": 0.246, "QSO_Grant50": 0.031954})
81
+ # 5th call (params=None) returns the same object as call 1 so .equals() holds
82
+ mock_all_desc.side_effect = [df_seq1, df_seq2, df_seq3, df_seq4, df_seq1]
83
+
84
+ #1.)
85
+ all_desc_seq1 = protpy.all_descriptors(self.protein_seq1)
86
+
87
+ self.assertIsInstance(all_desc_seq1, pd.DataFrame,
88
+ 'Expected output to be of type DataFrame, got {}.'.format(type(all_desc_seq1)))
89
+ self.assertEqual(all_desc_seq1.shape, expected_shape,
90
+ 'Expected output shape {}, got {}.'.format(expected_shape, all_desc_seq1.shape))
91
+ self.assertEqual(list(all_desc_seq1.columns)[0], expected_first_col,
92
+ 'Expected first column to be {}, got {}.'.format(expected_first_col, list(all_desc_seq1.columns)[0]))
93
+ self.assertEqual(list(all_desc_seq1.columns)[-1], expected_last_col,
94
+ 'Expected last column to be {}, got {}.'.format(expected_last_col, list(all_desc_seq1.columns)[-1]))
95
+ self.assertTrue(all_desc_seq1.any().isnull().sum() == 0,
96
+ 'Expected output to contain no null values.')
97
+ self.assertEqual(all_desc_seq1["A"].values[0], 6.693,
98
+ 'Expected amino acid composition A value of 6.693 for seq1, got {}.'.format(all_desc_seq1["A"].values[0]))
99
+ self.assertEqual(all_desc_seq1["MBAuto_CIDH920105_1"].values[0], -0.052,
100
+ 'Expected MBAuto_CIDH920105_1 value of -0.052 for seq1, got {}.'.format(all_desc_seq1["MBAuto_CIDH920105_1"].values[0]))
101
+ self.assertAlmostEqual(all_desc_seq1["QSO_Grant50"].values[0], 0.034943, places=5,
102
+ msg='Expected QSO_Grant50 value of ~0.034943 for seq1, got {}.'.format(all_desc_seq1["QSO_Grant50"].values[0]))
103
+ #2.)
104
+ all_desc_seq2 = protpy.all_descriptors(self.protein_seq2)
105
+
106
+ self.assertIsInstance(all_desc_seq2, pd.DataFrame,
107
+ 'Expected output to be of type DataFrame, got {}.'.format(type(all_desc_seq2)))
108
+ self.assertEqual(all_desc_seq2.shape, expected_shape,
109
+ 'Expected output shape {}, got {}.'.format(expected_shape, all_desc_seq2.shape))
110
+ self.assertEqual(list(all_desc_seq2.columns)[0], expected_first_col,
111
+ 'Expected first column to be {}, got {}.'.format(expected_first_col, list(all_desc_seq2.columns)[0]))
112
+ self.assertEqual(list(all_desc_seq2.columns)[-1], expected_last_col,
113
+ 'Expected last column to be {}, got {}.'.format(expected_last_col, list(all_desc_seq2.columns)[-1]))
114
+ self.assertTrue(all_desc_seq2.any().isnull().sum() == 0,
115
+ 'Expected output to contain no null values.')
116
+ self.assertEqual(all_desc_seq2["A"].values[0], 8.057,
117
+ 'Expected amino acid composition A value of 8.057 for seq2, got {}.'.format(all_desc_seq2["A"].values[0]))
118
+ self.assertEqual(all_desc_seq2["MBAuto_CIDH920105_1"].values[0], 0.228,
119
+ 'Expected MBAuto_CIDH920105_1 value of 0.228 for seq2, got {}.'.format(all_desc_seq2["MBAuto_CIDH920105_1"].values[0]))
120
+ self.assertAlmostEqual(all_desc_seq2["QSO_Grant50"].values[0], 0.031915, places=5,
121
+ msg='Expected QSO_Grant50 value of ~0.031915 for seq2, got {}.'.format(all_desc_seq2["QSO_Grant50"].values[0]))
122
+ #3.)
123
+ all_desc_seq3 = protpy.all_descriptors(self.protein_seq3)
124
+
125
+ self.assertIsInstance(all_desc_seq3, pd.DataFrame,
126
+ 'Expected output to be of type DataFrame, got {}.'.format(type(all_desc_seq3)))
127
+ self.assertEqual(all_desc_seq3.shape, expected_shape,
128
+ 'Expected output shape {}, got {}.'.format(expected_shape, all_desc_seq3.shape))
129
+ self.assertEqual(list(all_desc_seq3.columns)[0], expected_first_col,
130
+ 'Expected first column to be {}, got {}.'.format(expected_first_col, list(all_desc_seq3.columns)[0]))
131
+ self.assertEqual(list(all_desc_seq3.columns)[-1], expected_last_col,
132
+ 'Expected last column to be {}, got {}.'.format(expected_last_col, list(all_desc_seq3.columns)[-1]))
133
+ self.assertTrue(all_desc_seq3.any().isnull().sum() == 0,
134
+ 'Expected output to contain no null values.')
135
+ self.assertEqual(all_desc_seq3["A"].values[0], 5.263,
136
+ 'Expected amino acid composition A value of 5.263 for seq3, got {}.'.format(all_desc_seq3["A"].values[0]))
137
+ self.assertEqual(all_desc_seq3["MBAuto_CIDH920105_1"].values[0], 0.212,
138
+ 'Expected MBAuto_CIDH920105_1 value of 0.212 for seq3, got {}.'.format(all_desc_seq3["MBAuto_CIDH920105_1"].values[0]))
139
+ self.assertAlmostEqual(all_desc_seq3["QSO_Grant50"].values[0], 0.028037, places=5,
140
+ msg='Expected QSO_Grant50 value of ~0.028037 for seq3, got {}.'.format(all_desc_seq3["QSO_Grant50"].values[0]))
141
+ #4.)
142
+ all_desc_seq4 = protpy.all_descriptors(self.protein_seq4)
143
+
144
+ self.assertIsInstance(all_desc_seq4, pd.DataFrame,
145
+ 'Expected output to be of type DataFrame, got {}.'.format(type(all_desc_seq4)))
146
+ self.assertEqual(all_desc_seq4.shape, expected_shape,
147
+ 'Expected output shape {}, got {}.'.format(expected_shape, all_desc_seq4.shape))
148
+ self.assertEqual(list(all_desc_seq4.columns)[0], expected_first_col,
149
+ 'Expected first column to be {}, got {}.'.format(expected_first_col, list(all_desc_seq4.columns)[0]))
150
+ self.assertEqual(list(all_desc_seq4.columns)[-1], expected_last_col,
151
+ 'Expected last column to be {}, got {}.'.format(expected_last_col, list(all_desc_seq4.columns)[-1]))
152
+ self.assertTrue(all_desc_seq4.any().isnull().sum() == 0,
153
+ 'Expected output to contain no null values.')
154
+ self.assertEqual(all_desc_seq4["A"].values[0], 8.831,
155
+ 'Expected amino acid composition A value of 8.831 for seq4, got {}.'.format(all_desc_seq4["A"].values[0]))
156
+ self.assertEqual(all_desc_seq4["MBAuto_CIDH920105_1"].values[0], 0.246,
157
+ 'Expected MBAuto_CIDH920105_1 value of 0.246 for seq4, got {}.'.format(all_desc_seq4["MBAuto_CIDH920105_1"].values[0]))
158
+ self.assertAlmostEqual(all_desc_seq4["QSO_Grant50"].values[0], 0.031954, places=5,
159
+ msg='Expected QSO_Grant50 value of ~0.031954 for seq4, got {}.'.format(all_desc_seq4["QSO_Grant50"].values[0]))
160
+ #5.) passing None for params is equivalent to default
161
+ all_desc_none_params = protpy.all_descriptors(self.protein_seq1, params=None)
162
+ self.assertTrue(all_desc_none_params.equals(all_desc_seq1),
163
+ 'Expected params=None to produce same output as default params.')
164
+
165
+ self.assertEqual(mock_all_desc.call_count, 5,
166
+ 'Expected all_descriptors to be called exactly 5 times, got {}.'.format(mock_all_desc.call_count))
167
+
168
+ @patch('protpy.all_descriptors')
169
+ def test_all_descriptors_custom_params(self, mock_all_desc):
170
+ """ Testing all_descriptors with custom per-descriptor parameters (mocked). """
171
+ df_kmer_k3 = _mock_df(18357)
172
+ df_kmer_default = _mock_df(10757)
173
+ df_charge_custom = _mock_df(10757, {"PositiveCharge": 110.396})
174
+ df_charge_default = _mock_df(10757, {"PositiveCharge": 85.0})
175
+ df_custom_lag = _mock_df(10337)
176
+ df_ra2 = _mock_df(10753)
177
+ df_combined = _mock_df(17937)
178
+ mock_all_desc.side_effect = [
179
+ df_kmer_k3, df_kmer_default,
180
+ df_charge_custom, df_charge_default,
181
+ df_custom_lag, df_ra2, df_combined,
182
+ ]
183
+
184
+ #1.) kmer_composition k=3 increases feature count from 400 to 8000
185
+ kmer_k3 = protpy.all_descriptors(self.protein_seq1, params={
186
+ 'kmer_composition': {'k': 3},
187
+ })
188
+ kmer_default = protpy.all_descriptors(self.protein_seq1)
189
+ #k=3 adds 7600 extra features (8000-400)
190
+ self.assertEqual(kmer_k3.shape, (1, kmer_default.shape[1] + 7600),
191
+ 'Expected k=3 to add 7600 features, shape {}, got {}.'.format(
192
+ (1, kmer_default.shape[1] + 7600), kmer_k3.shape))
193
+ self.assertIsInstance(kmer_k3, pd.DataFrame,
194
+ 'Expected output to be of type DataFrame, got {}.'.format(type(kmer_k3)))
195
+ self.assertTrue(kmer_k3.any().isnull().sum() == 0,
196
+ 'Expected output to contain no null values.')
197
+ #2.) charge_distribution ph=5.5 changes PositiveCharge vs default ph=7.4
198
+ charge_custom = protpy.all_descriptors(self.protein_seq1, params={
199
+ 'charge_distribution': {'ph': 5.5},
200
+ })
201
+ charge_default = protpy.all_descriptors(self.protein_seq1)
202
+ self.assertIsInstance(charge_custom, pd.DataFrame,
203
+ 'Expected output to be of type DataFrame, got {}.'.format(type(charge_custom)))
204
+ self.assertNotEqual(
205
+ charge_custom["PositiveCharge"].values[0],
206
+ charge_default["PositiveCharge"].values[0],
207
+ 'Expected PositiveCharge to differ between ph=5.5 and ph=7.4 (default).')
208
+ self.assertEqual(charge_custom["PositiveCharge"].values[0], 110.396,
209
+ 'Expected PositiveCharge of 110.396 at ph=5.5 for seq1, got {}.'.format(
210
+ charge_custom["PositiveCharge"].values[0]))
211
+ #3.) reduced lag on autocorrelation and sequence-order descriptors reduces feature count
212
+ lag = 15
213
+ custom_lag = protpy.all_descriptors(self.protein_seq1, params={
214
+ 'moreaubroto_autocorrelation': {'lag': lag},
215
+ 'moran_autocorrelation': {'lag': lag},
216
+ 'geary_autocorrelation': {'lag': lag},
217
+ 'sequence_order_coupling_number_all': {'lag': lag},
218
+ 'quasi_sequence_order_all': {'lag': lag},
219
+ })
220
+ self.assertIsInstance(custom_lag, pd.DataFrame,
221
+ 'Expected output to be of type DataFrame, got {}.'.format(type(custom_lag)))
222
+ #each autocorrelation descriptor loses (30-15)*8=120 features, socn_all loses 30,
223
+ #qso_all loses (20+30)*2-(20+15)*2=100-70=30; total reduction=120*3+30+30=420
224
+ self.assertEqual(custom_lag.shape, (1, kmer_default.shape[1] - 420),
225
+ 'Expected lag=15 to reduce total by 420, shape {}, got {}.'.format(
226
+ (1, kmer_default.shape[1] - 420), custom_lag.shape))
227
+ self.assertTrue(custom_lag.any().isnull().sum() == 0,
228
+ 'Expected output to contain no null values.')
229
+ #4.) reduced_alphabet_composition alphabet_size=2 reduces feature count by 4 (6-2)
230
+ ra2 = protpy.all_descriptors(self.protein_seq1, params={
231
+ 'reduced_alphabet_composition': {'alphabet_size': 2},
232
+ })
233
+ self.assertEqual(ra2.shape, (1, kmer_default.shape[1] - 4),
234
+ 'Expected alphabet_size=2 to reduce total by 4, got shape {}.'.format(ra2.shape))
235
+ self.assertTrue(ra2.any().isnull().sum() == 0,
236
+ 'Expected output to contain no null values.')
237
+ #5.) multiple custom params applied simultaneously
238
+ combined = protpy.all_descriptors(self.protein_seq2, params={
239
+ 'charge_distribution': {'ph': 5.5},
240
+ 'kmer_composition': {'k': 3},
241
+ 'moreaubroto_autocorrelation': {'lag': 15},
242
+ 'moran_autocorrelation': {'lag': 15},
243
+ 'geary_autocorrelation': {'lag': 15},
244
+ 'sequence_order_coupling_number_all': {'lag': 15},
245
+ 'quasi_sequence_order_all': {'lag': 15},
246
+ })
247
+ self.assertIsInstance(combined, pd.DataFrame,
248
+ 'Expected output to be of type DataFrame, got {}.'.format(type(combined)))
249
+ self.assertEqual(combined.shape, (1, 17937),
250
+ 'Expected combined custom params shape (1, 17937), got {}.'.format(combined.shape))
251
+ self.assertTrue(combined.any().isnull().sum() == 0,
252
+ 'Expected output to contain no null values.')
253
+
254
+ self.assertEqual(mock_all_desc.call_count, 7,
255
+ 'Expected all_descriptors to be called exactly 7 times, got {}.'.format(mock_all_desc.call_count))
256
+
257
+ def test_all_descriptors_params_validation(self):
258
+ """ Testing that invalid params inputs raise the correct errors. """
259
+ # Validation is fast: errors are raised before any descriptor computation.
260
+ #1.) unknown descriptor name raises ValueError
261
+ with self.assertRaises(ValueError):
262
+ protpy.all_descriptors(self.protein_seq1, params={'unknown_descriptor': {'k': 2}})
263
+ #2.) a descriptor that takes no extra parameters raises ValueError
264
+ with self.assertRaises(ValueError):
265
+ protpy.all_descriptors(self.protein_seq1, params={'amino_acid_composition': {}})
266
+ with self.assertRaises(ValueError):
267
+ protpy.all_descriptors(self.protein_seq1, params={'conjoint_triad': {}})
268
+ with self.assertRaises(ValueError):
269
+ protpy.all_descriptors(self.protein_seq1, params={'gravy': {}})
270
+ #3.) params of wrong type raises TypeError
271
+ with self.assertRaises(TypeError):
272
+ protpy.all_descriptors(self.protein_seq1, params="lag=15")
273
+ with self.assertRaises(TypeError):
274
+ protpy.all_descriptors(self.protein_seq1, params=["kmer_composition"])
275
+ with self.assertRaises(TypeError):
276
+ protpy.all_descriptors(self.protein_seq1, params=123)
277
+ #4.) misspelled descriptor name raises ValueError with a useful message
278
+ try:
279
+ protpy.all_descriptors(self.protein_seq1, params={'kmer_compostion': {'k': 3}})
280
+ self.fail('Expected ValueError for misspelled descriptor name.')
281
+ except ValueError as e:
282
+ self.assertIn('kmer_compostion', str(e),
283
+ 'Expected error message to name the unrecognised key, got: {}'.format(e))
284
+
285
+ def test_all_descriptors_invalid_sequence(self):
286
+ """ Testing that invalid protein sequence inputs raise the correct errors. """
287
+ # Validation is fast: errors are raised before any descriptor computation.
288
+ #1.) sequence containing non-canonical amino acid characters raises ValueError
289
+ with self.assertRaises(ValueError):
290
+ protpy.all_descriptors("ABCDEF")
291
+ with self.assertRaises(ValueError):
292
+ protpy.all_descriptors("OOOOO")
293
+ with self.assertRaises(ValueError):
294
+ protpy.all_descriptors("")
295
+ #2.) non-string sequence raises TypeError
296
+ with self.assertRaises(TypeError):
297
+ protpy.all_descriptors(12345)
298
+ with self.assertRaises(TypeError):
299
+ protpy.all_descriptors(True)
300
+ with self.assertRaises(TypeError):
301
+ protpy.all_descriptors(["ACDEFG"])
302
+ #3.) invalid sequence with otherwise valid custom params still raises ValueError
303
+ with self.assertRaises(ValueError):
304
+ protpy.all_descriptors("ABCDEF", params={'kmer_composition': {'k': 3}})
@@ -22,8 +22,8 @@ class ProtpyTests(unittest.TestCase):
22
22
  """
23
23
  def test_protpy_metadata(self):
24
24
  """ Testing correct protpy version and metadata. """
25
- self.assertEqual(protpy.__version__, "1.3.0",
26
- "protpy version is not correct, expected version 1.3.0, got version {}".format(protpy.__version__))
25
+ self.assertEqual(protpy.__version__, "1.4.0",
26
+ "protpy version is not correct, expected version 1.4.0, got version {}".format(protpy.__version__))
27
27
  self.assertEqual(protpy.__name__, "protpy",
28
28
  "protpy software name is not correct, expected protpy, got {}.".format(protpy.__name__))
29
29
  self.assertEqual(protpy.__author__, "AJ McKenna: https://github.com/amckenna41",
@@ -47,84 +47,84 @@ class ProtpyTests(unittest.TestCase):
47
47
 
48
48
  def test_valid_descriptors(self):
49
49
  """ Testing correct list of available descriptors is included in package attribute. """
50
- self.assertEqual(len(protpy.all_descriptors), 36,
51
- "Expected there to be 36 total descriptors, got {}.".format(len(protpy.all_descriptors)))
52
- self.assertIsInstance(protpy.all_descriptors, list,
53
- "all_descriptors should be of type list, got {}.".format(type(protpy.all_descriptors)))
50
+ self.assertEqual(len(protpy.descriptor_names), 36,
51
+ "Expected there to be 36 total descriptors, got {}.".format(len(protpy.descriptor_names)))
52
+ self.assertIsInstance(protpy.descriptor_names, list,
53
+ "all_descriptors should be of type list, got {}.".format(type(protpy.descriptor_names)))
54
54
  # composition descriptors
55
- self.assertIn('amino_acid_composition', protpy.all_descriptors,
55
+ self.assertIn('amino_acid_composition', protpy.descriptor_names,
56
56
  "amino_acid_composition should be in available descriptors list.")
57
- self.assertIn('dipeptide_composition', protpy.all_descriptors,
57
+ self.assertIn('dipeptide_composition', protpy.descriptor_names,
58
58
  "dipeptide_composition should be in available descriptors list.")
59
- self.assertIn('tripeptide_composition', protpy.all_descriptors,
59
+ self.assertIn('tripeptide_composition', protpy.descriptor_names,
60
60
  "tripeptide_composition should be in available descriptors list.")
61
- self.assertIn('gravy', protpy.all_descriptors,
61
+ self.assertIn('gravy', protpy.descriptor_names,
62
62
  "gravy should be in available descriptors list.")
63
- self.assertIn('aromaticity', protpy.all_descriptors,
63
+ self.assertIn('aromaticity', protpy.descriptor_names,
64
64
  "aromaticity should be in available descriptors list.")
65
- self.assertIn('instability_index', protpy.all_descriptors,
65
+ self.assertIn('instability_index', protpy.descriptor_names,
66
66
  "instability_index should be in available descriptors list.")
67
- self.assertIn('isoelectric_point', protpy.all_descriptors,
67
+ self.assertIn('isoelectric_point', protpy.descriptor_names,
68
68
  "isoelectric_point should be in available descriptors list.")
69
- self.assertIn('molecular_weight', protpy.all_descriptors,
69
+ self.assertIn('molecular_weight', protpy.descriptor_names,
70
70
  "molecular_weight should be in available descriptors list.")
71
- self.assertIn('charge_distribution', protpy.all_descriptors,
71
+ self.assertIn('charge_distribution', protpy.descriptor_names,
72
72
  "charge_distribution should be in available descriptors list.")
73
- self.assertIn('hydrophobic_polar_charged_composition', protpy.all_descriptors,
73
+ self.assertIn('hydrophobic_polar_charged_composition', protpy.descriptor_names,
74
74
  "hydrophobic_polar_charged_composition should be in available descriptors list.")
75
- self.assertIn('secondary_structure_propensity', protpy.all_descriptors,
75
+ self.assertIn('secondary_structure_propensity', protpy.descriptor_names,
76
76
  "secondary_structure_propensity should be in available descriptors list.")
77
- self.assertIn('kmer_composition', protpy.all_descriptors,
77
+ self.assertIn('kmer_composition', protpy.descriptor_names,
78
78
  "kmer_composition should be in available descriptors list.")
79
- self.assertIn('reduced_alphabet_composition', protpy.all_descriptors,
79
+ self.assertIn('reduced_alphabet_composition', protpy.descriptor_names,
80
80
  "reduced_alphabet_composition should be in available descriptors list.")
81
- self.assertIn('motif_composition', protpy.all_descriptors,
81
+ self.assertIn('motif_composition', protpy.descriptor_names,
82
82
  "motif_composition should be in available descriptors list.")
83
- self.assertIn('amino_acid_pair_composition', protpy.all_descriptors,
83
+ self.assertIn('amino_acid_pair_composition', protpy.descriptor_names,
84
84
  "amino_acid_pair_composition should be in available descriptors list.")
85
- self.assertIn('aliphatic_index', protpy.all_descriptors,
85
+ self.assertIn('aliphatic_index', protpy.descriptor_names,
86
86
  "aliphatic_index should be in available descriptors list.")
87
- self.assertIn('extinction_coefficient', protpy.all_descriptors,
87
+ self.assertIn('extinction_coefficient', protpy.descriptor_names,
88
88
  "extinction_coefficient should be in available descriptors list.")
89
- self.assertIn('boman_index', protpy.all_descriptors,
89
+ self.assertIn('boman_index', protpy.descriptor_names,
90
90
  "boman_index should be in available descriptors list.")
91
- self.assertIn('aggregation_propensity', protpy.all_descriptors,
91
+ self.assertIn('aggregation_propensity', protpy.descriptor_names,
92
92
  "aggregation_propensity should be in available descriptors list.")
93
- self.assertIn('hydrophobic_moment', protpy.all_descriptors,
93
+ self.assertIn('hydrophobic_moment', protpy.descriptor_names,
94
94
  "hydrophobic_moment should be in available descriptors list.")
95
- self.assertIn('pseudo_amino_acid_composition', protpy.all_descriptors,
95
+ self.assertIn('pseudo_amino_acid_composition', protpy.descriptor_names,
96
96
  "pseudo_amino_acid_composition should be in available descriptors list.")
97
- self.assertIn('amphiphilic_pseudo_amino_acid_composition', protpy.all_descriptors,
97
+ self.assertIn('amphiphilic_pseudo_amino_acid_composition', protpy.descriptor_names,
98
98
  "amphiphilic_pseudo_amino_acid_composition should be in available descriptors list.")
99
99
  # autocorrelation descriptors
100
- self.assertIn('moreaubroto_autocorrelation', protpy.all_descriptors,
100
+ self.assertIn('moreaubroto_autocorrelation', protpy.descriptor_names,
101
101
  "moreaubroto_autocorrelation should be in available descriptors list.")
102
- self.assertIn('moran_autocorrelation', protpy.all_descriptors,
102
+ self.assertIn('moran_autocorrelation', protpy.descriptor_names,
103
103
  "moran_autocorrelation should be in available descriptors list.")
104
- self.assertIn('geary_autocorrelation', protpy.all_descriptors,
104
+ self.assertIn('geary_autocorrelation', protpy.descriptor_names,
105
105
  "geary_autocorrelation should be in available descriptors list.")
106
106
  # conjoint triad descriptor
107
- self.assertIn('conjoint_triad', protpy.all_descriptors,
107
+ self.assertIn('conjoint_triad', protpy.descriptor_names,
108
108
  "conjoint_triad should be in available descriptors list.")
109
109
  # CTD descriptors
110
- self.assertIn('ctd_composition', protpy.all_descriptors,
110
+ self.assertIn('ctd_composition', protpy.descriptor_names,
111
111
  "ctd_composition should be in available descriptors list.")
112
- self.assertIn('ctd_transition', protpy.all_descriptors,
112
+ self.assertIn('ctd_transition', protpy.descriptor_names,
113
113
  "ctd_transition should be in available descriptors list.")
114
- self.assertIn('ctd_distribution', protpy.all_descriptors,
114
+ self.assertIn('ctd_distribution', protpy.descriptor_names,
115
115
  "ctd_distribution should be in available descriptors list.")
116
- self.assertIn('ctd_', protpy.all_descriptors,
116
+ self.assertIn('ctd_', protpy.descriptor_names,
117
117
  "ctd_ should be in available descriptors list.")
118
118
  # sequence order descriptors
119
- self.assertIn('sequence_order_coupling_number_', protpy.all_descriptors,
119
+ self.assertIn('sequence_order_coupling_number_', protpy.descriptor_names,
120
120
  "sequence_order_coupling_number_ should be in available descriptors list.")
121
- self.assertIn('sequence_order_coupling_number', protpy.all_descriptors,
121
+ self.assertIn('sequence_order_coupling_number', protpy.descriptor_names,
122
122
  "sequence_order_coupling_number should be in available descriptors list.")
123
- self.assertIn('sequence_order_coupling_number_all', protpy.all_descriptors,
123
+ self.assertIn('sequence_order_coupling_number_all', protpy.descriptor_names,
124
124
  "sequence_order_coupling_number_all should be in available descriptors list.")
125
- self.assertIn('quasi_sequence_order', protpy.all_descriptors,
125
+ self.assertIn('quasi_sequence_order', protpy.descriptor_names,
126
126
  "quasi_sequence_order should be in available descriptors list.")
127
- self.assertIn('quasi_sequence_order_all', protpy.all_descriptors,
127
+ self.assertIn('quasi_sequence_order_all', protpy.descriptor_names,
128
128
  "quasi_sequence_order_all should be in available descriptors list.")
129
- self.assertIn('shannon_entropy', protpy.all_descriptors,
129
+ self.assertIn('shannon_entropy', protpy.descriptor_names,
130
130
  "shannon_entropy should be in available descriptors list.")
@@ -86,12 +86,12 @@ class ProtpyUtilsTests(unittest.TestCase):
86
86
 
87
87
  def test_registry_completeness(self):
88
88
  """All 36 descriptor names exported by protpy appear in _DESCRIPTOR_REGISTRY."""
89
- missing = [n for n in protpy.all_descriptors if n not in _DESCRIPTOR_REGISTRY]
89
+ missing = [n for n in protpy.descriptor_names if n not in _DESCRIPTOR_REGISTRY]
90
90
  self.assertEqual(
91
91
  missing, [],
92
92
  f"Descriptors in all_descriptors but missing from registry: {missing}",
93
93
  )
94
- self.assertEqual(len(_DESCRIPTOR_REGISTRY), len(protpy.all_descriptors),
94
+ self.assertEqual(len(_DESCRIPTOR_REGISTRY), len(protpy.descriptor_names),
95
95
  "Registry length doesn't match len(all_descriptors).")
96
96
 
97
97
  def test_registry_schema(self):
@@ -204,7 +204,7 @@ class ProtpyUtilsTests(unittest.TestCase):
204
204
  # Result is sorted
205
205
  self.assertEqual(descriptors, sorted(descriptors))
206
206
  # Every name in all_descriptors appears in the result
207
- for name in protpy.all_descriptors:
207
+ for name in protpy.descriptor_names:
208
208
  self.assertIn(name, descriptors)
209
209
 
210
210
  def test_list_descriptors_by_category(self):
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes