vortexpy 6.0.0__tar.gz → 6.0.2__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 (153) hide show
  1. {vortexpy-6.0.0/vortexpy.egg-info → vortexpy-6.0.2}/PKG-INFO +3 -1
  2. {vortexpy-6.0.0 → vortexpy-6.0.2}/README.md +2 -0
  3. vortexpy-6.0.2/example/TwistedDeferredTimeout.py +50 -0
  4. vortexpy-6.0.2/example/__init__.py +1 -0
  5. vortexpy-6.0.2/example/run_http_upgraded_websocket_ping_client.py +68 -0
  6. vortexpy-6.0.2/example/run_http_upgraded_websocket_ping_server.py +71 -0
  7. vortexpy-6.0.2/example/run_http_upgraded_websocket_rpc_test_client.py +67 -0
  8. vortexpy-6.0.2/example/run_http_upgraded_websocket_rpc_test_server.py +45 -0
  9. vortexpy-6.0.2/example/run_websocket_rpc_test_client.py +64 -0
  10. vortexpy-6.0.2/example/run_websocket_rpc_test_server.py +29 -0
  11. vortexpy-6.0.2/example/setup_example_logging.py +44 -0
  12. vortexpy-6.0.2/example/store_and_load_json.py +68 -0
  13. {vortexpy-6.0.0 → vortexpy-6.0.2}/pyproject.toml +15 -1
  14. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/DeferUtil.py +25 -2
  15. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/DeferUtil_test.py +58 -0
  16. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/Jsonable.py +22 -4
  17. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadEndpoint.py +26 -8
  18. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadEndpointTest.py +1 -3
  19. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadEnvelope.py +9 -9
  20. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadIO.py +9 -2
  21. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadResponse.py +7 -3
  22. vortexpy-6.0.2/vortex/PayloadResponse_test.py +42 -0
  23. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/SerialiseUtil.py +85 -6
  24. vortexpy-6.0.2/vortex/SerialiseUtil_test.py +186 -0
  25. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/Tuple.py +50 -3
  26. vortexpy-6.0.2/vortex/TupleBson.py +203 -0
  27. vortexpy-6.0.2/vortex/TupleBson_test.py +300 -0
  28. vortexpy-6.0.0/vortex/TupleRestful.py → vortexpy-6.0.2/vortex/TupleDocumentConverter.py +288 -89
  29. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TuplePolymorphicTupleTypeFieldArgTest.py +4 -1
  30. vortexpy-6.0.2/vortex/TupleRestful.py +139 -0
  31. vortexpy-6.0.2/vortex/TupleRestful_test.py +209 -0
  32. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexFactory.py +8 -1
  33. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexPayloadProtocol.py +6 -2
  34. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexPermission.py +1 -0
  35. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexPermissionError.py +1 -0
  36. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServer.py +5 -6
  37. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServerHttpResource.py +10 -1
  38. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServerWebsocket.py +25 -3
  39. vortexpy-6.0.2/vortex/VortexServerWebsocket_test.py +22 -0
  40. vortexpy-6.0.2/vortex/VortexServer_test.py +148 -0
  41. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexSession.py +5 -3
  42. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexTcpMemoryLeakPayloadTest.py +24 -24
  43. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexUtil.py +2 -0
  44. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexWritePushProducer.py +9 -8
  45. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexWritePushProducer_test.py +10 -6
  46. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/__init__.py +1 -1
  47. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLoader.py +56 -53
  48. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLoaderDelegate.py +14 -4
  49. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/event_bus/TupleChangeEventBus.py +7 -8
  50. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionProcessor.py +69 -36
  51. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionProcessorProxy.py +7 -6
  52. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionProcessorTestHandler.py +3 -3
  53. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataAccessGranterABC.py +4 -4
  54. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObservableCache.py +7 -7
  55. vortexpy-6.0.2/vortex/handler/TupleDataObservableCache_test.py +28 -0
  56. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObservableHandler.py +42 -35
  57. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObservableHandler_test.py +210 -2
  58. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObservableProxyHandler.py +47 -38
  59. vortexpy-6.0.2/vortex/handler/TupleDataObservableProxyHandler_test.py +214 -0
  60. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObserverClient.py +19 -6
  61. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataProviderABC.py +3 -1
  62. vortexpy-6.0.2/vortex/payload_many_tuples_benchmark_test.py +71 -0
  63. vortexpy-6.0.2/vortex/restful/restful_http_client_test.py +73 -0
  64. vortexpy-6.0.2/vortex/restful/restful_resource_test.py +76 -0
  65. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/rpc/RPC.py +71 -39
  66. vortexpy-6.0.2/vortex/rpc/RPC_test.py +114 -0
  67. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/sqla_orm/OrmCrudHandler.py +1 -4
  68. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/storage/TupleStorageSqlite.py +3 -3
  69. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/tuple_json_schema_builder.py +3 -1
  70. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/tuple_json_schema_test.py +4 -2
  71. vortexpy-6.0.2/vortex/tuple_test_fixtures.py +206 -0
  72. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/twisted_runtime_metrics.py +92 -48
  73. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/twisted_runtime_metrics_test.py +7 -7
  74. {vortexpy-6.0.0 → vortexpy-6.0.2/vortexpy.egg-info}/PKG-INFO +3 -1
  75. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortexpy.egg-info/SOURCES.txt +25 -3
  76. vortexpy-6.0.2/vortexpy.egg-info/top_level.txt +2 -0
  77. vortexpy-6.0.0/vortex/TupleRestfulTest.py +0 -267
  78. vortexpy-6.0.0/vortex/restful/RestfulHttpClientTest.py +0 -68
  79. vortexpy-6.0.0/vortex/restful/RestfulResourceTest.py +0 -108
  80. vortexpy-6.0.0/vortexpy.egg-info/top_level.txt +0 -1
  81. {vortexpy-6.0.0 → vortexpy-6.0.2}/LICENSE +0 -0
  82. {vortexpy-6.0.0 → vortexpy-6.0.2}/setup.cfg +0 -0
  83. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/DataWrapTuple.py +0 -0
  84. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/MtlsAuthorizedClientRegistry.py +0 -0
  85. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/MtlsAuthorizedClientRegistry_test.py +0 -0
  86. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/MtlsServerSslOptions.py +0 -0
  87. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/Payload.py +0 -0
  88. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadFilterKeys.py +0 -0
  89. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadPriority.py +0 -0
  90. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadResponseTest.py +0 -0
  91. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PayloadTest.py +0 -0
  92. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/PerformTestActionTuple.py +0 -0
  93. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TestTuple.py +0 -0
  94. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TupleAction.py +0 -0
  95. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TupleDataForTest.py +0 -0
  96. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TuplePerfTest.py +0 -0
  97. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TupleSelector.py +0 -0
  98. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/TupleTest.py +0 -0
  99. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexABC.py +0 -0
  100. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexAccessControlContextABC.py +0 -0
  101. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexAuthenticatorABC.py +0 -0
  102. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexClientHttp.py +0 -0
  103. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexClientHttpTest.py +0 -0
  104. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexClientTcp.py +0 -0
  105. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexClientWebsocketFactory.py +0 -0
  106. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexConnectionABC.py +0 -0
  107. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexEndpointPermission.py +0 -0
  108. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexFactory_test.py +0 -0
  109. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServerConnection.py +0 -0
  110. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServerConnection_test.py +0 -0
  111. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexServerTcp.py +0 -0
  112. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexSession_test.py +0 -0
  113. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexTcpMemoryLeakRawTest.py +0 -0
  114. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexTest.py +0 -0
  115. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/VortexUserDetailsABC.py +0 -0
  116. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLiveLockManager.py +0 -0
  117. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLiveLockManager_test.py +0 -0
  118. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLoaderTupleABC.py +0 -0
  119. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/TupleDataLoaderTuples.py +0 -0
  120. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/data_loader/__init__.py +0 -0
  121. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/event_bus/TupleChangeEventABC.py +0 -0
  122. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/event_bus/TupleChangeEventBusObserverABC.py +0 -0
  123. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/event_bus/__init__.py +0 -0
  124. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionProcessor_shutdown_test.py +0 -0
  125. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionProcessor_test.py +0 -0
  126. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionPushOffline.py +0 -0
  127. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleActionPushOffline_test.py +0 -0
  128. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataActionClient.py +0 -0
  129. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/TupleDataObservableTestHandler.py +0 -0
  130. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/VortexJSTupleLoaderTestHandler.py +0 -0
  131. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/handler/__init__.py +0 -0
  132. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/mypy_plugin.py +0 -0
  133. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/py.typed +0 -0
  134. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/GzippedDataHttpClient.py +0 -0
  135. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/GzippedDataHttpClientTest.py +0 -0
  136. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/GzippedPayloadHttpClient.py +0 -0
  137. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/RestfulHttpClient.py +0 -0
  138. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/RestfulResource.py +0 -0
  139. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/restful/__init__.py +0 -0
  140. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/rpc/RPCTest.py +0 -0
  141. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/rpc/__init__.py +0 -0
  142. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/sqla_orm/TupleProviderForDb.py +0 -0
  143. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/sqla_orm/VortexTupleJson.py +0 -0
  144. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/sqla_orm/__init__.py +0 -0
  145. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/storage/TupleActionStorageSqlite.py +0 -0
  146. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/storage/__init__.py +0 -0
  147. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/__init__.py +0 -0
  148. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/constants.py +0 -0
  149. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/json_schema_node_tuple.py +0 -0
  150. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortex/tuple_json_schema/tuple_json_schema_test_tuples.py +0 -0
  151. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortexpy.egg-info/dependency_links.txt +0 -0
  152. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortexpy.egg-info/entry_points.txt +0 -0
  153. {vortexpy-6.0.0 → vortexpy-6.0.2}/vortexpy.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vortexpy
