vrpc 2.6.0 → 3.0.0

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.
@@ -1,22 +0,0 @@
1
- #!/bin/bash
2
-
3
- script_dir=$(dirname `[[ $0 = /* ]] && echo "$0" || echo "$PWD/${0#./}"`)
4
- cd ${script_dir}
5
- if [ $? -ne 0 ]; then
6
- echo " Could not change directory to ${script_dir}"
7
- exit 1;
8
- fi
9
-
10
- INSTALL_PREFIX=${script_dir}
11
- mkdir -p build
12
- mkdir -p include
13
- pushd build
14
-
15
- ### CATCH (for testing) ###
16
-
17
- if [ ! -f ${INSTALL_PREFIX}/include/catch.hpp ]; then
18
- wget https://github.com/catchorg/Catch2/releases/download/v2.1.1/catch.hpp
19
- cp catch.hpp ../include
20
- fi
21
-
22
- popd
package/vrpc/VrpcLocal.js DELETED
@@ -1,269 +0,0 @@
1
- /*
2
- __/\\\________/\\\____/\\\\\\\\\______/\\\\\\\\\\\\\_________/\\\\\\\\\_
3
- __\/\\\_______\/\\\__/\\\///////\\\___\/\\\/////////\\\____/\\\////////__
4
- __\//\\\______/\\\__\/\\\_____\/\\\___\/\\\_______\/\\\__/\\\/___________
5
- ___\//\\\____/\\\___\/\\\\\\\\\\\/____\/\\\\\\\\\\\\\/__/\\\_____________
6
- ____\//\\\__/\\\____\/\\\//////\\\____\/\\\/////////___\/\\\_____________
7
- _____\//\\\/\\\_____\/\\\____\//\\\___\/\\\____________\//\\\____________
8
- ______\//\\\\\______\/\\\_____\//\\\__\/\\\_____________\///\\\__________
9
- _______\//\\\_______\/\\\______\//\\\_\/\\\_______________\////\\\\\\\\\_
10
- ________\///________\///________\///__\///___________________\/////////__
11
-
12
-
13
- Non-intrusively binds code and provides access in form of asynchronous remote
14
- procedure calls (RPC).
15
- Author: Dr. Burkhard C. Heisen (https://github.com/bheisen/vrpc)
16
-
17
-
18
- Licensed under the MIT License <http://opensource.org/licenses/MIT>.
19
- Copyright (c) 2018 - 2021 Dr. Burkhard C. Heisen <burkhard.heisen@heisenware.com>.
20
-
21
- Permission is hereby granted, free of charge, to any person obtaining a copy
22
- of this software and associated documentation files (the "Software"), to deal
23
- in the Software without restriction, including without limitation the rights
24
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25
- copies of the Software, and to permit persons to whom the Software is
26
- furnished to do so, subject to the following conditions:
27
-
28
- The above copyright notice and this permission notice shall be included in all
29
- copies or substantial portions of the Software.
30
-
31
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37
- SOFTWARE.
38
- */
39
-
40
- const EventEmitter = require('events')
41
- const { nanoid } = require('nanoid')
42
-
43
- /**
44
- * Client capable of creating proxy objects and locally calling
45
- * functions as provided through native addons.
46
- */
47
- class VrpcLocal {
48
- /**
49
- * @constructor
50
- * @param {Object} adapter An adapter object, typically loaded as native addon
51
- */
52
- constructor (adapter) {
53
- this._eventEmitter = new EventEmitter()
54
- this._invokeId = 0
55
- this._proxyId = 0
56
- this._adapter = adapter
57
- this._instance = nanoid(4)
58
-
59
- // Register callback handler
60
- this._adapter.onCallback((jsonString, jsonObject) => {
61
- // Only JS Adapters will provide the second argument
62
- const { id, data } = jsonObject || JSON.parse(jsonString)
63
- this._eventEmitter.emit(id, data)
64
- })
65
- }
66
-
67
- /**
68
- * Creates an instance of the specified class.
69
- *
70
- * @param {String} className Name of the class to create an instance of
71
- * @param {...Any} args Arguments to provide to the constructor
72
- * @return {Object} Proxy to the created instance
73
- */
74
- create (className, ...args) {
75
- if (typeof className === 'string') {
76
- return this._create({ className, args })
77
- }
78
- return this._create({
79
- className: className.className,
80
- instance: className.instance,
81
- args: className.args
82
- })
83
- }
84
-
85
- getInstance ({ className, instance }) {
86
- const json = {
87
- context: className,
88
- method: '__getNamed__',
89
- data: { _1: instance }
90
- }
91
- return this._createProxy(className, json)
92
- }
93
-
94
- delete ({ className, instance }) {
95
- let context
96
- if (typeof instance === 'string') {
97
- context = instance
98
- } else if (typeof instance === 'object') {
99
- context = instance._targetId
100
- }
101
- const json = {
102
- context: className,
103
- method: '__delete__',
104
- data: { _1: context }
105
- }
106
- return JSON.parse(this._adapter.call(JSON.stringify(json))).data.r
107
- }
108
-
109
- callStatic (className, functionName, ...args) {
110
- const json = {
111
- context: className,
112
- method: functionName,
113
- data: this._packData(className, functionName, ...args)
114
- }
115
- return JSON.parse(this._adapter.call(JSON.stringify(json))).data.r
116
- }
117
-
118
- /**
119
- * Retrieves an array of all available classes (names only)
120
- *
121
- * @return {Array.<String>} Array of class names
122
- */
123
- getAvailableClasses () {
124
- return JSON.parse(this._adapter.getClasses())
125
- }
126
-
127
- /**
128
- * Provides the names of all currently running instances.
129
- *
130
- * @param {String} className Name of class to retrieve the instances for
131
- * @return {Array.<String>} Array of instance names
132
- */
133
- getAvailableInstances (className) {
134
- return JSON.parse(this._adapter.getInstances(className))
135
- }
136
-
137
- /**
138
- * Provides all available member functions of the specified class.
139
- *
140
- * @param {String} className Name of class to provide member functions for
141
- * @return {Array.<String>} Array of member function names
142
- */
143
- getAvailableMemberFunctions (className) {
144
- return JSON.parse(this._adapter.getMemberFunctions(className))
145
- }
146
-
147
- /**
148
- * Provides all available static functions of a registered class.
149
- *
150
- * @param {String} className Name of class to provide static functions for
151
- * @return {Array.<String>} Array of static function names
152
- */
153
- getAvailableStaticFunctions (className) {
154
- return JSON.parse(this._adapter.getStaticFunctions(className))
155
- }
156
-
157
- getMetaData (className) {
158
- return JSON.parse(this._adapter.getMetaData(className))
159
- }
160
-
161
- // private:
162
-
163
- _create ({ className, instance, args = [] }) {
164
- const data = instance ? { _1: instance } : {}
165
- const offset = instance ? 2 : 1
166
- args.forEach((value, index) => {
167
- data[`_${index + offset}`] = value
168
- })
169
- const json = {
170
- context: className,
171
- method: instance ? '__createNamed__' : '__create__',
172
- data
173
- }
174
- return this._createProxy(className, json)
175
- }
176
-
177
- _createProxy (className, json) {
178
- // Create instance
179
- const ret = JSON.parse(this._adapter.call(JSON.stringify(json)))
180
- const instanceId = ret.data.r
181
- const proxyId = `${this._instance}-${this._proxyId++}`
182
- const proxy = {
183
- _targetId: instanceId,
184
- _proxyId: proxyId
185
- }
186
- let functions = JSON.parse(this._adapter.getMemberFunctions(className))
187
- // Strip off argument signature
188
- functions = functions.map(name => {
189
- const pos = name.indexOf('-')
190
- if (pos > 0) return name.substring(0, pos)
191
- else return name
192
- })
193
- // Remove overloads
194
- const uniqueFuncs = new Set(functions)
195
- // Build proxy
196
- uniqueFuncs.forEach(name => {
197
- proxy[name] = (...args) => {
198
- const json = {
199
- context: instanceId,
200
- method: name,
201
- data: this._packData(proxyId, name, ...args)
202
- }
203
- const { data } = JSON.parse(this._adapter.call(JSON.stringify(json)))
204
- if (data.e) throw new Error(data.e)
205
- // Handle functions returning a promise
206
- if (typeof data.r === 'string' && data.r.substr(0, 5) === '__p__') {
207
- return new Promise((resolve, reject) => {
208
- this._eventEmitter.once(data.r, promiseData => {
209
- if (promiseData.e) reject(new Error(promiseData.e))
210
- else resolve(promiseData.r)
211
- })
212
- })
213
- }
214
- return data.r
215
- }
216
- })
217
- return proxy
218
- }
219
-
220
- _packData (proxyId, functionName, ...args) {
221
- const data = {}
222
- args.forEach((value, index) => {
223
- // Check whether provided argument is a function
224
- if (this._isFunction(value)) {
225
- const id = `__f__${proxyId}-${functionName}-${index}-${this
226
- ._invokeId++ % Number.MAX_SAFE_INTEGER}`
227
- data[`_${index + 1}`] = id
228
- this._eventEmitter.once(id, data => {
229
- const args = Object.keys(data)
230
- .sort()
231
- .filter(value => value[0] === '_')
232
- .map(key => data[key])
233
- value.apply(null, args) // This is the actual function call
234
- })
235
- } else if (this._isEmitter(value)) {
236
- const { emitter, event } = value
237
- const id = `__f__${proxyId}-${functionName}-${index}-${event}`
238
- data[`_${index + 1}`] = id
239
- this._eventEmitter.on(id, data => {
240
- const args = Object.keys(data)
241
- .sort()
242
- .filter(value => value[0] === '_')
243
- .map(key => data[key])
244
- emitter.emit(event, ...args)
245
- })
246
- } else {
247
- data[`_${index + 1}`] = value
248
- }
249
- })
250
- return data
251
- }
252
-
253
- _isFunction (variable) {
254
- const getType = {}
255
- return variable && getType.toString.call(variable) === '[object Function]'
256
- }
257
-
258
- _isEmitter (variable) {
259
- return (
260
- typeof variable === 'object' &&
261
- variable.hasOwnProperty('emitter') &&
262
- variable.hasOwnProperty('event') &&
263
- typeof variable.emitter === 'object' &&
264
- typeof variable.emitter.emit === 'function'
265
- )
266
- }
267
- }
268
-
269
- module.exports = VrpcLocal
package/vrpc/VrpcLocal.py DELETED
@@ -1,171 +0,0 @@
1
- import json
2
- import sys
3
-
4
-
5
- class Proxy(object):
6
-
7
- def __init__(self, vrpc, caller):
8
- self._vrpc = vrpc
9
- self._caller = caller
10
-
11
- def _packData(self, function, *args):
12
- data = {}
13
- for index, arg in enumerate(args):
14
- # Argument is function
15
- if (hasattr(arg, '__call__')):
16
- id = self._caller.register_callback(function, index, arg)
17
- data["_{}".format(index + 1)] = id
18
- elif (self._isEmitter(arg)):
19
- id = self._caller.register_emitter(function, index, arg)
20
- data["_{}".format(index + 1)] = id
21
- else:
22
- data["_{}".format(index + 1)] = arg
23
- return data
24
-
25
- def _isEmitter(self, arg):
26
- pass
27
- return (
28
- type(arg) == tuple and
29
- len(arg) == 2 and
30
- hasattr(arg[0], '__call__') and
31
- type(arg[1] == str)
32
- )
33
-
34
-
35
- class Caller(object):
36
-
37
- def __init__(self, vrpc):
38
- self._invoke_id = 0
39
- self._callbacks = {}
40
- self._emitters = {}
41
- self._vrpc = vrpc
42
- self._vrpc.onCallback(self._handle_callback)
43
-
44
- def _handle_callback(self, json_string):
45
- payload = json.loads(json_string)
46
- id = payload['id']
47
- if id in self._callbacks:
48
- args = tuple(v for _, v in sorted(payload['data'].items()))
49
- self._callbacks[id](*args)
50
- self._callbacks.pop(id, None)
51
- elif id in self._emitters:
52
- emitter = self._emitters[id]
53
- args = tuple(v for _, v in sorted(payload['data'].items()))
54
- emitter[0](emitter[1], *args)
55
-
56
- def register_callback(self, function, index, callback):
57
- id = "__f__{}-{}-{}".format(function, index, self._invoke_id)
58
- self._invoke_id = (self._invoke_id + 1) % sys.maxsize
59
- if id in self._callbacks:
60
- return -1
61
- self._callbacks[id] = callback
62
- return id
63
-
64
- def register_emitter(self, function, index, emitter):
65
- id = "__f__{}-{}".format(function, index)
66
- self._emitters[id] = emitter
67
- return id
68
-
69
-
70
- class VrpcLocal(object):
71
- """Client capable of calling functions as provided by native modules."""
72
-
73
- def __init__(self, module=None):
74
- """Constructs an instance of a local client.
75
-
76
- Args:
77
- module (obj): A module object, typically loaded as native addon
78
-
79
- Todo:
80
- * Existing code reflects only an initial, minimal implementation
81
- * Still missing: availability functions, deletion, meta data, etc.
82
- * More sophisticated handling of potential threading in loaded addon
83
- """
84
- self._vrpc = module
85
- self._caller = Caller(self._vrpc)
86
-
87
- def create(self, class_name, *args):
88
- """Creates an instance of the specified class.
89
-
90
- Args:
91
- class_name (str): Name of the class to create an instance of
92
- *args Variable number of arguments to provide to the constructor
93
-
94
- Returns:
95
- Proxy to the created instance
96
- """
97
- json_string = {
98
- 'context': class_name,
99
- 'method': '__create__',
100
- 'data': {}
101
- }
102
- data = json_string['data']
103
- for index, a in enumerate(args):
104
- data["_{}".format(index + 1)] = a
105
-
106
- # Create instance
107
- ret = json.loads(self._vrpc.callRemote(json.dumps(json_string)))
108
- instanceId = ret['data']['r']
109
- functions = json.loads(
110
- self._vrpc.getMemberFunctions(class_name)
111
- )['functions']
112
- functions = self._remove_overloads(functions)
113
- proxy = {
114
- # Python lambdas are broken, I can't simply make this a multi-line
115
- # statement. Sorry PEP8!
116
- '__init__': lambda self, vrpc, caller: Proxy.__init__(self, vrpc, caller)
117
- }
118
- for function in functions:
119
- proxy[function] = self._make_function(instanceId, function, *args)
120
- instance = type(class_name, (Proxy,), proxy)(self._vrpc, self._caller)
121
- return instance
122
-
123
- def call_static(self, class_name, function_name, *args):
124
- """Calls a static function as made available through the native addon.
125
-
126
- Args:
127
- class_name (str): Name of the static function's class
128
- function_name (str): Name of the static function to be called
129
- *args: Positional arguments of the static function call
130
-
131
- Returns:
132
- any: The return value of the via-proxy called function
133
-
134
- Todo:
135
- * Support callbacks
136
- """
137
- json_string = {
138
- 'context': class_name,
139
- 'method': function_name,
140
- 'data': {}
141
- }
142
- data = json_string['data']
143
- for index, a in enumerate(args):
144
- data["_{}".format(index + 1)] = a
145
- ret = json.loads(self._vrpc.callRemote(json.dumps(json_string)))
146
- if (ret['data'].get('e')):
147
- raise RuntimeError(ret['data']['e'])
148
- return ret['data']['r']
149
-
150
- def _remove_overloads(self, functions):
151
- uniqueFunctions = set()
152
- for function in functions:
153
- # Strip off overload signature
154
- index = function.find('-')
155
- if (index > 0):
156
- function = function[0:index]
157
- uniqueFunctions.add(function)
158
- return uniqueFunctions
159
-
160
- def _make_function(self, instance_id, function, *args):
161
- def f(self, *args):
162
- json_string = {
163
- 'context': instance_id,
164
- 'method': function,
165
- 'data': self._packData(function, *args)
166
- }
167
- ret = json.loads(self._vrpc.callRemote(json.dumps(json_string)))
168
- if (ret['data'].get('e')):
169
- raise RuntimeError(ret['data']['e'])
170
- return ret['data']['r']
171
- return f
package/vrpc/__init__.py DELETED
@@ -1 +0,0 @@
1
- from .VrpcLocal import VrpcLocal
package/vrpc/module.cpp DELETED
@@ -1,183 +0,0 @@
1
- /*
2
- __/\\\________/\\\____/\\\\\\\\\______/\\\\\\\\\\\\\_________/\\\\\\\\\_
3
- __\/\\\_______\/\\\__/\\\///////\\\___\/\\\/////////\\\____/\\\////////__
4
- __\//\\\______/\\\__\/\\\_____\/\\\___\/\\\_______\/\\\__/\\\/___________
5
- ___\//\\\____/\\\___\/\\\\\\\\\\\/____\/\\\\\\\\\\\\\/__/\\\_____________
6
- ____\//\\\__/\\\____\/\\\//////\\\____\/\\\/////////___\/\\\_____________
7
- _____\//\\\/\\\_____\/\\\____\//\\\___\/\\\____________\//\\\____________
8
- ______\//\\\\\______\/\\\_____\//\\\__\/\\\_____________\///\\\__________
9
- _______\//\\\_______\/\\\______\//\\\_\/\\\_______________\////\\\\\\\\\_
10
- ________\///________\///________\///__\///___________________\/////////__
11
-
12
-
13
- Enables Python3 to run VRPC as native addon.
14
- Author: Dr. Burkhard C. Heisen (https://github.com/bheisen/vrpc)
15
-
16
-
17
- Licensed under the MIT License <http://opensource.org/licenses/MIT>.
18
- Copyright (c) 2018 - 2021 Dr. Burkhard C. Heisen <burkhard.heisen@heisenware.com>.
19
-
20
- Permission is hereby granted, free of charge, to any person obtaining a copy
21
- of this software and associated documentation files (the "Software"), to deal
22
- in the Software without restriction, including without limitation the rights
23
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24
- copies of the Software, and to permit persons to whom the Software is
25
- furnished to do so, subject to the following conditions:
26
-
27
- The above copyright notice and this permission notice shall be included in all
28
- copies or substantial portions of the Software.
29
-
30
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
- SOFTWARE.
37
- */
38
-
39
- #include <Python.h>
40
- #include "vrpc.hpp"
41
- #include "json.hpp"
42
-
43
- #ifndef VRPC_WITH_DL
44
- #include <binding.cpp>
45
- #endif
46
-
47
- namespace vrpc_python_bindings {
48
-
49
- static PyObject* callRemote(PyObject* self, PyObject* args) {
50
- const char* json_string;
51
- // Check whether we got a string as single argument
52
- if (!PyArg_ParseTuple(args, "s", &json_string)) {
53
- PyErr_SetString(PyExc_TypeError, "Wrong argument type, expecting string");
54
- return NULL;
55
- }
56
- std::string ret;
57
- try {
58
- ret = vrpc::LocalFactory::call(json_string);
59
- } catch (const std::exception& e) {
60
- PyErr_SetString(PyExc_RuntimeError, e.what());
61
- return NULL;
62
- }
63
- return PyUnicode_FromString(ret.c_str());
64
- }
65
-
66
- static PyObject* getMemberFunctions(PyObject* self, PyObject* args) {
67
- const char* class_name;
68
- // Check whether we got a string as single argument
69
- if (!PyArg_ParseTuple(args, "s", &class_name)) {
70
- PyErr_SetString(PyExc_TypeError, "Wrong argument type, expecting string");
71
- return NULL;
72
- }
73
- std::string ret;
74
- try {
75
- auto functions = vrpc::LocalFactory::get_member_functions(class_name);
76
- vrpc::json j;
77
- j["functions"] = functions;
78
- ret = j.dump();
79
- } catch (const std::exception& e) {
80
- PyErr_SetString(PyExc_RuntimeError, e.what());
81
- return NULL;
82
- }
83
- return PyUnicode_FromString(ret.c_str());
84
- }
85
-
86
- static PyObject* getStaticFunctions(PyObject* self, PyObject* args) {
87
- const char* class_name;
88
- // Check whether we got a string as single argument
89
- if (!PyArg_ParseTuple(args, "s", &class_name)) {
90
- PyErr_SetString(PyExc_TypeError, "Wrong argument type, expecting string");
91
- return NULL;
92
- }
93
- std::string ret;
94
- try {
95
- auto functions = vrpc::LocalFactory::get_static_functions(class_name);
96
- vrpc::json j;
97
- j["functions"] = functions;
98
- ret = j.dump();
99
- } catch (const std::exception& e) {
100
- PyErr_SetString(PyExc_RuntimeError, e.what());
101
- return NULL;
102
- }
103
- return PyUnicode_FromString(ret.c_str());
104
- }
105
-
106
- static PyObject* callback_handler = NULL;
107
-
108
- static void cppCallbackHandler(const vrpc::json& j) {
109
- _VRPC_DEBUG << "will call back with " << j << std::endl;
110
- PyObject* arglist = Py_BuildValue("(s)", j.dump().c_str());
111
- PyObject* result = PyObject_CallObject(callback_handler, arglist);
112
- Py_DECREF(arglist);
113
- }
114
-
115
- static PyObject* onCallback(PyObject*, PyObject* args) {
116
- PyObject* result = NULL;
117
- PyObject* tmp;
118
-
119
- if (PyArg_ParseTuple(args, "O:set_callback", &tmp)) {
120
- if (!PyCallable_Check(tmp)) {
121
- PyErr_SetString(PyExc_TypeError, "parameter must be callable");
122
- return NULL;
123
- }
124
- Py_XINCREF(tmp); // Add a reference to new callback
125
- Py_XDECREF(callback_handler); // Dispose of previous callback
126
- callback_handler = tmp; // Remember new callback
127
- // Boilerplate to return "None"
128
- Py_INCREF(Py_None);
129
- result = Py_None;
130
- // Register in vrpc
131
- vrpc::Callback::register_callback_handler(
132
- std::bind(cppCallbackHandler, std::placeholders::_1)
133
- );
134
- }
135
- return result;
136
- }
137
-
138
- // Define functions in module
139
- static PyMethodDef VrpcMethods[] = {
140
- {
141
- "callRemote",
142
- callRemote,
143
- METH_VARARGS,
144
- "Call bound C++ function"
145
- },
146
- {
147
- "getMemberFunctions",
148
- getMemberFunctions,
149
- METH_VARARGS,
150
- "Lists all available member functions for requested class"
151
- },
152
- {
153
- "getStaticFunctions",
154
- getStaticFunctions,
155
- METH_VARARGS,
156
- "Lists all available static function for requested class"
157
- },
158
- {
159
- "onCallback",
160
- onCallback,
161
- METH_VARARGS,
162
- "Sets callback handler for all vrpc callbacks"
163
- },
164
- {NULL, NULL, 0, NULL} // Sentinel
165
- };
166
-
167
- static struct PyModuleDef vrpc_module = {
168
- PyModuleDef_HEAD_INIT,
169
- // name of module
170
- VRPC_MODULE_NAME,
171
- // module documentation, may be NULL
172
- NULL,
173
- // size of per-interpreter state of the module or -1 if the module keeps state in global variables
174
- -1,
175
- VrpcMethods
176
- };
177
-
178
- // Module initialization
179
- PyMODINIT_FUNC \
180
- VRPC_MODULE_FUNC(void) {
181
- return PyModule_Create(&vrpc_module);
182
- }
183
- }