Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Locations overlap #236

Merged
merged 4 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"recommendations": [
"ms-python.black-formatter",
"ms-python.flake8",
"ms-python.python",
"ms-python.vscode-pylance",
]
}
15 changes: 15 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/CVS": true,
"**/.DS_Store": true,
"**/*.pyc": true,
"**/__pycache__": true
},
// Set flake8 path
"flake8.path": [".venv/bin/flake8"],
"black-formatter.path": [".venv/bin/black"],
"python.defaultInterpreterPath": ".venv/bin/python",
}
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ or by `pip install pyparsing requests cai2 scipy matplotlib pillow`

## Contributing

Please direct pull requests towards the `develop` branch.
Please direct pull requests towards the `dev_bjorn` branch.


### Local development
Expand All @@ -273,6 +273,7 @@ Please direct pull requests towards the `develop` branch.

```bash
# If you want the virtual environment to be created in this folder
# (this is now the default, see `poetry.toml`)
poetry config virtualenvs.in-project true

# Install dependencies (extras are required for tests to pass)
Expand All @@ -281,16 +282,17 @@ Please direct pull requests towards the `develop` branch.
# Activate virtual environment
poetry shell
```

2. Make your changes.
3. Add the necessary tests in `tests/`.
4. Run the tests from the root directory with `python run_test.py`.
5. Install `pre-commit` hooks if you haven't by running `pre-commit install`. `pre-commit` should be available in the environment, since it is installed by poetry.
6. Make a PR.

#### Building the documentation locally

Below the commands to run a local sphinx server that auto-updated when files are changed.

```
```bash
# Install docs dependency group
poetry install --with docs

Expand Down
343 changes: 340 additions & 3 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions poetry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[virtualenvs]
in-project = true
40 changes: 22 additions & 18 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,24 @@ version = "6.0.0-a.24.post.17+b7b559bd66"
[tool.poetry.dependencies]
appdirs = ">=1.4.4"
biopython = ">=1.80"
cai2 = {version = ">=1.0.5", optional = true}
matplotlib = {version = ">=3.4.3", optional = true}
cai2 = { version = ">=1.0.5", optional = true }
matplotlib = { version = ">=3.4.3", optional = true }
networkx = ">=2.8.8"
numpy = [
{version = ">1.26", python = ">=3.9"},
{version = "<1.24", python = "<3.9"},
{ version = ">1.26", python = ">=3.9" },
{ version = "<1.24", python = "<3.9" },
]
pillow = {version = ">=8.4.0", optional = true}
pillow = { version = ">=8.4.0", optional = true }
prettytable = ">=3.5.0"
pydivsufsort = ">=0.0.14"
pyfiglet = "0.8.post1"
pyparsing = {version = ">=2.4.7", optional = true}
pyperclip = {version = ">=1.8.2", optional = true}
pyparsing = { version = ">=2.4.7", optional = true }
pyperclip = { version = ">=1.8.2", optional = true }
python = ">=3.8,<4.0"
requests = {version = ">=2.26.0", optional = true}
requests = { version = ">=2.26.0", optional = true }
scipy = [
{version = ">=1.11.3", python = ">=3.12", optional = true},
{version = ">=1.9.3", python = "<3.12", optional = true},
{ version = ">=1.11.3", python = ">=3.12", optional = true },
{ version = ">=1.9.3", python = "<3.12", optional = true },
]
seguid = ">=0.0.5"
[tool.poetry.extras]
Expand All @@ -62,10 +62,7 @@ express = ["cai2"]
gel = ["scipy", "matplotlib", "pillow"]
[build-system]
build-backend = "poetry_dynamic_versioning.backend"
requires = [
"poetry-core",
"poetry-dynamic-versioning",
]
requires = ["poetry-core", "poetry-dynamic-versioning"]
[tool.poetry-dynamic-versioning]
enable = true
style = "semver"
Expand All @@ -87,13 +84,20 @@ numpydoc = "^1.6.0"
sphinx-autobuild = "^2021.3.14"
sphinx-rtd-theme = ">=1.3,<3.0"


[tool.poetry.group.dev.dependencies]
autopep8 = "^2.1.0"
black = "^24.4.2"
flake8-bugbear = [{ version = ">=24.4.21", python = ">=3.8.1" }]
pre-commit = [
{ version = ">3.6", python = ">=3.9" },
{ version = "<3.6", python = "<3.9" },
]

