prstools 0.0.3__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 (45) hide show
  1. prstools-0.0.3/LICENSE +21 -0
  2. prstools-0.0.3/MANIFEST.in +5 -0
  3. prstools-0.0.3/PKG-INFO +44 -0
  4. prstools-0.0.3/README.md +9 -0
  5. prstools-0.0.3/prstools/__init__.py +40 -0
  6. prstools-0.0.3/prstools/_cmd.py +352 -0
  7. prstools-0.0.3/prstools/_ext_utils.py +337 -0
  8. prstools-0.0.3/prstools/_modidx.py +32 -0
  9. prstools-0.0.3/prstools/data/__init__.py +0 -0
  10. prstools-0.0.3/prstools/data/_example/__init__.py +0 -0
  11. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/1kg_chr22_22004675_23374984.EUR.edgelist +21045 -0
  12. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/1kg_chr22_30667654_32269392.EUR.edgelist +45229 -0
  13. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/EUR/__init__.py +0 -0
  14. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/__init__.py +0 -0
  15. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/1kg_chr22_22004675_23374984.snplist +6156 -0
  16. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/1kg_chr22_30667654_32269392.snplist +9652 -0
  17. prstools-0.0.3/prstools/data/_example/ldgm_1kg_pop/snplist/__init__.py +0 -0
  18. prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/__init__.py +0 -0
  19. prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/ldblk_1kg_chr22.hdf5 +0 -0
  20. prstools-0.0.3/prstools/data/_example/ldref_1kg_pop/snpinfo_1kg_hm3 +937 -0
  21. prstools-0.0.3/prstools/data/_example/sumstats.tsv +948 -0
  22. prstools-0.0.3/prstools/data/_example/target.bed +0 -0
  23. prstools-0.0.3/prstools/data/_example/target.bim +947 -0
  24. prstools-0.0.3/prstools/data/_example/target.fam +4275 -0
  25. prstools-0.0.3/prstools/data/defs/__init__.py +0 -0
  26. prstools-0.0.3/prstools/data/defs/regdef/__init__.py +0 -0
  27. prstools-0.0.3/prstools/data/defs/regdef/regions_1blk_shift=0.regdef.tsv +1704 -0
  28. prstools-0.0.3/prstools/data/defs/regdef/regions_2blk_shift=0.regdef.tsv +855 -0
  29. prstools-0.0.3/prstools/data/defs/regdef/regions_2blk_shift=1.regdef.tsv +872 -0
  30. prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=0.regdef.tsv +575 -0
  31. prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=1.regdef.tsv +583 -0
  32. prstools-0.0.3/prstools/data/defs/regdef/regions_3blk_shift=2.regdef.tsv +592 -0
  33. prstools-0.0.3/prstools/parse_genet.py +198 -0
  34. prstools-0.0.3/prstools/scores.py +185 -0
  35. prstools-0.0.3/prstools/utils.py +561 -0
  36. prstools-0.0.3/prstools.egg-info/PKG-INFO +44 -0
  37. prstools-0.0.3/prstools.egg-info/SOURCES.txt +43 -0
  38. prstools-0.0.3/prstools.egg-info/dependency_links.txt +1 -0
  39. prstools-0.0.3/prstools.egg-info/entry_points.txt +7 -0
  40. prstools-0.0.3/prstools.egg-info/not-zip-safe +1 -0
  41. prstools-0.0.3/prstools.egg-info/requires.txt +15 -0
  42. prstools-0.0.3/prstools.egg-info/top_level.txt +1 -0
  43. prstools-0.0.3/settings.ini +58 -0
  44. prstools-0.0.3/setup.cfg +4 -0
  45. prstools-0.0.3/setup.py +87 -0