3
- Version: 6.0.0
3
+ Version: 6.0.2
4
4
  Summary: Flying Ion's observable, routable, data serialisation and transport code.
5
5
  Author-email: Flying Ion Pty Ltd <contact@flyingion.com>
6
6
  License: MIT
@@ -34,6 +34,8 @@ Flying Ion's observable, routable, data serialisation and transport code.
34
34
  See [README_PERMISSIONS.md](README_PERMISSIONS.md) for the two-level permission
35
35
  system (endpoint guards + access control context) introduced in v6.0.
36
36
 
37
+ **Tuple and Payload tutorials:** [docs/README.md](docs/README.md) (simple → full features, encode/decode, threaded decode).
38
+
37
39
  Why PY at the end? To be consistent with VortexJS, which is the Browser side package.
38
40
  See https://gitlab.com/flyingion/vortexjs
39
41
 
@@ -5,6 +5,8 @@ Flying Ion's observable, routable, data serialisation and transport code.
5
5
  See [README_PERMISSIONS.md](README_PERMISSIONS.md) for the two-level permission
6
6
  system (endpoint guards + access control context) introduced in v6.0.
7
7
 
8
+ **Tuple and Payload tutorials:** [docs/README.md](docs/README.md) (simple → full features, encode/decode, threaded decode).
9
+
8
10
  Why PY at the end? To be consistent with VortexJS, which is the Browser side package.
