msl-loadlib 1.0.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.
Files changed (46) hide show
  1. msl/examples/loadlib/Trig.class +0 -0
  2. msl/examples/loadlib/__init__.py +38 -0
  3. msl/examples/loadlib/cpp32.py +368 -0
  4. msl/examples/loadlib/cpp64.py +157 -0
  5. msl/examples/loadlib/cpp_lib32.dll +0 -0
  6. msl/examples/loadlib/cpp_lib64.dll +0 -0
  7. msl/examples/loadlib/dotnet32.py +346 -0
  8. msl/examples/loadlib/dotnet64.py +186 -0
  9. msl/examples/loadlib/dotnet_lib32.dll +0 -0
  10. msl/examples/loadlib/dotnet_lib64.dll +0 -0
  11. msl/examples/loadlib/echo32.py +44 -0
  12. msl/examples/loadlib/echo64.py +36 -0
  13. msl/examples/loadlib/fortran32.py +551 -0
  14. msl/examples/loadlib/fortran64.py +238 -0
  15. msl/examples/loadlib/fortran_lib32.dll +0 -0
  16. msl/examples/loadlib/fortran_lib64.dll +0 -0
  17. msl/examples/loadlib/java_lib.jar +0 -0
  18. msl/examples/loadlib/kernel32.py +76 -0
  19. msl/examples/loadlib/kernel64.py +46 -0
  20. msl/examples/loadlib/labview32.py +56 -0
  21. msl/examples/loadlib/labview64.py +51 -0
  22. msl/examples/loadlib/labview_lib32.dll +0 -0
  23. msl/examples/loadlib/labview_lib64.dll +0 -0
  24. msl/examples/loadlib/py.typed +1 -0
  25. msl/loadlib/__about__.py +15 -0
  26. msl/loadlib/__init__.py +27 -0
  27. msl/loadlib/_constants.py +42 -0
  28. msl/loadlib/_types.py +26 -0
  29. msl/loadlib/_version.py +21 -0
  30. msl/loadlib/activex.py +1221 -0
  31. msl/loadlib/client64.py +647 -0
  32. msl/loadlib/exceptions.py +66 -0
  33. msl/loadlib/freeze_server32.py +437 -0
  34. msl/loadlib/load_library.py +478 -0
  35. msl/loadlib/py.typed +1 -0
  36. msl/loadlib/py4j-wrapper.jar +0 -0
  37. msl/loadlib/server32-windows.exe +0 -0
  38. msl/loadlib/server32-windows.exe.config +22 -0
  39. msl/loadlib/server32.py +311 -0
  40. msl/loadlib/start_server32.py +309 -0
  41. msl/loadlib/utils.py +415 -0
  42. msl_loadlib-1.0.0.dist-info/METADATA +216 -0
  43. msl_loadlib-1.0.0.dist-info/RECORD +46 -0
  44. msl_loadlib-1.0.0.dist-info/WHEEL +4 -0
  45. msl_loadlib-1.0.0.dist-info/entry_points.txt +2 -0
  46. msl_loadlib-1.0.0.dist-info/licenses/LICENSE.txt +21 -0