prstools-0.0.3/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Menno Witteveen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ include settings.ini
2
+ include LICENSE
3
+ include CONTRIBUTING.md
4
+ include README.md
5
+ recursive-exclude * __pycache__
@@ -0,0 +1,44 @@
1
+ Metadata-Version: 2.1
2
+ Name: prstools
3
+ Version: 0.0.3
4
+ Summary: Convenient and powerfull Polygenic Risk Score creation.
5
+ Home-page: https://github.com/mennowitteveen/prstools
6
+ Author: Menno Witteveen et al.
7
+ Author-email: menno102@hotmail.com
8
+ License: MIT License
9
+ Keywords: PRS PGS polygenic genomics prediction genetics
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Natural Language :: English
13
+ Classifier: Programming Language :: Python :: 3.6
14
+ Classifier: Programming Language :: Python :: 3.7
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Requires-Python: >=3.6
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pandas
23
+ Requires-Dist: matplotlib
24
+ Requires-Dist: numpy
25
+ Requires-Dist: scipy
26
+ Requires-Dist: tqdm
27
+ Requires-Dist: h5py
28
+ Requires-Dist: ipython
29
+ Provides-Extra: dev
30
+ Requires-Dist: nbdev; extra == "dev"
31
+ Provides-Extra: full
32
+ Requires-Dist: mjwt; extra == "full"
33
+ Requires-Dist: pysnptools; extra == "full"
34
+ Requires-Dist: seaborn; extra == "full"
35
+
36
+ # prstools
37
+
38
+ <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
39
+
40
+ `prstools` is software to create Polygenic Risk Scores (PRS) directly
41
+ from the commandline <br> (and optionally from inside python).
42
+
43
+ It contains various tools to make PRS generation easier. Installation
44
+ and running the demo example should not take more than 10 minutes.
@@ -0,0 +1,9 @@
1
+ # prstools
2
+
3
+ <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
4
+
5
+ `prstools` is software to create Polygenic Risk Scores (PRS) directly
6
+ from the commandline <br> (and optionally from inside python).
7
+
8
+ It contains various tools to make PRS generation easier. Installation
9
+ and running the demo example should not take more than 10 minutes.
@@ -0,0 +1,40 @@
1
+ __version__ = "0.0.2"
2
+ _date = "18-02-2025"
3
+ # from . import *
4
+
5
+ # from . import models
6
+ # from . import loaders
7
+ # from . import utils
8
+ # from . import _cmd as cmd
9
+
10
+ # import .models
11
+ # from models import __
12
+ # from . import models.L2Pred
13
+ #
14
+ import importlib as _importlib # Import takes around 6 microseconds
15
+
16
+ # List of submodules to be included
17
+ _submodules = [
18
+ '_cmd',
19
+ 'loaders',
20
+ 'models',
21
+ 'utils'
22
+ ]
23
+
24
+ __all__ = _submodules + [
25
+ # 'LowLevelCallable',
26
+ # 'test',
27
+ # 'show_config',
28
+ '__version__',
29
+ ]
30
+
31
+ def __dir__():
32
+ return __all__
33
+
34
+ def __getattr__(name):
35
+ if name in _submodules:
36
+ return _importlib.import_module(f'prstools.{name}')
37
+ try:
38
+ return globals()[name]
39
+ except KeyError:
40
+ raise AttributeError(f"Module 'prstools' has no attribute '{name}'")
@@ -0,0 +1,352 @@
1
+ import os, time, sys, argparse, json
2
+
3
+
4
+ def set_cpu_envvars(cpus=1):
5
+ if cpus != -1: # disabling.
6
+ #MKL_NUM_THREADS=1 NUMEXPR_NUM_THREADS=1 OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1
7
+ print(f'Setting environmental variables to control number of cpus used (={cpus}).')
8
+ n_cores = cpus # Correction, this does do something, although its quite opaque
9
+ os.environ['OPENBLAS_NUM_THREADS'] = str(n_cores)
10
+ os.environ['MKL_NUM_THREADS'] = str(n_cores) # For Intel MKL
11
+ os.environ['OMP_NUM_THREADS'] = str(n_cores)
12
+ os.environ['NUMEXPR_NUM_THREADS'] = str(n_cores) # For NumExpr
13
+ # os.environ['OMP_DYNAMIC'] = 'FALSE'
14
+ # os.environ['OMP_THREAD_LIMIT'] = str(n_cores)
15
+ # os.environ['OMP_NESTED'] = 'FALSE'
16
+ # os.environ['OMP_PROC_BIND'] = 'TRUE'
17
+ else:
18
+ print('Skipping the setting of environmental variables')
19
+
20
+
21
+ ##################################################### BEST IF THIS IS ALREADY DONE BY THE TIME THIS CODE RUNS ############
22
+
23
+ ## CLI mechanics functionality:
24
+ def process_subparserkwgs(subparserkwg_lst):
25
+ from textwrap import dedent
26
+ for i, spkwg in enumerate(subparserkwg_lst):
27
+ if type(spkwg) is type({}): continue
28
+ elif 'PRSTCLI' in str(getattr(spkwg,'__bases__','')):
29
+ new_spkwg = spkwg._get_cli_spkwg()
30
+ subparserkwg_lst[i] = new_spkwg
31
+ elif 'BasePred' in str(getattr(spkwg,'__bases__','')):
32
+ from .utils import retrieve_pkwargs
33
+ doc = dedent(spkwg.__doc__)
34
+ new_spkwg = dict(
35
+ cmdname = spkwg.__name__.lower(), #command name
36
+ clsname = spkwg.__name__, #class name
37
+ description= doc,
38
+ help = doc.split('\n')[0],
39
+ epilog = spkwg._get_cli_epilog(),
40
+ module = spkwg.__module__,
41
+ pkwargs = retrieve_pkwargs(spkwg),
42
+ subtype = 'BasePred'
43
+ )
44
+ subparserkwg_lst[i] = new_spkwg
45
+ else:
46
+ print(str(getattr(spkwg,'__bases__','')))
47
+ raise NotImplementedError('Contact dev.')
48
+ return subparserkwg_lst
49
+ def retrieve_classmethod(*, clsname, methodname, modulename='prstools.models'):
50
+ #models = importlib.reload(models)
51
+ def pipefun(*args,**kwargs):
52
+ import importlib
53
+ cls = getattr(importlib.import_module(modulename), clsname)
54
+ return getattr(cls,methodname)(*args,**kwargs)
55
+ return pipefun
56
+ def process_argkwargs(kwargs, setverbosetrue=False):
57
+ kwargs = kwargs.copy()
58
+ kwargs['help'] = argparse.SUPPRESS if kwargs.get('help', None) is None else kwargs['help']
59
+ if kwargs.get('type',None) is bool:
60
+ if not kwargs['default']:
61
+ kwargs.pop('type')
62
+ kwargs['action']='store_true'
63
+ kwargs['default'] = argparse.SUPPRESS
64
+ if setverbosetrue:
65
+ raise NotImplementedError()
66
+ if 'default' in kwargs and kwargs['default'] == 'SUPPRESS':
67
+ kwargs['default'] = argparse.SUPPRESS
68
+ if (kwargs['help'] != argparse.SUPPRESS):
69
+ if not (kwargs.get('default', 'idontexist') in ['idontexist', argparse.SUPPRESS]):
70
+ kwargs['help'] += f" (default: {kwargs.pop('default')})"
71
+ if 'required' in kwargs:
72
+ if kwargs['required'] is True:
73
+ kwargs['help'] = kwargs['help'] + ' (required)'
74
+ # kwargs['help'] = '* '+kwargs['help'] + format_bold(' (required)')
75
+ return kwargs
76
+ def format_color(text, color_code): return f"\033[{color_code}m{text}\033[0m"
77
+ def format_bold(text): return f"\033[1m{text}\033[0m"
78
+ ##################################################### BEST IF THIS IS ALREADY DONE BY THE TIME THIS CODE RUNS ############
79
+
80
+
81
+
82
+ ## Formatting functionality:
83
+ class CustomArgumentParser(argparse.ArgumentParser):
84
+
85
+ def format_usage(self):
86
+ usage = super().format_usage()
87
+ return self.usage_optionals_formattingx(usage)
88
+ def format_help(self):
89
+ string = super().format_help()
90
+ string = self.usage_optionals_formattingx(string)
91
+ return string.replace('usage:','\nUsage:\n')
92
+
93
+ def usage_optionals_formattingx(self, string):
94
+ # print(string.find('\n'))
95
+ # loc = max(string.find('[-h]'), 0)
96
+ # print(loc*'-')
97
+ string = string.replace('] [',' ')
98
+ # string = string.replace('> [','>\n'+loc*'-'+'[')
99
+ return string
100
+ class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter,argparse.RawDescriptionHelpFormatter): #, argparse.RawDescriptionHelpFormatter):
101
+ def __init__(self, prog, indent_increment=1, max_help_position=60, width=None, minwidth=0):
102
+ if not width:
103
+ import shutil # Width processing
104
+ width = shutil.get_terminal_size().columns-2
105
+ width = max(width, minwidth)
106
+ _excl_lst = ['self', 'kwg_dt','_excl_lst','CustomFormatter','__class__','minwidth', 'shutil']
107
+ kwg_dt = {key: item for key, item in locals().items() if not (key in _excl_lst)}
108
+ super(CustomFormatter, self).__init__(**kwg_dt) #prog, indent_increment=indent_increment, max_help_position=max_help_position, width=width)
109
+
110
+ def _get_default_metavar_for_optional(self, action):
111
+ return '<'+action.dest+'>' #.upper()
112
+
113
+ def _format_action_invocation(self, action):
114
+ if not action.option_strings:
115
+ metavar, = self._metavar_formatter(action, action.dest)(1)
116
+ return metavar
117
+ else:
118
+ parts = []
119
+ if action.nargs == 0:
120
+ parts.extend(action.option_strings)
121
+ else:
122
+ default = '<'+action.dest+'>'#.upper()
123
+ args_string = self._format_args(action, default)
124
+ parts.extend(action.option_strings)
125
+ parts = parts[::-1]
126
+ parts[-1] += ' %s' % args_string
127
+ # if parts[-1] in ['']
128
+ # if action.required: return '\b\b* '+', '.join(parts)
129
+ return ', '.join(parts)
130
+
131
+ def parse_args(argv=None, description="Convenient and powerfull Polygenic Risk Score creation. \n\'prst\' is a commandline shorthand for \'prstools\'",
132
+ subparserkwg_lst=None, basecmd='prstools', return_spkwg=False, reload=False):
133
+
134
+ # Prepare parsing params:
135
+ if argv is None: argv=sys.argv[1:]; basecmd=sys.argv[0]
136
+ #from prstools.models import L2Pred, PRSCS
137
+ #subparserkwg_lst = [L2Pred, PRSCS]
138
+ if subparserkwg_lst is None:
139
+ if reload: import importlib; from prstools import _parser_vars; importlib.reload(_parser_vars)
140
+ from prstools._parser_vars import subparserkwg_lst
141
+ else:
142
+ subparserkwg_lst=process_subparserkwgs(subparserkwg_lst)
143
+ # subparserkwg_lst contains the information to construct parsers
144
+ # This is generated from model code by the developer and saved
145
+
146
+ # Construct Parser:
147
+ parser = CustomArgumentParser(
148
+ description=description,
149
+ argument_default=argparse.SUPPRESS,
150
+ add_help=False,
151
+ formatter_class=CustomFormatter
152
+ )
153
+ general_group = parser.add_argument_group('General Options')
154
+ parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS, help=argparse.SUPPRESS) # , help='Show help')
155
+
156
+
157
+ if return_spkwg: return subparserkwg_lst
158
+
159
+ def prscsx_linkfun(**kwg): from prstools.PRScsx.PRScsx import main; sys.argv = sys.argv[1:]; main()
160
+ def prscs_linkfun(**kwg): from prstools.PRScs.PRScs import main; sys.argv = sys.argv[1:]; main()
161
+ xtr = dict(subtype='external')
162
+ ext_lst = [dict(cmdname='prscsx',help="PRS-CSx (original): A cross-population polygenic prediction method with continuous shrinkage "
163
+ "(CS) priors trained with multiple GWAS summary statistics.",func=prscsx_linkfun, **xtr),
164
+ dict(cmdname='prscs',help="PRS-CS (original): A polygenic prediction method with continuous shrinkage (CS) priors trained with GWAS summary statistics.", func=prscs_linkfun, **xtr)]
165
+ subparserkwg_lst += ext_lst
166
+
167
+ # Add Subparser structure:
168
+ subparser = parser.add_subparsers(title="Models & Utility Commands", dest="command", metavar='<command>'+' \b'*2, help="") #trick: +' \b'*0
169
+ extcmds = []; prc = process_argkwargs
170
+ for i, spkwg in enumerate(subparserkwg_lst):
171
+ if spkwg['subtype'] == 'BasePred':
172
+ # Create Model parser and add basic help:
173
+ model_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
174
+ description=spkwg['description'],
175
+ epilog=spkwg['epilog'],
176
+ formatter_class=CustomFormatter,
177
+ argument_default=argparse.SUPPRESS,
178
+ add_help=False)
179
+
180
+ modelgeneral_group = model_parser.add_argument_group('General Options')
181
+ modelgeneral_group.add_argument('-h', '--help', action='help', help='Show this help message and exit.') #default=argparse.SUPPRESS
182
+ # WARNING!: there is still something wrong with the default of this --cpus cli argument, it does not seem to get pushed into the setting of the number of cores function.
183
+ modelgeneral_group.add_argument('--cpus', '-c', **prc(dict(metavar='<number-of-cpus>', default=-1, type=int, help='The number of cpus to use. This will generate environmental variables inside \
184
+ of the python session, which will control the number of used cores. Functionality can be turned-off completely, by setting it to -1.\
185
+ (devnote: for default=1 some things have to be modified) ')))
186
+
187
+ # Add data related kwargs:
188
+ data_group = model_parser.add_argument_group('Data Arguments (first 5 required)')
189
+ data_group.add_argument("--ref","--ref_dir","-r",
190
+ **prc(dict(required=True, metavar='<dir/refcode>',
191
+ help="Path to the directory that contains the LD reference panel. You can download this reference data "
192
+ f"manually with \'{basecmd} downloadref\'. Soon it will be possible to automatically download it on the fly.")))
193
+ data_group.add_argument("--target", "--bim_prefix", "-t",
194
+ **prc(dict(required=True, metavar='<bim-prefix>',
195
+ help="Specify the directory and prefix of the bim file for the target dataset.")))
196
+ data_group.add_argument("--sst","--sst_file","-s", **prc(dict(required=True, metavar='<file>',
197
+ help="The summary statistics file from which the model will be created. The file should contain columns: SNP, A1, A2, BETA or OR, P or SE information. "
198
+ "At the moment, the file is assumed to be tab-seperated, if you like other formats please let devs know."
199
+ f"Alternative column names can be specified with --columns (more info below). SNP column should contain rsid\'s. "
200
+ f"See {format_color('https://tinyurl.com/sstxampl','34')} for an example.")))
201
+ data_group.add_argument("--out","--out_dir","-o",
202
+ **prc(dict(required=True, metavar='<dir+prefix>',
203
+ help="Output prefix for the results (variant weights). This should be a combination of the desired output dir and file prefix.")))
204
+ data_group.add_argument("--n_gwas","-n",
205
+ **prc(dict(required=False, type=int, metavar='<num>', default=None,
206
+ help="Sample size of the GWAS. Not required if sumstat has a 'N' column.")))
207
+ data_group.add_argument("--chrom", #lambda x: x.split(',')
208
+ type=str, metavar='<chroms>', default='all',
209
+ help="Optional: Select specific chromosome to work with. You can specify a specific chromosome as e.g. \"--chrom 3\". All chromosomes are used by default.")
210
+ data_group.add_argument("--colmap", #lambda x: x.split(',')
211
+ type=str, metavar='<alternative_colnames>',
212
+ help="Optional: Allows one to specify an alterative column name for columns SNP,A1,A2,BETA,OR,P,SE,N (in that order). "
213
+ "Forinstance \"--colmap rsid,a1,a2,beta_gwas,,pvalue,beta_standard_error,\" (OR & N are excluded in this example). "
214
+ "When the command is run a quick this_column -> that_column conversion table will be shown. "
215
+ "Additionaly prstools has many internal checks to make sure a good PRS will be generated! ")
216
+
217
+ # Add model-related arguments (hyper parameters and such):
218
+ modelargs_group = model_parser.add_argument_group('Model Arguments (all optional)')
219
+ for argname, item in spkwg['pkwargs'].items():
220
+ # if argname == 'n_iter':ergerg
221
+ #cargs, ckwargs = process_pkwargs(item) << -- underconstruction, need 2 add verbose=True
222
+ modelargs_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
223
+ # Below 'func' contains a delayed import of a classmethod that can run the full method from arg
224
+ # This means the import (which can be slow) will take place only when run, leading to big speedups
225
+ # and a snappy cmdline tool, which is nice for users. In case the model is PRSCS2 it in effect says:
226
+ # .. .set_defaults(func=PRSCS2.run_from_cli_params_thiswholenamecouldchange_imasocalledclassmethod, .. etc
227
+ func = retrieve_classmethod(clsname=spkwg['clsname'], methodname='from_cli_params_and_run')
228
+ model_parser.set_defaults(func=func, pkwargs=spkwg['pkwargs'], model_parser=model_parser)
229
+ elif spkwg['subtype'] == 'function':
230
+ funct_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
231
+ description=spkwg['description'],
232
+ formatter_class=CustomFormatter,
233
+ argument_default=argparse.SUPPRESS,
234
+ add_help=False)
235
+ general_group = funct_parser.add_argument_group('Options')
236
+ general_group.add_argument('-h', '--help', action='help', help='Show this help message and exit.')
237
+ for argname, item in spkwg['pkwargs'].items():
238
+ general_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
239
+ func = globals()[spkwg['cmdname']]
240
+ funct_parser.set_defaults(func=func)
241
+ elif spkwg['subtype'] == 'external':
242
+ linked_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'], description='unneeded', add_help=False) #, description='descption prscx')
243
+ linked_parser.set_defaults(func=spkwg['func'])
244
+ extcmds+=[spkwg['cmdname']]
245
+ elif spkwg['subtype'] == 'PRSTCLI':
246
+ subcmd_parser = subparser.add_parser(spkwg['cmdname'], help=spkwg['help'],
247
+ description=spkwg['description'],
248
+ epilog=spkwg['epilog'],
249
+ formatter_class=CustomFormatter,
250
+ argument_default=argparse.SUPPRESS,
251
+ add_help=False)
252
+
253
+ # Add groups and respective arguments:
254
+ for grpname, grpkwg in spkwg['groups'].items():
255
+ cur_group = subcmd_parser.add_argument_group(grpkwg['grpheader'])
256
+ for argname, item in grpkwg['pkwargs'].items():
257
+ cur_group.add_argument(*item['args'], **process_argkwargs(item['kwargs']))
258
+
259
+ # Set func to be linked to all the args:
260
+ func = retrieve_classmethod(modulename=spkwg['modulename'], clsname=spkwg['clsname'], methodname='from_cli_params_and_run')
261
+ subcmd_parser.set_defaults(func=func) # Yes it needs to b
262
+ else:
263
+ raise Exception('Subparser subtype not recognized, Contact dev.')
264
+
265
+ # Commence actual parsing:
266
+ if len(argv)<2: argv+=['-h']
267
+ knargs, _ = parser.parse_known_args(argv)
268
+ if knargs.command in extcmds:
269
+ return knargs
270
+ else:
271
+ args = parser.parse_args(argv)
272
+ return args
273
+ # import json
274
+ def main(argv=None):
275
+
276
+ if argv is None: argv=sys.argv[1:]
277
+ args = parse_args(argv)
278
+ display_info = True if 'pkwargs' in args else False
279
+ from prstools import __version__, _date# as version, date
280
+ timestampfmt = "%a, %d %b %Y %H:%M:%S %z"
281
+ if display_info:
282
+ param_dt = vars(args)
283
+ topstr = '\n'.join([
284
+ f'PRSTOOLS v{__version__} ({_date})',
285
+ f'Running command: {args.command}',
286
+ f'Options in effect:'
287
+ ])
288
+ print(topstr)
289
+ for act in args.model_parser._actions:
290
+ key = act.dest
291
+ if not key in param_dt: continue
292
+ item = param_dt[key]
293
+ fun = lambda: item is args.pkwargs[key]['kwargs'].get('default',None)
294
+ cond0 = fun() if key in args.pkwargs else False
295
+ if cond0 or key in ['func','pkwargs','command','model_parser']: continue
296
+ pitem = item if type(item) is not bool else ''
297
+ print(' --%s %s' % (key, pitem))
298
+ print()
299
+
300
+ args_dt = vars(args)
301
+ # Need to happen here because it needs to happen before numpy/scipy is imported:
302
+ if 'cpus' in args_dt: set_cpu_envvars(**{key:item for key, item in args_dt.items() if key=='cpus'})
303
+ # Initialize logs and grab certain parts:
304
+ from prstools.utils import get_prstlogs; import pandas as pd; import socket
305
+ start = pd.Timestamp.now(); hostname = socket.gethostname(); cwd=os.getcwd()
306
+ prstlogs = get_prstlogs()
307
+ prstlogs['__version__'] = __version__
308
+ prstlogs['times']['start'] = start
309
+ prstlogs['cwd'] = cwd
310
+ prstlogs['hostname'] = hostname
311
+ prstlogs['argv'] = argv
312
+ #prstlogs['args_dt'] = args_dt
313
+ if display_info:
314
+ envstr = '\n'.join([
315
+ f'Hostname: {hostname}',
316
+ f'Working directory: {cwd}',
317
+ f'Start time: {start.strftime(timestampfmt)}',
318
+ f'']) #Just empty line for spacing
319
+ print(envstr)
320
+
321
+ # Run the actual task:
322
+ result = args.func(**args_dt)
323
+
324
+ # Some post main-task things:
325
+ stop = pd.Timestamp.now(); prstlogs['times']['stop'] = stop; prstlogs.finish()
326
+ if display_info: print(f'End time: {stop.strftime(timestampfmt)}',)
327
+ # add return functionality later
328
+
329
+ if '_isdevenv_prstools' in locals() or '--dev' in sys.argv:
330
+
331
+ if 'In' in locals():
332
+ with open('../prstools/_cmd.py', 'w') as f: f.write(In[-1])
333
+ print('Written to:', f.name);
334
+
335
+ from prstools import models, utils; import importlib
336
+ importlib.reload(models); importlib.reload(utils)
337
+
338
+ try:
339
+ from prstools.models import XPRS, PRSCS2, SPRSCS, PredPRS, Dentist, SNPFilter
340
+ from prstools.utils import DownloadUtil, store_argparse_dicts , Combine
341
+ store_argparse_dicts([DownloadUtil, Combine,
342
+ XPRS, PRSCS2, SPRSCS, PredPRS, Dentist, SNPFilter
343
+ ])
344
+ print('Saved new argparse dict. (mind: dont forget the suppress mechanism, this is something in the argparse-dict processing)')
345
+ except Exception as e:
346
+ print(e, 'Import issue.'); raise e
347
+
348
+ if 'In' in locals():
349
+ get_ipython().system('time python ../prstools/_cmd.py | tail -1 #l2pred # afster a normal pip install, !time prst seems to have parity with this faster approach.')
350
+ else:
351
+ if __name__ == '__main__':
352
+ main()