Skip to content

Commit d805dd3

Browse files
authored
Merge pull request #195 from SigProfilerSuite/python-312-fix-p2
Python 312 fix p2
2 parents d7deef0 + f102649 commit d805dd3

4 files changed

Lines changed: 81 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
## [1.1.3] - 2026-01-23
10+
### Fixed
11+
- Fixed Python 3.12 compatibility issues with pandas StringArray in `set_index()` calls:
12+
- Replaced `set_index()` with direct index assignment using `pd.Index()` to avoid StringArray unhashable type errors
13+
- Fixed index restoration from `devopts` dictionary in both `denovo_refit_option` and `decompose_fit_option` paths
14+
- Fixed index assignment in `make_final_solution()` for process matrices, exposure matrices, and signature statistics
15+
916
## [1.1.2] - 2026-01-23
1017
### Fixed
1118
- Fixed Python 3.12 compatibility issues with pandas DataFrame/Series indexing and method calls:

SigProfilerAssignment/decompose_subroutines.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,19 @@ def make_final_solution(
11251125
pass
11261126

11271127
processAvg = pd.DataFrame(processAvg.astype(float))
1128-
processes = processAvg.set_index(index)
1128+
# Convert index to pandas Index to handle StringArray compatibility in Python 3.12+
1129+
# StringArray is unhashable and cannot be used directly with set_index
1130+
if isinstance(index, str):
1131+
processes = processAvg.set_index(index)
1132+
else:
1133+
# Convert to list first, then create pandas Index and assign directly
1134+
if hasattr(index, 'tolist'):
1135+
index_list = index.tolist()
1136+
else:
1137+
index_list = list(index)
1138+
# Assign index directly instead of using set_index to avoid column lookup
1139+
processes = processAvg.copy()
1140+
processes.index = pd.Index(index_list)
11291141
processes.columns = allsigids
11301142
processes = processes.rename_axis("MutationType", axis="columns")
11311143
processes.to_csv(
@@ -1140,8 +1152,17 @@ def make_final_solution(
11401152
index_label=[processes.columns.name],
11411153
)
11421154
exposureAvg = pd.DataFrame(exposureAvg.astype(int))
1143-
allsigids = np.array(allsigids)
1144-
exposures = exposureAvg.set_index(allsigids)
1155+
# Convert allsigids to list to handle StringArray compatibility in Python 3.12+
1156+
if isinstance(allsigids, str):
1157+
allsigids_list = allsigids
1158+
elif hasattr(allsigids, 'tolist'):
1159+
allsigids_list = allsigids.tolist()
1160+
else:
1161+
allsigids_list = list(allsigids)
1162+
allsigids = np.array(allsigids_list)
1163+
# Assign index directly instead of using set_index to avoid column lookup
1164+
exposures = exposureAvg.copy()
1165+
exposures.index = pd.Index(allsigids_list)
11451166
exposures.columns = allcolnames
11461167
exposures = exposures.T
11471168
exposures = exposures.rename_axis("Samples", axis="columns")
@@ -1258,7 +1279,18 @@ def make_final_solution(
12581279
if refit_denovo_signatures:
12591280
try:
12601281
process_std_error = pd.DataFrame(process_std_error)
1261-
processSTE = process_std_error.set_index(index)
1282+
# Convert index to pandas Index to handle StringArray compatibility in Python 3.12+
1283+
if isinstance(index, str):
1284+
processSTE = process_std_error.set_index(index)
1285+
else:
1286+
# Convert to list first, then create pandas Index and assign directly
1287+
if hasattr(index, 'tolist'):
1288+
index_list = index.tolist()
1289+
else:
1290+
index_list = list(index)
1291+
# Assign index directly instead of using set_index to avoid column lookup
1292+
processSTE = process_std_error.copy()
1293+
processSTE.index = pd.Index(index_list)
12621294
processSTE.columns = allsigids
12631295
processSTE = processSTE.rename_axis("MutationType", axis="columns")
12641296
processSTE.to_csv(
@@ -1276,7 +1308,16 @@ def make_final_solution(
12761308
pass
12771309
if refit_denovo_signatures:
12781310
try:
1279-
signature_stats = signature_stats.set_index(allsigids)
1311+
# Convert allsigids to list to handle StringArray compatibility in Python 3.12+
1312+
if isinstance(allsigids, str):
1313+
allsigids_list = allsigids
1314+
elif hasattr(allsigids, 'tolist'):
1315+
allsigids_list = allsigids.tolist()
1316+
else:
1317+
allsigids_list = list(allsigids)
1318+
# Assign index directly instead of using set_index to avoid column lookup
1319+
signature_stats = signature_stats.copy()
1320+
signature_stats.index = pd.Index(allsigids_list)
12801321
signature_stats = signature_stats.rename_axis("Signatures", axis="columns")
12811322
signature_stats.to_csv(
12821323
layer_directory

SigProfilerAssignment/decomposition.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,19 @@ def spa_analyze(
577577
listOfSignatures = devopts["listOfSignatures"]
578578
index = devopts["index"]
579579
colnames = devopts["colnames"]
580-
genomes = genomes.set_index(index)
580+
# Convert index to pandas Index to handle StringArray compatibility in Python 3.12+
581+
# StringArray is unhashable and cannot be used directly with set_index
582+
if isinstance(index, str):
583+
# If it's a column name, use set_index normally
584+
genomes = genomes.set_index(index)
585+
else:
586+
# Convert to list first, then create pandas Index and assign directly
587+
if hasattr(index, 'tolist'):
588+
index_list = index.tolist()
589+
else:
590+
index_list = list(index)
591+
# Assign index directly instead of using set_index to avoid column lookup
592+
genomes.index = pd.Index(index_list)
581593
genomes.columns = colnames
582594
# genomes = genomes.rename_axis("Mutation Types", axis="columns")
583595

@@ -766,7 +778,19 @@ def spa_analyze(
766778
listOfSignatures = devopts["listOfSignatures"]
767779
index = devopts["index"]
768780
colnames = devopts["colnames"]
769-
genomes = genomes.set_index(index)
781+
# Convert index to pandas Index to handle StringArray compatibility in Python 3.12+
782+
# StringArray is unhashable and cannot be used directly with set_index
783+
if isinstance(index, str):
784+
# If it's a column name, use set_index normally
785+
genomes = genomes.set_index(index)
786+
else:
787+
# Convert to list first, then create pandas Index and assign directly
788+
if hasattr(index, 'tolist'):
789+
index_list = index.tolist()
790+
else:
791+
index_list = list(index)
792+
# Assign index directly instead of using set_index to avoid column lookup
793+
genomes.index = pd.Index(index_list)
770794
genomes.columns = colnames
771795
make_decomposition_plots = devopts["make_decomposition_plots"]
772796
# genomes = genomes.rename_axis("Mutation Types", axis="columns")

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
if os.path.exists("dist"):
77
shutil.rmtree("dist")
88

9-
VERSION = "1.1.2"
9+
VERSION = "1.1.3"
1010

1111

1212
def write_version_py(filename="SigProfilerAssignment/version.py"):
@@ -15,7 +15,7 @@ def write_version_py(filename="SigProfilerAssignment/version.py"):
1515
# THIS FILE IS GENERATED FROM SigProfilerAssignment SETUP.PY
1616
short_version = '%(version)s'
1717
version = '%(version)s'
18-
Update = 'v1.1.2: Fixed to_csv() calls for Python 3.12 compatibility'
18+
Update = 'v1.1.3: Fixed set_index() calls for Python 3.12 StringArray compatibility'
1919
2020
"""
2121
fh = open(filename, "w")

0 commit comments

Comments
 (0)