pytq-cxx 1.0.2__tar.gz → 1.1.1__tar.gz

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 (25) hide show
  1. {pytq_cxx-1.0.2/pytq_cxx.egg-info → pytq_cxx-1.1.1}/PKG-INFO +8 -3
  2. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/README_pytq.md +6 -1
  3. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/bind.cpp +33 -1
  4. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/internal/promise_utils.h +28 -6
  5. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/thread_pool.h +6 -4
  6. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/timer_queue.h +11 -8
  7. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/utils/sched_utils.h +25 -2
  8. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/version.h +1 -1
  9. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/pyproject.toml +1 -1
  10. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/pytq/__init__.py +2 -2
  11. pytq_cxx-1.1.1/pytq/pythonize.py +22 -0
  12. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1/pytq_cxx.egg-info}/PKG-INFO +8 -3
  13. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/pytq_cxx.egg-info/SOURCES.txt +1 -1
  14. pytq_cxx-1.0.2/pytq/awaitable_future.py +0 -19
  15. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/MANIFEST.in +0 -0
  16. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/internal/concepts.h +0 -0
  17. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/internal/log4cxx_proxy.h +0 -0
  18. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/include/yatq/utils/logging_utils.h +0 -0
  19. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/_yatq/traits.h +0 -0
  20. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/pytq_cxx.egg-info/dependency_links.txt +0 -0
  21. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/pytq_cxx.egg-info/top_level.txt +0 -0
  22. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/setup.cfg +0 -0
  23. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/setup.py +0 -0
  24. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/setup_helpers/find_dep_headers.cmake +0 -0
  25. {pytq_cxx-1.0.2 → pytq_cxx-1.1.1}/setup_helpers/find_dep_libs.cmake +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pytq-cxx
3
- Version: 1.0.2
3
+ Version: 1.1.1
4
4
  Summary: single-threaded timer demultiplexer backed by C++ implementation
5
5
  Author-email: Nikita Vaganov <nikita.e.vaganov@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/vaganov/yatq