[tool.pytest.ini_options]
minversion = "6.0.2"
python_files = "test_*.py"
testpaths = [
"tests",
"src",
]
testpaths = ["tests", "src"]
[tool.black]
include = '\.pyi?$'
line-length = 119
Expand Down
25 changes: 25 additions & 0 deletions src/pydna/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,31 @@ def location_boundaries(loc: _Union[_sl, _cl]):
return loc.parts[0].start, loc.parts[-1].end


def locations_overlap(loc1: _Union[_sl, _cl], loc2: _Union[_sl, _cl], seq_len):
start1, end1 = location_boundaries(loc1)
start2, end2 = location_boundaries(loc2)

boundaries1 = [(start1, end1)]
boundaries2 = [(start2, end2)]

if start1 > end1:
boundaries1 = [
[start1, end1 + seq_len],
[start1 - seq_len, end1],
]
if start2 > end2:
boundaries2 = [
[start2, end2 + seq_len],
[start2 - seq_len, end2],
]

for b1, b2 in _itertools.product(boundaries1, boundaries2):
if b1[0] < b2[1] and b1[1] > b2[0]:
return True

return False


if __name__ == "__main__":
cached = _os.getenv("pydna_cached_funcs", "")
_os.environ["pydna_cached_funcs"] = ""
Expand Down
27 changes: 14 additions & 13 deletions tests/test_module_dseq.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,7 @@ def test_left_end_position():

def test_apply_cut():
from pydna.dseq import Dseq
from Bio.Restriction import EcoRI, BamHI

seq = Dseq('aaGAATTCaa', circular=False)

Expand Down Expand Up @@ -876,31 +877,31 @@ def test_apply_cut():
# Overlapping cuts should return an error
seq = Dseq('aaGAATTCaa', circular=True)
first_cuts = [
((3, -4), None),
((7, 4), None),
((3, -4), BamHI),
((7, 4), BamHI),
# Spanning the origin
((9, -8), None),
((8, 8), None),
((9, -8), BamHI),
((8, 8), BamHI),
]

overlapping_cuts = [
((4, -4), None),
((2, -4), None),
((2, -6), None),
((8, 4), None),
((6, 4), None),
((8, 6), None),
((4, -4), EcoRI),
((2, -4), EcoRI),
((2, -6), EcoRI),
((8, 4), EcoRI),
((6, 4), EcoRI),
((8, 6), EcoRI),
# Spanning the origin
((7, -8), None),
((6, 8), None),
((7, -8), EcoRI),
((6, 8), EcoRI),
]

for first_cut in first_cuts:
for second_cut in overlapping_cuts:
try:
seq.apply_cut(first_cut, second_cut)
except ValueError as e:
assert e.args[0] == 'Cuts overlap'
assert e.args[0] == 'Cuts by BamHI EcoRI overlap.'
else:
print(first_cut, second_cut)
assert False, 'Expected ValueError'
Expand Down
36 changes: 36 additions & 0 deletions tests/test_module_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,5 +475,41 @@ def test_shift_location():
assert shift_location(shift_location(loc, 1, 6), -1, 6) == loc


def test_locations_overlap():
from pydna.utils import locations_overlap, shift_location
from Bio.SeqFeature import SimpleLocation

# exact ===== |
# greater ========= |
# inner == |
# right ===== |
# left ===== |
# main ===== |
# -----------------------------------------
# 0123456789
main_overlap = SimpleLocation(5, 10)
inner_overlap = SimpleLocation(6, 8)
right_overlap = SimpleLocation(6, 11)
left_overlap = SimpleLocation(4, 9)
exact_overlap = SimpleLocation(5, 10)
greater_overlap = SimpleLocation(3, 12)
no_overlap_left = SimpleLocation(0, 5)
no_overlap_right = SimpleLocation(11, 15)

overlapping_locations = [inner_overlap, right_overlap, left_overlap, exact_overlap, greater_overlap]
non_overlapping_locations = [no_overlap_left, no_overlap_right]

for shift in range(20):
main_shifted = shift_location(main_overlap, shift, 20)
for loc in overlapping_locations:
loc_shifted = shift_location(loc, shift, 20)
assert locations_overlap(main_shifted, loc_shifted, 20)
for loc in non_overlapping_locations:
loc_shifted = shift_location(loc, shift, 20)
assert not locations_overlap(main_shifted, loc_shifted, 20)




if __name__ == "__main__":
pytest.main([__file__, "-vv", "-s"])
Loading