wowool-sdk-cpp 3.6.1__cp313-cp313-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.
@@ -0,0 +1,1432 @@
1
+ // ----------------------------------------------------------------------------------
2
+ // Copyright (c) 2024 Wowool, All Rights Reserved.
3
+ // NOTICE: All information contained herein is, and remains the property of Wowool.
4
+ // ----------------------------------------------------------------------------------
5
+ #define WITH_THREAD
6
+
7
+ #include "wowool_plugin.hpp"
8
+ // #include <codecvt>
9
+ #include <functional>
10
+ #include <iostream>
11
+ #include <mutex>
12
+ #include <pybind11/pybind11.h>
13
+ #include <pybind11/stl.h>
14
+ // #include <pybind11/stl_bind.h>
15
+ #include <regex>
16
+ #include <string>
17
+ #include <vector>
18
+ #include "nlohmann/json.hpp"
19
+ #include "plugins/api.hpp"
20
+ #include "wowool/common/c/plugin.h"
21
+ #include "wowool/common/exception.hpp"
22
+ #include "wowool/common/options.hpp"
23
+
24
+ // Undefine Logging
25
+ #define LOG_PLUGIN "[plugin]"
26
+ #define LOG_PYTHON "[py]"
27
+ #define TRACE 0
28
+ #define ERROR 0
29
+ #define DEBUG 0
30
+ #define WARNING 0
31
+ #define INFO 0
32
+ //#define WLOG(x, m) std::cout << m << std::endl;
33
+ #define WLOG(x, m)
34
+ // #define DEBUG_PYTHON_PLUGIN_MSG(x) std::cerr << "Thread ID: " << std::this_thread::get_id() << x << std::endl;
35
+ #define DEBUG_PYTHON_PLUGIN_MSG(x)
36
+
37
+ #ifdef __cplusplus
38
+ extern "C" {
39
+ #endif
40
+
41
+ struct _object;
42
+ typedef _object PyObject;
43
+
44
+ #ifdef __cplusplus
45
+ }
46
+ #endif
47
+
48
+ namespace py = pybind11;
49
+ using namespace wowool;
50
+
51
+ bool called_from_python_host_system = false;
52
+ ///////////////////////////////////////////////////////////////////////////////////////
53
+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
54
+ // forward declaration of global variable because the python people did not do a
55
+ // good job in creating a decent c/c++ api. we need to have this variable when
56
+ // we do the pytroushka :-) operation. which is from a python script :
57
+ // --> which call the wowool python api
58
+ // ----> which calls the c++ api
59
+ // ------> which triggers call in python
60
+ // ----------> which call back c++ functions
61
+ // -------------> which could eventually call python functions.
62
+ // in short when we call Py_IsInitialized from within a native python script
63
+ // we cannot call Py_IsInitialized otherwise the python people will make sure
64
+ // we crash. ( even if they say we need to ALWAYS call Py_IsInitialized ). but
65
+ // they forgot about the pytroushkas
66
+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
67
+
68
+ py::object python_object_range_obj;
69
+
70
+ namespace wow {
71
+ namespace python {
72
+
73
+ // Convert a vector to a python list.
74
+ template<class T>
75
+ py::list to_list(std::vector<T> const &v)
76
+ {
77
+ typename std::vector<T>::const_iterator iter;
78
+ py::list list;
79
+ for (iter = v.begin(); iter != v.end(); ++iter)
80
+ {
81
+ list.append(*iter);
82
+ }
83
+ return list;
84
+ }
85
+
86
+ // wrapper class to make sure we close properly the python instance
87
+ class python_instance
88
+ {
89
+ public:
90
+ bool initialized_has_been_called = false;
91
+ python_instance(bool embbeded_in_python = false)
92
+ {
93
+ if (called_from_python_host_system)
94
+ return;
95
+
96
+ if (embbeded_in_python)
97
+ return;
98
+
99
+ {
100
+ DEBUG_PYTHON_PLUGIN_MSG("!!!!!!!!! Initialize Py_Initialize")
101
+ Py_Initialize();
102
+ DEBUG_PYTHON_PLUGIN_MSG("!!!!!!!!! Initialize PyEval_SaveThread")
103
+ PyEval_SaveThread();
104
+ initialized_has_been_called = true;
105
+ }
106
+ }
107
+
108
+ ~python_instance()
109
+ {
110
+ DEBUG_PYTHON_PLUGIN_MSG("!!!!!!!!! ~python_instance()")
111
+ if (called_from_python_host_system)
112
+ return;
113
+ if (initialized_has_been_called)
114
+ {
115
+ DEBUG_PYTHON_PLUGIN_MSG("!!!!!!!!! PyGILState_Ensure")
116
+ PyGILState_Ensure();
117
+ DEBUG_PYTHON_PLUGIN_MSG("!!!!!!!!! Py_Finalize")
118
+ Py_Finalize();
119
+ }
120
+ }
121
+ };
122
+
123
+ typedef std::function<bool(plugin_Annotation const *)>
124
+ filter_annotation_filter_type;
125
+
126
+ ///////////////////////////////////////////////////////////////////////////////
127
+ // AttributesPair
128
+ /////////////////////////////////////////////////////////////////////////////////////////////
129
+ AttributesPair::AttributesPair()
130
+ : name_(nullptr)
131
+ , value_(nullptr)
132
+ {
133
+ }
134
+
135
+ AttributesPair::AttributesPair(void const *n, void *v)
136
+ : name_(std::string(wowool_plugin_string_to_string(n)))
137
+ , value_(std::string(wowool_plugin_any_to_string(v)))
138
+ {
139
+ }
140
+
141
+ std::string AttributesPair::to_string() const
142
+ {
143
+ std::string retval = name_;
144
+ retval += ":";
145
+ retval += value_;
146
+ return retval;
147
+ }
148
+
149
+ ///////////////////////////////////////////////////////////////////////////////
150
+ // python_object_attributes
151
+ /////////////////////////////////////////////////////////////////////////////////////////////
152
+ python_object_attributes::python_object_attributes()
153
+ : cncpt()
154
+ {
155
+ }
156
+
157
+ python_object_attributes::python_object_attributes(plugin_Annotation const *cncpt_)
158
+ : cncpt(cncpt_)
159
+ {
160
+ int idx = 0;
161
+ void *key = wowool_plugin_concept_attribute_key(cncpt, idx);
162
+ while (key)
163
+ {
164
+ void *value = wowool_plugin_concept_attribute_value(cncpt, idx);
165
+ this->emplace_back(key, value);
166
+ key = wowool_plugin_concept_attribute_key(cncpt, ++idx);
167
+ }
168
+ }
169
+
170
+ bool python_object_attributes::has(std::string const &key) const
171
+ {
172
+ if (!this->empty())
173
+ {
174
+ return wowool_plugin_concept_has_attribute(cncpt, key.c_str());
175
+ }
176
+ return false;
177
+ }
178
+
179
+ bool python_object_attributes::pybool() const
180
+ {
181
+ return cncpt == nullptr;
182
+ }
183
+
184
+ std::string python_object_attributes::to_string() const
185
+ {
186
+ std::stringstream strm;
187
+ strm << '[';
188
+ std::copy(begin(), end(), std::ostream_iterator<AttributesPair>(strm, ", "));
189
+ strm << ']';
190
+ return strm.str();
191
+ }
192
+
193
+ std::once_flag once;
194
+ thread_local c_context thrd_context;
195
+
196
+ // #define PYTHON_LOCK python::python_lock pylock;
197
+ std::mutex global_python_mutex;
198
+ // #define PYTHON_LOCK std::lock_guard<std::mutex> guard(global_python_mutex);
199
+ // #define PYTHON_LOCK
200
+ std::string get_python_error_message();
201
+
202
+ class python_instance;
203
+
204
+ // return the current error message in the python module.
205
+ std::string get_python_error_message()
206
+ {
207
+ PyObject *type = nullptr, *value = nullptr, *traceback = nullptr,
208
+ *pyString = nullptr;
209
+ PyErr_Fetch(&type, &value, &traceback);
210
+ PyErr_Clear();
211
+ std::string message = "Python error: ";
212
+ if (type != nullptr && (pyString = PyObject_Str(type)) != nullptr && (PyUnicode_Check(pyString)))
213
+ {
214
+ PyObject *pyStr = PyUnicode_AsEncodedString(pyString, "utf-8", "Error ~");
215
+ const char *strExcType = PyBytes_AS_STRING(pyStr);
216
+ message += strExcType;
217
+ Py_XDECREF(strExcType);
218
+ Py_XDECREF(pyStr);
219
+ }
220
+ else
221
+ {
222
+ message += "<unknown exception type> ";
223
+ }
224
+ Py_XDECREF(pyString);
225
+ if (value != nullptr && (pyString = PyObject_Str(value)) != nullptr && (PyUnicode_Check(pyString)))
226
+ {
227
+ message += ": ";
228
+ PyObject *pyStr = PyUnicode_AsEncodedString(pyString, "utf-8", "Error ~");
229
+ const char *strExcType = PyBytes_AS_STRING(pyStr);
230
+ message += strExcType;
231
+ Py_XDECREF(strExcType);
232
+ Py_XDECREF(pyStr);
233
+ }
234
+ else
235
+ {
236
+ message += "<unknown exception date> ";
237
+ }
238
+ Py_XDECREF(pyString);
239
+
240
+ char const *verbose = std::getenv("WOWOOL_LOG_LEVEL");
241
+ if (verbose && strcmp(verbose, "DEBUG") == 0)
242
+ {
243
+ // Get the trace
244
+ PyObject *tracebackModule = PyImport_ImportModule("traceback");
245
+ if (tracebackModule != nullptr)
246
+ {
247
+ PyObject *tbList = nullptr;
248
+ PyObject *emptyString = nullptr;
249
+ PyObject *strRetval = nullptr;
250
+
251
+ tbList = PyObject_CallMethod(tracebackModule, "format_exception", "OOO", type, value == nullptr ? Py_None : value, traceback == nullptr ? Py_None : traceback);
252
+
253
+ if (tbList)
254
+ {
255
+ emptyString = PyUnicode_FromString("");
256
+
257
+ strRetval = PyObject_CallMethod(emptyString, "join", "O", tbList);
258
+ if (strRetval)
259
+ {
260
+ PyObject *pyStr = PyUnicode_AsEncodedString(strRetval, "utf-8", "Error ~");
261
+ const char *strExcType = PyBytes_AS_STRING(pyStr);
262
+ message += "\n";
263
+ message += strExcType;
264
+ Py_XDECREF(strExcType);
265
+ Py_XDECREF(pyStr);
266
+ }
267
+
268
+ Py_DECREF(tbList);
269
+ if (emptyString)
270
+ Py_DECREF(emptyString);
271
+ }
272
+ if (strRetval)
273
+ Py_DECREF(strRetval);
274
+ Py_DECREF(tracebackModule);
275
+ }
276
+ else
277
+ {
278
+ // chrRetval = strdup("Unable to import traceback module.");
279
+ message += "Unable to import traceback module.";
280
+ }
281
+ }
282
+ Py_XDECREF(type);
283
+ Py_XDECREF(value);
284
+ Py_XDECREF(traceback);
285
+
286
+ return message;
287
+ // FIXME: Now we have an error message .. log it or something.
288
+ }
289
+
290
+ char *alloc_string(std::string const &str)
291
+ {
292
+ if (str.length() != 0)
293
+ {
294
+ char *data = (char *)malloc(str.size() + 1);
295
+ memcpy(data, str.c_str(), str.size());
296
+ data[str.size()] = 0;
297
+ return data;
298
+ }
299
+ else
300
+ {
301
+ return nullptr;
302
+ }
303
+ }
304
+
305
+ //----------------------------------------------------------------
306
+ // class to collect the python modules
307
+ //----------------------------------------------------------------
308
+ class Facade
309
+ {
310
+ public:
311
+ Facade(std::string const &module);
312
+ char *call(char const *module_name, char const *function_name, wowool::plugins::Arguments const &arguments, tir_exception *ex);
313
+ ~Facade();
314
+
315
+ std::string name;
316
+ py::object module;
317
+ };
318
+
319
+ typedef std::shared_ptr<Facade> Facade_ptr;
320
+ typedef std::map<std::string, Facade_ptr> FacadeCollection;
321
+
322
+ Facade::Facade(std::string const &module_name)
323
+ : name(module_name)
324
+ , module(py::module::import(name.c_str()))
325
+ {
326
+ }
327
+
328
+ Facade::~Facade()
329
+ {
330
+ }
331
+
332
+ char *Facade::call(char const *module_name, char const *function_name, wowool::plugins::Arguments const &arguments, tir_exception *ex)
333
+ {
334
+ assert(module);
335
+ WLOG(TRACE, LOG_PLUGIN << LOG_PYTHON << "call(" << function_name << ")");
336
+ PyObject *pFunc = nullptr;
337
+ pFunc = PyObject_GetAttrString(module.ptr(), function_name);
338
+ if (pFunc && PyCallable_Check(pFunc))
339
+ {
340
+ PyObject *pArgs, *pValue;
341
+ pArgs = PyTuple_New(arguments.size());
342
+ for (size_t i = 0; i < arguments.size(); ++i)
343
+ {
344
+ if (arguments[i].type == wowool::plugins::do_char_ptr)
345
+ {
346
+ pValue = PyUnicode_FromString((char *)arguments[i].data);
347
+ if (!pValue)
348
+ {
349
+ Py_DECREF(pArgs);
350
+ Py_XDECREF(pFunc);
351
+ WLOG(ERROR, "Cannot convert argument");
352
+ return nullptr;
353
+ }
354
+ /* pValue reference stolen here: */
355
+ PyTuple_SetItem(pArgs, i, pValue);
356
+ }
357
+ else if (arguments[i].type == wowool::plugins::do_pydict)
358
+ {
359
+ py::dict &data = *((py::dict *)(arguments[i].data));
360
+ data.inc_ref();
361
+ PyTuple_SetItem(pArgs, i, data.ptr());
362
+ }
363
+ else if (arguments[i].type == wowool::plugins::do_annotation)
364
+ {
365
+ try
366
+ {
367
+ // get the object constructor.
368
+ // create a python object.
369
+ py::object pyobj = python_object_range_obj((plugin_Annotation *)arguments[i].data);
370
+ pyobj.inc_ref();
371
+ PyTuple_SetItem(pArgs, i, pyobj.ptr());
372
+ } catch (std::exception &ex)
373
+ {
374
+ std::cerr << "error adding annotation attribute. " << ex.what() << std::endl;
375
+ }
376
+ }
377
+ }
378
+
379
+ pValue = PyObject_CallObject(pFunc, pArgs);
380
+ if (pValue != nullptr)
381
+ {
382
+ std::string retval;
383
+ if (PyBool_Check(pValue))
384
+ {
385
+ if (PyObject_IsTrue(pValue))
386
+ {
387
+ retval = "true";
388
+ }
389
+ else
390
+ {
391
+ retval = "false";
392
+ }
393
+ }
394
+ else if (PyUnicode_Check(pValue))
395
+ {
396
+ retval = py::str(pValue);
397
+ }
398
+ Py_DECREF(pValue);
399
+ Py_DECREF(pArgs);
400
+ Py_XDECREF(pFunc);
401
+ WLOG(TRACE, LOG_PLUGIN << LOG_PYTHON << "RETURN (" << retval << ")");
402
+ return alloc_string(retval);
403
+ }
404
+ else
405
+ {
406
+ std::string errstr = get_python_error_message();
407
+ WLOG(ERROR, "Could not execute python function:" << function_name << " in module " << module_name << ":" << errstr.c_str());
408
+ wowool::common::throw_c_exception(ex, errstr.c_str());
409
+ return nullptr;
410
+ }
411
+
412
+ Py_DECREF(pArgs);
413
+ Py_XDECREF(pFunc);
414
+ }
415
+ else
416
+ {
417
+ WLOG(ERROR, "Could not find python function:" << function_name << " in module " << module_name);
418
+ }
419
+
420
+ /* Release the thread. No Python API allowed beyond this point. */
421
+ // PyGILState_Release(gstate);
422
+
423
+ WLOG(ERROR, "Could not find python function:" << function_name << " in module " << module_name);
424
+ return nullptr;
425
+ }
426
+
427
+ struct IsURI
428
+ {
429
+ IsURI(std::string const &uri_)
430
+ : uri(uri_.c_str())
431
+ {
432
+ }
433
+
434
+ const char *uri;
435
+
436
+ bool operator()(plugin_Annotation const *a) const
437
+ {
438
+ return ((wowool_plugin_get_type(a) == AnnotationType_Concept) && (strcmp(wowool_plugin_concept_uri(a), uri) == 0));
439
+ }
440
+ };
441
+
442
+ std::ostream &operator<<(std::ostream &out, AttributesPair const &data)
443
+ {
444
+ out << '(' << data.name() << '=' << data.value() << ')';
445
+ return out;
446
+ }
447
+
448
+ typedef std::pair<std::string, std::string> AttributePair;
449
+ typedef std::map<std::string, std::string> AttributeCollection;
450
+
451
+ AttributeCollection convert_py_options(py::dict const &kwargs)
452
+ {
453
+ AttributeCollection options;
454
+ for (auto const item : kwargs)
455
+ {
456
+ options.emplace(py::str(item.first), py::str(item.second));
457
+ }
458
+ return options;
459
+ }
460
+
461
+ c_context const &get_current_context() { return thrd_context; }
462
+
463
+ static std::shared_ptr<python::python_instance> python_instance_singleton;
464
+
465
+ void create_python_instance()
466
+ {
467
+ python_instance_singleton.reset(new python::python_instance());
468
+ }
469
+
470
+ void init_python_instance() { std::call_once(once, &create_python_instance); }
471
+
472
+ struct PyLock
473
+ {
474
+ PyLock()
475
+ {
476
+ DEBUG_PYTHON_PLUGIN_MSG(" >> PyGILState_Ensure");
477
+ gstate = PyGILState_Ensure();
478
+ DEBUG_PYTHON_PLUGIN_MSG(" << PyGILState_Ensure");
479
+ }
480
+
481
+ ~PyLock()
482
+ {
483
+ DEBUG_PYTHON_PLUGIN_MSG(" >> PyGILState_Release");
484
+ PyGILState_Release(gstate);
485
+ DEBUG_PYTHON_PLUGIN_MSG(" << PyGILState_Release");
486
+ }
487
+
488
+ // PyThreadState *python_interprter;
489
+ PyGILState_STATE gstate;
490
+ };
491
+
492
+ struct python_user_data_object
493
+ {
494
+ python_user_data_object()
495
+ : pydict(nullptr)
496
+ {
497
+ pydict = new py::dict();
498
+ }
499
+
500
+ ~python_user_data_object()
501
+ {
502
+ DEBUG_PYTHON_PLUGIN_MSG(">> ~python_user_data_object");
503
+ if (pydict)
504
+ {
505
+ PyLock pylock;
506
+ DEBUG_PYTHON_PLUGIN_MSG(">> delete python_user_data_object");
507
+ delete pydict;
508
+ DEBUG_PYTHON_PLUGIN_MSG("<< delete python_user_data_object");
509
+ }
510
+ }
511
+
512
+ // PyThreadState *python_interprter;
513
+ py::dict *pydict;
514
+ // std::shared_ptr<python::python_instance> py_instance;
515
+ };
516
+
517
+ typedef std::shared_ptr<python_user_data_object> python_user_data;
518
+ thread_local python_user_data thread_python_user_data;
519
+
520
+ // create the python dictionary as user document data.
521
+ python_user_data &create_userdata()
522
+ {
523
+ PyLock pylock;
524
+ DEBUG_PYTHON_PLUGIN_MSG("PYDEBUG: create_userdata");
525
+
526
+ thread_python_user_data.reset(new python_user_data_object);
527
+ // py::gil_scoped_acquire acquire;
528
+ thread_python_user_data->pydict = new py::dict();
529
+
530
+ return thread_python_user_data;
531
+ }
532
+
533
+ python_user_data &get_current_userdata() { return thread_python_user_data; }
534
+
535
+ // release the user data when we are done with the document.
536
+ void release_userdata()
537
+ {
538
+ DEBUG_PYTHON_PLUGIN_MSG("PYDEBUG: release_userdata");
539
+ if (thread_python_user_data.get())
540
+ {
541
+ DEBUG_PYTHON_PLUGIN_MSG("PYDEBUG: release_userdata.reset()");
542
+ PyLock pylock;
543
+ thread_python_user_data.reset();
544
+ }
545
+ }
546
+
547
+ ///////////////////////////////////////////////////////////////////////////////
548
+ // python_token
549
+ // object that represents a token object in python.
550
+ /////////////////////////////////////////////////////////////////////////////////////////////
551
+ python_token::python_token()
552
+ : token(nullptr)
553
+ {
554
+ }
555
+
556
+ python_token::python_token(plugin_Annotation const *token_)
557
+ : token(token_)
558
+ {
559
+ }
560
+
561
+ bool python_token::has_property(std::string const &prop) const
562
+ {
563
+ return wowool_plugin_token_has_attribute(token, prop.c_str());
564
+ }
565
+
566
+ std::string python_token::head() const
567
+ {
568
+ return wowool_plugin_token_head(token);
569
+ }
570
+
571
+ std::string python_token::pos(int idx) const
572
+ {
573
+ return wowool_plugin_token_pos(token, idx);
574
+ }
575
+
576
+ std::string python_token::stem(int idx) const
577
+ {
578
+ return wowool_plugin_token_stem(token, idx);
579
+ }
580
+
581
+ std::string python_token::lemma(int idx) const
582
+ {
583
+ return wowool_plugin_token_stem(token, idx);
584
+ }
585
+
586
+ std::string python_token::str() const
587
+ {
588
+ return std::string(wowool_plugin_token_literal(token));
589
+ }
590
+
591
+ std::string python_token::literal() const
592
+ {
593
+ return std::string(wowool_plugin_token_literal(token));
594
+ }
595
+
596
+ ///////////////////////////////////////////////////////////////////////////////
597
+ // python_object_range
598
+ // object that represent a annotation range in python.
599
+ /////////////////////////////////////////////////////////////////////////////////////////////
600
+ python_object_range::python_object_range() {}
601
+
602
+ python_object_range::python_object_range(plugin_Annotation const *cncpt)
603
+ {
604
+ begin = cncpt;
605
+ if (begin)
606
+ {
607
+ end = wowool_plugin_concept_get_end(cncpt);
608
+ }
609
+ }
610
+
611
+ python_object_range::~python_object_range() {}
612
+
613
+ python_object_range::python_object_range(plugin_Annotation const *begin_, plugin_Annotation const *end_)
614
+ {
615
+ begin = begin_;
616
+ end = end_;
617
+ }
618
+
619
+ void python_object_range::remove_concept()
620
+ {
621
+ wowool_plugin_concept_remove(const_cast<plugin_Annotation *>(begin));
622
+ }
623
+
624
+ int python_object_range::get_begin_offset() const
625
+ {
626
+ if (begin)
627
+ return wowool_plugin_get_begin_offset(begin);
628
+ return -1;
629
+ }
630
+
631
+ int python_object_range::get_end_offset() const
632
+ {
633
+ plugin_Annotation const *it = end;
634
+ while (it != nullptr)
635
+ {
636
+ if (wowool_plugin_get_type(it) == AnnotationType_Token)
637
+ {
638
+ return wowool_plugin_get_end_offset(it);
639
+ }
640
+ it = wowool_plugin_get_prev(it);
641
+ }
642
+ return get_begin_offset();
643
+ }
644
+
645
+ std::string python_object_range::get_uri() const
646
+ {
647
+ if (begin && wowool_plugin_get_type(begin) == AnnotationType_Concept)
648
+ return std::string(wowool_plugin_concept_uri(begin));
649
+ return "";
650
+ }
651
+
652
+ std::vector<python_object_range> python_object_range::find_with_filter(
653
+ filter_annotation_filter_type const &filter)
654
+ {
655
+ std::vector<python_object_range> retval;
656
+ // tir::wowool::is_concept filter;
657
+
658
+ // algin to the begin end offset of the given annotation.
659
+ auto it = wowool_plugin_align_begin(begin, end);
660
+
661
+ while (it != end)
662
+ {
663
+ if (filter(it))
664
+ {
665
+ if (!wowool_plugin_concept_is_deleted(it))
666
+ {
667
+ retval.emplace_back(python_object_range(it));
668
+ }
669
+ }
670
+ it = wowool_plugin_get_next(it);
671
+ }
672
+ return retval;
673
+ }
674
+
675
+ python_object_attributes python_object_range::attributes()
676
+ {
677
+ return python_object_attributes(begin);
678
+ }
679
+
680
+ bool python_object_range::has(std::string const &key) const
681
+ {
682
+ return wowool_plugin_concept_has_attribute(begin, key.c_str());
683
+ }
684
+
685
+ std::string python_object_range::get_attribute(std::string const &key) const
686
+ {
687
+ return std::string(wowool_plugin_concept_get_attribute(begin, key.c_str()));
688
+ }
689
+
690
+ bool python_object_range::add_attribute(std::string const &key, std::string const &value)
691
+ {
692
+ return wowool_plugin_concept_add_attribute(
693
+ const_cast<plugin_Annotation *>(begin), key.c_str(), value.c_str());
694
+ }
695
+
696
+ // filter a range of annotations.
697
+ std::vector<python_object_range>
698
+ python_object_range::regex(std::string const &uri)
699
+ {
700
+ std::regex re(uri);
701
+ std::smatch what;
702
+ // Note: uri is a char pointer !
703
+ return find_with_filter([&](plugin_Annotation const *a) -> bool {
704
+ if (wowool_plugin_get_type(a) == AnnotationType_Concept)
705
+ {
706
+ std::string uri = wowool_plugin_concept_uri(a);
707
+ return std::regex_match(uri, what, re);
708
+ }
709
+ return false;
710
+ });
711
+ }
712
+
713
+ python_object_range python_object_range::add_concept(std::string const &uri)
714
+ {
715
+ auto const context = python::get_current_context();
716
+ plugin_Annotation *annotation = wowool_plugin_update_concept_in_collection(&context, begin, end, uri.c_str());
717
+ if (annotation)
718
+ {
719
+ return python_object_range(annotation);
720
+ }
721
+ else
722
+ {
723
+ return python_object_range();
724
+ }
725
+ }
726
+
727
+ // implements the python calls capture["person" ]
728
+ // argument is a string
729
+ std::vector<python_object_range>
730
+ python_object_range::get_item(std::string const &uri)
731
+ {
732
+ return find(uri);
733
+ }
734
+
735
+ // implements the python calls capture["person","boss", .... ]
736
+ // argument is a tuple (a,b,c,...)
737
+ std::vector<python_object_range>
738
+ python_object_range::get_item(py::tuple const &elements)
739
+ {
740
+ std::vector<python_object_range> results;
741
+ for (auto const item : elements)
742
+ {
743
+ std::string key = py::str(item);
744
+ std::vector<python_object_range> tmp = find(key);
745
+ std::copy(tmp.begin(), tmp.end(), std::back_inserter(results));
746
+ }
747
+ return results;
748
+ }
749
+
750
+ // implements the python calls capture.person
751
+ // argument is a string
752
+ py::object python_object_range::get_attr(std::string const &uri)
753
+ {
754
+ return find_one(uri);
755
+ }
756
+
757
+ py::object python_object_range::find_one(std::string const &uri)
758
+ {
759
+ assert(begin);
760
+ // Note do note align for the attribute.
761
+ if (wowool_plugin_get_type(begin) == AnnotationType_Concept)
762
+ {
763
+ if (wowool_plugin_concept_has_attribute(begin, uri.c_str()))
764
+ {
765
+ return py::str(
766
+ std::string(wowool_plugin_concept_get_attribute(begin, uri.c_str())));
767
+ }
768
+ }
769
+
770
+ std::vector<python_object_range> results;
771
+ if (uri.size() >= 2 && uri[0] == '/' && uri[uri.size() - 1] == '/')
772
+ {
773
+ results = regex(uri.substr(1, uri.size() - 2));
774
+ }
775
+ else
776
+ {
777
+ IsURI filter(uri);
778
+ results = find_with_filter(filter);
779
+ }
780
+ if (results.size())
781
+ return py::cast(results[0]);
782
+ return py::none();
783
+ }
784
+
785
+ std::vector<python_object_range>
786
+ python_object_range::find(std::string const &uri)
787
+ {
788
+ if (uri.size() > 2 && uri[0] == '/' && uri[uri.size() - 1] == '/')
789
+ return regex(uri.substr(1, uri.size() - 2));
790
+ IsURI filter(uri);
791
+ return find_with_filter(filter);
792
+ }
793
+
794
+ std::vector<int> python_object_range::find_int(std::string const &uri)
795
+ {
796
+ return std::vector<int>();
797
+ }
798
+
799
+ py::list python_object_range::tokens()
800
+ {
801
+ if (begin == nullptr)
802
+ {
803
+ std::vector<python_token> v;
804
+ return python::to_list(v);
805
+ }
806
+ std::vector<python_token> retval;
807
+ std::stringstream strm;
808
+ auto it = begin;
809
+ while (it != end)
810
+ {
811
+ if (wowool_plugin_get_type(it) == AnnotationType_Token)
812
+ {
813
+ retval.emplace_back(it);
814
+ }
815
+ it = wowool_plugin_get_next(it);
816
+ }
817
+ return python::to_list(retval);
818
+ }
819
+
820
+ std::string python_object_range::str() { return literal(); }
821
+
822
+ std::string python_object_range::repr() const
823
+ {
824
+ std::stringstream out;
825
+ auto it = begin;
826
+ while (it != end)
827
+ {
828
+ if (wowool_plugin_get_type(it) == AnnotationType_Token)
829
+ {
830
+ out << "T:" << wowool_plugin_token_literal(it) << std::endl;
831
+ }
832
+ else if (wowool_plugin_get_type(it) == AnnotationType_Concept)
833
+ {
834
+ out << "C:" << wowool_plugin_concept_uri(it) << std::endl;
835
+ }
836
+ it = wowool_plugin_get_next(it);
837
+ }
838
+ return out.str();
839
+ }
840
+
841
+ std::string python_object_range::literal(std::string const delimiter)
842
+ {
843
+ if (begin == nullptr)
844
+ return "";
845
+ return std::string(
846
+ wowool_plugin_range_literal(begin, end, delimiter.c_str()));
847
+ }
848
+
849
+ std::string python_object_range::text()
850
+ {
851
+ if (begin == nullptr)
852
+ return "";
853
+ return std::string(
854
+ wowool_plugin_range_literal(begin, end, " "));
855
+ }
856
+
857
+ // Need to fix the canonical
858
+ // Example: vijf jaar geleden --> 5 jaar geleden
859
+ std::string python_object_range::canonical(std::string const delimiter)
860
+ {
861
+ if (begin == nullptr)
862
+ return "";
863
+
864
+ if (wowool_plugin_get_type(begin) == AnnotationType_Concept)
865
+ {
866
+ if (wowool_plugin_concept_has_attribute(begin, "canonical"))
867
+ {
868
+ return py::str(
869
+ std::string(wowool_plugin_concept_get_attribute(begin, "canonical")));
870
+ }
871
+ else
872
+ {
873
+ return literal(delimiter);
874
+ }
875
+ }
876
+
877
+ return std::string(
878
+ wowool_plugin_range_literal(begin, end, delimiter.c_str()));
879
+ }
880
+
881
+ std::string python_object_range::stem(std::string const delimiter)
882
+ {
883
+ if (begin == nullptr)
884
+ return "";
885
+ return std::string(wowool_plugin_range_stem(begin, end, delimiter.c_str()));
886
+ }
887
+
888
+ std::string python_object_range::lemma()
889
+ {
890
+ if (begin == nullptr)
891
+ return "";
892
+ return std::string(wowool_plugin_range_stem(begin, end, " "));
893
+ }
894
+
895
+ bool python_object_range::pybool() const
896
+ {
897
+ return begin != nullptr;
898
+ }
899
+
900
+ bool operator==(python_object_range const &lhs, python_object_range const &rhs)
901
+ {
902
+ return ((lhs.begin == rhs.begin) && (lhs.end == rhs.end));
903
+ }
904
+
905
+ // the match context api.
906
+ python_object_match_context::python_object_match_context() { context = python::get_current_context(); }
907
+
908
+ python_object_range python_object_match_context::capture()
909
+ {
910
+ return python_object_range(python::get_current_context().capture);
911
+ }
912
+
913
+ python_object_range python_object_match_context::rule()
914
+ {
915
+ if (context.rule == nullptr)
916
+ return python_object_range(python::get_current_context().capture);
917
+ return python_object_range(python::get_current_context().rule);
918
+ }
919
+
920
+ python_object_range python_object_match_context::sentence()
921
+ {
922
+ if (context.sent)
923
+ {
924
+ return python_object_range(wowool_plugin_sentence_begin(context.sent), wowool_plugin_sentence_end(context.sent));
925
+ }
926
+ return python_object_range();
927
+ }
928
+
929
+ python_object_range python_object_match_context::make_range(python_object_range begin_, python_object_range end_)
930
+ {
931
+ return python_object_range(begin_.begin, end_.end);
932
+ }
933
+
934
+ std::string python_object_match_context::to_string() { return wowool_plugin_concept_uri(context.capture); }
935
+
936
+ const std::string python_object_match_context::property(std::string const &key) { return wowool_plugin_property(&context, key.c_str()); }
937
+
938
+ }
939
+ } // namespace wow::python
940
+ // ----------------------------------------------------------------------------
941
+ // Plugin code to be loaded in the cpp module
942
+ // ----------------------------------------------------------------------------
943
+ namespace wow {
944
+ namespace python {
945
+
946
+ using wowool::plugins::Arguments;
947
+
948
+ // convert UTF-8 string to wstring
949
+ std::string wstring_to_utf8(const std::wstring &wstr)
950
+ {
951
+ std::string utf8;
952
+ for (wchar_t wc : wstr)
953
+ {
954
+ if (wc <= 0x7F)
955
+ {
956
+ utf8.push_back(static_cast<char>(wc)); // ASCII range (1 byte)
957
+ }
958
+ else if (wc <= 0x7FF)
959
+ {
960
+ utf8.push_back(static_cast<char>(0xC0 | ((wc >> 6) & 0x1F))); // 2 bytes
961
+ utf8.push_back(static_cast<char>(0x80 | (wc & 0x3F)));
962
+ }
963
+ else if (wc <= 0xFFFF)
964
+ {
965
+ utf8.push_back(static_cast<char>(0xE0 | ((wc >> 12) & 0x0F))); // 3 bytes
966
+ utf8.push_back(static_cast<char>(0x80 | ((wc >> 6) & 0x3F)));
967
+ utf8.push_back(static_cast<char>(0x80 | (wc & 0x3F)));
968
+ }
969
+ else
970
+ {
971
+ utf8.push_back(static_cast<char>(0xF0 | ((wc >> 18) & 0x07))); // 4 bytes
972
+ utf8.push_back(static_cast<char>(0x80 | ((wc >> 12) & 0x3F)));
973
+ utf8.push_back(static_cast<char>(0x80 | ((wc >> 6) & 0x3F)));
974
+ utf8.push_back(static_cast<char>(0x80 | (wc & 0x3F)));
975
+ }
976
+ }
977
+ return utf8;
978
+ }
979
+
980
+ std::wstring utf8_to_wstring(const std::string &str)
981
+ {
982
+ std::wstring wstr;
983
+ size_t i = 0;
984
+ while (i < str.size())
985
+ {
986
+ unsigned char ch = str[i];
987
+ wchar_t wc = 0;
988
+ int extra_bytes = 0;
989
+
990
+ if ((ch & 0x80) == 0)
991
+ { // 1-byte character (ASCII)
992
+ wc = ch;
993
+ }
994
+ else if ((ch & 0xE0) == 0xC0)
995
+ { // 2-byte character
996
+ wc = ch & 0x1F;
997
+ extra_bytes = 1;
998
+ }
999
+ else if ((ch & 0xF0) == 0xE0)
1000
+ { // 3-byte character
1001
+ wc = ch & 0x0F;
1002
+ extra_bytes = 2;
1003
+ }
1004
+ else if ((ch & 0xF8) == 0xF0)
1005
+ { // 4-byte character
1006
+ wc = ch & 0x07;
1007
+ extra_bytes = 3;
1008
+ }
1009
+
1010
+ for (int j = 0; j < extra_bytes; ++j)
1011
+ {
1012
+ if (++i >= str.size()) return {}; // Invalid UTF-8
1013
+ wc = (wc << 6) | (str[i] & 0x3F);
1014
+ }
1015
+ wstr.push_back(wc);
1016
+ ++i;
1017
+ }
1018
+ return wstr;
1019
+ }
1020
+
1021
+ class Plugin : public wowool::plugins::API
1022
+ {
1023
+ public:
1024
+ Plugin();
1025
+ virtual ~Plugin();
1026
+
1027
+ virtual bool load_modules(char const *json_options, tir_exception *) noexcept;
1028
+ bool _nolock_load_modules(char const *json_options, tir_exception *) noexcept;
1029
+
1030
+ virtual char *call(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept;
1031
+
1032
+ char *_nolock_call(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept;
1033
+
1034
+ // virtual char *init(char const *module_name, char const *name, wowool::plugins::Arguments
1035
+ // const &arguments, tir_exception *ex) noexcept;
1036
+ virtual char *open_document(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept;
1037
+ virtual char *close_document(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept;
1038
+ virtual char *trigger(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept;
1039
+ virtual void release_document(tir_exception *) noexcept;
1040
+ virtual void set_document_property(char const *key, char const *value, tir_exception *) noexcept;
1041
+
1042
+ virtual void release(void *ptr) noexcept;
1043
+
1044
+ virtual void delete_this(tir_exception *) noexcept { py_modules.clear(); }
1045
+
1046
+ virtual void set_context(c_context *ctxt) noexcept
1047
+ {
1048
+ thrd_context.blackbrd = ctxt->blackbrd;
1049
+ thrd_context.sent = ctxt->sent;
1050
+ thrd_context.rule = ctxt->rule;
1051
+ thrd_context.capture = ctxt->capture;
1052
+ }
1053
+
1054
+ private:
1055
+ FacadeCollection py_modules;
1056
+ };
1057
+
1058
+ Plugin::Plugin()
1059
+ : wowool::plugins::API()
1060
+ {
1061
+ }
1062
+
1063
+ Plugin::~Plugin() {}
1064
+
1065
+ void Plugin::release_document(tir_exception *ex) noexcept
1066
+ {
1067
+ release_userdata();
1068
+ }
1069
+
1070
+ void Plugin::set_document_property(char const *key, char const *value, tir_exception *) noexcept
1071
+ {
1072
+ python_user_data &ud = get_current_userdata();
1073
+ if (ud.get() == nullptr)
1074
+ {
1075
+ ud = create_userdata();
1076
+ }
1077
+ PyLock py_lock;
1078
+ if (ud.get() != nullptr && ud->pydict != nullptr)
1079
+ {
1080
+ (*ud->pydict)[key] = value;
1081
+ }
1082
+ }
1083
+
1084
+ #define LOG_TRACE LOG(TRACE)
1085
+ #define TIR_LOG_DEBUG LOG(DEBUG)
1086
+ static std::string empty;
1087
+
1088
+ std::string const get(nlohmann::json const &options, std::string const key)
1089
+ {
1090
+ if (options.find(key) != options.end())
1091
+ {
1092
+ return options[key].get<std::string>();
1093
+ }
1094
+ return empty;
1095
+ }
1096
+
1097
+ bool has(nlohmann::json const &options, std::string const key)
1098
+ {
1099
+ return (options.find(key) != options.end());
1100
+ }
1101
+
1102
+ // Load the given modules.
1103
+ bool Plugin::load_modules(char const *json_options, tir_exception *ex) noexcept
1104
+ {
1105
+ bool retval = false;
1106
+ retval = _nolock_load_modules(json_options, ex);
1107
+ return retval;
1108
+ }
1109
+
1110
+ char *Plugin::call(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept
1111
+ {
1112
+ try
1113
+ {
1114
+ char *retval = nullptr;
1115
+ // python_object_range_obj = py::module::import("wowool_plugin").attr("annotation_range");
1116
+
1117
+ python_user_data &ud = get_current_userdata();
1118
+ if (ud.get() == nullptr)
1119
+ {
1120
+ ud = create_userdata();
1121
+ }
1122
+
1123
+ PyLock pylock;
1124
+ retval = _nolock_call(module_name, name, arguments, ex);
1125
+ return retval;
1126
+ } catch (pybind11::error_already_set const &ex)
1127
+ {
1128
+ std::cerr << "Error: already set" << ex.what() << std::endl;
1129
+ return nullptr;
1130
+ } catch (std::exception const &ex)
1131
+ {
1132
+ std::cerr << "Error: " << ex.what() << std::endl;
1133
+ return nullptr;
1134
+ }
1135
+ }
1136
+
1137
+ // Load the given modules.
1138
+ bool Plugin::_nolock_load_modules(char const *json_options, tir_exception *ex) noexcept
1139
+ {
1140
+ // std::ofstream fo("dump.txt");
1141
+ WLOG(TRACE, LOG_PLUGIN << LOG_PYTHON << "load_modules(" << json_options << ")\n");
1142
+ nlohmann::json options = nlohmann::json::parse(json_options);
1143
+
1144
+ //#ifdef WIN32
1145
+ // set_python_home(options);
1146
+ //#endif
1147
+
1148
+ bool embbeded_in_python = true;
1149
+ {
1150
+ if (!has(options, "pytryoshka"))
1151
+ {
1152
+ embbeded_in_python = false;
1153
+ }
1154
+ }
1155
+
1156
+ if (!embbeded_in_python)
1157
+ {
1158
+ WLOG(TRACE, LOG_PLUGIN << LOG_PYTHON << "init_python_instance");
1159
+ wow::python::init_python_instance(); // Py_Initialize();
1160
+ }
1161
+
1162
+ return true;
1163
+ }
1164
+
1165
+ using wowool::plugins::Arguments;
1166
+ namespace lbp = wowool::plugins;
1167
+
1168
+ char *Plugin::_nolock_call(char const *module_name, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept
1169
+ {
1170
+ if (auto it = py_modules.find(module_name); it != py_modules.end())
1171
+ {
1172
+ auto const &module = it->second;
1173
+ if (module.get())
1174
+ {
1175
+ char *retval = module->call(module_name, name, arguments, ex);
1176
+ return retval;
1177
+ }
1178
+ return nullptr;
1179
+ }
1180
+ else
1181
+ {
1182
+ WLOG(INFO, LOG_PLUGIN << LOG_PYTHON << "Loading python module: " << module_name);
1183
+ try
1184
+ {
1185
+ Facade_ptr ptr(new Facade(module_name));
1186
+ WLOG(DEBUG, LOG_PLUGIN << LOG_PYTHON << "OK Module:" << module_name);
1187
+ py_modules.emplace(module_name, ptr);
1188
+ auto const &module = py_modules.at(module_name);
1189
+ char *retval = module->call(module_name, name, arguments, ex);
1190
+ return retval;
1191
+ } catch (pybind11::error_already_set const &ex_import)
1192
+ {
1193
+ std::cerr << "Error:[wowool_plugin] Could not import " << module_name << " module"
1194
+ << "\n"
1195
+ << ex_import.what() << ")" << std::endl;
1196
+ py_modules.emplace(module_name, Facade_ptr());
1197
+ }
1198
+ }
1199
+
1200
+ return nullptr;
1201
+ }
1202
+
1203
+ char *Plugin::open_document(char const *module, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept
1204
+ {
1205
+ create_userdata();
1206
+ return trigger(module, name, arguments, ex);
1207
+ }
1208
+
1209
+ char *Plugin::close_document(char const *module, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept
1210
+ {
1211
+ char *result = trigger(module, name, arguments, ex);
1212
+ release_userdata();
1213
+ return result;
1214
+ }
1215
+
1216
+ char *Plugin::trigger(char const *module, char const *name, wowool::plugins::Arguments const &arguments, tir_exception *ex) noexcept
1217
+ {
1218
+ python_user_data &ud = get_current_userdata();
1219
+ if (ud.get() == nullptr)
1220
+ {
1221
+ create_userdata();
1222
+ }
1223
+
1224
+ Arguments decorated_arguments = arguments;
1225
+ if (ud.get() != nullptr)
1226
+ {
1227
+ decorated_arguments.emplace(decorated_arguments.begin(), wowool::plugins::do_pydict, ud->pydict);
1228
+ }
1229
+ char *retval = call(module, name, decorated_arguments, ex);
1230
+ return retval;
1231
+ }
1232
+
1233
+ // release a pointer which got return by this api, We need to have this as the
1234
+ // malloc and the free has to happen in the same module.
1235
+ // example alloc_string( ... )
1236
+ void Plugin::release(void *ptr) noexcept
1237
+ {
1238
+ DEBUG_PYTHON_PLUGIN_MSG("Plugin::release");
1239
+ if (ptr != nullptr)
1240
+ {
1241
+ free(ptr);
1242
+ }
1243
+ }
1244
+ }
1245
+ } // namespace wow::python
1246
+
1247
+ //
1248
+ // Dynamic shared object (DSO) and dynamic-link library (DLL) support
1249
+ //
1250
+ #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
1251
+ //#define WOW_BOOST_SYMBOL_EXPORT __attribute__((__dllexport__))
1252
+ #define WOW_BOOST_SYMBOL_EXPORT __declspec(dllexport)
1253
+
1254
+ #else
1255
+ #define WOW_BOOST_SYMBOL_EXPORT __attribute__((__visibility__("default")))
1256
+ #endif
1257
+
1258
+ extern "C" WOW_BOOST_SYMBOL_EXPORT wow::python::Plugin plugin;
1259
+
1260
+ wow::python::Plugin plugin;
1261
+
1262
+ // ----------------------------------------------------------------------------------
1263
+ // Copyright (c) 2024 Wowool, All Rights Reserved.
1264
+ // NOTICE: All information contained herein is, and remains the property of Wowool.
1265
+ // !!! Note merging the code with the python plugin module.
1266
+ // ----------------------------------------------------------------------------------
1267
+ typedef std::vector<wow::python::AttributesPair> python_object_attributes_type;
1268
+ typedef wow::python::python_object_range python_object_range;
1269
+ using wow::python::AttributesPair;
1270
+ using wow::python::python_object_attributes;
1271
+ using wow::python::python_object_match_context;
1272
+ using wow::python::python_token;
1273
+
1274
+ PYBIND11_MAKE_OPAQUE(python_object_attributes_type);
1275
+
1276
+ // ----------------------------------------------------------------------------
1277
+ // Python Bindings for the wowool_plugin.
1278
+ // ----------------------------------------------------------------------------
1279
+ PYBIND11_MODULE(_wowool_plugin, m)
1280
+ {
1281
+ using namespace pybind11::literals;
1282
+
1283
+ py::class_<python_token>(m, "python_token")
1284
+ .def("has_property", &python_token::has_property)
1285
+ .def_property_readonly("literal", [](python_token &self) { return self.literal(); })
1286
+ .def_property_readonly("text", [](python_token &self) { return self.literal(); })
1287
+ .def("head", &python_token::head)
1288
+ .def("pos", &python_token::pos, py::arg("idx") = 0)
1289
+ .def("stem", &python_token::stem, py::arg("idx") = 0)
1290
+ .def_property_readonly("lemma", [](python_token &self) { return self.lemma(0); })
1291
+ .def("__repr__", &python_token::str, "Returns literal")
1292
+ .def("__str__", &python_token::str, "Returns literal");
1293
+
1294
+ py::class_<python_object_range>(m, "annotation_range", "\nA annotation range marks the begin and "
1295
+ "end of a annotation collection.")
1296
+ .def(py::init([](plugin_Annotation *cnpt) {
1297
+ return new python_object_range(cnpt);
1298
+ })) // C++ constructor, shadowed by raw ctor
1299
+ .def_property_readonly("tokens", &python_object_range::tokens, "Returns a list with the tokens of this range.")
1300
+ .def_property_readonly("text", &python_object_range::text, "Returns the literal string of this range, you can specify the "
1301
+ "literal delimiter.")
1302
+ .def("literal", &python_object_range::literal, "\n:param separator: separator between the tokens, default space."
1303
+ "\n:type separator: str"
1304
+ ":returns: a literal string of this range, you can specify the "
1305
+ "literal delimiter ",
1306
+ py::arg("separator") = " ")
1307
+ .def("canonical", &python_object_range::canonical, "\n:param separator: separator between the tokens, default space."
1308
+ "\n:type separator: str"
1309
+ ":returns: a canonical string of this range, you can specify the "
1310
+ "canonical delimiter ",
1311
+ py::arg("separator") = " ")
1312
+ .def("__repr__", &python_object_range::repr, ":returns: the literal string of this range, you can specify the "
1313
+ "stem delimiter.")
1314
+ .def("__str__", &python_object_range::str, ":returns: the literal string of this range, you can specify the "
1315
+ "stem delimiter.")
1316
+ .def("stem", &python_object_range::stem, "\n:param separator: separator between the tokens, default space."
1317
+ "\n:type separator: str"
1318
+ ":returns: a string with the stems of this range, you can specify "
1319
+ "the literal delimiter ",
1320
+ py::arg("separator") = " ")
1321
+ .def_property_readonly("lemma", &python_object_range::lemma, ":returns: a string with the stems of this range, you can specify ")
1322
+ .def("find", &python_object_range::find, "\n:param uri: uri of a concept to find."
1323
+ "\n:type uri: str"
1324
+ "\n:returns: a list of annotation_range object"
1325
+ "\n:type: list(annotation_range)",
1326
+ py::arg("uri"))
1327
+ .def("find_one", &python_object_range::find_one, "\n:param uri: uri of a concept to find."
1328
+ "\n:type uri: str"
1329
+ "\n:returns: a annotation_range object"
1330
+ "\n:type: annotation_range",
1331
+ py::arg("uri"))
1332
+ // when accessing the scope using a . then the return will be one range.
1333
+ // example capture.person will return the first person.
1334
+ // .def("__getattr__", &python_object_range::get_attr )
1335
+ .def(
1336
+ "__getattr__",
1337
+ static_cast<py::object (python_object_range::*)(std::string const &)>(
1338
+ &python_object_range::get_attr))
1339
+ // when accessing the scope using a ['person'] then the return will be a
1340
+ // vector of ranges example capture['person'] will return the all the
1341
+ // persons in the scope.
1342
+ .def("__getitem__", static_cast<std::vector<python_object_range> (python_object_range::*)(std::string const &)>(&python_object_range::get_item))
1343
+ .def("__getitem__", static_cast<std::vector<python_object_range> (python_object_range::*)(py::tuple const &)>(&python_object_range::get_item))
1344
+ .def("attributes", &python_object_range::attributes, "Returns the Attribute Object of this range.")
1345
+ .def("has", &python_object_range::has, "\n:param name: name of the attribute."
1346
+ "\n:type name: str"
1347
+ "\n:returns: true if this range has the given attribute."
1348
+ "\n:type: bool",
1349
+ py::arg("name"))
1350
+ .def("attribute", &python_object_range::get_attribute, "\n:param name: name of the attribute."
1351
+ "\n:type name: str"
1352
+ "\n:returns: the value of the given attribute."
1353
+ "\n:type: str",
1354
+ py::arg("name"))
1355
+ .def("add_attribute", &python_object_range::add_attribute, "Add a attribute to this range", py::arg("key"), py::arg("value"))
1356
+ .def("add_concept", &python_object_range::add_concept, "Add a concept ( semantic annotation ) over this range."
1357
+ "\n"
1358
+ "\n ::"
1359
+ "\n"
1360
+ "\n capture = match.capture()"
1361
+ "\n capture.add_concept('other_uri')"
1362
+ "\n",
1363
+ py::arg("uri"))
1364
+ .def_property_readonly("uri", &python_object_range::get_uri, "\n:returns: the uri of this annotation"
1365
+ "\n:type: str")
1366
+ .def_property_readonly("begin_offset", &python_object_range::get_begin_offset, "\n:returns: a int with the begin offset of this range."
1367
+ "\n:type begin_offset: int")
1368
+ .def_property_readonly("end_offset", &python_object_range::get_end_offset, "\n:returns: a int with the end offset of this range."
1369
+ "\n:type end_offset: int")
1370
+ .def("remove", &python_object_range::remove_concept, "remove the annotation over this range.")
1371
+ .def("__bool__", &python_object_range::pybool);
1372
+
1373
+ py::class_<python_object_match_context>(
1374
+ m, "match_info", "\nIs all the data related to the match of the triggered function."
1375
+ "\nThis object contains the capture, rule and the sentence where the "
1376
+ "match was located."
1377
+ "\n\nEXAMPLE"
1378
+ "\n match = wowool_plugin.match_info()"
1379
+ "\n capture_group = match.capture()")
1380
+ .def(py::init([]() { return new python_object_match_context(); }))
1381
+ .def("uri", &python_object_match_context::to_string, ":returns: the uro of the rule")
1382
+ .def("sentence", &python_object_match_context::sentence, "The sentence object (range) where the match has occurred.")
1383
+ .def("rule", &python_object_match_context::rule, ":returns: the annotation range that the rule has matched. "
1384
+ "\n"
1385
+ "\n ::"
1386
+ "\n"
1387
+ "\n ex rule: { <'Mr'> { <'Fawlty'> }= "
1388
+ "::python::module_name::silly_person }= rule_context;"
1389
+ "\n"
1390
+ "\nHere the range is 'Mr Fawlty'= rule_context."
1391
+ "\n:type: annotation_range")
1392
+ .def("capture", &python_object_match_context::capture, ":returns: the annotation range that we have captured. "
1393
+ "\n"
1394
+ "\n ::"
1395
+ "\n"
1396
+ "\n ex rule: { <'Mr'> { <'Fawlty'> }= "
1397
+ "::python::module_name::silly_person }= rule_context;"
1398
+ "\n"
1399
+ "\nHere the range is 'Fawlty'= silly_person."
1400
+ "\n:type: annotation_range")
1401
+ .def("property", &python_object_match_context::property, ":returns: a property of the range (ex: language)", py::arg("key"))
1402
+ .def("range", &python_object_match_context::make_range, "\n:param begin_range: begin position of the range."
1403
+ "\n:type begin_range: annotation_range"
1404
+ "\n:param end_range: end position of the range."
1405
+ "\n:type end_range: annotation_range"
1406
+ "\n:returns: a annotation range for the given begin and end "
1407
+ "annotation."
1408
+ "\n:type: annotation_range",
1409
+ py::arg("begin_range"),
1410
+ py::arg("end_range"));
1411
+
1412
+ // py::bind_vector<python_object_attributes>(m, "python_object_attributes");
1413
+
1414
+ py::class_<python_object_attributes>(m, "Attributes")
1415
+ .def("has", &python_object_attributes::has)
1416
+ .def("__len__", &python_object_attributes::size)
1417
+ .def(
1418
+ "__iter__",
1419
+ [](python_object_attributes &v) {
1420
+ return py::make_iterator(v.begin(), v.end());
1421
+ },
1422
+ py::keep_alive<0, 1>()) /*Keep vector alive while iterator is used*/
1423
+ .def("__bool__", &python_object_attributes::pybool)
1424
+ .def("__repr__", &python_object_attributes::to_string)
1425
+ .def("__str__", &python_object_attributes::to_string);
1426
+
1427
+ py::class_<AttributesPair>(m, "attributes_vp")
1428
+ .def("name", &AttributesPair::name)
1429
+ .def("value", &AttributesPair::value)
1430
+ .def("__repr__", &AttributesPair::to_string)
1431
+ .def("__str__", &AttributesPair::to_string);
1432
+ }