9
11
  See https://gitlab.com/flyingion/vortexjs
10
12
 
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ # from twisted.internet import task, defer
10
+ #
11
+ # def logTimeout(result, timeout):
12
+ # print("Got {0!r} but actually timed out after {1} seconds".format(
13
+ # result, timeout))
14
+ # return result + " (timed out)"
15
+ #
16
+ # def main(reactor):
17
+ # # generate a deferred with a custom canceller function, and never
18
+ # # never callback or errback it to guarantee it gets timed out
19
+ # d = defer.Deferred()#lambda c: c.callback("Everything's ok!"))
20
+ # d.addTimeout(2, reactor)#, onTimeoutCancel=logTimeout)
21
+ # d.addBoth(print)
22
+ # return d
23
+ #
24
+ # task.react(main)
25
+ #
26
+
27
+
28
+ import random
29
+
30
+ from twisted.internet import task
31
+
32
+
33
+ def f():
34
+ return "Hopefully this will be called in 3 seconds or less"
35
+
36
+
37
+ def main(reactor):
38
+ delay = random.uniform(1, 5)
39
+
40
+ def called(result):
41
+ print("{0} seconds later:".format(delay), result)
42
+
43
+ d = task.deferLater(reactor, delay, f)
44
+ d.addTimeout(3, reactor).addBoth(called)
45
+
46
+ return d
47
+
48
+
49
+ # f() will be timed out if the random delay is greater than 3 seconds
50
+ task.react(main)
@@ -0,0 +1 @@
1
+ """Vortexpy runnable examples and local test servers."""
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ from datetime import datetime
11
+
12
+ import pytz
13
+ from twisted.internet import task
14
+ from twisted.internet.defer import inlineCallbacks
15
+
16
+ from example.setup_example_logging import setupExampleLogging
17
+ from vortex.PayloadEnvelope import PayloadEnvelope
18
+ from vortex.PayloadResponse import PayloadResponse
19
+ from vortex.VortexClientWebsocketFactory import VortexClientWebsocketFactory
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+
24
+ setupExampleLogging()
25
+
26
+ if __name__ == "__main__":
27
+ import sys
28
+
29
+ from twisted.python import log
30
+ from twisted.internet import reactor, ssl
31
+
32
+ log.startLogging(sys.stdout)
33
+
34
+ @inlineCallbacks
35
+ def sendMessage():
36
+ factory = VortexClientWebsocketFactory(
37
+ "test_websocket", url="ws://127.0.0.1:9000/vortexws"
38
+ )
39
+ yield factory.connect("127.0.0.1", 9000, ssl.ClientContextFactory())
40
+
41
+ filt = {
42
+ "key": "ws_test",
43
+ }
44
+
45
+ while True:
46
+ payloadEnvelope = PayloadEnvelope(filt)
47
+ payloadEnvelope.encodedPayload = b"*" * 163880
48
+ responseDeferred = PayloadResponse(payloadEnvelope)
49
+ logger.info(payloadEnvelope.date)
50
+
51
+ # factory.sendVortexMsg(payload.toVortexMsg())
52
+
53
+ factory.sendVortexMsg(
54
+ payloadEnvelope.toVortexMsg(base64Encode=False)
55
+ )
56
+ logger.info(payloadEnvelope.date)
57
+
58
+ yield responseDeferred
59
+ logger.info(
60
+ "CALL COMPLETE, Time Taken: %s",
61
+ datetime.now(pytz.utc) - payloadEnvelope.date,
62
+ )
63
+
64
+ yield task.deferLater(reactor, 5, lambda: None)
65
+
66
+ reactor.callLater(0.5, sendMessage)
67
+
68
+ reactor.run()
@@ -0,0 +1,71 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ import os
11
+
12
+ from twisted.web import server
13
+ from txwebsocket.txws import WebSocketUpgradeHTTPChannel
14
+
15
+ from example.setup_example_logging import setupExampleLogging
16
+ from txhttputil.site.FileUnderlayResource import FileUnderlayResource
17
+ from vortex.PayloadEndpoint import PayloadEndpoint
18
+ from vortex.PayloadEnvelope import PayloadEnvelope
19
+ from vortex.VortexABC import SendVortexMsgResponseCallable
20
+ from vortex.VortexFactory import VortexFactory
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ setupExampleLogging()
25
+
26
+ if __name__ == "__main__":
27
+ import sys
28
+
29
+ from twisted.python import log
30
+ from twisted.internet import reactor
31
+
32
+ log.startLogging(sys.stdout)
33
+
34
+ resource = FileUnderlayResource()
35
+ resource.enableSinglePageApplication()
36
+ resource.addFileSystemRoot(
37
+ os.path.dirname(os.path.realpath(__file__)) + "/test_serve"
38
+ )
39
+
40
+ site = server.Site(resource)
41
+ site.protocol = WebSocketUpgradeHTTPChannel
42
+
43
+ class Test:
44
+ def logDate(
45
+ self,
46
+ payloadEnvelope: PayloadEnvelope,
47
+ sendResponse: SendVortexMsgResponseCallable,
48
+ *args,
49
+ **kwargs,
50
+ ):
51
+ logger.info(payloadEnvelope.filt)
52
+ logger.info(payloadEnvelope.date)
53
+
54
+ sendResponse(payloadEnvelope.toVortexMsg())
55
+
56
+ test = Test()
57
+ endpoint = PayloadEndpoint(
58
+ filt={
59
+ "key": "ws_test",
60
+ },
61
+ callable_=test.logDate,
62
+ )
63
+
64
+ # VortexFactory.createWebsocketServer("test_websocket", 9000)
65
+
66
+ VortexFactory.createHttpWebsocketServer("vortexws", resource)
67
+ reactor.listenTCP(9000, site)
68
+
69
+ reactor.run()
70
+
71
+ endpoint.shutdown()
@@ -0,0 +1,67 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ from datetime import datetime
11
+
12
+ import pytz
13
+ from twisted.internet import reactor
14
+ from twisted.internet import task
15
+ from twisted.internet.defer import inlineCallbacks
16
+
17
+ from example.setup_example_logging import setupExampleLogging
18
+ from vortex.DeferUtil import vortexLogFailure
19
+ from vortex.VortexFactory import VortexFactory
20
+ from vortex.rpc.RPCTest import myRemoteAddMethod
21
+ from vortex.rpc.RPCTest import myRemoteExceptionMethod
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ setupExampleLogging()
26
+
27
+
28
+ @inlineCallbacks
29
+ def connect():
30
+ # BEGIN WEBSOCKET HTTP UPGRADED CLIENT CONNECT
31
+
32
+ yield VortexFactory.createWebsocketClient(
33
+ name="sendVortexName",
34
+ host="127.0.0.1",
35
+ port=10101,
36
+ url="ws://127.0.0.1:10101/vortexws",
37
+ )
38
+ # END WEBSOCKET HTTP UPGRADED CLIENT CONNECT
39
+
40
+
41
+ def callRpcException():
42
+ d = myRemoteExceptionMethod(7, kwarg1=4)
43
+ d.addCallback(lambda v: logger.debug("SUCCESS, result = %s", v))
44
+ d.addErrback(vortexLogFailure, logger)
45
+ return d
46
+
47
+
48
+ @inlineCallbacks
49
+ def callRpc():
50
+ while True:
51
+ startDate = datetime.now(pytz.utc)
52
+ v = yield myRemoteAddMethod(7, kwarg1=4)
53
+ logger.debug(
54
+ "CALL COMPLETE, result = %s, Time Taken: %s",
55
+ v,
56
+ datetime.now(pytz.utc) - startDate,
57
+ )
58
+
59
+ yield task.deferLater(reactor, 5, lambda: None)
60
+
61
+
62
+ if __name__ == "__main__":
63
+ reactor.callLater(0, logger.info, "RPCTest client running")
64
+ reactor.callLater(0, connect)
65
+ reactor.callLater(25, callRpcException)
66
+ reactor.callLater(28, callRpc)
67
+ reactor.run()
@@ -0,0 +1,45 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ import os
11
+
12
+ from twisted.internet import reactor
13
+ from twisted.web import server
14
+ from txhttputil.site.FileUnderlayResource import FileUnderlayResource
15
+ from txwebsocket.txws import WebSocketUpgradeHTTPChannel
16
+
17
+ from example.setup_example_logging import setupExampleLogging
18
+ from vortex.VortexFactory import VortexFactory
19
+ from vortex.rpc.RPCTest import myRemoteAddMethod
20
+ from vortex.rpc.RPCTest import myRemoteExceptionMethod
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ setupExampleLogging()
25
+
26
+ if __name__ == "__main__":
27
+ # BEGIN WEBSOCKET HTTP UPGRADED CLIENT CONNECT
28
+ resource = FileUnderlayResource()
29
+ resource.enableSinglePageApplication()
30
+ resource.addFileSystemRoot(
31
+ os.path.dirname(os.path.realpath(__file__)) + "/test_serve"
32
+ )
33
+
34
+ site = server.Site(resource)
35
+ site.protocol = WebSocketUpgradeHTTPChannel
36
+
37
+ VortexFactory.createHttpWebsocketServer("listenVortexName", resource)
38
+ reactor.listenTCP(10101, site)
39
+ # END WEBSOCKET HTTP UPGRADED CLIENT CONNECT
40
+
41
+ reactor.callLater(0, logger.info, "RPCTest server running")
42
+
43
+ reactor.callLater(0, myRemoteExceptionMethod.start)
44
+ reactor.callLater(0, myRemoteAddMethod.start)
45
+ reactor.run()
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ from datetime import datetime
11
+
12
+ import pytz
13
+ from twisted.internet import reactor
14
+ from twisted.internet import task
15
+ from twisted.internet.defer import inlineCallbacks
16
+
17
+ from example.setup_example_logging import setupExampleLogging
18
+ from vortex.DeferUtil import vortexLogFailure
19
+ from vortex.VortexFactory import VortexFactory
20
+ from vortex.rpc.RPCTest import myRemoteAddMethod
21
+ from vortex.rpc.RPCTest import myRemoteExceptionMethod
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+ setupExampleLogging()
26
+
27
+
28
+ @inlineCallbacks
29
+ def connect():
30
+ # BEGIN WEBSOCKET CLIENT CONNECT
31
+ yield VortexFactory.createWebsocketClient(
32
+ "sendVortexName", "127.0.0.1", 10102, "ws://127.0.0.1:10102/vortexws"
33
+ )
34
+ # END WEBSOCKET CLIENT CONNECT
35
+
36
+ reactor.callLater(2, callRpcException)
37
+ reactor.callLater(5, callRpc)
38
+
39
+
40
+ def callRpcException():
41
+ d = myRemoteExceptionMethod(7, kwarg1=4)
42
+ d.addCallback(lambda v: logger.debug("SUCCESSS, result = %s", v))
43
+ d.addErrback(vortexLogFailure, logger)
44
+ return d
45
+
46
+
47
+ @inlineCallbacks
48
+ def callRpc():
49
+ while True:
50
+ startDate = datetime.now(pytz.utc)
51
+ v = yield myRemoteAddMethod(7, kwarg1=4)
52
+ logger.debug(
53
+ "CALL COMPLETE, result = %s, Time Taken: %s",
54
+ v,
55
+ datetime.now(pytz.utc) - startDate,
56
+ )
57
+
58
+ yield task.deferLater(reactor, 5, lambda: None)
59
+
60
+
61
+ if __name__ == "__main__":
62
+ reactor.callLater(0, logger.info, "RPCTest client running")
63
+ reactor.callLater(0, connect)
64
+ reactor.run()
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+
11
+ from twisted.internet import reactor
12
+
13
+ from vortex.VortexFactory import VortexFactory
14
+ from vortex.rpc.RPCTest import myRemoteAddMethod
15
+ from vortex.rpc.RPCTest import myRemoteExceptionMethod
16
+
17
+ logger = logging.getLogger(__name__)
18
+ logging.basicConfig()
19
+
20
+ if __name__ == "__main__":
21
+ # BEGIN WEBSOCKET CLIENT CONNECT
22
+ VortexFactory.createWebsocketServer("listenVortexName", 10102)
23
+ # END WEBSOCKET CLIENT CONNECT
24
+
25
+ reactor.callLater(0, logger.info, "RPCTest server running")
26
+
27
+ reactor.callLater(0, myRemoteExceptionMethod.start)
28
+ reactor.callLater(0, myRemoteAddMethod.start)
29
+ reactor.run()
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import logging
10
+ import sys
11
+ from datetime import datetime
12
+
13
+ from twisted.internet import defer
14
+
15
+
16
+ def setupExampleLogging():
17
+ defer.setDebugging(True)
18
+ logging.root.setLevel(logging.DEBUG)
19
+
20
+ console = logging.StreamHandler()
21
+ logging.root.addHandler(console)
22
+
23
+ class MyFormatter(logging.Formatter):
24
+ converter = datetime.fromtimestamp
25
+
26
+ def formatTime(self, record, datefmt=None):
27
+ ct = self.converter(record.created)
28
+ if datefmt:
29
+ s = ct.strftime(datefmt)
30
+ else:
31
+ t = ct.strftime("%Y-%m-%d %H:%M:%S")
32
+ s = "%s,%03d" % (t, record.msecs)
33
+ return s
34
+
35
+ formatter = MyFormatter(
36
+ fmt="%(asctime)s %(message)s", datefmt="%Y-%m-%d,%H:%M:%S.%f"
37
+ )
38
+ console.setFormatter(formatter)
39
+
40
+ # Start the twisted logging
41
+
42
+ from twisted.python import log
43
+
44
+ log.startLogging(sys.stdout)
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2016-2026 Flying Ion Pty Ltd
2
+ #
3
+ # This software is open source; the MIT license applies.
4
+ # See LICENSE for the full license text.
5
+ #
6
+ # Website : https://flyingion.com
7
+ # Support : contact@flyingion.com
8
+
9
+ import json
10
+ import os.path
11
+
12
+ from vortex.Tuple import Tuple
13
+ from vortex.Tuple import TupleField
14
+ from vortex.Tuple import addTupleType
15
+
16
+ JSON_DIR = os.path.expanduser("~/my-app-storage.json")
17
+
18
+
19
+ @addTupleType
20
+ class MyItem(Tuple):
21
+ __tupleType__ = "MyItem"
22
+ myBool: bool = TupleField()
23
+ myStr: str = TupleField()
24
+
25
+
26
+ @addTupleType
27
+ class MyData(Tuple):
28
+ __tupleType__ = "MyData"
29
+ myItems: list[MyItem] = TupleField([])
30
+ myName: str = TupleField()
31
+
32
+
33
+ def store(tuple_: Tuple):
34
+ jsonObj = tuple_.tupleToRestfulJsonDict()
35
+ jsonStr = json.dumps(
36
+ jsonObj,
37
+ indent=4,
38
+ sort_keys=True,
39
+ separators=(", ", ": "),
40
+ )
41
+
42
+ with open(JSON_DIR, "wb") as f:
43
+ f.write(jsonStr.encode())
44
+ f.write(b"\n")
45
+
46
+
47
+ def load() -> MyData:
48
+ with open(JSON_DIR, "rb") as f:
49
+ jsonStr = f.read().decode()
50
+
51
+ jsonObj = json.loads(jsonStr)
52
+
53
+ tuple_ = Tuple.restfulJsonDictToTupleWithValidation(jsonObj, MyData)
54
+ assert isinstance(tuple_, MyData), "tuple_ is not of type MyData"
55
+ return tuple_
56
+
57
+
58
+ if __name__ == "__main__":
59
+ # Make the data
60
+ myData = MyData(myName="A good name")
61
+ myData.myItems.append(MyItem(myBool=False, myStr="store me"))
62
+ myData.myItems.append(MyItem(myBool=True, myStr="and me too"))
63
+
64
+ store(myData)
65
+
66
+ myLoadedData = load()
67
+
68
+ assert myData.myName == myLoadedData.myName, "myName didn't load correctly"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "vortexpy"
7
- version = "6.0.0"
7
+ version = "6.0.2"
8
8
  license = {text = "MIT"}
