phanos 0.3.2__tar.gz → 0.3.3__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 (31) hide show
  1. {phanos-0.3.2 → phanos-0.3.3}/CHANGELOG.md +9 -0
  2. {phanos-0.3.2 → phanos-0.3.3}/PKG-INFO +2 -2
  3. {phanos-0.3.2 → phanos-0.3.3}/pyproject.toml +1 -1
  4. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/tree.py +4 -2
  5. {phanos-0.3.2 → phanos-0.3.3}/test/test_tree.py +28 -0
  6. {phanos-0.3.2 → phanos-0.3.3}/.gitignore +0 -0
  7. {phanos-0.3.2 → phanos-0.3.3}/LICENSE +0 -0
  8. {phanos-0.3.2 → phanos-0.3.3}/README.md +0 -0
  9. {phanos-0.3.2 → phanos-0.3.3}/requirements-dev.txt +0 -0
  10. {phanos-0.3.2 → phanos-0.3.3}/requirements.txt +0 -0
  11. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/__init__.py +0 -0
  12. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/config.py +0 -0
  13. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/log.py +0 -0
  14. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/messaging.py +0 -0
  15. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/metrics.py +0 -0
  16. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/publisher.py +0 -0
  17. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/py.typed +0 -0
  18. {phanos-0.3.2 → phanos-0.3.3}/src/phanos/types.py +0 -0
  19. {phanos-0.3.2 → phanos-0.3.3}/test/__init__.py +0 -0
  20. {phanos-0.3.2 → phanos-0.3.3}/test/common.py +0 -0
  21. {phanos-0.3.2 → phanos-0.3.3}/test/dummy_api.py +0 -0
  22. {phanos-0.3.2 → phanos-0.3.3}/test/profiling.py +0 -0
  23. {phanos-0.3.2 → phanos-0.3.3}/test/run_tests.py +0 -0
  24. {phanos-0.3.2 → phanos-0.3.3}/test/test_async.py +0 -0
  25. {phanos-0.3.2 → phanos-0.3.3}/test/test_config.py +0 -0
  26. {phanos-0.3.2 → phanos-0.3.3}/test/test_handlers.py +0 -0
  27. {phanos-0.3.2 → phanos-0.3.3}/test/test_messaging.py +0 -0
  28. {phanos-0.3.2 → phanos-0.3.3}/test/test_metrics.py +0 -0
  29. {phanos-0.3.2 → phanos-0.3.3}/test/test_publisher.py +0 -0
  30. {phanos-0.3.2 → phanos-0.3.3}/test/test_sync.py +0 -0
  31. {phanos-0.3.2 → phanos-0.3.3}/test/testing_data.py +0 -0
@@ -6,6 +6,14 @@ this file.
6
6
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
7
7
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [0.3.3] - 2026-10-26
10
+
11
+ ### Fixed
12
+
13
+ - `ContextTree.find_and_delete_node` searched only the first branch of the tree - with concurrent requests
14
+ (async) a node of a finished request was not found and stayed in the tree forever (memory leak)
15
+ - `ContextTree.clear` skipped every other sibling node
16
+
9
17
  ## [0.3.2] - 2024-03-21
10
18
 
11
19
  ### Changed
@@ -14,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
14
22
  - `Profiler.tree` is now initialized in `Profiler.__init__` instead of in configuration methods
15
23
 
16
24
  ### Fixed
25
+
17
26
  - `curr_node` ContextVar and `Profiler.tree` are now properly initialized in `Profiler` instance
18
27
 
19
28
  ## [0.3.1] - 2024-03-21
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.5
2
2
  Name: phanos
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Python client to gather data for Prometheus logging in server with multiple instances and workers.
5
5
  Project-URL: Homepage, https://github.com/kajotgames/phanos
6
6
  Project-URL: Bug Tracker, https://github.com/kajotgames/phanos/issues
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "phanos"
7
- version = "0.3.2"
7
+ version = "0.3.3"
8
8
  authors = [
9
9
  { name="Miroslav Bulička", email="bulickamiroslav@gmail.com" },
10
10
  ]
@@ -122,7 +122,8 @@ class ContextTree(log.InstanceLoggerMixin):
122
122
  return deleted
123
123
 
124
124
  for child in root.children:
125
- return self._find_and_delete_node(node, child)
125
+ if self._find_and_delete_node(node, child):
126
+ return True
126
127
 
127
128
  return False
128
129
 
@@ -141,7 +142,8 @@ class ContextTree(log.InstanceLoggerMixin):
141
142
 
142
143
  def _clear(self, root: MethodTreeNode) -> None:
143
144
  """Deletes whole subtree starting from param 'root'. Deletes from bottom to top"""
144
- for child in root.children:
145
+ # a copy - deleting a child removes it from `root.children`
146
+ for child in list(root.children):
145
147
  self._clear(child)
146
148
 
147
149
  if not root == self.root:
@@ -153,6 +153,21 @@ class TestContextTree(unittest.TestCase):
153
153
  self.assertTrue(ctx_tree.find_and_delete_node(node))
154
154
  mock_delete_node.assert_called_with(node)
155
155
 
156
+ @unittest.skipUnless(test_init, SKIP_REASON_INIT)
157
+ def test_find_and_delete_node_beyond_first_branch(self):
158
+ """concurrent requests leave sibling nodes - a node in any branch must be found, not only in the first one"""
159
+ ctx_tree, node, child1, child2 = construct_tree()
160
+ sibling = MethodTreeNode(dummy_api.DummyDbAccess.test_method)
161
+ ctx_tree.root.add_child(sibling)
162
+
163
+ with self.subTest("second child of the root"):
164
+ self.assertTrue(ctx_tree.find_and_delete_node(sibling))
165
+ self.assertEqual(ctx_tree.root.children, [node])
166
+
167
+ with self.subTest("second child of a nested node"):
168
+ self.assertTrue(ctx_tree.find_and_delete_node(child2))
169
+ self.assertEqual(node.children, [child1])
170
+
156
171
  @unittest.skipUnless(test_init, SKIP_REASON_INIT)
157
172
  @patch("src.phanos.tree.ContextTree.delete_node")
158
173
  def test_clear(self, mock_delete_node: MagicMock):
@@ -166,3 +181,16 @@ class TestContextTree(unittest.TestCase):
166
181
  self.assertIn(node, call_nodes)
167
182
  self.assertIn(child1, call_nodes)
168
183
  self.assertIn(child2, call_nodes)
184
+
185
+ @unittest.skipUnless(test_init, SKIP_REASON_INIT)
186
+ def test_clear_deletes_all_siblings(self):
187
+ ctx_tree, node, child1, child2 = construct_tree()
188
+ siblings = [MethodTreeNode(dummy_api.DummyDbAccess.test_method) for _ in range(3)]
189
+ for sibling in siblings:
190
+ ctx_tree.root.add_child(sibling)
191
+
192
+ ctx_tree.clear()
193
+
194
+ self.assertEqual(ctx_tree.root.children, [])
195
+ for deleted in [node, child1, child2, *siblings]:
196
+ self.assertIsNone(deleted.parent)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes