cool-seq-tool 0.14.4__tar.gz → 0.14.5__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 (65) hide show
  1. cool_seq_tool-0.14.5/.github/CODEOWNERS +1 -0
  2. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/PKG-INFO +1 -1
  3. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/exon_genomic_coords.py +15 -10
  4. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/resources/status.py +10 -3
  5. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/sources/uta_database.py +27 -3
  6. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool.egg-info/PKG-INFO +1 -1
  7. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool.egg-info/SOURCES.txt +1 -0
  8. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/mappers/test_exon_genomic_coords.py +26 -14
  9. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/sources/test_uta_database.py +98 -0
  10. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.coveragerc +0 -0
  11. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/ISSUE_TEMPLATE/bug-report.yaml +0 -0
  12. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/ISSUE_TEMPLATE/feature-request.yaml +0 -0
  13. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/workflows/checks.yaml +0 -0
  14. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/workflows/pr-priority-label.yaml +0 -0
  15. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/workflows/release.yml +0 -0
  16. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.github/workflows/stale.yaml +0 -0
  17. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.gitignore +0 -0
  18. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.pre-commit-config.yaml +0 -0
  19. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/.readthedocs.yaml +0 -0
  20. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/CITATION.cff +0 -0
  21. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/LICENSE +0 -0
  22. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/README.md +0 -0
  23. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/Makefile +0 -0
  24. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/make.bat +0 -0
  25. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/_static/img/biomart.png +0 -0
  26. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/_templates/module_summary.rst +0 -0
  27. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/changelog.rst +0 -0
  28. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/conf.py +0 -0
  29. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/contributing.rst +0 -0
  30. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/index.rst +0 -0
  31. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/install.rst +0 -0
  32. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/license.rst +0 -0
  33. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/reference/index.rst +0 -0
  34. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/transcript_selection.rst +0 -0
  35. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/docs/source/usage.rst +0 -0
  36. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/pyproject.toml +0 -0
  37. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/setup.cfg +0 -0
  38. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/__init__.py +0 -0
  39. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/app.py +0 -0
  40. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/handlers/__init__.py +0 -0
  41. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/handlers/seqrepo_access.py +0 -0
  42. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/__init__.py +0 -0
  43. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/alignment.py +0 -0
  44. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/feature_overlap.py +0 -0
  45. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/liftover.py +0 -0
  46. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/mappers/mane_transcript.py +0 -0
  47. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/resources/__init__.py +0 -0
  48. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/resources/data_files.py +0 -0
  49. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/resources/transcript_mapping.tsv +0 -0
  50. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/schemas.py +0 -0
  51. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/sources/__init__.py +0 -0
  52. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/sources/mane_transcript_mappings.py +0 -0
  53. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/sources/transcript_mappings.py +0 -0
  54. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool/utils.py +0 -0
  55. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool.egg-info/dependency_links.txt +0 -0
  56. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool.egg-info/requires.txt +0 -0
  57. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/src/cool_seq_tool.egg-info/top_level.txt +0 -0
  58. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/conftest.py +0 -0
  59. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/handlers/test_feature_overlap.py +0 -0
  60. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/handlers/test_seqrepo_access.py +0 -0
  61. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/mappers/test_alignment.py +0 -0
  62. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/mappers/test_liftover.py +0 -0
  63. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/mappers/test_mane_transcript.py +0 -0
  64. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/sources/test_mane_transcript_mappings.py +0 -0
  65. {cool_seq_tool-0.14.4 → cool_seq_tool-0.14.5}/tests/test_utils.py +0 -0
@@ -0,0 +1 @@
1
+ * @GenomicMedLab/cool-seq-tool-maintainers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cool_seq_tool
3
- Version: 0.14.4
3
+ Version: 0.14.5
4
4
  Summary: Common Operation on Lots of Sequences Tool
5
5
  Author: Kori Kuzma, James Stevenson, Katie Stahl, Alex Wagner
6
6
  License: MIT License
@@ -2,6 +2,7 @@
2
2
 
3
3
  import logging
4
4
 
5
+ from ga4gh.core.models import Extension
5
6
  from ga4gh.vrs.models import SequenceLocation, SequenceReference
6
7
  from pydantic import ConfigDict, Field, StrictInt, StrictStr, model_validator