9
9
  authors = [{name = "Flying Ion Pty Ltd", email = "contact@flyingion.com"}]
10
10
  description = "Flying Ion's observable, routable, data serialisation and transport code."
@@ -53,3 +53,17 @@ namespaces = false
53
53
 
54
54
  [project.entry-points."mypy.plugins"]
55
55
  vortex_defer = "vortex.mypy_plugin:plugin"
56
+
57
+ [tool.pytest.ini_options]
58
+ testpaths = ["vortex"]
59
+ python_files = ["*_test.py"]
60
+ python_functions = ["test*"]
61
+ norecursedirs = ["_trial_temp", "example", "old_fork"]
62
+ markers = [
63
+ "trial: legacy Twisted Trial *Test.py modules (not collected; run with trial CLI)",
64
+ "slow: large payload or timing benchmarks",
65
+ "integration: docker or multi-process integration suites under test-integration/",
66
+ ]
67
+
68
+ [tool.taskipy.tasks]
69
+ test-integrations = "bash -c 'pytest test-integration/ -xvs -m integration'"
@@ -32,6 +32,7 @@ def callMethodLater(func):
32
32
  def wrapper(*args, **kwargs):
33
33
  return reactor.callLater(0, func, *args, **kwargs)
34
34
 
35
+ wrapper.__wrapped__ = func
35
36
  return wrapper
