peff-digest 0.1.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 (43) hide show
  1. peff_digest-0.1.0/.github/copilot-instructions.md +38 -0
  2. peff_digest-0.1.0/.github/workflows/ci.yml +60 -0
  3. peff_digest-0.1.0/.github/workflows/release.yml +37 -0
  4. peff_digest-0.1.0/.gitignore +115 -0
  5. peff_digest-0.1.0/HISTORY.md +5 -0
  6. peff_digest-0.1.0/MANIFEST.in +11 -0
  7. peff_digest-0.1.0/PKG-INFO +235 -0
  8. peff_digest-0.1.0/README.md +207 -0
  9. peff_digest-0.1.0/config.toml +41 -0
  10. peff_digest-0.1.0/justfile +31 -0
  11. peff_digest-0.1.0/pyproject.toml +68 -0
  12. peff_digest-0.1.0/src/peff_digest/__init__.py +18 -0
  13. peff_digest-0.1.0/src/peff_digest/api.py +114 -0
  14. peff_digest-0.1.0/src/peff_digest/cli.py +108 -0
  15. peff_digest-0.1.0/src/peff_digest/config.py +83 -0
  16. peff_digest-0.1.0/src/peff_digest/digest.py +563 -0
  17. peff_digest-0.1.0/src/peff_digest/io.py +195 -0
  18. peff_digest-0.1.0/tests/conftest.py +35 -0
  19. peff_digest-0.1.0/tests/data/PEFF_AnnotID_Insulin_Valid.peff +17 -0
  20. peff_digest-0.1.0/tests/data/PEFF_Minimal_INValid1.peff +8 -0
  21. peff_digest-0.1.0/tests/data/PEFF_Minimal_Valid.peff +11 -0
  22. peff_digest-0.1.0/tests/data/PEFF_Tiny_INValid1.peff +71 -0
  23. peff_digest-0.1.0/tests/data/PEFF_Tiny_Valid.peff +74 -0
  24. peff_digest-0.1.0/tests/data/SmallTestDB-PEFF0.9.peff +256 -0
  25. peff_digest-0.1.0/tests/data/SmallTestDB-PEFF1.0.peff +256 -0
  26. peff_digest-0.1.0/tests/data/UniProtExport_3prot.peff +41 -0
  27. peff_digest-0.1.0/tests/data/complex.peff +12 -0
  28. peff_digest-0.1.0/tests/data/minimal.peff +13 -0
  29. peff_digest-0.1.0/tests/data/multidb.peff +21 -0
  30. peff_digest-0.1.0/tests/data/proteoform_ENST00000000412.peff +20 -0
  31. peff_digest-0.1.0/tests/data/proteoform_ENST00000000412.png +0 -0
  32. peff_digest-0.1.0/tests/data/small_test.fasta +9 -0
  33. peff_digest-0.1.0/tests/test_ann_to_map.py +83 -0
  34. peff_digest-0.1.0/tests/test_api.py +108 -0
  35. peff_digest-0.1.0/tests/test_config.py +57 -0
  36. peff_digest-0.1.0/tests/test_cut_sites.py +44 -0
  37. peff_digest-0.1.0/tests/test_digest_core.py +150 -0
  38. peff_digest-0.1.0/tests/test_io.py +271 -0
  39. peff_digest-0.1.0/tests/test_psimod.py +193 -0
  40. peff_digest-0.1.0/tests/test_semi_enzymatic.py +78 -0
  41. peff_digest-0.1.0/tests/test_smoke.py +42 -0
  42. peff_digest-0.1.0/tests/test_terminal_mods.py +57 -0
  43. peff_digest-0.1.0/tests/test_variants.py +277 -0