Binary file
@@ -0,0 +1,38 @@
1
+ """Examples showing how to load a 32-bit library in 64-bit Python."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from .cpp32 import Cpp32, FourPoints, NPoints, Point
8
+ from .cpp64 import Cpp64
9
+ from .dotnet32 import DotNet32
10
+ from .dotnet64 import DotNet64
11
+ from .echo32 import Echo32
12
+ from .echo64 import Echo64
13
+ from .fortran32 import Fortran32
14
+ from .fortran64 import Fortran64
15
+ from .kernel32 import Kernel32
16
+ from .kernel64 import Kernel64
17
+ from .labview32 import Labview32
18
+ from .labview64 import Labview64
19
+
20
+ EXAMPLES_DIR: Path = Path(__file__).parent
21
+
22
+ __all__: list[str] = [
23
+ "Cpp32",
24
+ "Cpp64",
25
+ "DotNet32",
26
+ "DotNet64",
27
+ "Echo32",
28
+ "Echo64",
29
+ "Fortran32",
30
+ "Fortran64",
31
+ "FourPoints",
32
+ "Kernel32",
33
+ "Kernel64",
34
+ "Labview32",
35
+ "Labview64",
36
+ "NPoints",
37
+ "Point",
38
+ ]
@@ -0,0 +1,368 @@
1
+ """Wrapper around a 32-bit C++ library.
2
+
3
+ Example of a server that loads a 32-bit library, [cpp_lib][cpp-lib],
4
+ in a 32-bit Python interpreter to host the library. The corresponding [Cpp64][] class
5
+ is created in a 64-bit Python interpreter and the [Cpp64][] class sends requests
6
+ to the [Cpp32][] class which calls the 32-bit library to execute the request and
7
+ then returns the response from the library.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import ctypes
13
+ import math
14
+ from pathlib import Path
15
+ from typing import TYPE_CHECKING
16
+
17
+ from msl.loadlib import Server32
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Sequence
21
+ from ctypes import Array
22
+
23
+
24
+ class Cpp32(Server32):
25
+ """Wrapper around a 32-bit C++ library."""
26
+
27
+ def __init__(self, host: str, port: int) -> None:
28
+ """Wrapper around a 32-bit C++ library.
29
+
30
+ This class demonstrates how to send/receive various data types to/from a
31
+ 32-bit C++ library via [ctypes][]{:target="_blank"}.
32
+
33
+ Args:
34
+ host: The IP address (or hostname) to use for the server.
35
+ port: The port to open for the server.
36
+ """
37
+ # By not specifying the extension of the library file the server will open
38
+ # the appropriate file based on the operating system.
39
+ path = Path(__file__).parent / "cpp_lib32"
40
+ super().__init__(path, "cdll", host, port)
41
+
42
+ def add(self, a: int, b: int) -> int:
43
+ """Add two integers.
44
+
45
+ The corresponding C++ code is
46
+
47
+ ```cpp
48
+ int add(int a, int b) {
49
+ return a + b;
50
+ }
51
+ ```
52
+
53
+ See the corresponding [Cpp64.add][msl.examples.loadlib.Cpp64.add] method.
54
+
55
+ Args:
56
+ a: First integer.
57
+ b: Second integer.
58
+
59
+ Returns:
60
+ The sum, `a + b`.
61
+ """
62
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
63
+ self.lib.add.restype = ctypes.c_int32
64
+ self.lib.add.argtypes = [ctypes.c_int32, ctypes.c_int32]
65
+ result: int = self.lib.add(a, b)
66
+ return result
67
+
68
+ def subtract(self, a: float, b: float) -> float:
69
+ """Subtract two floating-point numbers *('float' refers to the C++ data type)*.
70
+
71
+ The corresponding C++ code is
72
+
73
+ ```cpp
74
+ float subtract(float a, float b) {
75
+ return a - b;
76
+ }
77
+ ```
78
+
79
+ See the corresponding [Cpp64.subtract][msl.examples.loadlib.Cpp64.subtract] method.
80
+
81
+ Args:
82
+ a: First floating-point number.
83
+ b: Second floating-point number.
84
+
85
+ Returns:
86
+ The difference, `a - b`.
87
+ """
88
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
89
+ self.lib.subtract.restype = ctypes.c_float
90
+ self.lib.subtract.argtypes = [ctypes.c_float, ctypes.c_float]
91
+ result: float = self.lib.subtract(a, b)
92
+ return result
93
+
94
+ def add_or_subtract(self, a: float, b: float, *, do_addition: bool) -> float:
95
+ """Add or subtract two double-precision numbers *('double' refers to the C++ data type)*.
96
+
97
+ The corresponding C++ code is
98
+
99
+ ```cpp
100
+ double add_or_subtract(double a, double b, bool do_addition) {
101
+ if (do_addition) {
102
+ return a + b;
103
+ } else {
104
+ return a - b;
105
+ }
106
+ }
107
+ ```
108
+
109
+ See the corresponding [Cpp64.add_or_subtract][msl.examples.loadlib.Cpp64.add_or_subtract] method.
110
+
111
+ Args:
112
+ a: First double-precision number.
113
+ b: Second double-precision number.
114
+ do_addition: Whether to add or subtract the numbers.
115
+
116
+ Returns:
117
+ `a + b` if `do_addition` is `True` else `a - b`.
118
+ """
119
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
120
+ self.lib.add_or_subtract.restype = ctypes.c_double
121
+ self.lib.add_or_subtract.argtypes = [ctypes.c_double, ctypes.c_double, ctypes.c_bool]
122
+ result: float = self.lib.add_or_subtract(a, b, do_addition)
123
+ return result
124
+
125
+ def scalar_multiply(self, a: float, xin: Sequence[float]) -> list[float]:
126
+ """Multiply each element in an array by a number.
127
+
128
+ The corresponding C++ code is
129
+
130
+ ```cpp
131
+ void scalar_multiply(double a, double* xin, int n, double* xout) {
132
+ for (int i = 0; i < n; i++) {
133
+ xout[i] = a * xin[i];
134
+ }
135
+ }
136
+ ```
137
+
138
+ See the corresponding [Cpp64.scalar_multiply][msl.examples.loadlib.Cpp64.scalar_multiply] method.
139
+
140
+ Args:
141
+ a: Scalar value.
142
+ xin: Array to modify.
143
+
144
+ Returns:
145
+ A new array with each element in `xin` multiplied by `a`.
146
+ """
147
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
148
+ self.lib.scalar_multiply.restype = None
149
+ self.lib.scalar_multiply.argtypes = [
150
+ ctypes.c_double,
151
+ ctypes.POINTER(ctypes.c_double),
152
+ ctypes.c_int32,
153
+ ctypes.POINTER(ctypes.c_double),
154
+ ]
155
+
156
+ n = len(xin)
157
+ c_xin = (ctypes.c_double * n)(*xin) # convert input array to ctypes
158
+ c_xout = (ctypes.c_double * n)() # allocate memory for output array
159
+ self.lib.scalar_multiply(a, c_xin, n, c_xout)
160
+ return list(c_xout)
161
+
162
+ def reverse_string_v1(self, original: str) -> str:
163
+ """Reverse a string (version 1).
164
+
165
+ In this method Python allocates the memory for the reversed string and
166
+ passes the string to C++.
167
+
168
+ The corresponding C++ code is
169
+
170
+ ```cpp
171
+ void reverse_string_v1(const char* original, int n, char* reversed) {
172
+ for (int i = 0; i < n; i++) {
173
+ reversed[i] = original[n-i-1];
174
+ }
175
+ }
176
+ ```
177
+
178
+ See the corresponding [Cpp64.reverse_string_v1][msl.examples.loadlib.Cpp64.reverse_string_v1] method.
179
+
180
+ Args:
181
+ original: The original string.
182
+
183
+ Returns:
184
+ The string reversed.
185
+ """
186
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
187
+ self.lib.reverse_string_v1.restype = None
188
+ self.lib.reverse_string_v1.argtypes = [ctypes.c_char_p, ctypes.c_int32, ctypes.c_char_p]
189
+
190
+ n = len(original)
191
+ rev = ctypes.create_string_buffer(n)
192
+ self.lib.reverse_string_v1(original.encode(), n, rev)
193
+ return rev.raw.decode()
194
+
195
+ def reverse_string_v2(self, original: str) -> str:
196
+ """Reverse a string (version 2).
197
+
198
+ In this method C++ allocates the memory for the reversed string and passes
199
+ the string to Python.
200
+
201
+ The corresponding C++ code is
202
+
203
+ ```cpp
204
+ char* reverse_string_v2(char* original, int n) {
205
+ char* reversed = new char[n];
206
+ for (int i = 0; i < n; i++) {
207
+ reversed[i] = original[n - i - 1];
208
+ }
209
+ return reversed;
210
+ }
211
+ ```
212
+
213
+ See the corresponding [Cpp64.reverse_string_v2][msl.examples.loadlib.Cpp64.reverse_string_v2] method.
214
+
215
+ Args:
216
+ original: The original string.
217
+
218
+ Returns:
219
+ The string reversed.
220
+ """
221
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
222
+ self.lib.reverse_string_v2.restype = ctypes.c_char_p
223
+ self.lib.reverse_string_v2.argtypes = [ctypes.c_char_p, ctypes.c_int32]
224
+
225
+ n = len(original)
226
+ rev = self.lib.reverse_string_v2(original.encode(), n)
227
+ return ctypes.string_at(rev, n).decode()
228
+
229
+ def distance_4_points(self, four_points: FourPoints) -> float:
230
+ """Calculates the total distance connecting 4 [Point][msl.examples.loadlib.cpp32.Point]s.
231
+
232
+ The corresponding C++ code is
233
+
234
+ ```cpp
235
+ double distance_4_points(FourPoints p) {
236
+ double d = distance(p.points[0], p.points[3]);
237
+ for (int i = 1; i < 4; i++) {
238
+ d += distance(p.points[i], p.points[i-1]);
239
+ }
240
+ return d;
241
+ }
242
+ ```
243
+
244
+ See the corresponding [Cpp64.distance_4_points][msl.examples.loadlib.Cpp64.distance_4_points] method.
245
+
246
+ Args:
247
+ four_points: The points to use to calculate the total distance.
248
+
249
+ Returns:
250
+ The total distance connecting the 4 points.
251
+ """
252
+ # restype should be defined elsewhere, shown here for illustrative purposes
253
+ self.lib.distance_4_points.restype = ctypes.c_double
254
+ result: float = self.lib.distance_4_points(four_points)
255
+ return result
256
+
257
+ def circumference(self, radius: float, n: int) -> float:
258
+ """Estimates the circumference of a circle.
259
+
260
+ This method calls the `distance_n_points` function in [cpp_lib][cpp-lib].
261
+
262
+ The corresponding C++ code uses the [NPoints][msl.examples.loadlib.cpp32.NPoints]
263
+ struct as the input parameter to sum the distance between adjacent points on the circle.
264
+
265
+ ```cpp
266
+ double distance_n_points(NPoints p) {
267
+ if (p.n < 2) {
268
+ return 0.0;
269
+ }
270
+ double d = distance(p.points[0], p.points[p.n-1]);
271
+ for (int i = 1; i < p.n; i++) {
272
+ d += distance(p.points[i], p.points[i-1]);
273
+ }
274
+ return d;
275
+ }
276
+ ```
277
+
278
+ See the corresponding [Cpp64.circumference][msl.examples.loadlib.Cpp64.circumference] method.
279
+
280
+ Args:
281
+ radius: The radius of the circle.
282
+ n: The number of points to use to estimate the circumference.
283
+
284
+ Returns:
285
+ The estimated circumference of the circle.
286
+ """
287
+ # restype and argtypes should be defined elsewhere, shown here for illustrative purposes
288
+ self.lib.distance_n_points.restype = ctypes.c_double
289
+ self.lib.distance_n_points.argtypes = [NPoints]
290
+
291
+ theta = 0.0
292
+ delta = (2.0 * math.pi) / float(n) if n != 0 else 0
293
+
294
+ pts = NPoints()
295
+ pts.n = n
296
+ pts.points = (Point * n)()
297
+ for i in range(n):
298
+ pts.points[i] = Point(radius * math.cos(theta), radius * math.sin(theta))
299
+ theta += delta
300
+ result: float = self.lib.distance_n_points(pts)
301
+ return result
302
+
303
+
304
+ class Point(ctypes.Structure):
305
+ """C++ struct that is a fixed size in memory.
306
+
307
+ This object can be [pickle][]{:target="_blank"}d.
308
+
309
+ ```cpp
310
+ struct Point {
311
+ double x;
312
+ double y;
313
+ };
314
+ ```
315
+ """
316
+
317
+ _fields_ = ( # pyright: ignore[reportUnannotatedClassAttribute]
318
+ ("x", ctypes.c_double),
319
+ ("y", ctypes.c_double),
320
+ )
321
+
322
+
323
+ class FourPoints(ctypes.Structure):
324
+ """C++ struct that is a fixed size in memory."""
325
+
326
+ _fields_ = ( # pyright: ignore[reportUnannotatedClassAttribute]
327
+ ("points", (Point * 4)),
328
+ )
329
+
330
+ def __init__(self, point1: Point, point2: Point, point3: Point, point4: Point) -> None:
331
+ """C++ struct that is a fixed size in memory.
332
+
333
+ This object can be [pickle][]{:target="_blank"}d.
334
+
335
+ ```cpp
336
+ struct FourPoints {
337
+ Point points[4];
338
+ };
339
+ ```
340
+
341
+ Args:
342
+ point1: The first point.
343
+ point2: The second point.
344
+ point3: The third point.
345
+ point4: The fourth point.
346
+ """
347
+ super().__init__()
348
+ self.points: Array[Point] = (Point * 4)(point1, point2, point3, point4)
349
+
350
+
351
+ class NPoints(ctypes.Structure):
352
+ """C++ struct that is **not** a fixed size in memory.
353
+
354
+ This object cannot be [pickle][]{:target="_blank"}d because it contains a pointer.
355
+ A 32-bit process and a 64-bit process cannot share a pointer.
356
+
357
+ ```cpp
358
+ struct NPoints {
359
+ int n;
360
+ Point *points;
361
+ };
362
+ ```
363
+ """
364
+
365
+ _fields_ = ( # pyright: ignore[reportUnannotatedClassAttribute]
366
+ ("n", ctypes.c_int),
367
+ ("points", ctypes.POINTER(Point)),
368
+ )
@@ -0,0 +1,157 @@
1
+ """Communicates with the [cpp_lib][cpp-lib] library via the [Cpp32][] class that is running on a server."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING
7
+
8
+ from msl.loadlib import Client64
9
+
10
+ if TYPE_CHECKING:
11
+ from collections.abc import Sequence
12
+
13
+ from .cpp32 import FourPoints
14
+
15
+
16
+ class Cpp64(Client64):
17
+ """Communicates with a 32-bit C++ library."""
18
+
19
+ def __init__(self) -> None:
20
+ """Communicates with a 32-bit C++ library via the server running [Cpp32][].
21
+
22
+ This class demonstrates how to communicate with a 32-bit C++ library if an
23
+ instance of this class is created within a 64-bit Python interpreter.
24
+ """
25
+ # specify the name of the corresponding 32-bit server module, cpp32,
26
+ # which hosts the 32-bit C++ library -- cpp_lib32.
27
+ super().__init__("cpp32", append_sys_path=Path(__file__).parent)
28
+
29
+ def add(self, a: int, b: int) -> int:
30
+ """Add two integers.
31
+
32
+ See the corresponding [Cpp32.add][msl.examples.loadlib.cpp32.Cpp32.add] method.
33
+
34
+ Args:
35
+ a: First integer.
36
+ b: Second integer.
37
+
38
+ Returns:
39
+ The sum, `a + b`.
40
+ """
41
+ reply: int = self.request32("add", a, b)
42
+ return reply
43
+
44
+ def subtract(self, a: float, b: float) -> float:
45
+ """Subtract two floating-point numbers *('float' refers to the C++ data type)*.
46
+
47
+ See the corresponding [Cpp32.subtract][msl.examples.loadlib.cpp32.Cpp32.subtract] method.
48
+
49
+ Args:
50
+ a: First floating-point number.
51
+ b: Second floating-point number.
52
+
53
+ Returns:
54
+ The difference, `a - b`.
55
+ """
56
+ reply: float = self.request32("subtract", a, b)
57
+ return reply
58
+
59
+ def add_or_subtract(self, a: float, b: float, *, do_addition: bool) -> float:
60
+ """Add or subtract two floating-point numbers *('double' refers to the C++ data type)*.
61
+
62
+ See the corresponding [Cpp32.add_or_subtract][msl.examples.loadlib.cpp32.Cpp32.add_or_subtract] method.
63
+
64
+ Args:
65
+ a: First double-precision number.
66
+ b: Second double-precision number.
67
+ do_addition: Whether to add or subtract the numbers.
68
+
69
+ Returns:
70
+ `a + b` if `do_addition` is `True` else `a - b`.
71
+ """
72
+ reply: float = self.request32("add_or_subtract", a, b, do_addition=do_addition)
73
+ return reply
74
+
75
+ def scalar_multiply(self, a: float, xin: Sequence[float]) -> list[float]:
76
+ """Multiply each element in an array by a number.
77
+
78
+ See the corresponding [Cpp32.scalar_multiply][msl.examples.loadlib.cpp32.Cpp32.scalar_multiply] method.
79
+
80
+ Args:
81
+ a: Scalar value.
82
+ xin: Array to modify.
83
+
84
+ Returns:
85
+ A new array with each element in `xin` multiplied by `a`.
86
+ """
87
+ reply: list[float] = self.request32("scalar_multiply", a, xin)
88
+ return reply
89
+
90
+ def reverse_string_v1(self, original: str) -> str:
91
+ """Reverse a string (version 1).
92
+
93
+ In this method Python allocates the memory for the reversed string
94
+ and passes the string to C++.
95
+
96
+ See the corresponding [Cpp32.reverse_string_v1][msl.examples.loadlib.cpp32.Cpp32.reverse_string_v1] method.
97
+
98
+ Args:
99
+ original: The original string.
100
+
101
+ Returns:
102
+ The string reversed.
103
+ """
104
+ reply: str = self.request32("reverse_string_v1", original)
105
+ return reply
106
+
107
+ def reverse_string_v2(self, original: str) -> str:
108
+ """Reverse a string (version 2).
109
+
110
+ In this method C++ allocates the memory for the reversed string and passes
111
+ the string to Python.
112
+
113
+ See the corresponding [Cpp32.reverse_string_v2][msl.examples.loadlib.cpp32.Cpp32.reverse_string_v2] method.
114
+
115
+ Args:
116
+ original: The original string.
117
+
118
+ Returns:
119
+ The string reversed.
120
+ """
121
+ reply: str = self.request32("reverse_string_v2", original)
122
+ return reply
123
+
124
+ def distance_4_points(self, points: FourPoints) -> float:
125
+ """Calculates the total distance connecting 4 [Point][msl.examples.loadlib.cpp32.Point]s.
126
+
127
+ See the corresponding [Cpp32.distance_4_points][msl.examples.loadlib.cpp32.Cpp32.distance_4_points] method.
128
+
129
+ Args:
130
+ points: The points to use to calculate the total distance.
131
+ Since `points` is a struct that is a fixed size we can pass the
132
+ [ctypes.Structure][]{:target="_blank"} object directly from 64-bit Python to
133
+ the 32-bit Python. The [ctypes][]{:target="_blank"} module on the 32-bit server
134
+ can load the [pickle][]{:target="_blank"}d [ctypes.Structure][]{:target="_blank"}.
135
+
136
+ Returns:
137
+ The total distance connecting the 4 points.
138
+ """
139
+ reply: float = self.request32("distance_4_points", points)
140
+ return reply
141
+
142
+ def circumference(self, radius: float, n: int) -> float:
143
+ """Estimates the circumference of a circle.
144
+
145
+ This method calls the `distance_n_points` function in [cpp_lib][cpp-lib].
146
+
147
+ See the corresponding [Cpp32.circumference][msl.examples.loadlib.cpp32.Cpp32.circumference] method.
148
+
149
+ Args:
150
+ radius: The radius of the circle.
151
+ n: The number of points to use to estimate the circumference.
152
+
153
+ Returns:
154
+ The estimated circumference of the circle.
155
+ """
156
+ reply: float = self.request32("circumference", radius, n)
157
+ return reply
Binary file
Binary file