@@ -18,4 +18,9 @@ see [yatq homepage](https://github.com/vaganov/yatq)
18
18
 
19
19
  **NB:** Module name is, however, **pytq**
20
20
 
21
- from pytq import ThreadPool, TimerQueue, AwaitableFuture
21
+ from pytq import ThreadPool, TimerQueue, pythonize
22
+
23
+ **NB:** On _macOS_ one may need to specify **MACOSX_DEPLOYMENT_TARGET** environment variable on install. Do not set
24
+ higher than the current _macOS_ version. Minimal supported version is **13.4**
25
+
26
+ (venv) $ MACOSX_DEPLOYMENT_TARGET=13.4 pip install pytq-cxx
@@ -6,4 +6,9 @@ see [yatq homepage](https://github.com/vaganov/yatq)
6
6
 
7
7
  **NB:** Module name is, however, **pytq**
8
8
 
9
- from pytq import ThreadPool, TimerQueue, AwaitableFuture
9
+ from pytq import ThreadPool, TimerQueue, pythonize
10
+
11
+ **NB:** On _macOS_ one may need to specify **MACOSX_DEPLOYMENT_TARGET** environment variable on install. Do not set
12
+ higher than the current _macOS_ version. Minimal supported version is **13.4**
13
+
14
+ (venv) $ MACOSX_DEPLOYMENT_TARGET=13.4 pip install pytq-cxx
@@ -3,6 +3,8 @@
3
3
  #include <pybind11/chrono.h>
4
4
  #include <pybind11/functional.h>
5
5
 
6
+ #include <functional>
7
+
6
8
  #ifndef YATQ_DISABLE_FUTURES
7
9
  #define BOOST_THREAD_PROVIDES_FUTURE
8
10
  #define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
@@ -18,7 +20,9 @@
18
20
  namespace py = pybind11;
19
21
 
20
22
  using result_type = py::object;
23
+ #ifndef YATQ_DISABLE_FUTURES
21
24
  using Future = boost::future<result_type>;
25
+ #endif
22
26
  using Executable = std::function<result_type(void)>;
23
27
  using ThreadPool = yatq::ThreadPool<Executable>;
24
28
  using TimerQueue = yatq::TimerQueue<ThreadPool>;
@@ -26,10 +30,38 @@ using TimerQueue = yatq::TimerQueue<ThreadPool>;
26
30
  PYBIND11_MODULE(_yatq, m) {
27
31
  #ifndef YATQ_DISABLE_FUTURES
28
32
  auto boost_submodule = m.def_submodule("boost");
33
+
34
+ py::enum_<boost::launch>(boost_submodule, "launch")
35
+ .value("none", boost::launch::none)
36
+ .value("async_", boost::launch::async) // sic!
37
+ .value("deferred", boost::launch::deferred)
38
+ #ifdef BOOST_THREAD_PROVIDES_EXECUTORS
39
+ .value("executor", boost::launch::executor)
40
+ #endif
41
+ .value("inherit", boost::launch::inherit)
42
+ .value("sync", boost::launch::sync)
43
+ .value("any", boost::launch::any)
44
+ .export_values();
45
+
29
46
  py::class_<Future>(boost_submodule, "future")
30
47
  .def("get", &Future::get, py::call_guard<py::gil_scoped_release>())
31
48
  .def("wait", &Future::wait, py::call_guard<py::gil_scoped_release>())
32
- .def("is_ready", py::overload_cast<>(&Future::is_ready, py::const_));
49
+ .def("is_ready", py::overload_cast<>(&Future::is_ready, py::const_))
50
+ .def(
51
+ "then",
52
+ [] (Future& _this, std::function<result_type(Future&&)>&& func) {
53
+ return _this.then(std::move(func));
54
+ },
55
+ py::arg("func")
56
+ )
57
+ .def(
58
+ "then",
59
+ [] (Future& _this, boost::launch policy, std::function<result_type(Future&&)>&& func) {
60
+ return _this.then(policy, std::move(func));
61
+ },
62
+ py::arg("policy"),
63
+ py::arg("func")
64
+ );
33
65
  #endif
34
66
 
35
67
  #ifndef YATQ_DISABLE_PTHREAD
@@ -3,28 +3,50 @@
3
3
 
4
4
  #include <type_traits>
5
5
 
6
+ #include <boost/exception_ptr.hpp>
7
+
6
8
  namespace yatq::internal {
7
9
 
8
10
  template<typename result_type, typename Job, typename Promise>
9
11
  std::enable_if_t<!std::is_void_v<result_type>> run_and_set_value(Job job, Promise promise) {
10
- promise.set_value(job());
12
+ try {
13
+ promise.set_value(job());
14
+ }
15
+ catch (...) {
16
+ promise.set_exception(boost::current_exception());
17
+ }
11
18
  }
12
19
 
13
20
  template<typename result_type, typename Job, typename Promise>
14
21
  std::enable_if_t<std::is_void_v<result_type>> run_and_set_value(Job job, Promise promise) {
15
- job();
16
- promise.set_value();
22
+ try {
23
+ job();
24
+ promise.set_value();
25
+ }
26
+ catch (...) {
27
+ promise.set_exception(boost::current_exception());
28
+ }
17
29
  }
18
30
 
19
31
  template<typename result_type, typename Future, typename Promise>
20
32
  std::enable_if_t<!std::is_void_v<result_type>> get_and_set_value(Future future, Promise promise) {
21
- promise.set_value(future.get());
33
+ try {
34
+ promise.set_value(future.get());
35
+ }
36
+ catch (...) {
37
+ promise.set_exception(boost::current_exception());
38
+ }
22
39
  }
23
40
 
24
41
  template<typename result_type, typename Future, typename Promise>
25
42
  std::enable_if_t<std::is_void_v<result_type>> get_and_set_value(Future future, Promise promise) {
26
- future.get();
27
- promise.set_value();
43
+ try {
44
+ future.get();
45
+ promise.set_value();
46
+ }
47
+ catch (...) {
48
+ promise.set_exception(boost::current_exception());
49
+ }
28
50
  }
29
51
 
30
52
  }
@@ -2,8 +2,8 @@
2
2
  #define _YATQ_THREAD_POOL_H
3
3
 
4
4
  #include <condition_variable>
5
- #include <cstdlib>
6
5
  #include <deque>
6
+ #include <format>
7
7
  #include <functional>
8
8
  #include <mutex>
9
9
  #include <string>
@@ -17,7 +17,9 @@
17
17
  #endif
18
18
 
19
19
  #include "yatq/internal/concepts.h"
20
+ #ifndef YATQ_DISABLE_FUTURES
20
21
  #include "yatq/internal/promise_utils.h"
22
+ #endif
21
23
  #include "yatq/internal/log4cxx_proxy.h"
22
24
 
23
25
  namespace yatq {
@@ -65,8 +67,8 @@ public:
65
67
  if (!_running) {
66
68
  _running = true;
67
69
  for (int i = 0; i < num_threads; ++i) {
68
- std::string thread_tag = "pool thread #" + std::to_string(i);
69
- auto thread = std::thread(&ThreadPool::thread_routine, this, thread_tag);
70
+ std::string thread_tag = std::format("pool thread #{}", i);
71
+ auto thread = std::thread(&ThreadPool::thread_routine, this, std::move(thread_tag));
70
72
  _pool.push_back(std::move(thread));
71
73
  }
72
74
  }
@@ -119,7 +121,7 @@ public:
119
121
  }
120
122
 
121
123
  private:
122
- void thread_routine(const std::string& thread_tag) {
124
+ void thread_routine(std::string&& thread_tag) {
123
125
  #ifndef YATQ_DISABLE_LOGGING
124
126
  static auto logger = log4cxx::Logger::getLogger("yatq.thread_pool");
125
127
  #endif
@@ -4,6 +4,7 @@
4
4
  #include <algorithm>
5
5
  #include <chrono>
6
6
  #include <condition_variable>
7
+ #include <format>
7
8
  #include <mutex>
8
9
  #include <thread>
9
10
  #include <unordered_map>
@@ -16,7 +17,9 @@
16
17
  #endif
17
18
 
18
19
  #include "yatq/internal/concepts.h"
20
+ #ifndef YATQ_DISABLE_FUTURES
19
21
  #include "yatq/internal/promise_utils.h"
22
+ #endif
20
23
  #include "yatq/internal/log4cxx_proxy.h"
21
24
  #include "yatq/utils/logging_utils.h"
22
25
  #ifndef YATQ_DISABLE_PTHREAD
@@ -171,7 +174,7 @@ public:
171
174
  if (is_first) {
172
175
  _cond.notify_one();
173
176
  }
174
- LOG4CXX_DEBUG(logger, "New timer uid=" + std::to_string(uid));
177
+ LOG4CXX_DEBUG(logger, std::format("New timer uid={}", uid));
175
178
  return {
176
179
  uid
177
180
  , deadline
@@ -197,7 +200,7 @@ public:
197
200
  std::lock_guard<std::mutex> guard(_lock);
198
201
  auto i = _jobs.find(uid);
199
202
  if (i != _jobs.end()) {
200
- LOG4CXX_DEBUG(logger, "Canceling timer uid=" + std::to_string(uid));
203
+ LOG4CXX_DEBUG(logger, std::format("Canceling timer uid={}", uid));
201
204
  _jobs.erase(i);
202
205
  was_removed = true;
203
206
  was_first = (_heap[0].uid == uid);
@@ -233,7 +236,7 @@ public:
233
236
  _cond.notify_one();
234
237
  }
235
238
  auto canceled_timers = total_timers - total_jobs;
236
- LOG4CXX_DEBUG(logger, "Cleared " + std::to_string(total_jobs) + " timers and " + std::to_string(canceled_timers) + " canceled timers");
239
+ LOG4CXX_DEBUG(logger, std::format("Cleared {} timers and {} canceled timers", total_jobs, canceled_timers));
237
240
  }
238
241
 
239
242
  /**
@@ -258,7 +261,7 @@ public:
258
261
  *i++ = std::move(heap_entry);
259
262
  }
260
263
  else {
261
- LOG4CXX_DEBUG(logger, "Timer uid=" + std::to_string(heap_entry.uid) + " has been canceled");
264
+ LOG4CXX_DEBUG(logger, std::format("Timer uid={} has been canceled", heap_entry.uid));
262
265
  }
263
266
  }
264
267
  std::make_heap(heap.begin(), heap.end(), TimerQueue::heap_cmp);
@@ -266,7 +269,7 @@ public:
266
269
  }
267
270
  }
268
271
  // NB: 'demux()' never waits on a canceled timer => no need to notify
269
- LOG4CXX_DEBUG(logger, "Purged " + std::to_string(canceled_timers) + " canceled timers");
272
+ LOG4CXX_DEBUG(logger, std::format("Purged {} canceled timers", canceled_timers));
270
273
  }
271
274
 
272
275
  /**
@@ -298,7 +301,7 @@ private:
298
301
  auto current_uid = _heap[0].uid;
299
302
  auto i = _jobs.find(current_uid);
300
303
  if (i == _jobs.end()) {
301
- LOG4CXX_DEBUG(logger, "Timer uid=" + std::to_string(current_uid) + " has been canceled");
304
+ LOG4CXX_DEBUG(logger, std::format("Timer uid={} has been canceled", current_uid));
302
305
  std::pop_heap(_heap.begin(), _heap.end(), TimerQueue::heap_cmp);
303
306
  _heap.pop_back();
304
307
  deadline_expired = false;
@@ -309,7 +312,7 @@ private:
309
312
  deadline_expired = (_heap[0].deadline <= now);
310
313
  }
311
314
  if (deadline_expired) {
312
- LOG4CXX_DEBUG(logger, "Executing timer uid=" + std::to_string(current_uid));
315
+ LOG4CXX_DEBUG(logger, std::format("Executing timer uid={}", current_uid));
313
316
  auto node = _jobs.extract(i);
314
317
  std::pop_heap(_heap.begin(), _heap.end(), TimerQueue::heap_cmp);
315
318
  _heap.pop_back();
@@ -336,7 +339,7 @@ private:
336
339
  // NB: without this explicit cast duration type may be deduced incorrectly
337
340
  // on Linux this leads to waiting for a random time point
338
341
  std::chrono::time_point<Clock, typename Clock::duration> deadline = _heap[0].deadline;
339
- LOG4CXX_TRACE(logger, "Wait until " + utils::time_point_to_string(deadline));
342
+ LOG4CXX_TRACE(logger, std::format("Wait until {}", utils::time_point_to_string(deadline)));
340
343
  bool notified = _cond.wait_until(
341
344
  guard,
342
345
  deadline,
@@ -2,6 +2,7 @@
2
2
  #define _YATQ_UTILS_SCHED_UTILS_H
3
3
 
4
4
  #include <cerrno>
5
+ #include <format>
5
6
  #include <string>
6
7
 
7
8
  #include <pthread.h>
@@ -13,6 +14,14 @@ namespace yatq::utils {
13
14
 
14
15
  typedef enum {min_priority = 0, max_priority = -1} priority_t;
15
16
 
17
+ /**
18
+ * set scheduling parameters for a thread
19
+ * @param handle thread handle
20
+ * @param sched_policy \a SCHED_OTHER | \a SCHED_RR | \a SCHED_FIFO
21
+ * @param priority explicit priority
22
+ * @param thread_tag thread tag (used for logging purposes only)
23
+ * @return \a true if scheduling parameters have been set and \a false otherwise
24
+ */
16
25
  inline bool set_sched_params(pthread_t handle, int sched_policy, int priority, const std::string& thread_tag = "unspecified") {
17
26
  #ifndef YATQ_DISABLE_LOGGING
18
27
  static auto logger = log4cxx::Logger::getLogger("yatq.utils.sched");
@@ -23,15 +32,29 @@ inline bool set_sched_params(pthread_t handle, int sched_policy, int priority, c
23
32
  pthread_getschedparam(handle, &prev_sched_policy, &sched);
24
33
  sched.sched_priority = priority;
25
34
  if (pthread_setschedparam(handle, sched_policy, &sched) == 0) {
26
- LOG4CXX_INFO(logger, "Set sched params thread=" + thread_tag + " policy=" + sched_policy_to_string(sched_policy) + " priority=" + std::to_string(priority));
35
+ LOG4CXX_INFO(
36
+ logger,
37
+ std::format(
38
+ "Set sched params thread='{}' policy={} priority={}",
39
+ thread_tag, sched_policy_to_string(sched_policy), priority
40
+ )
41
+ );
27
42
  return true;
28
43
  }
29
44
  else {
30
- LOG4CXX_WARN(logger, "Failed to set sched params thread=" + thread_tag + ": " + std::string(std::strerror(errno)));
45
+ LOG4CXX_WARN(logger, std::format("Failed to set sched params thread='{}': {}", thread_tag, std::strerror(errno)));
31
46
  return false;
32
47
  }
33
48
  }
34
49
 
50
+ /**
51
+ * set scheduling parameters for a thread
52
+ * @param handle thread handle
53
+ * @param sched_policy \a SCHED_OTHER | \a SCHED_RR | \a SCHED_FIFO
54
+ * @param priority_tag \a yatq::utils::max_priority | \a yatq::utils::min_priority
55
+ * @param thread_tag thread tag (used for logging purposes only)
56
+ * @return \a true if scheduling parameters have been set and \a false otherwise
57
+ */
35
58
  inline bool set_sched_params(pthread_t handle, int sched_policy, priority_t priority_tag, const std::string& thread_tag = "unspecified") {
36
59
  int priority;
37
60
  switch (priority_tag) {
@@ -1,6 +1,6 @@
1
1
  #ifndef _YATQ_VERSION_H
2
2
  #define _YATQ_VERSION_H
3
3
 
4
- #define YATQ_VERSION "1.0.2"
4
+ #define YATQ_VERSION "1.1.1"
5
5
 
6
6
  #endif
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pytq-cxx"
7
- version = "1.0.2"
7
+ version = "1.1.1"
8
8
  authors = [{name="Nikita Vaganov", email="nikita.e.vaganov@gmail.com"}]
9
9
  description = "single-threaded timer demultiplexer backed by C++ implementation"
10
10
  readme = "README_pytq.md"
@@ -1,5 +1,5 @@
1
1
  from _yatq import __version__, TimerQueue, TimerHandle, ThreadPool, utils
2
- from .awaitable_future import AwaitableFuture
2
+ from .pythonize import pythonize
3
3
 
4
4
 
5
- __all__ = ['__version__', 'TimerQueue', 'TimerHandle', 'ThreadPool', 'utils', 'AwaitableFuture']
5
+ __all__ = ['__version__', 'TimerQueue', 'TimerHandle', 'ThreadPool', 'utils', 'pythonize']
@@ -0,0 +1,22 @@
1
+ import asyncio
2
+ from typing import Any
3
+
4
+ import _yatq.boost
5
+
6
+
7
+ __all__ = ['pythonize']
8
+
9
+
10
+ def pythonize(src: _yatq.boost.future) -> asyncio.Future[Any]:
11
+ chained = asyncio.Future()
12
+
13
+ def on_done(future: _yatq.boost.future):
14
+ try:
15
+ result = future.get()
16
+ except Exception as exc:
17
+ chained.get_loop().call_soon_threadsafe(chained.set_exception, exc)
18
+ else:
19
+ chained.get_loop().call_soon_threadsafe(chained.set_result, result)
20
+
21
+ src.then(func=on_done, policy=_yatq.boost.launch.sync)
22
+ return chained
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pytq-cxx
3
- Version: 1.0.2
3
+ Version: 1.1.1
4
4
  Summary: single-threaded timer demultiplexer backed by C++ implementation
5
5
  Author-email: Nikita Vaganov <nikita.e.vaganov@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/vaganov/yatq
@@ -18,4 +18,9 @@ see [yatq homepage](https://github.com/vaganov/yatq)
18
18
 
19
19
  **NB:** Module name is, however, **pytq**
20
20
 
21
- from pytq import ThreadPool, TimerQueue, AwaitableFuture
21
+ from pytq import ThreadPool, TimerQueue, pythonize
22
+
23
+ **NB:** On _macOS_ one may need to specify **MACOSX_DEPLOYMENT_TARGET** environment variable on install. Do not set
24
+ higher than the current _macOS_ version. Minimal supported version is **13.4**
25
+
26
+ (venv) $ MACOSX_DEPLOYMENT_TARGET=13.4 pip install pytq-cxx
@@ -13,7 +13,7 @@ _yatq/include/yatq/internal/promise_utils.h
13
13
  _yatq/include/yatq/utils/logging_utils.h
14
14
  _yatq/include/yatq/utils/sched_utils.h
15
15
  pytq/__init__.py
16
- pytq/awaitable_future.py
16
+ pytq/pythonize.py
17
17
  pytq_cxx.egg-info/PKG-INFO
18
18
  pytq_cxx.egg-info/SOURCES.txt
19
19
  pytq_cxx.egg-info/dependency_links.txt
@@ -1,19 +0,0 @@
1
- import asyncio
2
-
3
-
4
- __all__ = ['AwaitableFuture']
5
-
6
-
7
- class AwaitableFuture:
8
- def __init__(self, future):
9
- self._future = future
10
-
11
- def __await__(self):
12
- while not self._future.is_ready():
13
- yield
14
- return self._future.get() # NB: return, not yield
15
-
16
- async def get(self):
17
- while not self._future.is_ready():
18
- await asyncio.sleep(0)
19
- return self._future.get()
File without changes
File without changes
File without changes
File without changes