@@ -0,0 +1,38 @@
1
+ ## Copilot Instructions
2
+
3
+ ### VERY IMPORTANT INSTRUCTIONS
4
+
5
+ USE THE JUSTFILE WHENEVER POSSIBLE. IF THERE IS NOT A JUSTFILE COMMAND CHECK AGAIN... IF THERE IS STILL NOT A FUCKING JUST COMAND... USE UV PACKAGE MANAGER! THIS IS ALREADY INSTALLED AND AVAILABLE. DO NOT, UNDER ANY CIRCUMSTANCES, INSTALL ANY DEPENDENCIES USING NPM, YARN, PIP, GEM, OR ANY OTHER PACKAGE MANAGER. AND NEVER USE PYHTON / PYTEST DIRECTLY!!! ALWAYS USE JUST FOR AVAILABLE COMMANDS AND ONLY FALL BACK TO UV IF THERE IS NO JUST COMMAND AVAILABLE.
6
+
7
+ ### Available Tools
8
+ - Use `just` for all project commands. See `just --list` for available commands.
9
+ - Use `uv` for package management and running scripts. See `uv --help` for usage.
10
+ - Use `git` for version control.
11
+ - Use ty for type checking. `uv run ty check src/ tests/` or `just ty`
12
+ - Use pytest for testing. `uv run pytest tests/` or `just test`
13
+ - use ruff for linting and formatting. `uv run ruff check src/ tests/` or `just lint` and `uv run ruff format src/` or `just format`
14
+
15
+ ### Code Style & Philosophy
16
+
17
+ - **Type everything**: Use comprehensive type hints (NDArray, Literal, Protocol, Self, etc.). Generic types should be specific. Use pyhton 3.12 features where applicable. Match-case statements preferred over if-elif chains for discrete values >= 3. Use list, tuple, set over List, Tuple, Set where possible. Dont use Union or Optional, use | operator.
18
+ - **Immutability**: Prefer frozen dataclasses with `slots=True` and functional transformations over mutation. Though this is not absolute.
19
+ - **Explicit over implicit**: Clear, descriptive names. No magic. If there's a performance trade-off, make it obvious.
20
+ - **Simplicity**: Simple, readable code over clever one-liners. Break complex logic into smaller functions.
21
+
22
+ Test do not need to be strongly typed but should still use type hints where reasonable. dont worry about exhaustive typing in tests, nor running ruff/ty on tests.
23
+
24
+ ### Documentation
25
+
26
+ - Concise docstrings - no novels
27
+ - Document the "why" when non-obvious, not the "what"
28
+ - Type hints are documentation - don't repeat them in docstrings. Methods/Function should be able to get by with no/minimal docstrings if types are clear.
29
+ - Use `Raises` section in docstrings for exceptions
30
+ - No placeholder comments like "TODO: implement later" - use `raise NotImplementedError("reason")`
31
+
32
+ ### Response Style
33
+
34
+ - Get to the point
35
+ - Show code, minimal explanation
36
+ - If I'm wrong, tell me directly
37
+ - Assume I know Python well - no hand-holding
38
+
@@ -0,0 +1,60 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: astral-sh/setup-uv@v5
19
+ with:
20
+ enable-cache: true
21
+ - run: uv sync
22
+ - run: uv run ruff check src
23
+ - run: uv run ruff format --check src
24
+
25
+ type-check:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ - uses: astral-sh/setup-uv@v5
30
+ with:
31
+ enable-cache: true
32
+ - run: uv sync
33
+ - run: uv run ty check src
34
+
35
+ test:
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ matrix:
39
+ python-version: ["3.12", "3.13"]
40
+ steps:
41
+ - uses: actions/checkout@v4
42
+ - uses: astral-sh/setup-uv@v5
43
+ with:
44
+ enable-cache: true
45
+ - run: uv python install ${{ matrix.python-version }}
46
+ - run: uv sync --python ${{ matrix.python-version }}
47
+ - run: uv run pytest tests
48
+
49
+ build:
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+ - uses: astral-sh/setup-uv@v5
54
+ with:
55
+ enable-cache: true
56
+ - run: uv build
57
+ - uses: actions/upload-artifact@v4
58
+ with:
59
+ name: dist
60
+ path: dist/
@@ -0,0 +1,37 @@
1
+ name: Release
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: read
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - uses: astral-sh/setup-uv@v5
18
+ with:
19
+ enable-cache: true
20
+ - run: uv build
21
+ - uses: actions/upload-artifact@v4
22
+ with:
23
+ name: dist
24
+ path: dist/
25
+
26
+ publish:
27
+ needs: build
28
+ runs-on: ubuntu-latest
29
+ environment: pypi
30
+ permissions:
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/download-artifact@v4
34
+ with:
35
+ name: dist
36
+ path: dist/
37
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,115 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ target/
76
+
77
+ # Jupyter Notebook
78
+ .ipynb_checkpoints
79
+
80
+ # IPython
81
+ profile_default/
82
+ ipython_config.py
83
+
84
+ # pyenv
85
+ .python-version
86
+
87
+ # pipenv
88
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
90
+ # with no cross-platform support, pipenv may install dependencies that don't work, or not
91
+ # install all needed dependencies.
92
+ #Pipfile.lock
93
+
94
+ # poetry
95
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
96
+ # This is especially recommended for binary packages to ensure reproducible builds.
97
+ # However, if you need to use different versions of dependencies on different environments,
98
+ # you may want to ignore it.
99
+ #poetry.lock
100
+
101
+ # uv
102
+ .venv
103
+ uv.lock
104
+
105
+ # ruff
106
+ .ruff_cache/
107
+
108
+ # mypy
109
+ .mypy_cache/
110
+ .dmypy.json
111
+ dmypy.json
112
+
113
+ # editors
114
+ .vscode/
115
+ .idea/
@@ -0,0 +1,5 @@
1
+ # History
2
+
3
+ ## 0.1.0 (2026-03-19)
4
+
5
+ * First release on PyPI.
@@ -0,0 +1,11 @@
1
+ include HISTORY.md
2
+ include README.md
3
+ include .gitignore
4
+
5
+ recursive-include tests *
6
+ recursive-include .github *
7
+
8
+ recursive-exclude * __pycache__
9
+ recursive-exclude * *.py[co]
10
+
11
+ recursive-include *.md justfile *.jpg *.png *.gif
@@ -0,0 +1,235 @@
1
+ Metadata-Version: 2.4
2
+ Name: peff_digest
3
+ Version: 0.1.0
4
+ Summary: PEFF-aware in-silico protein digestion with PTM enumeration, sequence variants, and ProForma output.
5
+ Author-email: Patrick Garrett <pgarrett@scripps.edu>
6
+ Maintainer-email: Patrick Garrett <pgarrett@scripps.edu>
7
+ License: MIT
8
+ Keywords: PEFF,PTM,ProForma,bioinformatics,digestion,peptide,proteomics
9
+ Classifier: Intended Audience :: Science/Research
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
16
+ Classifier: Typing :: Typed
17
+ Requires-Python: >=3.12
18
+ Requires-Dist: pefftacular>=0.1.0
19
+ Requires-Dist: peptacular>=3.1.0
20
+ Requires-Dist: polars>=1.0
21
+ Requires-Dist: psimodpy
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: tomli-w>=1.0
24
+ Requires-Dist: tqdm>=4.67.3
25
+ Requires-Dist: unimodpy
26
+ Requires-Dist: uniprotptmpy
27
+ Description-Content-Type: text/markdown
28
+
29
+ # peff_digest
30
+
31
+ A PEFF-aware protein digest tool. Given a PEFF file and enzymatic digestion parameters, produces a CSV of peptides with their sequence (ProForma notation), variant annotation, length, and monoisotopic mass.
32
+
33
+ Each PEFF `VariantSimple` and `VariantComplex` annotation is applied independently (not combined). PEFF PTMs (`ModResPsi` / `ModResUnimod`) are applied combinatorially up to a configurable limit per peptide. Fixed and variable user-defined modifications — including terminal modifications — are also supported.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ uv sync
39
+ # or
40
+ just install
41
+ ```
42
+
43
+ Requires Python 3.12+.
44
+
45
+ ## Usage
46
+
47
+ ### Via config file
48
+
49
+ ```bash
50
+ peff-digest --config config.toml
51
+ ```
52
+
53
+ ### Via flags
54
+
55
+ ```bash
56
+ peff-digest --peff-file human.peff --output-file peptides.csv
57
+ ```
58
+
59
+ Flags override any values set in `--config`. Run `peff-digest --help` for the full flag reference.
60
+
61
+ ### Output
62
+
63
+ The output CSV has five columns:
64
+
65
+ | Column | Description |
66
+ |---|---|
67
+ | `protein_id` | `db_unique_id` from the PEFF header |
68
+ | `sequence` | ProForma-annotated peptide sequence (includes mods) |
69
+ | `variant` | PEFF variant notation, e.g. `(42\|R)`, or empty for canonical |
70
+ | `length` | Peptide length in residues |
71
+ | `mass` | Monoisotopic mass in Da, or empty if not computable |
72
+
73
+ ## Config reference
74
+
75
+ All options can be set in a TOML or JSON config file. TOML example:
76
+
77
+ ```toml
78
+ peff_file = "human.peff"
79
+ output_file = "peptides.csv"
80
+
81
+ cleave_on = "KR"
82
+ missed_cleavages = 2
83
+ semi_enzymatic = false
84
+ max_ptm_per_peptide = 2
85
+ min_length = 7
86
+ max_length = 40
87
+ restrict_after = "P"
88
+ restrict_before = ""
89
+ cterminal = true
90
+ min_mass = 400.0
91
+ max_mass = 10000.0
92
+ drop_invalid_mass = false
93
+ annotate_variants = true
94
+
95
+ # Internal modifications — one [[internal_mods]] block per mod:
96
+ # [[internal_mods]]
97
+ # modification = "Carbamidomethyl"
98
+ # residue = "C"
99
+ # mod_type = "fixed"
100
+ #
101
+ # [[internal_mods]]
102
+ # modification = "Oxidation"
103
+ # residue = "M"
104
+ # mod_type = "variable"
105
+
106
+ # Terminal modifications — one [[terminal_mods]] block per mod:
107
+ # [[terminal_mods]]
108
+ # modification = "Acetyl"
109
+ # position = "nterm"
110
+ # mod_type = "variable"
111
+ # protein_terminus = true # only the first peptide of each protein
112
+ #
113
+ # [[terminal_mods]]
114
+ # modification = "UNIMOD:737"
115
+ # position = "nterm"
116
+ # mod_type = "fixed"
117
+ # residue = "M" # only if the terminal residue is M
118
+ #
119
+ # [[terminal_mods]]
120
+ # modification = "Amidated"
121
+ # position = "cterm"
122
+ # mod_type = "variable"
123
+ ```
124
+
125
+ ### `DigestConfig` fields
126
+
127
+ | Field | Type | Default | Description |
128
+ |---|---|---|---|
129
+ | `peff_file` | `str` | required | Path to the input PEFF file. Must exist. |
130
+ | `output_file` | `str` | `"peptides.csv"` | Path for the output CSV. |
131
+ | `cleave_on` | `str` | `"KR"` | Amino acids at which to cleave (e.g. `"KR"` for trypsin). |
132
+ | `missed_cleavages` | `int` | `2` | Maximum number of missed cleavage sites per peptide. Min 0. |
133
+ | `semi_enzymatic` | `bool` | `false` | Include semi-enzymatic peptides (one non-enzymatic terminus). |
134
+ | `max_ptm_per_peptide` | `int` | `2` | Maximum number of variable mods (PEFF + user) applied simultaneously per peptide. `0` disables all variable mods. Min 0. |
135
+ | `min_length` | `int` | `7` | Minimum peptide length in residues (inclusive). Min 1. |
136
+ | `max_length` | `int` | `40` | Maximum peptide length in residues (inclusive). Min 1. |
137
+ | `restrict_after` | `str` | `"P"` | Skip cleavage when the following residue is in this set (e.g. `"P"` for trypsin/Pro rule). |
138
+ | `restrict_before` | `str` | `""` | Skip cleavage when the preceding residue is in this set. |
139
+ | `cterminal` | `bool` | `true` | `true` = C-terminal cleavage (standard); `false` = N-terminal. |
140
+ | `internal_mods` | `list[InternalMod]` | `[]` | Per-residue modifications. See `InternalMod` fields below. |
141
+ | `terminal_mods` | `list[TerminalMod]` | `[]` | Terminal modifications. See `TerminalMod` fields below. |
142
+ | `min_mass` | `float \| None` | `None` | Minimum peptide mass in Da. Ignored if `None`. |
143
+ | `max_mass` | `float \| None` | `None` | Maximum peptide mass in Da. Ignored if `None`. |
144
+ | `drop_invalid_mass` | `bool` | `false` | If `true`, exclude peptides whose mass cannot be computed. |
145
+ | `annotate_variants` | `bool` | `true` | If `false`, do not set `peptide_name` on variant peptides. |
146
+ | `workers` | `int \| None` | `None` | Number of worker processes. Defaults to all available CPUs. Min 1. |
147
+
148
+ ### `InternalMod` fields
149
+
150
+ | Field | Type | Default | Description |
151
+ |---|---|---|---|
152
+ | `modification` | `str` | required | Modification name (e.g. `"Carbamidomethyl"`, `"UNIMOD:21"`). |
153
+ | `residue` | `str` | required | One or more amino acids the mod applies to (e.g. `"C"` or `"KR"`). |
154
+ | `mod_type` | `"fixed" \| "variable"` | required | `"fixed"` = always applied; `"variable"` = enumerated combinatorially (counts against `max_ptm_per_peptide`). |
155
+
156
+ ### `TerminalMod` fields
157
+
158
+ | Field | Type | Default | Description |
159
+ |---|---|---|---|
160
+ | `modification` | `str` | required | Modification name (e.g. `"Acetyl"`, `"UNIMOD:737"`). |
161
+ | `position` | `"nterm" \| "cterm"` | required | Which terminus to apply the mod to. |
162
+ | `mod_type` | `"fixed" \| "variable"` | required | `"fixed"` = always applied; `"variable"` = enumerated combinatorially (counts against `max_ptm_per_peptide`). |
163
+ | `residue` | `str \| None` | `None` | If set, the mod is only applied when the terminal residue is in this string (e.g. `"M"` or `"KR"`). |
164
+ | `protein_terminus` | `bool` | `false` | If `true`, only apply to the protein-level terminus (first peptide for N-term, last for C-term). |
165
+
166
+ ## Python API
167
+
168
+ ### Full digest → Polars DataFrame
169
+
170
+ ```python
171
+ from peff_digest import DigestConfig, InternalMod, TerminalMod, digest
172
+
173
+ config = DigestConfig(
174
+ peff_file="human.peff",
175
+ missed_cleavages=2,
176
+ min_length=7,
177
+ max_length=40,
178
+ min_mass=400.0,
179
+ max_mass=10000.0,
180
+ drop_invalid_mass=True,
181
+ internal_mods=[
182
+ InternalMod(modification="Carbamidomethyl", residue="C", mod_type="fixed"),
183
+ InternalMod(modification="Oxidation", residue="M", mod_type="variable"),
184
+ ],
185
+ terminal_mods=[
186
+ TerminalMod(modification="Acetyl", position="nterm", mod_type="variable", protein_terminus=True),
187
+ ],
188
+ )
189
+
190
+ df = digest(config)
191
+ print(df)
192
+ ```
193
+
194
+ Returns a `polars.DataFrame` with columns `protein_id`, `sequence`, `variant`, `length`, `mass`. All filtering from the config (mass bounds, `drop_invalid_mass`) is applied before returning.
195
+
196
+ ### Single-entry digest
197
+
198
+ ```python
199
+ import pefftacular as pf
200
+ from peff_digest import InternalMod, TerminalMod, digest_peff_sequence
201
+
202
+ entry = next(iter(pf.PeffReader("human.peff")))
203
+
204
+ peptides = digest_peff_sequence(
205
+ entry,
206
+ cleave_on="KR",
207
+ missed_cleavages=2,
208
+ min_length=7,
209
+ max_length=40,
210
+ restrict_after="P",
211
+ internal_mods=[
212
+ InternalMod(modification="Carbamidomethyl", residue="C", mod_type="fixed"),
213
+ InternalMod(modification="Oxidation", residue="M", mod_type="variable"),
214
+ ],
215
+ max_ptm_per_peptide=2,
216
+ terminal_mods=[
217
+ TerminalMod(modification="Acetyl", position="nterm", mod_type="variable", protein_terminus=True),
218
+ TerminalMod(modification="Amidated", position="cterm", mod_type="variable"),
219
+ ],
220
+ )
221
+
222
+ for peptide in peptides:
223
+ print(str(peptide), len(peptide), peptide.mass())
224
+ ```
225
+
226
+ Returns a `set[peptacular.ProFormaAnnotation]`. Each element supports `len()`, `.mass()`, `str()`, and `.peptide_name` (PEFF variant notation, or `None` for canonical).
227
+
228
+ ## Development
229
+
230
+ ```bash
231
+ just lint # ruff check
232
+ just format # ruff format + import sort
233
+ just test # pytest
234
+ just check # lint + type check (ty) + test
235
+ ```