36
37
 
37
38
 
@@ -46,7 +47,7 @@ def nonConcurrentMethod(method):
46
47
  call.running = False
47
48
 
48
49
  call.running = False
49
-
50
+ call.__wrapped__ = method
50
51
  return call
51
52
 
52
53
 
@@ -60,6 +61,7 @@ def maybeDeferredWrap(funcToWrap):
60
61
  def func(*args, **kwargs):
61
62
  return maybeDeferred(funcToWrap, *args, **kwargs)
62
63
 
64
+ func.__wrapped__ = funcToWrap
63
65
  return func
64
66
 
65
67
 
@@ -78,6 +80,7 @@ def ensureDeferredWrap(funcToWrap):
78
80
  def func(*args, **kwargs):
79
81
  return ensureDeferred(funcToWrap(*args, **kwargs))
80
82
 
83
+ func.__wrapped__ = funcToWrap
81
84
  return func
82
85
 
83
86
 
@@ -140,6 +143,7 @@ def vortexInlineCallbacksLogAndConsumeFailure(loggerArg):
140
143
  d.addErrback(vortexLogAndConsumeFailure, loggerArg)
141
144
  return d
142
145
 
146
+ called.__wrapped__ = funcToWrap
143
147
  return called
144
148
 
145
149
  return wrapper
