bscampp 1.0.7__py3-none-any.whl → 1.0.8__py3-none-any.whl

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.
bscampp/__init__.py CHANGED
@@ -12,7 +12,7 @@ import logging, os
12
12
  # not really needed for BSCAMPP but safe to update here
13
13
  os.sys.setrecursionlimit(1000000)
14
14
 
15
- __version__ = "1.0.7"
15
+ __version__ = "1.0.8"
16
16
  _INSTALL_PATH = __path__[0]
17
17
 
18
18
  # global variables to store all loggers
bscampp/configs.py CHANGED
@@ -4,6 +4,8 @@ try:
4
4
  except ImportError:
5
5
  from ConfigParser import configparser
6
6
  from argparse import ArgumentParser, Namespace
7
+ import subprocess
8
+
7
9
  from bscampp.init_configs import init_config_file
8
10
  from bscampp import get_logger, log_exception
9
11
  #from bscampp.utils import inferDataType
@@ -116,6 +118,24 @@ def _read_config_file(filename, cparser, opts,
116
118
  setattr(opts, section, section_name_space)
117
119
  return config_defaults
118
120
 
121
+ # validate a given binary file is executable
122
+ def validate_binary_executable(name, path):
123
+ # 1. make sure path exists
124
+ if not os.path.exists(path):
125
+ raise FileNotFoundError(f"{path} is not found!")
126
+
127
+ # 2. make sure path is executable with no IO error
128
+ try:
129
+ p = subprocess.Popen([path], text=True, stdout=subprocess.PIPE,
130
+ stderr=subprocess.PIPE)
131
+ _, __ = p.communicate()
132
+ except OSError:
133
+ raise AssertionError(' '.join([
134
+ f"{path} is not executable! Please do the followings:",
135
+ f"\n\n\t1. obtain a working executable for the software: {name}",
136
+ f"\n\t2. modify {main_config_path} to replace the old executable path\n",
137
+ ]))
138
+
119
139
  '''
120
140
  Build Config class
121
141
  '''
@@ -169,6 +189,8 @@ def buildConfigs(parser, cmdline_args, child_process=False, rerun=False):
169
189
 
170
190
  # sanity check for existence of base placement binary path
171
191
  if Configs.placement_method == 'epa-ng':
172
- assert os.path.exists(Configs.epang_path), 'epa-ng not detected!'
192
+ validate_binary_executable(Configs.placement_method, Configs.epang_path)
193
+ #assert os.path.exists(Configs.epang_path), 'epa-ng not detected!'
173
194
  elif Configs.placement_method == 'pplacer':
174
- assert os.path.exists(Configs.pplacer_path), 'pplacer not detected!'
195
+ validate_binary_executable(Configs.placement_method, Configs.pplacer_path)
196
+ #assert os.path.exists(Configs.pplacer_path), 'pplacer not detected!'
bscampp/functions.py CHANGED
@@ -33,6 +33,8 @@ def recompileBinariesFromDir(dir):
33
33
 
34
34
  if cmake_p.returncode != 0:
35
35
  _LOG.error("cmake failed!")
36
+ print("STDOUT:", cmake_stdout)
37
+ print("STDERR:", cmake_stderr)
36
38
  exit(cmake_p.returncode)
37
39
  else:
38
40
  _LOG.warning("cmake succeeded!")
@@ -63,14 +65,26 @@ def ensureBinaryExecutable(binpath):
63
65
  _LOG.warning(f"{binpath} does not exist!")
64
66
  b_recompile = True
65
67
  else:
66
- p = subprocess.Popen([binpath], stdout=subprocess.PIPE,
67
- stderr=subprocess.PIPE)
68
- stdout, stderr = p.communicate()
68
+ """
69
+ added @ 6.13.2025 by Chengze Shen
70
+ - try-catch OSError to indicate that the binary files
71
+ - are not executable on the current sytem and need to be
72
+ - recompiled
73
+ """
74
+ try:
75
+ p = subprocess.Popen([binpath], stdout=subprocess.PIPE,
76
+ stderr=subprocess.PIPE)
77
+ stdout, stderr = p.communicate()
78
+ returncode = p.returncode
79
+ except OSError as e:
80
+ # indicating we need to recompile: anything other than 255 or -1
81
+ returncode = 7
82
+
69
83
  # 255 or -1 indicates that the binaries work
70
- if p.returncode == 255 or p.returncode == -1:
84
+ if returncode == 255 or returncode == -1:
71
85
  pass
72
86
  else:
73
- _LOG.warning(f"{binpath} return code is {p.returncode}!")
87
+ _LOG.warning(f"{binpath} return code is {returncode}!")
74
88
  b_recompile = True
75
89
 
76
90
  if b_recompile:
@@ -525,18 +539,22 @@ def placeQueriesToSubtrees(tree, leaf_dict, new_subtree_dict, placed_query_list,
525
539
  field_to_idx = {field: i for i, field in enumerate(fields)}
526
540
 
527
541
  for tmp_place in place_json["placements"]:
528
- # convert qname back using qname_map_rev
529
- tmp_name = tmp_place[tgt][0]
530
-
531
- # >EPA-ng: tgt=="n" --> qname is string
532
- if isinstance(tmp_name, str):
533
- qname = qname_map_rev[tmp_name]
534
- tmp_place[tgt][0] = qname
535
- # >pplacer: tgt=="nm" --> qname is a list of two fields
536
- elif isinstance(tmp_name, list):
537
- qname = qname_map_rev[tmp_name[0]]
538
- tmp_place[tgt][0][0] = qname
539
- placed_query_list.append(qname)
542
+ # Fixed @ 7.7.2025 - Chengze Shen
543
+ # - pplacer actually can report multiple items
544
+ # - in the ["nm"] field.
545
+ for _idx in range(len(tmp_place[tgt])):
546
+ # convert qname back using qname_map_rev
547
+ tmp_name = tmp_place[tgt][_idx]
548
+
549
+ # >EPA-ng: tgt=="n" --> qname is string
550
+ if isinstance(tmp_name, str):
551
+ qname = qname_map_rev[tmp_name]
552
+ tmp_place[tgt][_idx] = qname
553
+ # >pplacer: tgt=="nm" --> qname is a list of two fields
554
+ elif isinstance(tmp_name, list):
555
+ qname = qname_map_rev[tmp_name[0]]
556
+ tmp_place[tgt][_idx][0] = qname
557
+ placed_query_list.append(qname)
540
558
 
541
559
  #placed_query_list.append(tmp_place[tgt][0])
542
560
  for i in range(len(tmp_place["p"])):
bscampp/init_configs.py CHANGED
@@ -71,11 +71,6 @@ def init_config_file(homepath, rerun=False, prioritize_user_software=True):
71
71
  cparser.set('basic', 'hamming_distance_dir',
72
72
  os.path.join(tools_dir, 'hamming_distance'))
73
73
 
74
- # macOS TODO: need to recompile the binaries
75
- if 'macos' in platform_name.lower():
76
- cparser.set('basic', 'hamming_distance_dir',
77
- os.path.join(tools_dir, 'macOS', 'hamming_distance'))
78
-
79
74
  # prioritize user's software
80
75
  if prioritize_user_software:
81
76
  print('Detecting existing software from user\'s environment...')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bscampp
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: BSCAMPP and SCAMPP - Scalable Phylogenetic Placement Tools
5
5
  Author-email: Eleanor Wedell <ewedell2@illinois.edu>, Chengze Shen <chengze5@illinois.edu>
6
6
  License: MIT License
@@ -106,8 +106,11 @@ please contact Eleanor Wedell (ewedell2@illinois.edu).
106
106
  EPA-ng and/or pplacer are requirements since BSCAMPP and SCAMPP will use them as the base phylogenetic placement methods.
107
107
  By default, the software will search for binary executables of `pplacer` and `epa-ng` in the user's environment when running for the first time.
108
108
  We also included a compiled version of `pplacer` for the Linux system under `bscampp/tools`.
109
- * **C++ OpenMP**:
110
- We also use OpenMP to speed up the similarity comparison between sequences using C++, which is required to run the pre-compiled binaries.
109
+ * **(macOS) EPA-ng and pplacer**:
110
+ For macOS systems, you need to have `EPA-ng` and/or `pplacer` installed in your environment.
111
+ * **cmake and C++ OpenMP**:
112
+ We also use C++ with OpenMP to speed up the similarity comparison between sequences, which is required to run the pre-compiled binaries.
113
+ In the case of macOS systems, the software will automatically recompile the binaries using `cmake`, which is required to be installed.
111
114
 
112
115
  ### (1) Install with `pip`
113
116
  The easiest way to install BSCAMPP and SCAMPP is to use `pip install`. This will also install all required Python packages.
@@ -1,8 +1,8 @@
1
- bscampp/__init__.py,sha256=iWcT9i33I9mkOxFgfa7aRxjn_tRPYY7yW6zcuhbjTWk,2289
2
- bscampp/configs.py,sha256=M53nndokxi3WczhpKGWpxOcI2nXIkgpQKhj5gYpee8w,6101
1
+ bscampp/__init__.py,sha256=IB6IZQO2RRGF0EOTQ5wL5zzwFXACvuINO9gD3KV4klA,2289
2
+ bscampp/configs.py,sha256=z40mkOwYTeqNjpcEDtyA4G3LskN86sZWc4Vdk46OywA,7014
3
3
  bscampp/default.config,sha256=CEfsUHBy--vwJhEcUuJ0btfuGQWb_lKMVWUIP9f5YGw,112
4
- bscampp/functions.py,sha256=ywv3-h1l81YayioSTmNiciBZnbi56zyIGc-5Ni-jXG4,23016
5
- bscampp/init_configs.py,sha256=EA9sMN5jWj6zj2b-7tN19LhX2Ef61ByQLxQRLHAqLDM,3600
4
+ bscampp/functions.py,sha256=f5YY9LaIW3LieFvlWvcUlWysEuqVuwJXTmOq5laFxJE,23782
5
+ bscampp/init_configs.py,sha256=hDCH2oatgli2wSmi-uDM96TSiBvLKTAhobBSSKfjl2g,3381
6
6
  bscampp/jobs.py,sha256=v7buZJs1AnNoXiILwu-W8fo3QjxAh3i9Mp7xfmlJvAY,7569
7
7
  bscampp/pipeline.py,sha256=J-RQH54R27m6fhzIpGX0MJuE3ZFk5rcnsROpwC_n5CE,13960
8
8
  bscampp/utils.py,sha256=-wns6FaWMKD2wVqjxdBQvjTdagTjywBIaGfqb2mupe4,30039
@@ -17,9 +17,9 @@ bscampp/tools/hamming_distance/src/fragment_tree_hamming.cpp,sha256=xCmyAT-OZJOD
17
17
  bscampp/tools/hamming_distance/src/fragment_tree_hamming_new.cpp,sha256=eKxgODRlpf0hU84QjNhigvRhWCT9tiJZjA5oQFQ1bUk,7404
18
18
  bscampp/tools/hamming_distance/src/homology.cpp,sha256=ZE0uXZWQ-cN4U1Wk5kUr_KKHgzsgA6Sno-IViRa4tmI,6053
19
19
  bscampp/tools/hamming_distance/src/new_hamming.cpp,sha256=fBRm99RquBZgZjaLOn9xDI3cH9NchhrxKbL-11j8fmk,5342
20
- bscampp-1.0.7.dist-info/licenses/LICENSE,sha256=HEa4YQdOR0e2Gz-NiOwr9X6aJcZtY0AGmlJQDmfN0Iw,1064
21
- bscampp-1.0.7.dist-info/METADATA,sha256=2Tk1eF72pNPIttqSsfwiNclB8H0bShbMhca0aAr8wKo,12602
22
- bscampp-1.0.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
23
- bscampp-1.0.7.dist-info/entry_points.txt,sha256=4Ft83qHc39tNNpMLgSgFXDHM-vuAB99JtmczCQj5pq8,204
24
- bscampp-1.0.7.dist-info/top_level.txt,sha256=1loGRUAft6Tcdq0f3lHbVwWN7W_SW1srfhAVSpg9DWE,8
25
- bscampp-1.0.7.dist-info/RECORD,,
20
+ bscampp-1.0.8.dist-info/licenses/LICENSE,sha256=HEa4YQdOR0e2Gz-NiOwr9X6aJcZtY0AGmlJQDmfN0Iw,1064
21
+ bscampp-1.0.8.dist-info/METADATA,sha256=2w_otUXBGIuvf6nXV-7hY958cxllhTZd6T18rB5nR8Q,12877
22
+ bscampp-1.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ bscampp-1.0.8.dist-info/entry_points.txt,sha256=4Ft83qHc39tNNpMLgSgFXDHM-vuAB99JtmczCQj5pq8,204
24
+ bscampp-1.0.8.dist-info/top_level.txt,sha256=1loGRUAft6Tcdq0f3lHbVwWN7W_SW1srfhAVSpg9DWE,8
25
+ bscampp-1.0.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5