7
8
 
@@ -65,9 +66,6 @@ class TxSegment(BaseModelForbidExtra):
65
66
  genomic_location: SequenceLocation = Field(
66
67
  ..., description="The genomic position of a transcript segment."
67
68
  )
68
- is_exonic: bool = Field(
69
- default=True, description="If the position occurs on an exon"
70
- )
71
69
 
72
70
  @model_validator(mode="before")
73
71
  def check_seg_pos(cls, values: dict) -> dict: # noqa: N805
@@ -99,8 +97,8 @@ class TxSegment(BaseModelForbidExtra):
99
97
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
100
98
  },
101
99
  "end": 154192135,
100
+ "extensions": [{"name": "is_exonic", "value": True}],
102
101
  },
103
- "is_exonic": True,
104
102
  }
105
103
  }
106
104
  )
@@ -157,8 +155,8 @@ class GenomicTxSeg(BaseModelForbidExtra):
157
155
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
158
156
  },
159
157
  "end": 154192135,
158
+ "extensions": [{"name": "is_exonic", "value": True}],
160
159
  },
161
- "is_exonic": True,
162
160
  },
163
161
  "errors": [],
164
162
  }
@@ -224,8 +222,8 @@ class GenomicTxSegService(BaseModelForbidExtra):
224
222
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
225
223
  },
226
224
  "end": 154192135,
225
+ "extensions": [{"name": "is_exonic", "value": True}],
227
226
  },
228
- "is_exonic": True,
229
227
  },
230
228
  "seg_end": {
231
229
  "exon_ord": 7,
@@ -237,8 +235,8 @@ class GenomicTxSegService(BaseModelForbidExtra):
237
235
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
238
236
  },
239
237
  "start": 154170399,
238
+ "extensions": [{"name": "is_exonic", "value": True}],
240
239
  },
241
- "is_exonic": True,
242
240
  },
243
241
  }
244
242
  }
@@ -730,7 +728,12 @@ class ExonGenomicCoordsMapper:
730
728
  ), None
731
729
 
732
730
  def _get_vrs_seq_loc(
733
- self, genomic_ac: str, genomic_pos: int, is_seg_start: bool, strand: Strand
731
+ self,
732
+ genomic_ac: str,
733
+ genomic_pos: int,
734
+ is_seg_start: bool,
735
+ strand: Strand,
736
+ is_exonic: bool = True,
734
737
  ) -> tuple[SequenceLocation | None, str | None]:
735
738
  """Create VRS Sequence Location for genomic position where transcript segment
736
739
  occurs
@@ -740,6 +743,8 @@ class ExonGenomicCoordsMapper:
740
743
  :param is_seg_start: ``True`` if ``genomic_pos`` is where the transcript segment
741
744
  starts. ``False`` if ``genomic_pos`` is where the transcript segment ends.
742
745
  :param strand: Strand
746
+ :param is_exonic: A boolean indicating if the genomic breakpoint occurs
747
+ on an exon. By default, this is set to ``True``.
743
748
  :return: Tuple containing VRS location (if successful) and error message (if
744
749
  unable to get GA4GH identifier for ``genomic_ac``).
745
750
  """
@@ -759,6 +764,7 @@ class ExonGenomicCoordsMapper:
759
764
  ),
760
765
  start=genomic_pos if use_start else None,
761
766
  end=genomic_pos if not use_start else None,
767
+ extensions=[Extension(name="is_exonic", value=is_exonic)],
762
768
  ), None
763
769
 
764
770
  async def _genomic_to_tx_segment(
@@ -947,7 +953,7 @@ class ExonGenomicCoordsMapper:
947
953
  )
948
954
 
949
955
  genomic_location, err_msg = self._get_vrs_seq_loc(
950
- genomic_ac, genomic_pos, is_seg_start, strand
956
+ genomic_ac, genomic_pos, is_seg_start, strand, is_exonic
951
957
  )
952
958
  if err_msg:
953
959
  return GenomicTxSeg(errors=[err_msg])
@@ -961,7 +967,6 @@ class ExonGenomicCoordsMapper:
961
967
  exon_ord=exon_num,
962
968
  offset=offset,
963
969
  genomic_location=genomic_location,
