Skip to content
New issue

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

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

Already on GitHub? # to your account

Added python 3.10 and 3.11 support #251

Merged
merged 4 commits into from
Nov 1, 2024
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ jobs:
timeout-minutes: 20
strategy:
matrix:
python-version: [3.8, 3.9]
python-version: ["3.8", "3.9", "3.10", "3.11"]

steps:
- uses: actions/checkout@v2
@@ -34,7 +34,7 @@ jobs:
run: |
pip install pytest-cov
pip install codecov
pip install ".[spatial]"
pip install .
- name: Test with pytest
run: |
pytest -vv test/ --cov-report=xml --cov=cassiopeia
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -167,3 +167,4 @@ cassiopeia/tools/branch_length_estimator/_iid_exponential_bayesian.cpp
docs/api/reference/**
.vscode
cassiopeia/config.ini
environment.yml
4 changes: 2 additions & 2 deletions cassiopeia/plotting/utilities.py
Original file line number Diff line number Diff line change
@@ -395,9 +395,9 @@ def get_random_indel_colors(
if "none" in indel.lower():
indel2color[indel] = rgb_to_hsv((0.75, 0.75, 0.75))
elif indel == "NC":
indel2color[indel] = rgb_to_hsv((0, 0, 0))
indel2color[indel] = rgb_to_hsv((0.0, 0.0, 0.0))
elif indel == "missing":
indel2color[indel] = rgb_to_hsv((1, 1, 1))
indel2color[indel] = rgb_to_hsv((1.0, 1.0, 1.0))
else:
# randomly pick a color family and then draw random colors
# from that family
1 change: 0 additions & 1 deletion cassiopeia/solver/HybridSolver.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import multiprocessing
import networkx as nx
import numpy as np
from numpy.lib.arraysetops import unique
import pandas as pd
from tqdm.auto import tqdm

18 changes: 13 additions & 5 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -3,19 +3,27 @@

def pytest_addoption(parser):
parser.addoption(
"--runslow", action="store_true", default=False, help="run slow tests"
"--runslow", action="store_true", default=False, help="run slow tests",
)
parser.addoption(
"--runspatial", action="store_true", default=False, help="run spatial tests",
)


def pytest_configure(config):
config.addinivalue_line("markers", "slow: mark test as slow to run")
config.addinivalue_line("markers", "spatial: mark test as spatial to run")



def pytest_collection_modifyitems(config, items):
if config.getoption("--runslow"):
# --runslow given in cli: do not skip slow tests
return
run_slow = config.getoption("--runslow")
run_spatial = config.getoption("--runspatial")
skip_slow = pytest.mark.skip(reason="need --runslow option to run")
skip_spatial = pytest.mark.skip(reason="need --runspatial option to run")

for item in items:
if "slow" in item.keywords:
if "slow" in item.keywords and not run_slow:
item.add_marker(skip_slow)
if "spatial" in item.keywords and not run_spatial:
item.add_marker(skip_spatial)
24 changes: 13 additions & 11 deletions pyproject.toml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -4,9 +4,10 @@ classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"Natural Language :: English",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
@@ -20,7 +21,7 @@ license = "MIT"
name = "cassiopeia-lineage"
readme = 'README.md'
repository = "https://github.com/YosefLab/Cassiopeia"
version = "2.0.0"
version = "2.1.0"

include = [
{path = "cassiopeia/preprocess/*.so", format = "wheel"},
@@ -46,20 +47,19 @@ codecov = {version = ">=2.0.8", optional = true}
cvxpy = "*"
ete3 = ">=3.1.1"
hits = "*"
importlib-metadata = {version = "^1.0", python = "<3.8"}
ipython = {version = ">=7.20", optional = true, python = ">=3.7"}
ipython = {version = ">=7.20", optional = true}
isort = {version = ">=5.7", optional = true}
itolapi = "*"
jupyter = {version = ">=1.0", optional = true}
matplotlib = ">=2.2.2"
nbconvert = ">=5.4.0"
nbformat = ">=4.4.0"
nbconvert = {version = ">=5.4.0", optional = true}
nbformat = {version = ">=4.4.0", optional = true}
nbsphinx = {version = "*", optional = true}
nbsphinx-link = {version = "*", optional = true}
networkx = "==3.1"
networkx = ">=3.1"
ngs-tools = ">=1.5.6"
numba = ">=0.51.0,<0.59.0"
numpy = ">=1.22"
numba = ">=0.51.0"
numpy = ">=1.22, <3.0"
opencv-python = {version = ">=4.5.4.60", optional = true}
pandas = ">=1.1.4"
parameterized = "*"
@@ -75,7 +75,7 @@ pyvista = {version = "=0.41.0", optional = true}
scanpydoc = {version = ">=0.5", optional = true}
scikit-image = {version = ">=0.19.1", optional = true}
scikit-learn = {version = ">=1.0.2", optional = true}
scipy = ">=1.2.0,<=1.11.4"
scipy = ">=1.2.0"
sphinx = {version = ">=3.4", optional = true}
sphinx-autodoc-typehints = {version = "*", optional = true}
sphinx-gallery = {version = ">0.6", optional = true}
@@ -93,7 +93,7 @@ script = "build.py"

[build-system]
build-backend = "poetry.core.masonry.api"
requires = ["poetry-core>=1.0.7", "Cython", "numpy>=1.19.5,<1.22", "setuptools", "pip>=22.0.0"]
requires = ["poetry-core>=1.0.7", "Cython", "numpy>=1.19.5", "setuptools", "pip>=22.0.0"]

[tool.poetry.scripts]
cassiopeia-preprocess = 'cassiopeia.preprocess.cassiopeia_preprocess:main'
@@ -103,6 +103,8 @@ dev = ["black", "pytest", "flake8", "codecov", "jupyter", "pre-commit", "isort"]
docs = [
"sphinx",
"scanpydoc",
"nbconvert",
"nbformat",
"nbsphinx",
"nbsphinx-link",
"ipython",
11 changes: 8 additions & 3 deletions test/plotting_tests/local_3d_test.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import pytest
import unittest
from unittest import mock

import networkx as nx
import numpy as np
import pandas as pd

import cassiopeia as cas
from cassiopeia.plotting import local_3d
@@ -20,6 +18,7 @@ def setUp(self):

self.labels = local_3d.labels_from_coordinates(self.tree)

@pytest.mark.spatial
def test_interpolate_branch(self):
parent = (0, 0, 0)
child = (1, 1, 1)
@@ -28,6 +27,7 @@ def test_interpolate_branch(self):
local_3d.interpolate_branch(parent, child),
)

@pytest.mark.spatial
def test_polyline_from_points(self):
points = np.array(
[
@@ -39,6 +39,7 @@ def test_polyline_from_points(self):
poly = local_3d.polyline_from_points(points)
np.testing.assert_array_equal(points, poly.points)

@pytest.mark.spatial
def test_average_mixing(self):
c1 = (0, 0, 0)
c2 = (0.1, 0.2, 0.3)
@@ -47,14 +48,17 @@ def test_average_mixing(self):
(0.2, 0.3, 0.1), local_3d.average_mixing(c1, c2, c3)
)

@pytest.mark.spatial
def test_highlight(self):
c = (0.8, 0.2, 0.0)
np.testing.assert_allclose((1.0, 0.25, 0.0), local_3d.highlight(c))

@pytest.mark.spatial
def test_lowlight(self):
c = (0.8, 0.2, 0.0)
np.testing.assert_allclose((0.3, 0.075, 0.0), local_3d.lowlight(c))

@pytest.mark.spatial
def test_labels_from_coordinates(self):
# invalid shape
with self.assertRaises(ValueError):
@@ -82,6 +86,7 @@ def test_labels_from_coordinates(self):
spatial_simulator.overlay_data(dense_tree)
labels = local_3d.labels_from_coordinates(dense_tree, shape=(100, 100))

@pytest.mark.spatial
def test_Tree3D(self):
# There isn't a good way to test this, other than making sure there
# are no errors on initialization.
5 changes: 5 additions & 0 deletions test/simulator_tests/clonal_spatial_simulator_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import pytest
import unittest

import networkx as nx
@@ -53,6 +54,7 @@ def setUp(self):
tree=topology, cell_meta=self.cell_meta
)

@pytest.mark.spatial
def test_init(self):
with self.assertRaises(DataSimulatorError):
ClonalSpatialDataSimulator()
@@ -69,6 +71,7 @@ def test_init(self):
self.assertEqual(simulator.dim, 3)
np.testing.assert_array_equal(np.ones((10, 10, 10), dtype=bool), simulator.space)

@pytest.mark.spatial
def test_overlay_data(self):
simulator = ClonalSpatialDataSimulator((100, 100))
simulator.overlay_data(self.basic_tree)
@@ -107,6 +110,7 @@ def test_overlay_data(self):
self.basic_tree.cell_meta, expected_cell_meta
)

@pytest.mark.spatial
def test_overlay_data_with_space(self):
simulator = ClonalSpatialDataSimulator(space=np.ones((100, 100), dtype=bool))
simulator.overlay_data(self.basic_tree)
@@ -144,6 +148,7 @@ def test_overlay_data_with_space(self):
self.basic_tree.cell_meta, expected_cell_meta
)

@pytest.mark.spatial
def test_overlay_data_with_existing_cell_meta(self):
simulator = ClonalSpatialDataSimulator((100, 100))
simulator.overlay_data(self.tree_with_cell_meta)
73 changes: 0 additions & 73 deletions test/solver_tests/sharedmutationjoiner_test.py
Original file line number Diff line number Diff line change
@@ -348,79 +348,6 @@ def test_basic_solver(self):
nx.shortest_path_length(expected_tree, sample1, sample2),
)

def test_solver_no_numba(self):
self.smj_solver_no_numba.solve(self.basic_tree)

# test that the dissimilarity map and character matrix were not altered
cm = pd.DataFrame.from_dict(
{
"a": [0, 1, 2],
"b": [1, 1, 2],
"c": [2, 2, 2],
"d": [1, 1, 1],
"e": [0, 0, 0],
},
orient="index",
columns=["x1", "x2", "x3"],
)
for i in self.basic_similarity_map.index:
for j in self.basic_similarity_map.columns:
self.assertEqual(
self.basic_similarity_map.loc[i, j],
self.basic_tree.get_dissimilarity_map().loc[i, j],
)
for i in self.basic_tree.character_matrix.index:
for j in self.basic_tree.character_matrix.columns:
self.assertEqual(
cm.loc[i, j], self.basic_tree.character_matrix.loc[i, j]
)

# test leaves exist in tree
_leaves = self.basic_tree.leaves

self.assertEqual(len(_leaves), self.basic_similarity_map.shape[0])
for _leaf in _leaves:
self.assertIn(_leaf, self.basic_similarity_map.index.values)

# test for expected number of edges
edges = list(self.basic_tree.edges)
self.assertEqual(len(edges), 8)

# test relationships between samples
expected_tree = nx.DiGraph()
expected_tree.add_edges_from(
[
("5", "a"),
("5", "b"),
("6", "5"),
("6", "c"),
("7", "d"),
("7", "e"),
("8", "6"),
("8", "7"),
]
)

observed_tree = self.basic_tree.get_tree_topology()
triplets = itertools.combinations(["a", "b", "c", "d", "e"], 3)
for triplet in triplets:

expected_triplet = find_triplet_structure(triplet, expected_tree)
observed_triplet = find_triplet_structure(triplet, observed_tree)
self.assertEqual(expected_triplet, observed_triplet)

# compare tree distances
observed_tree = observed_tree.to_undirected()
expected_tree = expected_tree.to_undirected()
for i in range(len(_leaves)):
sample1 = _leaves[i]
for j in range(i + 1, len(_leaves)):
sample2 = _leaves[j]
self.assertEqual(
nx.shortest_path_length(observed_tree, sample1, sample2),
nx.shortest_path_length(expected_tree, sample1, sample2),
)

def test_smj_solver_weights(self):
self.smj_solver_modified_pp.solve(self.pp_tree_priors)
observed_tree = self.pp_tree_priors.get_tree_topology()
Loading