kdsource 0.2.0__py3-none-win_amd64.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.
kdsource/__init__.py ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Python module for creating and optimizing KDSource objects.
4
+
5
+ KDSource's are particle sources for Monte Carlo radiation transport
6
+ simulations. The full distribution and documentation can be found in the
7
+ project GitHub page:
8
+
9
+ https://github.com/KDSource/KDSource
10
+
11
+ A KDSource object is based on a particle list in MCPL format (see
12
+ https://mctools.github.io/mcpl/), on which a Kernel Density Estimation
13
+ (KDE) is applied, using KDEpy library (see
14
+ https://github.com/tommyod/KDEpy).
15
+
16
+ With kdsource Python library you can create, optimize, and export
17
+ KDSource objects as XML files. These files can be later used as
18
+ distributional sources in other Monte Carlo simulations, using the tools
19
+ available in the full distribution.
20
+
21
+ If you use KDSource tools in your work, please add the following
22
+ reference:
23
+
24
+ Abbate, O. I., Schmidt, N. S., Prieto, Z. M., Robledo, J. I.,
25
+ Dawidowski, J., Márquez, A. A., & Márquez Damián, J. I. KDSource,
26
+ a tool for the generation of Monte Carlo particle sources using
27
+ kernel density estimation [Computer software].
28
+ https://github.com/KDSource/KDSource
29
+
30
+ """
31
+
32
+ __version__ = "0.2.0"
33
+ versionint = int('2000')
34
+ version = ( int('0'),
35
+ int('2'),
36
+ int('0') )
37
+ __author__ = "KDSource"
38
+
39
+ #NOTE: Keep __init__.py essentially empty. In particular, no import statements
40
+ #here.
kdsource/_chooks.py ADDED
@@ -0,0 +1,101 @@
1
+ def _str2cstr(s):
2
+ #converts any string (str,bytes,unicode,path) to bytes
3
+ if hasattr(s,'__fspath__'):
4
+ s = str(s)
5
+ try:
6
+ return s if isinstance(s,bytes) else s.encode('utf8')
7
+ except UnicodeEncodeError as e:
8
+ from .exceptions import NCBadInput
9
+ raise NCBadInput("Only unicode strings are supported") from e
10
+
11
+ def _cstr2str(s):
12
+ #converts bytes object to str
13
+ try:
14
+ return s if isinstance(s,str) else s.decode('utf8')
15
+ except UnicodeDecodeError as e:
16
+ from .exceptions import NCBadInput
17
+ raise NCBadInput("Only UTF8-encoded C-strings are supported") from e
18
+
19
+ __cache_fcts=[None]
20
+ def _load_fcts():
21
+ if __cache_fcts[0] is not None:
22
+ return __cache_fcts[0]
23
+ from ._chooks_loadlib import _loadlib_kdsource
24
+ import ctypes
25
+ allfcts = {}
26
+ lib = _loadlib_kdsource()
27
+
28
+ ###### resample_to_mcpl
29
+ kds_rng_fct_t = ctypes.CFUNCTYPE( ctypes.c_double )
30
+ rawfct_rs = lib.kdsource_resample_to_mcpl
31
+ rawfct_rs.restype=None
32
+ rawfct_rs.argtypes=( kds_rng_fct_t,
33
+ ctypes.c_char_p,
34
+ ctypes.c_char_p,
35
+ ctypes.c_uint64 )
36
+ def fct_rs( rng_fct, kds_sourcefile, destination_mcpl, nout ):
37
+ rawfct_rs( kds_rng_fct_t(rng_fct),
38
+ _str2cstr(kds_sourcefile),
39
+ _str2cstr(destination_mcpl),
40
+ ctypes.c_uint64(nout) )
41
+ allfcts['resample_to_mcpl'] = fct_rs
42
+
43
+ ###### write_mcpl
44
+ dblptr = ctypes.POINTER(ctypes.c_double)
45
+ int32ptr = ctypes.POINTER(ctypes.c_int32)
46
+ uint32ptr = ctypes.POINTER(ctypes.c_uint32)
47
+ rawfct_wm = lib.kdsource_write_mcpl
48
+ rawfct_wm.restype = None
49
+ rawfct_wm.argtypes=( ctypes.c_char_p,ctypes.c_uint64,ctypes.c_uint,
50
+ dblptr,dblptr,dblptr,
51
+ dblptr,dblptr,dblptr,dblptr,dblptr,dblptr,int32ptr,
52
+ dblptr,dblptr,dblptr, uint32ptr)
53
+ def get_ndarray_to_cptr():
54
+ import numpy as np
55
+ def ndarray_fix_type(arr, dtypename):
56
+ a = np.asarray(arr)
57
+ dt = np.dtype(dtypename)
58
+ if a.dtype == dt and a.flags['C_CONTIGUOUS']:
59
+ return a
60
+ return a.astype(dt, copy=True)
61
+ def ndarray_to_cptr(keepalive,a,dtypename='float64',cptr=dblptr):
62
+ keepalive.append( ndarray_fix_type(a,dtypename) )
63
+ return keepalive[-1].ctypes.data_as(cptr)
64
+ return ndarray_to_cptr
65
+ def fct_wm( filename, nparticles,
66
+ ekin, x, y, z, ux, uy, uz, time, weight, pdgcode,
67
+ polx, poly, polz, userflags, double_prec ):
68
+ import numbers
69
+ flags = 1 if double_prec else 0
70
+ keepalive=[]
71
+ a2c = get_ndarray_to_cptr()
72
+ if isinstance(pdgcode, numbers.Integral):
73
+ flags += 2
74
+ pdgcode_array = (ctypes.c_int32 * 1)(int(pdgcode))
75
+ pdgcode_arg = ctypes.cast(pdgcode_array, int32ptr)
76
+ else:
77
+ pdgcode_arg = a2c(keepalive,pdgcode,'int32',int32ptr)
78
+ if isinstance(weight, numbers.Number):
79
+ flags += 4
80
+ weight_array = (ctypes.c_double * 1)(float(weight))
81
+ weight_arg = ctypes.cast(weight_array, dblptr)
82
+ else:
83
+ weight_arg = a2c(keepalive,weight)
84
+
85
+ c_polx = a2c(keepalive,polx) if polx is not None else None
86
+ c_poly = a2c(keepalive,poly) if poly is not None else None
87
+ c_polz = a2c(keepalive,polz) if polz is not None else None
88
+ c_userflags = ( a2c(keepalive,pdgcode,'uint32',uint32ptr)
89
+ if userflags is not None else None )
90
+ rawfct_wm( _str2cstr(filename),
91
+ ctypes.c_uint64(nparticles),
92
+ ctypes.c_uint(flags),
93
+ a2c(keepalive,ekin),
94
+ a2c(keepalive,x), a2c(keepalive,y), a2c(keepalive,z),
95
+ a2c(keepalive,ux), a2c(keepalive,uy), a2c(keepalive,uz),
96
+ a2c(keepalive,time), weight_arg, pdgcode_arg,
97
+ c_polx, c_poly, c_polz, c_userflags )
98
+ allfcts['write_mcpl'] = fct_wm
99
+
100
+ __cache_fcts[0]=allfcts
101
+ return __cache_fcts[0]
@@ -0,0 +1,34 @@
1
+ _loadlib_cache = [None,None]
2
+ def _loadlib_kdsource():
3
+ if _loadlib_cache[1]:
4
+ return _loadlib_cache[1]
5
+ from .config import config
6
+ _loadlib_cache[0] = _loadlib_frompath(_get_mcpl_shlibpath())
7
+ _loadlib_cache[1] = _loadlib_frompath(config('shlibpath'))
8
+ return _loadlib_cache[1]
9
+
10
+ def _loadlib_mcpl():
11
+ if _loadlib_cache[0] is None:
12
+ _loadlib_kdsource()
13
+ return _loadlib_cache[0]
14
+
15
+ def _get_mcpl_shlibpath():
16
+ import subprocess
17
+ rv = subprocess.run( ['mcpl-config','--show','shlibpath'],
18
+ check = True, capture_output = True )
19
+ if rv.returncode or rv.stderr:
20
+ raise RuntimeError('Problems invoking mcpl-config for shlibpath')
21
+ import pathlib
22
+ return pathlib.Path(rv.stdout.decode().strip()).absolute().resolve()
23
+
24
+ def _loadlib_frompath(libpath):
25
+ import ctypes
26
+ try:
27
+ lib = ctypes.CDLL(libpath)
28
+ except TypeError:
29
+ lib = None
30
+ if lib is None:
31
+ #On Windows, providing a Path rather than str can yield TypeError:
32
+ lib = ctypes.CDLL(str(libpath))
33
+ return lib
34
+
@@ -0,0 +1,55 @@
1
+
2
+ def parse_args(argv=None):
3
+ from argparse import ArgumentParser
4
+ from .config import config_items
5
+ import textwrap
6
+ def wrap(t,w=59):
7
+ return textwrap.fill( ' '.join(t.split()), width=w )
8
+
9
+ parser = ArgumentParser(
10
+ description
11
+ ='Provide basic information about KDSource installation'
12
+ )
13
+ parser.add_argument('-v','--version',action='store_true',
14
+ help=wrap("""Show the KDSource version number and
15
+ exit."""))
16
+ parser.add_argument('-i','--intversion',action='store_true',
17
+ help=wrap("""Show KDSource version encoded into
18
+ single integral number (e.g. v1.2.3 is 1002003) and
19
+ exit."""))
20
+ parser.add_argument('-s','--summary',action='store_true',
21
+ help=wrap("""Print summary information about
22
+ installation and exit. This displays all the
23
+ information that is otherwise available via the --show
24
+ flag."""))
25
+ parser.add_argument("--show",metavar="ITEM", choices=['list']+config_items,
26
+ help=wrap("""Print value of the requested information
27
+ ITEM for the current NCrystal installation and exit. Run
28
+ with "--show list" to get a list of available ITEM
29
+ values."""))
30
+ return parser.parse_args(argv)
31
+
32
+
33
+ def main(argv=None):
34
+ from .config import summary, config, config_items
35
+ args = parse_args(argv)
36
+ if args.version:
37
+ print(config('version'))
38
+ elif args.intversion:
39
+ print(config('intversion'))
40
+ elif args.summary:
41
+ summary()
42
+ elif args.show:
43
+ if args.show == 'list':
44
+ for c in sorted(config_items):
45
+ print(c)
46
+ elif args.show not in config_items:
47
+ raise SystemExit('ERROR: Unknown configuration item "%s"'%args.show)
48
+ else:
49
+ print(config(args.show))
50
+ else:
51
+ summary()
52
+
53
+
54
+ if __name__ == '__main__':
55
+ main()
@@ -0,0 +1,38 @@
1
+
2
+ def parse_args(argv=None):
3
+ from argparse import ArgumentParser
4
+ import textwrap
5
+ def wrap(t,w=59):
6
+ return textwrap.fill( ' '.join(t.split()), width=w )
7
+
8
+ parser = ArgumentParser(
9
+ description=wrap("""Generate new MCPL files based upon an existing
10
+ kernel density estimate XML file.""",
11
+ 79 )
12
+ )
13
+ parser.add_argument('kdefile',metavar='KDEFILE',
14
+ help=wrap("""Kernel Density Estimate .xml file generated
15
+ via KDSource python interface."""))
16
+ parser.add_argument('outmcpl',metavar='OUTMCPL',
17
+ help=wrap("""Name of MCPL file which will be created."""))
18
+ parser.add_argument('nparticles',metavar='NPARTICLES',type=int,
19
+ help=wrap("""Number of particles to sample and place in
20
+ OUTMCPL."""))
21
+ parser.add_argument('-s','--seed',metavar='SEED',type=int,
22
+ help=wrap("""Seed value of Number of particles to sample
23
+ and place in OUTMCPL. If not set, a random seed is
24
+ generated (based on bytes from os.urandom)."""))
25
+ parser.add_argument('-f','--force',action='store_true',
26
+ help=wrap("""Will overwrite existing file if it already
27
+ exists."""))
28
+
29
+ return parser.parse_args(argv)
30
+
31
+ def main(argv=None):
32
+ from .resample import resample_to_mcpl
33
+ args = parse_args(argv)
34
+ resample_to_mcpl( args.kdefile, args.outmcpl, args.nparticles,
35
+ force=args.force, rng = args.seed )
36
+
37
+ if __name__ == '__main__':
38
+ main()
@@ -0,0 +1,194 @@
1
+ _cache = {}
2
+ def load(datakey):
3
+ if datakey in _cache:
4
+ return _cache[datakey]
5
+ import numpy
6
+ _cache[datakey] = numpy.fromstring(_data[datakey], unpack=True, sep=None)
7
+ return _cache[datakey]
8
+
9
+ _data = {
10
+ 'ARN_neutron' :
11
+ """0. 0.0
12
+ 2.53E-02 1.06E+01
13
+ 2.00E+03 7.70E+00
14
+ 2.50E+04 1.93E+01
15
+ 1.44E+05 1.27E+02
16
+ 2.50E+05 2.03E+02
17
+ 5.65E+05 3.43E+02
18
+ 1.20E+06 4.25E+02
19
+ 2.50E+06 4.16E+02
20
+ 2.80E+06 4.13E+02
21
+ 3.20E+06 4.11E+02
22
+ 5.00E+06 4.05E+02
23
+ 1.48E+07 5.36E+02
24
+ 1.90E+07 5.84E+02
25
+ 5.00E+07 5.84E+02
26
+ """,
27
+ 'ARN_photon' :
28
+ """0.0 0.0
29
+ 1.00E+04 6.10E-02
30
+ 1.50E+04 8.30E-01
31
+ 2.00E+04 1.05E+00
32
+ 3.00E+04 8.10E-01
33
+ 4.00E+04 6.40E-01
34
+ 5.00E+04 5.50E-01
35
+ 6.00E+04 5.10E-01
36
+ 8.00E+04 5.30E-01
37
+ 1.00E+05 6.10E-01
38
+ 1.50E+05 8.90E-01
39
+ 2.00E+05 1.20E+00
40
+ 3.00E+05 1.80E+00
41
+ 4.00E+05 2.38E+00
42
+ 5.00E+05 2.93E+00
43
+ 6.00E+05 3.44E+00
44
+ 8.00E+05 4.38E+00
45
+ 1.00E+06 5.20E+00
46
+ 1.50E+06 6.90E+00
47
+ 2.00E+06 8.60E+00
48
+ 3.00E+06 1.11E+01
49
+ 4.00E+06 1.34E+01
50
+ 5.00E+06 1.55E+01
51
+ 6.00E+06 1.76E+01
52
+ 8.00E+06 2.16E+01
53
+ 1.00E+07 2.56E+01
54
+ 5.00E+07 2.56E+01
55
+ """,
56
+ 'ICRP_neutron':
57
+ """0.00 0.00
58
+ 1.00E-03 3.09E+00
59
+ 1.00E-02 3.55E+00
60
+ 2.50E-02 4.00E+00
61
+ 1.00E-01 5.20E+00
62
+ 2.00E-01 5.87E+00
63
+ 5.00E-01 6.59E+00
64
+ 1.00E+00 7.03E+00
65
+ 2.00E+00 7.39E+00
66
+ 5.00E+00 7.71E+00
67
+ 1.00E+01 7.82E+00
68
+ 2.00E+01 7.84E+00
69
+ 5.00E+01 7.82E+00
70
+ 1.00E+02 7.79E+00
71
+ 2.00E+02 7.73E+00
72
+ 5.00E+02 7.54E+00
73
+ 1.00E+03 7.54E+00
74
+ 2.00E+03 7.61E+00
75
+ 5.00E+03 7.97E+00
76
+ 1.00E+04 9.11E+00
77
+ 2.00E+04 1.22E+01
78
+ 3.00E+04 1.57E+01
79
+ 5.00E+04 2.30E+01
80
+ 7.00E+04 3.06E+01
81
+ 1.00E+05 4.19E+01
82
+ 1.50E+05 6.06E+01
83
+ 2.00E+05 7.88E+01
84
+ 3.00E+05 1.14E+02
85
+ 5.00E+05 1.77E+02
86
+ 7.00E+05 2.32E+02
87
+ 9.00E+05 2.79E+02
88
+ 1.00E+06 3.01E+02
89
+ 1.20E+06 3.30E+02
90
+ 1.50E+06 3.65E+02
91
+ 2.00E+06 4.07E+02
92
+ 3.00E+06 4.58E+02
93
+ 4.00E+06 4.83E+02
94
+ 5.00E+06 4.94E+02
95
+ 6.00E+06 4.98E+02
96
+ 7.00E+06 4.99E+02
97
+ 8.00E+06 4.99E+02
98
+ 9.00E+06 5.00E+02
99
+ 1.00E+07 5.00E+02
100
+ 1.20E+07 4.99E+02
101
+ 1.40E+07 4.95E+02
102
+ 1.50E+07 4.93E+02
103
+ 1.60E+07 4.90E+02
104
+ 1.80E+07 4.84E+02
105
+ 2.00E+07 4.77E+02
106
+ 2.10E+07 4.74E+02
107
+ 3.00E+07 4.53E+02
108
+ 5.00E+07 4.33E+02
109
+ 7.50E+07 4.39E+02
110
+ 1.00E+08 4.44E+02
111
+ 1.30E+08 4.46E+02
112
+ 1.50E+08 4.46E+02
113
+ 1.80E+08 4.47E+02
114
+ 2.00E+08 4.48E+02
115
+ 3.00E+08 4.73E+02
116
+ 4.00E+08 5.15E+02
117
+ 5.00E+08 5.33E+02
118
+ 6.00E+08 5.69E+02
119
+ 7.00E+08 6.25E+02
120
+ 8.00E+08 6.38E+02
121
+ 9.00E+08 6.45E+02
122
+ 1.00E+09 6.63E+02
123
+ 2.00E+09 7.69E+02
124
+ 5.00E+09 1.04E+03
125
+ 1.00E+10 1.39E+03
126
+ """,
127
+ 'ICRP_photon':
128
+ """0.00 0.00
129
+ 5.00E+03 1.34E-02
130
+ 6.00E+03 1.66E-02
131
+ 7.00E+03 2.25E-02
132
+ 8.00E+03 3.35E-02
133
+ 9.00E+03 4.90E-02
134
+ 1.00E+04 6.85E-02
135
+ 1.20E+04 1.05E-01
136
+ 1.30E+04 1.22E-01
137
+ 1.50E+04 1.56E-01
138
+ 1.70E+04 1.81E-01
139
+ 2.00E+04 2.25E-01
140
+ 2.50E+04 2.75E-01
141
+ 3.00E+04 3.12E-01
142
+ 4.00E+04 3.50E-01
143
+ 5.00E+04 3.69E-01
144
+ 6.00E+04 3.89E-01
145
+ 7.00E+04 4.11E-01
146
+ 8.00E+04 4.43E-01
147
+ 1.00E+05 5.18E-01
148
+ 1.50E+05 7.47E-01
149
+ 2.00E+05 1.00E+00
150
+ 3.00E+05 1.51E+00
151
+ 4.00E+05 2.00E+00
152
+ 5.00E+05 2.47E+00
153
+ 5.11E+05 2.52E+00
154
+ 6.00E+05 2.91E+00
155
+ 6.62E+05 3.17E+00
156
+ 8.00E+05 3.73E+00
157
+ 1.00E+06 4.49E+00
158
+ 1.12E+06 4.90E+00
159
+ 1.33E+06 5.60E+00
160
+ 1.50E+06 6.12E+00
161
+ 2.00E+06 7.48E+00
162
+ 3.00E+06 9.75E+00
163
+ 4.00E+06 1.17E+01
164
+ 5.00E+06 1.34E+01
165
+ 6.00E+06 1.50E+01
166
+ 6.13E+06 1.52E+01
167
+ 8.00E+06 1.86E+01
168
+ 1.00E+07 2.21E+01
169
+ 1.50E+07 3.04E+01
170
+ 2.00E+07 3.82E+01
171
+ 3.00E+07 5.13E+01
172
+ 4.00E+07 6.18E+01
173
+ 5.00E+07 7.23E+01
174
+ 6.00E+07 8.21E+01
175
+ 8.00E+07 9.81E+01
176
+ 1.00E+08 1.10E+02
177
+ 1.50E+08 1.30E+02
178
+ 2.00E+08 1.44E+02
179
+ 3.00E+08 1.61E+02
180
+ 4.00E+08 1.73E+02
181
+ 5.00E+08 1.81E+02
182
+ 6.00E+08 1.87E+02
183
+ 8.00E+08 1.96E+02
184
+ 1.00E+09 2.06E+02
185
+ 1.50E+09 2.13E+02
186
+ 2.00E+09 2.36E+02
187
+ 3.00E+09 2.53E+02
188
+ 4.00E+09 2.67E+02
189
+ 5.00E+09 2.77E+02
190
+ 6.00E+09 2.85E+02
191
+ 8.00E+09 2.99E+02
192
+ 1.00E+10 3.07E+02
193
+ """
194
+ }
kdsource/api.py ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Python module for creating and optimizing KDSource objects.
4
+
5
+ KDSource's are particle sources for Monte Carlo radiation transport
6
+ simulations. The full distribution and documentation can be found in the
7
+ project GitHub page:
8
+
9
+ https://github.com/KDSource/KDSource
10
+
11
+ A KDSource object is based on a particle list in MCPL format (see
12
+ https://mctools.github.io/mcpl/), on which a Kernel Density Estimation
13
+ (KDE) is applied, using KDEpy library (see
14
+ https://github.com/tommyod/KDEpy).
15
+
16
+ With kdsource Python library you can create, optimize, and export
17
+ KDSource objects as XML files. These files can be later used as
18
+ distributional sources in other Monte Carlo simulations, using the tools
19
+ available in the full distribution.
20
+
21
+ If you use KDSource tools in your work, please add the following
22
+ reference:
23
+
24
+ Abbate, O. I., Schmidt, N. S., Prieto, Z. M., Robledo, J. I.,
25
+ Dawidowski, J., Márquez, A. A., & Márquez Damián, J. I. KDSource,
26
+ a tool for the generation of Monte Carlo particle sources using
27
+ kernel density estimation [Computer software].
28
+ https://github.com/KDSource/KDSource
29
+
30
+ """
31
+
32
+ __version__ = "0.2.0"
33
+ versionint = int('2000')
34
+ version = ( int('0'),
35
+ int('2'),
36
+ int('0') )
37
+ __author__ = "KDSource"
38
+
39
+ #Convenience module with ~all imports (leaving __init__.py empty as per
40
+ #best-practice, and to not make e.g. CLI scripts fail due to missing un-needed
41
+ #dependency)
42
+ from . import geom #noqa F401
43
+ from . import kde #noqa F401
44
+ from . import plist #noqa F401
45
+ from .geom import Geometry, Metric #noqa F401
46
+ from .kde import bw_silv #noqa F401
47
+ from .kdsource import KDSource, load #noqa F401
48
+ from .plist import PList, appendssv, convert2mcpl, join2mcpl, savessv #noqa F401
49
+ from .writemcpl import write_mcpl #noqa F401
50
+ from .resample import resample_to_mcpl #noqa F401
kdsource/config.py ADDED
@@ -0,0 +1,121 @@
1
+ import pathlib as _p
2
+ _datadir = _p.Path(__file__).parent.joinpath('data').absolute()
3
+ config_items = [
4
+ 'version',
5
+ 'intversion',
6
+ 'includedir',
7
+ 'libdir',
8
+ 'libpath',
9
+ 'libname',
10
+ 'shlibdir',
11
+ 'shlibpath',
12
+ 'shlibname',
13
+ 'buildflags',
14
+ ]
15
+
16
+ def summary():
17
+ """Print summary of all config items"""
18
+ print("KDSource v%s with configuration:"%config('version'))
19
+ print()
20
+ maxlen = max(len(item) for item in config_items)
21
+ for item in config_items:
22
+ print(' %s : %s'%(item.rjust(maxlen),config(item)))
23
+
24
+ _config_cache={}
25
+ def config(item):
26
+ """Return configuration item (available are those in the config_item list).
27
+ """
28
+ c = _config_cache.get(item)
29
+ if c is not None:
30
+ return c
31
+ c = _config_deduce(item)
32
+ _config_cache[item] = c
33
+ return c
34
+
35
+ def _config_deduce(item):
36
+ if item not in config_items:
37
+ raise RuntimeError(f"unknown config item: {item}")
38
+ if 'lib' not in item:
39
+ if item=='includedir':
40
+ return _datadir.joinpath('include')
41
+ if item=='buildflags':
42
+ import platform
43
+ if platform.system()=='Windows':
44
+ return '"/I%s" "%s"'%(config('includedir'),config('libpath'))
45
+ import shlex
46
+ return shlex.join(
47
+ shlex.quote(e)
48
+ for e in [ "-Wl,-rpath,%s"%config('libdir'),
49
+ "-Wl,%s"%config('libpath'),
50
+ "-I%s"%config('includedir') ]
51
+ )
52
+ if item=='intversion':
53
+ return "2000"
54
+ if item=='version':
55
+ return "0.2.0"
56
+
57
+ winsuffix = '.lib'
58
+ look_in_scripts_for_dll = False
59
+ if item.startswith('sh'):
60
+ winsuffix = '.dll'
61
+ item = item[2:]
62
+ #The next is only True on Windows in python installations:
63
+ look_in_scripts_for_dll = bool('1')
64
+
65
+ if look_in_scripts_for_dll:
66
+ p = _win_find_dll()
67
+ if item=='libdir':
68
+ return p.parent
69
+ return p.name if item=='libname' else p
70
+
71
+ libdir = _datadir.joinpath('lib')
72
+
73
+ if item=='libdir':
74
+ return libdir
75
+
76
+ libs = list( e for e in libdir.glob('*') if 'kdsource' in e.name.lower() )
77
+ libs_win = [ e for e in libs if e.name.lower().endswith(winsuffix) ]
78
+ libs_other = [ e for e in libs if not e.name.lower().endswith(winsuffix) ]
79
+ libs = libs_win or libs_other
80
+
81
+ if not libs:
82
+ raise RuntimeError('Inconsistent installation of KDSource'
83
+ ' (could not find shared lib)')
84
+ if len(libs)!=1:
85
+ s = ' '.join(e.name for e in libs)
86
+ raise RuntimeError('Inconsistent installation of KDSource (multiple'
87
+ f' libs: {s})')
88
+ assert len(libs)==1
89
+ return libs[0].name if item=='libname' else libs[0]
90
+
91
+ __cache_windll = [None]
92
+ def _win_find_dll():
93
+ #Windows. The DLL is in the scripts directory (to be in %PATH%). To be safe
94
+ #we look not only in the default scheme, but also in a few other preferred
95
+ #schemes. The sysconfig usage below assumes python 3.10 or later:
96
+ if __cache_windll[0] is not None:
97
+ return __cache_windll[0]
98
+
99
+ import sysconfig
100
+ import pathlib
101
+ schemes = [ sysconfig.get_default_scheme() ]
102
+ for scheme_key in ['prefix','home','user']:
103
+ scheme = sysconfig.get_preferred_scheme(scheme_key)
104
+ if scheme not in schemes:
105
+ schemes.append(scheme)
106
+ ln, ln2, res = 'kdsource.dll', 'kdsource.DLL', None
107
+ for scheme in schemes:
108
+ p = pathlib.Path( sysconfig.get_path('scripts',scheme) )
109
+ p1 = p.joinpath(ln)
110
+ if p1.is_file():
111
+ res = p1
112
+ break
113
+ p2 = p.joinpath(ln2)
114
+ if p2.is_file():
115
+ res = p2
116
+ break
117
+ if res is None:
118
+ raise RuntimeError('Unable to locate shared library (expected '
119
+ f'{ln} in Python site scripts directory)')
120
+ __cache_windll[0] = res.absolute().resolve()
121
+ return __cache_windll[0]