@@ -153,6 +157,7 @@ def deferToThreadWrapWithLogger(
153
157
  loggerArg: logging.Logger,
154
158
  consumeError: bool = False,
155
159
  checkMainThread: bool = True,
160
+ logException: bool = True,
156
161
  ) -> Callable[[Callable[_P, _R]], Callable[_P, Deferred[_R]]]:
157
162
  """Defer To Thread Wrap With Logger
158
163
 
@@ -163,6 +168,9 @@ def deferToThreadWrapWithLogger(
163
168
  :param checkMainThread: Don't use this parameter, it's only needed during reactor
164
169
  startup when the reactors thread isn't properly set and the check
165
170
  fails.
171
+ :param logException: When True, thread exceptions are logged at ERROR with a full
172
+ traceback. When False, the same events are logged at DEBUG with a
173
+ neutral message so log analysers are not triggered.
166
174
 
167
175
  :return: A decorator that makes the wrapped callable return a Deferred.
168
176
 
@@ -230,11 +238,26 @@ def deferToThreadWrapWithLogger(
230
238
  methodFrame,
231
239
  )
232
240
 
241
+ def handleFailure(failure):
242
+ if logException:
243
+ return vortexLogFailure(
244
+ failure, loggerArg, consumeError=consumeError
245
+ )
246
+
247
+ loggerArg.debug(
248
+ "Threaded call failed in %s.%s: %s",
249
+ funcToWrap.__module__,
250
+ funcToWrap.__qualname__,
251
+ failure.getErrorMessage(),
252
+ )
253
+ return True if consumeError else failure
254
+
233
255
  d: Deferred[_R] = deferToThread(timedFuncToRun, *args, **kwargs)
234
256
  d.addCallback(checkForInlineCallbackYield)
235
- d.addErrback(vortexLogFailure, loggerArg, consumeError=consumeError)
257
+ d.addErrback(handleFailure)
236
258
  return d
237
259
 
260
+ func.__wrapped__ = funcToWrap
238
261
  return func
239
262
 
240
263
  return wrapper