964
- is_exonic=is_exonic,
965
970
  ),
966
971
  )
967
972
 
@@ -3,6 +3,7 @@
3
3
  import logging
4
4
  from collections import namedtuple
5
5
  from pathlib import Path
6
+ from urllib.parse import urlparse
6
7
 
7
8
  from agct._core import ChainfileError
8
9
  from asyncpg import InvalidCatalogNameError, UndefinedTableError
@@ -11,7 +12,7 @@ from biocommons.seqrepo import SeqRepo
11
12
  from cool_seq_tool.handlers.seqrepo_access import SEQREPO_ROOT_DIR, SeqRepoAccess
12
13
  from cool_seq_tool.mappers.liftover import LiftOver
13
14
  from cool_seq_tool.resources.data_files import DataFile, get_data_file
14
- from cool_seq_tool.sources.uta_database import UTA_DB_URL, UtaDatabase
15
+ from cool_seq_tool.sources.uta_database import UTA_DB_URL, ParseResult, UtaDatabase
15
16
 
16
17
  _logger = logging.getLogger(__name__)
17
18
 
@@ -119,14 +120,20 @@ async def check_status(
119
120
  else:
120
121
  status["liftover"] = True
121
122
 
123
+ parsed_result = ParseResult(urlparse(db_url))
124
+ sanitized_url = parsed_result.sanitized_url
122
125
  try:
123
126
  await UtaDatabase.create(db_url)
127
+ except ValueError:
128
+ _logger.exception("Database URL is not valid")
124
129
  except (OSError, InvalidCatalogNameError, UndefinedTableError):
125
- _logger.exception("Encountered error instantiating UTA at URI %s", UTA_DB_URL)
130
+ _logger.exception(
131
+ "Encountered error instantiating UTA at URI %s", sanitized_url
132
+ )
126
133
  except Exception as e:
127
134
  _logger.critical(
128
135
  "Encountered unexpected error instantiating UTA from URI %s: %s",
129
- UTA_DB_URL,
136
+ sanitized_url,
130
137
  e,
131
138
  )
132
139
  else:
@@ -5,7 +5,7 @@ import logging
5
5
  from os import environ
6
6
  from typing import Any, Literal, TypeVar
7
7
  from urllib.parse import ParseResult as UrlLibParseResult
8
- from urllib.parse import quote, unquote, urlparse
8
+ from urllib.parse import unquote, urlparse, urlunparse
9
9
 
10
10
  import asyncpg
11
11
  import boto3
@@ -101,8 +101,7 @@ class UtaDatabase:
101
101
  """
102
102
  self.schema = None
103
103
  self._connection_pool = None
104
- original_pwd = db_url.split("//")[-1].split("@")[0].split(":")[-1]
105
- self.db_url = db_url.replace(original_pwd, quote(original_pwd))
104
+ self.db_url = db_url
106
105
  self.args = self._get_conn_args()
107
106
 
108
107
  def _get_conn_args(self) -> DbConnectionArgs:
@@ -954,3 +953,28 @@ class ParseResult(UrlLibParseResult):
954
953
  """Create schema property."""
955
954
  path_elems = self.path.split("/")
956
955
  return path_elems[2] if len(path_elems) > 2 else None
956
+
957
+ @property
958
+ def sanitized_url(self) -> str:
959
+ """Sanitized DB URL with the password masked"""
960
+ netloc = ""
961
+ if self.username:
962
+ netloc += self.username
963
+ if self.password is not None and self.password != "":
964
+ netloc += ":***"
965
+ netloc += "@"
966
+ if self.hostname:
967
+ netloc += f"{self.hostname}"
968
+ if self.port:
969
+ netloc += f":{self.port}"
970
+
971
+ return urlunparse(
972
+ (
973
+ self.scheme,
974
+ netloc,
975
+ self.path,
976
+ self.params,
977
+ self.query,
978
+ self.fragment,
979
+ )
980
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cool_seq_tool
3
- Version: 0.14.4
3
+ Version: 0.14.5
4
4
  Summary: Common Operation on Lots of Sequences Tool
5
5
  Author: Kori Kuzma, James Stevenson, Katie Stahl, Alex Wagner
6
6
  License: MIT License
@@ -6,6 +6,7 @@ CITATION.cff
6
6
  LICENSE
7
7
  README.md
8
8
  pyproject.toml
9
+ .github/CODEOWNERS
9
10
  .github/ISSUE_TEMPLATE/bug-report.yaml
10
11
  .github/ISSUE_TEMPLATE/feature-request.yaml
11
12
  .github/workflows/checks.yaml
@@ -183,8 +183,8 @@ def tpm3_exon1():
183
183
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
184
184
  },
185
185
  "end": 154192135,
186
+ "extensions": [{"name": "is_exonic", "value": True}],
186
187
  },
187
- "is_exonic": True,
188
188
  },
189
189
  }
190
190
  return GenomicTxSeg(**params)
@@ -208,8 +208,8 @@ def tpm3_exon8():
208
208
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
209
209
  },
210
210
  "start": 154170399,
211
+ "extensions": [{"name": "is_exonic", "value": True}],
211
212
  },
212
- "is_exonic": True,
213
213
  },
214
214
  }
215
215
  return GenomicTxSeg(**params)
@@ -294,8 +294,8 @@ def mane_braf():
294
294
  "refgetAccession": "SQ.F-LrLMe1SRpfUZHkQmvkVKFEGaoDeHul",
295
295
  },
296
296
  "end": 140801559,
297
+ "extensions": [{"name": "is_exonic", "value": True}],
297
298
  },
298
- "is_exonic": True,
299
299
  },
300
300
  "seg_end": {
301
301
  "exon_ord": 14,
@@ -307,8 +307,8 @@ def mane_braf():
307
307
  "refgetAccession": "SQ.F-LrLMe1SRpfUZHkQmvkVKFEGaoDeHul",
308
308
  },
309
309
  "start": 140753336,
310
+ "extensions": [{"name": "is_exonic", "value": True}],
310
311
  },
311
- "is_exonic": True,
312
312
  },
313
313
  }
314
314
  return GenomicTxSegService(**params)
@@ -332,6 +332,7 @@ def wee1_exon2_exon11():
332
332
  "refgetAccession": "SQ.2NkFm8HK88MqeNkCgj78KidCAXgnsfV1",
333
333
  },
334
334
  "start": 9576092,
335
+ "extensions": [{"name": "is_exonic", "value": True}],
335
336
  },
336
337
  },
337
338
  "seg_end": {
@@ -344,6 +345,7 @@ def wee1_exon2_exon11():
344
345
  "refgetAccession": "SQ.2NkFm8HK88MqeNkCgj78KidCAXgnsfV1",
345
346
  },
346
347
  "end": 9588449,
348
+ "extensions": [{"name": "is_exonic", "value": True}],
347
349
  },
348
350
  },
349
351
  }
@@ -368,6 +370,7 @@ def mane_wee1_exon2_exon11():
368
370
  "refgetAccession": "SQ.2NkFm8HK88MqeNkCgj78KidCAXgnsfV1",
369
371
  },
370
372
  "start": 9576092,
373
+ "extensions": [{"name": "is_exonic", "value": True}],
371
374
  },
372
375
  },
373
376
  "seg_end": {
@@ -380,6 +383,7 @@ def mane_wee1_exon2_exon11():
380
383
  "refgetAccession": "SQ.2NkFm8HK88MqeNkCgj78KidCAXgnsfV1",
381
384
  },
382
385
  "end": 9588449,
386
+ "extensions": [{"name": "is_exonic", "value": True}],
383
387
  },
384
388
  },
385
389
  }
@@ -404,6 +408,7 @@ def ntrk1_exon10_exon17():
404
408
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
405
409
  },
406
410
  "start": 156874570,
411
+ "extensions": [{"name": "is_exonic", "value": True}],
407
412
  },
408
413
  },
409
414
  "seg_end": {
@@ -416,6 +421,7 @@ def ntrk1_exon10_exon17():
416
421
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
417
422
  },
418
423
  "end": 156881850,
424
+ "extensions": [{"name": "is_exonic", "value": True}],
419
425
  },
420
426
  },
421
427
  }
@@ -441,8 +447,8 @@ def zbtb10_exon3_end():
441
447
  "refgetAccession": "SQ.209Z7zJ-mFypBEWLk4rNC6S_OxY5p7bs",
442
448
  },
443
449
  "end": 80514010,
450
+ "extensions": [{"name": "is_exonic", "value": False}],
444
451
  },
445
- "is_exonic": False,
446
452
  },
447
453
  }
448
454
  return GenomicTxSegService(**params)
@@ -466,8 +472,8 @@ def zbtb10_exon5_start():
466
472
  "refgetAccession": "SQ.209Z7zJ-mFypBEWLk4rNC6S_OxY5p7bs",
467
473
  },
468
474
  "start": 80518580,
475
+ "extensions": [{"name": "is_exonic", "value": False}],
469
476
  },
470
- "is_exonic": False,
471
477
  },
472
478
  "seg_end": None,
473
479
  }
@@ -493,8 +499,8 @@ def tpm3_exon6_end():
493
499
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
494
500
  },
495
501
  "start": 154171410,
502
+ "extensions": [{"name": "is_exonic", "value": False}],
496
503
  },
497
- "is_exonic": False,
498
504
  },
499
505
  }
500
506
  return GenomicTxSegService(**params)
@@ -518,8 +524,8 @@ def tpm3_exon5_start():
518
524
  "refgetAccession": "SQ.Ya6Rs7DHhDeg7YaOSg1EoNi3U_nQ9SvO",
519
525
  },
520
526
  "end": 154173080,
527
+ "extensions": [{"name": "is_exonic", "value": False}],
521
528
  },
522
- "is_exonic": False,
523
529
  },
524
530
  "seg_end": None,
525
531
  }
@@ -545,8 +551,8 @@ def gusbp3_exon2_end():
545
551
  "refgetAccession": "SQ.aUiQCzCPZ2d0csHbMSbh2NzInhonSXwI",
546
552
  },
547
553
  "start": 69680764,
554
+ "extensions": [{"name": "is_exonic", "value": False}],
548
555
  },
549
- "is_exonic": False,
550
556
  },
551
557
  }
552
558
  return GenomicTxSegService(**params)
@@ -570,8 +576,8 @@ def eln_grch38_intronic():
570
576
  "refgetAccession": "SQ.F-LrLMe1SRpfUZHkQmvkVKFEGaoDeHul",
571
577
  },
572
578
  "start": 74028173,
579
+ "extensions": [{"name": "is_exonic", "value": True}],
573
580
  },
574
- "is_exonic": True,
575
581
  },
576
582
  "seg_end": {
577
583
  "exon_ord": 7,
@@ -583,8 +589,8 @@ def eln_grch38_intronic():
583
589
  "refgetAccession": "SQ.F-LrLMe1SRpfUZHkQmvkVKFEGaoDeHul",
584
590
  },
585
591
  "end": 74043599,
592
+ "extensions": [{"name": "is_exonic", "value": False}],
586
593
  },
587
- "is_exonic": False,
588
594
  },
589
595
  }
590
596
  return GenomicTxSegService(**params)
@@ -608,8 +614,8 @@ def gusbp3_exon5_start():
608
614
  "refgetAccession": "SQ.aUiQCzCPZ2d0csHbMSbh2NzInhonSXwI",
609
615
  },
610
616
  "end": 69645878,
617
+ "extensions": [{"name": "is_exonic", "value": False}],
611
618
  },
612
- "is_exonic": False,
613
619
  },
614
620
  "seg_end": None,
615
621
  }
@@ -660,7 +666,10 @@ def genomic_tx_seg_service_checks(actual, expected=None, is_valid=True):
660
666
  assert (
661
667
  actual_seg.genomic_location.end == expected_seg.genomic_location.end
662
668
  )
663
- assert actual_seg.is_exonic == expected_seg.is_exonic
669
+ assert (
670
+ actual_seg.genomic_location.extensions
671
+ == expected_seg.genomic_location.extensions
672
+ )
664
673
 
665
674
  assert actual.errors == expected.errors
666
675
  else:
@@ -728,7 +737,10 @@ def genomic_tx_seg_checks(actual, expected=None, is_valid=True):
728
737
  actual_seg.genomic_location.start == expected_seg.genomic_location.start
729
738
  )
730
739
  assert actual_seg.genomic_location.end == expected_seg.genomic_location.end
731
- assert actual_seg.is_exonic == expected_seg.is_exonic
740
+ assert (
741
+ actual_seg.genomic_location.extensions
742
+ == expected_seg.genomic_location.extensions
743
+ )
732
744
 
733
745
  assert actual.errors == expected.errors
734
746
  else:
@@ -1,11 +1,14 @@
1
1
  """Test UTA data source."""
2
2
 
3
+ from urllib.parse import urlparse
4
+
3
5
  import pytest
4
6
 
5
7
  from cool_seq_tool.schemas import Strand
6
8
  from cool_seq_tool.sources.uta_database import (
7
9
  GenomicTxData,
8
10
  GenomicTxMetadata,
11
+ ParseResult,
9
12
  TxExonAlnData,
10
13
  )
11
14
 
@@ -360,3 +363,98 @@ async def test_get_mane_transcripts_from_genomic_pos(test_db):
360
363
  # invalid ac
361
364
  resp = await test_db.get_transcripts_from_genomic_pos("NC_000007.14232", 140753336)
362
365
  assert resp == []
366
+
367
+
368
+ @pytest.mark.parametrize(
369
+ ("raw_url", "expected"),
370
+ [
371
+ # Username + password
372
+ (
373
+ "postgresql://user:pass@localhost:5432/dbname",
374
+ {
375
+ "scheme": "postgresql",
376
+ "username": "user",
377
+ "password": "pass",
378
+ "hostname": "localhost",
379
+ "port": 5432,
380
+ "database": "dbname",
381
+ "sanitized_url": "postgresql://user:***@localhost:5432/dbname",
382
+ },
383
+ ),
384
+ # Username with null password
385
+ (
386
+ "postgresql://user@localhost/dbname",
387
+ {
388
+ "scheme": "postgresql",
389
+ "username": "user",
390
+ "password": None,
391
+ "hostname": "localhost",
392
+ "port": None,
393
+ "database": "dbname",
394
+ "sanitized_url": "postgresql://user@localhost/dbname",
395
+ },
396
+ ),
397
+ # Password is "0"
398
+ (
399
+ "postgresql://user:0@localhost/dbname",
400
+ {
401
+ "scheme": "postgresql",
402
+ "username": "user",
403
+ "password": "0",
404
+ "hostname": "localhost",
405
+ "port": None,
406
+ "database": "dbname",
407
+ "sanitized_url": "postgresql://user:***@localhost/dbname",
408
+ },
409
+ ),
410
+ # Empty password
411
+ (
412
+ "postgresql://user:@localhost/dbname",
413
+ {
414
+ "scheme": "postgresql",
415
+ "username": "user",
416
+ "password": "",
417
+ "hostname": "localhost",
418
+ "port": None,
419
+ "database": "dbname",
420
+ "sanitized_url": "postgresql://user@localhost/dbname",
421
+ },
422
+ ),
423
+ # No username
424
+ (
425
+ "postgresql://localhost:5432/dbname",
426
+ {
427
+ "scheme": "postgresql",
428
+ "username": None,
429
+ "password": None,
430
+ "hostname": "localhost",
431
+ "port": 5432,
432
+ "database": "dbname",
433
+ "sanitized_url": "postgresql://localhost:5432/dbname",
434
+ },
435
+ ),
436
+ # With query params
437
+ (
438
+ "postgresql://user:secret@localhost/dbname?query#fragment",
439
+ {
440
+ "scheme": "postgresql",
441
+ "username": "user",
442
+ "password": "secret",
443
+ "hostname": "localhost",
444
+ "port": None,
445
+ "database": "dbname",
446
+ "sanitized_url": "postgresql://user:***@localhost/dbname?query#fragment",
447
+ },
448
+ ),
449
+ ],
450
+ )
451
+ async def test_parsed_url(raw_url, expected):
452
+ parsed_result = ParseResult(urlparse(raw_url))
453
+
454
+ assert parsed_result.scheme == expected["scheme"]
455
+ assert parsed_result.username == expected["username"]
456
+ assert parsed_result.password == expected["password"]
457
+ assert parsed_result.hostname == expected["hostname"]
458
+ assert parsed_result.port == expected["port"]
459
+ assert parsed_result.database == expected["database"]
460
+ assert parsed_result.sanitized_url == expected["sanitized_url"]
File without changes
File without changes
File without changes