@@ -0,0 +1,19 | |||||
|
1 | #include <Data/DateTimeRange.h> | |||
|
2 | #include <TimeSeries.h> | |||
|
3 | #include <functional> | |||
|
4 | #include <iostream> | |||
|
5 | #include <memory> | |||
|
6 | ||||
|
7 | ||||
|
8 | class PythonInterpreter | |||
|
9 | { | |||
|
10 | public: | |||
|
11 | PythonInterpreter(); | |||
|
12 | void add_register_callback(std::function<void(const std::vector<std::string>&, | |||
|
13 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)>)> | |||
|
14 | callback); | |||
|
15 | ~PythonInterpreter(); | |||
|
16 | void eval(const std::string& file); | |||
|
17 | ||||
|
18 | private: | |||
|
19 | }; |
@@ -0,0 +1,47 | |||||
|
1 | #include "python_interpreter.h" | |||
|
2 | #include <Data/DateTimeRange.h> | |||
|
3 | #include <TimeSeries.h> | |||
|
4 | #include <functional> | |||
|
5 | #include <iostream> | |||
|
6 | #include <pybind11/embed.h> | |||
|
7 | #include <pybind11/functional.h> | |||
|
8 | #include <pybind11/stl.h> | |||
|
9 | ||||
|
10 | namespace py = pybind11; | |||
|
11 | ||||
|
12 | ||||
|
13 | PYBIND11_EMBEDDED_MODULE(PythonProviders, m) {} | |||
|
14 | static pybind11::gil_scoped_release* _rel = nullptr; | |||
|
15 | ||||
|
16 | PythonInterpreter::PythonInterpreter() | |||
|
17 | { | |||
|
18 | py::initialize_interpreter(false); | |||
|
19 | } | |||
|
20 | ||||
|
21 | void PythonInterpreter::add_register_callback(std::function<void(const std::vector<std::string>&, | |||
|
22 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)>)> | |||
|
23 | callback) | |||
|
24 | { | |||
|
25 | py::module PythonProviders = py::module::import("PythonProviders"); | |||
|
26 | PythonProviders.attr("register_product") = callback; | |||
|
27 | } | |||
|
28 | ||||
|
29 | PythonInterpreter::~PythonInterpreter() | |||
|
30 | { | |||
|
31 | if (_rel) | |||
|
32 | delete _rel; | |||
|
33 | py::finalize_interpreter(); | |||
|
34 | } | |||
|
35 | ||||
|
36 | void PythonInterpreter::eval(const std::string& file) | |||
|
37 | { | |||
|
38 | try | |||
|
39 | { | |||
|
40 | py::eval_file(file); | |||
|
41 | } | |||
|
42 | catch (py::error_already_set const& pythonErr) | |||
|
43 | { | |||
|
44 | std::cout << pythonErr.what(); | |||
|
45 | } | |||
|
46 | _rel = new py::gil_scoped_release(); | |||
|
47 | } |
@@ -1,1 +1,1 | |||||
1 | Subproject commit a0c89a70c83c407d12cf22096a0e7ffae4763e00 |
|
1 | Subproject commit 68c01155acd227b01fa3c9f7926215e8cedd70df |
@@ -1,26 +1,42 | |||||
1 | include_directories(include) |
|
1 | include_directories(include) | |
2 | FILE (GLOB_RECURSE python_providers |
|
2 | FILE (GLOB_RECURSE python_provider_srcs | |
3 |
include/ |
|
3 | include/python_providers.h | |
4 |
src/ |
|
4 | src/python_providers.cpp | |
5 |
resources/ |
|
5 | resources/python_providers.qrc | |
6 | ) |
|
6 | ) | |
7 |
|
7 | |||
|
8 | FILE (GLOB_RECURSE python_interpreter_srcs | |||
|
9 | include/python_interpreter.h | |||
|
10 | src/python_interpreter.cpp | |||
|
11 | ) | |||
|
12 | ||||
|
13 | add_library(python_interpreter ${python_interpreter_srcs}) | |||
|
14 | target_link_libraries(python_interpreter PRIVATE pybind11::embed) | |||
|
15 | target_link_libraries(python_interpreter PUBLIC sciqlopcore) | |||
|
16 | target_compile_definitions(python_interpreter PRIVATE QT_NO_KEYWORDS) | |||
|
17 | SET_TARGET_PROPERTIES(python_interpreter PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) | |||
|
18 | ||||
8 | add_definitions(-DQT_PLUGIN) |
|
19 | add_definitions(-DQT_PLUGIN) | |
9 | add_definitions(-DSCIQLOP_PLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/python_providers.json") |
|
20 | add_definitions(-DSCIQLOP_PLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/python_providers.json") | |
10 | if(NOT BUILD_SHARED_LIBS) |
|
21 | if(NOT BUILD_SHARED_LIBS) | |
11 | add_definitions(-DQT_STATICPLUGIN) |
|
22 | add_definitions(-DQT_STATICPLUGIN) | |
12 | endif() |
|
23 | endif() | |
13 |
|
24 | |||
14 | add_library(python_providers ${python_providers}) |
|
25 | add_library(python_providers ${python_provider_srcs}) | |
15 | SET_TARGET_PROPERTIES(python_providers PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) |
|
26 | SET_TARGET_PROPERTIES(python_providers PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE) | |
16 |
|
27 | |||
17 | target_link_libraries(python_providers PUBLIC sciqlopgui) |
|
28 | target_link_libraries(python_providers PUBLIC sciqlopgui) | |
18 |
target_link_libraries(python_providers PRIVATE py |
|
29 | target_link_libraries(python_providers PRIVATE python_interpreter) | |
19 | ADD_DEFINITIONS(-DQT_NO_KEYWORDS) |
|
30 | ||
20 | install(TARGETS python_providers |
|
31 | install(TARGETS python_providers | |
21 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop |
|
32 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |
22 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop |
|
33 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |
23 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) |
|
34 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | |
24 |
|
35 | |||
|
36 | install(TARGETS python_interpreter | |||
|
37 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |||
|
38 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop | |||
|
39 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | |||
|
40 | ||||
25 | include(sciqlop_tests) |
|
41 | include(sciqlop_tests) | |
26 |
|
42 |
@@ -2,9 +2,10 | |||||
2 | #define PYTHON_PROVIDERS_H |
|
2 | #define PYTHON_PROVIDERS_H | |
3 |
|
3 | |||
4 | #include <Plugin/IPlugin.h> |
|
4 | #include <Plugin/IPlugin.h> | |
5 |
|
5 | #include <QUuid> | ||
6 |
|
6 | |||
7 | #include <memory> |
|
7 | #include <memory> | |
|
8 | #include <python_interpreter.h> | |||
8 |
|
9 | |||
9 | #ifndef SCIQLOP_PLUGIN_JSON_FILE_PATH |
|
10 | #ifndef SCIQLOP_PLUGIN_JSON_FILE_PATH | |
10 | #define SCIQLOP_PLUGIN_JSON_FILE_PATH "python_providers.json" |
|
11 | #define SCIQLOP_PLUGIN_JSON_FILE_PATH "python_providers.json" | |
@@ -21,6 +22,12 public: | |||||
21 | /// @sa IPlugin::initialize() |
|
22 | /// @sa IPlugin::initialize() | |
22 | void initialize() override; |
|
23 | void initialize() override; | |
23 | ~PythonProviders(); |
|
24 | ~PythonProviders(); | |
|
25 | ||||
|
26 | private: | |||
|
27 | void register_product(const std::vector<std::string>& path_list, | |||
|
28 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string& name, double, double)> | |||
|
29 | f); | |||
|
30 | PythonInterpreter _interpreter; | |||
24 | }; |
|
31 | }; | |
25 |
|
32 | |||
26 | #endif // PYTHON_PROVIDERS_H |
|
33 | #endif // PYTHON_PROVIDERS_H |
@@ -1,17 +1,158 | |||||
1 | #include "python_providers.h" |
|
1 | #include "python_providers.h" | |
2 | #include <pybind11/embed.h> |
|
2 | #include <Data/DataProviderParameters.h> | |
3 | namespace py = pybind11; |
|
3 | #include <Data/DateTimeRange.h> | |
|
4 | #include <Data/IDataProvider.h> | |||
|
5 | #include <Data/ScalarTimeSerie.h> | |||
|
6 | #include <Data/SpectrogramTimeSerie.h> | |||
|
7 | #include <Data/VectorTimeSerie.h> | |||
|
8 | #include <DataSource/DataSourceController.h> | |||
|
9 | #include <DataSource/DataSourceItem.h> | |||
|
10 | #include <DataSource/DataSourceItemAction.h> | |||
|
11 | #include <QDir> | |||
|
12 | #include <QStandardPaths> | |||
|
13 | #include <QStringList> | |||
|
14 | #include <SqpApplication.h> | |||
|
15 | #include <TimeSeries.h> | |||
|
16 | #include <functional> | |||
|
17 | #include <iostream> | |||
|
18 | ||||
|
19 | ||||
|
20 | const auto DATA_SOURCE_NAME = QStringLiteral("PythonProviders"); | |||
|
21 | ||||
|
22 | struct noop_deleter | |||
|
23 | { | |||
|
24 | void operator()(TimeSeries::ITimeSerie*) {} | |||
|
25 | }; | |||
|
26 | ||||
|
27 | class PythonProvider : public IDataProvider | |||
|
28 | { | |||
|
29 | public: | |||
|
30 | PythonProvider( | |||
|
31 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)> f) | |||
|
32 | : _pythonFunction { f } | |||
|
33 | { | |||
|
34 | } | |||
|
35 | ||||
|
36 | PythonProvider(const PythonProvider& other) : _pythonFunction { other._pythonFunction } {} | |||
|
37 | ||||
|
38 | std::shared_ptr<IDataProvider> clone() const override | |||
|
39 | { | |||
|
40 | return std::make_shared<PythonProvider>(*this); | |||
|
41 | } | |||
|
42 | virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override | |||
|
43 | { | |||
|
44 | auto product = parameters.m_Data.value("PRODUCT", "").toString().toStdString(); | |||
|
45 | auto range = parameters.m_Range; | |||
|
46 | auto result = _pythonFunction(product, range.m_TStart, range.m_TEnd); | |||
|
47 | if (auto ts = std::dynamic_pointer_cast<VectorTimeSerie>(result)) | |||
|
48 | { | |||
|
49 | return new VectorTimeSerie(*ts); | |||
|
50 | } | |||
|
51 | if (auto ts = std::dynamic_pointer_cast<ScalarTimeSerie>(result)) | |||
|
52 | { | |||
|
53 | return new ScalarTimeSerie(*ts); | |||
|
54 | } | |||
|
55 | if (auto ts = std::dynamic_pointer_cast<SpectrogramTimeSerie>(result)) | |||
|
56 | { | |||
|
57 | return new SpectrogramTimeSerie(*ts); | |||
|
58 | } | |||
|
59 | return nullptr; | |||
|
60 | } | |||
|
61 | ||||
|
62 | private: | |||
|
63 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)> | |||
|
64 | _pythonFunction; | |||
|
65 | }; | |||
|
66 | ||||
4 |
|
67 | |||
5 | void PythonProviders::initialize() |
|
68 | void PythonProviders::initialize() | |
6 | { |
|
69 | { | |
7 | py::initialize_interpreter(false); |
|
70 | _interpreter.add_register_callback( | |
8 | py::print("Hello, World!"); |
|
71 | [this](const std::vector<std::string>& path_list, | |
9 | py::print("Hello, World!"); |
|
72 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)> | |
10 | py::print("Hello, World!"); |
|
73 | f) { this->register_product(path_list, f); }); | |
11 | py::print("Hello, World!"); |
|
74 | ||
|
75 | for (const auto& path : QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation)) | |||
|
76 | { | |||
|
77 | auto dir = QDir(path + "/python"); | |||
|
78 | if (dir.exists()) | |||
|
79 | { | |||
|
80 | for (const auto& entry : | |||
|
81 | dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name)) | |||
|
82 | { | |||
|
83 | if (entry.isFile() && entry.suffix() == "py") | |||
|
84 | { | |||
|
85 | _interpreter.eval(entry.absoluteFilePath().toStdString()); | |||
|
86 | } | |||
|
87 | } | |||
|
88 | } | |||
|
89 | } | |||
|
90 | } | |||
|
91 | ||||
|
92 | PythonProviders::~PythonProviders() {} | |||
|
93 | ||||
|
94 | std::unique_ptr<DataSourceItem> make_folder_item(const QString& name) | |||
|
95 | { | |||
|
96 | return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name); | |||
|
97 | } | |||
|
98 | ||||
|
99 | template <typename T> | |||
|
100 | DataSourceItem* make_path_items( | |||
|
101 | const T& path_list_begin, const T& path_list_end, DataSourceItem* root) | |||
|
102 | { | |||
|
103 | std::for_each(path_list_begin, path_list_end, [&root](const auto& folder_name) mutable { | |||
|
104 | auto folder_ptr = root->findItem(folder_name); | |||
|
105 | if (folder_ptr == nullptr) | |||
|
106 | { | |||
|
107 | auto folder = make_folder_item(folder_name); | |||
|
108 | folder_ptr = folder.get(); | |||
|
109 | root->appendChild(std::move(folder)); | |||
|
110 | } | |||
|
111 | root = folder_ptr; | |||
|
112 | }); | |||
|
113 | return root; | |||
|
114 | } | |||
|
115 | ||||
|
116 | std::unique_ptr<DataSourceItem> make_product_item( | |||
|
117 | const QVariantHash& metaData, const QUuid& dataSourceUid) | |||
|
118 | { | |||
|
119 | auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, metaData); | |||
|
120 | ||||
|
121 | // Adds plugin name to product metadata | |||
|
122 | result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME); | |||
|
123 | result->setData(DataSourceItem::ID_DATA_KEY, metaData.value(DataSourceItem::NAME_DATA_KEY)); | |||
|
124 | ||||
|
125 | auto productName = metaData.value(DataSourceItem::NAME_DATA_KEY).toString(); | |||
|
126 | ||||
|
127 | // Add action to load product from DataSourceController | |||
|
128 | result->addAction( | |||
|
129 | std::make_unique<DataSourceItemAction>(QObject::tr("Load %1 product").arg(productName), | |||
|
130 | [productName, dataSourceUid](DataSourceItem& item) { | |||
|
131 | if (auto app = sqpApp) | |||
|
132 | { | |||
|
133 | app->dataSourceController().loadProductItem(dataSourceUid, item); | |||
|
134 | } | |||
|
135 | })); | |||
|
136 | ||||
|
137 | return result; | |||
12 | } |
|
138 | } | |
13 |
|
139 | |||
14 | PythonProviders::~PythonProviders() |
|
140 | void PythonProviders::register_product(const std::vector<std::string>& path_list, | |
|
141 | std::function<std::shared_ptr<TimeSeries::ITimeSerie>(std::string&, double, double)> f) | |||
15 | { |
|
142 | { | |
16 | py::finalize_interpreter(); |
|
143 | auto& dataSourceController = sqpApp->dataSourceController(); | |
|
144 | auto id = dataSourceController.registerDataSource(DATA_SOURCE_NAME); | |||
|
145 | auto root = make_folder_item(DATA_SOURCE_NAME); | |||
|
146 | std::for_each( | |||
|
147 | std::cbegin(path_list), std::cend(path_list), [id, f, root = root.get()](const auto& path) { | |||
|
148 | auto path_list = QString::fromStdString(path).split('/'); | |||
|
149 | auto name = *(std::cend(path_list) - 1); | |||
|
150 | auto path_item | |||
|
151 | = make_path_items(std::cbegin(path_list), std::cend(path_list) - 1, root); | |||
|
152 | path_item->appendChild( | |||
|
153 | make_product_item({ { DataSourceItem::NAME_DATA_KEY, name } }, id)); | |||
|
154 | }); | |||
|
155 | dataSourceController.setDataSourceItem(id, std::move(root)); | |||
|
156 | dataSourceController.setDataProvider(id, std::make_unique<PythonProvider>(f)); | |||
|
157 | std::cout << "Gone there" << std::endl; | |||
17 | } |
|
158 | } |
General Comments 0
You need to be logged in to leave comments.
Login now