pyquerytracker 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 MuddyHope
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyquerytracker
3
+ Version: 0.1.0
4
+ Summary: A lightweight, decorator-based query performance tracking library for Python applications. Monitor and analyze database query performance with ease.
5
+ Author-email: MuddyHope <daktarisun@gmail.com>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/MuddyHope/pyquerytracker
8
+ Project-URL: Issues, https://github.com/MuddyHope/pyquerytracker/issues
9
+ Keywords: performance,database,query,decorator,tracking
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # 🐍 pyquerytracker
24
+
25
+ **pyquerytracker** is a lightweight Python utility to **track and analyze database query performance** using simple decorators. It enables developers to gain visibility into SQL execution time, log metadata, and export insights in JSON format — with optional FastAPI integration and scheduled reporting.
26
+
27
+ ---
28
+
29
+ ## 🚀 Features
30
+
31
+ - ✅ Easy-to-use decorator to track function execution (e.g., SQL queries)
32
+ - ✅ Capture runtime, function name, args, return values, and more
33
+
34
+ ## TODO Features
35
+ - ✅ Export logs to JSON or CSV
36
+ - ✅ FastAPI integration to expose tracked metrics via REST API
37
+ - ✅ Schedule periodic exports using `APScheduler`
38
+ - ✅ Plug-and-play with any Python database client (SQLAlchemy, psycopg2, etc.)
39
+ - ✅ Modular and extensible design
40
+
41
+ ---
42
+
43
+ ## 📦 Installation
44
+
45
+ ```bash
46
+ pip install pyquerytracker
47
+ ```
48
+
49
+ ## Usage
50
+ ### Basic Usage
51
+ ```python
52
+ import time
53
+ from pyquerytracker import TrackQuery
54
+
55
+ @TrackQuery()
56
+ def run_query():
57
+ time.sleep(0.3) # Simulate SQL execution
58
+ return "SELECT * FROM users;"
59
+
60
+ run_query()
61
+ ```
62
+ ### Output
63
+ ```bash
64
+ 2025-06-14 14:23:00,123 - pyquerytracker - INFO - Function run_query executed successfully in 305.12ms
65
+ ```
66
+
67
+ ### With Configure
68
+ ```
69
+ import logging
70
+ from pyquerytracker.config import configure
71
+
72
+ configure(
73
+ slow_log_threshold_ms=200, # Log queries slower than 200ms
74
+ slow_log_level=logging.DEBUG # Use DEBUG level for slow logs
75
+ )
76
+ ```
77
+
78
+ ### Output
79
+ ```bash
80
+ 2025-06-14 14:24:45,456 - pyquerytracker - WARNING - Slow execution: run_query took 501.87ms
81
+ ```
82
+
83
+
84
+
@@ -0,0 +1,62 @@
1
+ # 🐍 pyquerytracker
2
+
3
+ **pyquerytracker** is a lightweight Python utility to **track and analyze database query performance** using simple decorators. It enables developers to gain visibility into SQL execution time, log metadata, and export insights in JSON format — with optional FastAPI integration and scheduled reporting.
4
+
5
+ ---
6
+
7
+ ## 🚀 Features
8
+
9
+ - ✅ Easy-to-use decorator to track function execution (e.g., SQL queries)
10
+ - ✅ Capture runtime, function name, args, return values, and more
11
+
12
+ ## TODO Features
13
+ - ✅ Export logs to JSON or CSV
14
+ - ✅ FastAPI integration to expose tracked metrics via REST API
15
+ - ✅ Schedule periodic exports using `APScheduler`
16
+ - ✅ Plug-and-play with any Python database client (SQLAlchemy, psycopg2, etc.)
17
+ - ✅ Modular and extensible design
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
22
+
23
+ ```bash
24
+ pip install pyquerytracker
25
+ ```
26
+
27
+ ## Usage
28
+ ### Basic Usage
29
+ ```python
30
+ import time
31
+ from pyquerytracker import TrackQuery
32
+
33
+ @TrackQuery()
34
+ def run_query():
35
+ time.sleep(0.3) # Simulate SQL execution
36
+ return "SELECT * FROM users;"
37
+
38
+ run_query()
39
+ ```
40
+ ### Output
41
+ ```bash
42
+ 2025-06-14 14:23:00,123 - pyquerytracker - INFO - Function run_query executed successfully in 305.12ms
43
+ ```
44
+
45
+ ### With Configure
46
+ ```
47
+ import logging
48
+ from pyquerytracker.config import configure
49
+
50
+ configure(
51
+ slow_log_threshold_ms=200, # Log queries slower than 200ms
52
+ slow_log_level=logging.DEBUG # Use DEBUG level for slow logs
53
+ )
54
+ ```
55
+
56
+ ### Output
57
+ ```bash
58
+ 2025-06-14 14:24:45,456 - pyquerytracker - WARNING - Slow execution: run_query took 501.87ms
59
+ ```
60
+
61
+
62
+
@@ -0,0 +1,27 @@
1
+ [project]
2
+ name = "pyquerytracker"
3
+ version = "0.1.0"
4
+ description = "A lightweight, decorator-based query performance tracking library for Python applications. Monitor and analyze database query performance with ease."
5
+ authors = [
6
+ {name = "MuddyHope", email = "daktarisun@gmail.com"}
7
+ ]
8
+ license = {text = "MIT"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ ]
13
+ keywords = ["performance", "database", "query", "decorator", "tracking"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Software Development :: Libraries :: Python Modules"
23
+ ]
24
+
25
+ [project.urls]
26
+ Repository = "https://github.com/MuddyHope/pyquerytracker"
27
+ Issues = "https://github.com/MuddyHope/pyquerytracker/issues"
@@ -0,0 +1,4 @@
1
+ from .core import TrackQuery
2
+ from .config import configure
3
+
4
+ __all__ = ["TrackQuery", "configure"]
@@ -0,0 +1,66 @@
1
+ from enum import Enum
2
+ from dataclasses import dataclass
3
+ from typing import Optional
4
+ import logging
5
+
6
+
7
+ class ExportType(str, Enum):
8
+ """
9
+ Enum representing supported export formats for query tracking logs.
10
+
11
+ Attributes:
12
+ JSON: Export logs in JSON format.
13
+ CSV: Export logs in CSV format.
14
+ """
15
+
16
+ JSON = "json"
17
+ CSV = "csv"
18
+
19
+
20
+ @dataclass
21
+ class Config:
22
+ """
23
+ Configuration settings for the query tracking system.
24
+
25
+ Attributes:
26
+ slow_log_threshold_ms (float): Threshold in milliseconds above which a query is considered slow.
27
+ Defaults to 100.0 ms.
28
+ slow_log_level (int): Logging level for slow query logs (e.g., logging.WARNING, logging.INFO).
29
+ Defaults to logging.WARNING.
30
+ """
31
+
32
+ # TODO: Adding export functionality
33
+ slow_log_threshold_ms: float = 100.0
34
+ slow_log_level: int = logging.WARNING
35
+
36
+
37
+ _config: Config = Config()
38
+
39
+
40
+ def configure(
41
+ slow_log_threshold_ms: Optional[float] = None,
42
+ slow_log_level: Optional[int] = None,
43
+ ):
44
+ """
45
+ Configure global settings for query tracking.
46
+
47
+ Args:
48
+ slow_log_threshold_ms (Optional[float]): Threshold in milliseconds to log a query as "slow".
49
+ If not provided, defaults to 100.0 ms.
50
+ slow_log_level (Optional[int]): Logging level for slow queries (e.g., logging.INFO, logging.WARNING).
51
+ If not provided, defaults to logging.WARNING.
52
+ """
53
+ if slow_log_threshold_ms is not None:
54
+ _config.slow_log_threshold_ms = slow_log_threshold_ms
55
+ if slow_log_level is not None:
56
+ _config.slow_log_level = slow_log_level
57
+
58
+
59
+ def get_config() -> Config:
60
+ """
61
+ Retrieve the current query tracking configuration.
62
+
63
+ Returns:
64
+ TrackerConfig: The current configuration settings.
65
+ """
66
+ return _config
@@ -0,0 +1,102 @@
1
+ import time
2
+ import logging
3
+ from functools import update_wrapper
4
+ from typing import Any, Callable, TypeVar, Generic
5
+ from pyquerytracker.config import get_config
6
+
7
+ # Set up logger
8
+ logger = logging.getLogger("pyquerytracker")
9
+ if not logger.handlers:
10
+ handler = logging.StreamHandler()
11
+ formatter = logging.Formatter(
12
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
13
+ )
14
+ handler.setFormatter(formatter)
15
+ logger.addHandler(handler)
16
+ logger.setLevel(logging.INFO)
17
+
18
+ T = TypeVar("T")
19
+
20
+
21
+ class TrackQuery(Generic[T]):
22
+ """
23
+ Class-based decorator to track and log the execution time of functions or methods.
24
+
25
+ Logs include:
26
+ - Function name
27
+ - Class name (if method)
28
+ - Execution time (ms)
29
+ - Arguments
30
+ - Errors (if any)
31
+
32
+ Usage:
33
+ @TrackQuery()
34
+ def my_function():
35
+ ...
36
+ """
37
+
38
+ def __init__(self) -> None:
39
+ self.config = get_config()
40
+
41
+ def __call__(self, func: Callable[..., T]) -> Callable[..., T]:
42
+ def wrapped(*args: Any, **kwargs: Any) -> T:
43
+ start = time.perf_counter()
44
+ class_name = None
45
+
46
+ # Try to detect if this is an instance or class method
47
+ if args:
48
+ possible_self_or_cls = args[0]
49
+ if hasattr(possible_self_or_cls, "__class__"):
50
+ if isinstance(possible_self_or_cls, type):
51
+ # classmethod
52
+ class_name = possible_self_or_cls.__name__
53
+ else:
54
+ # instance method
55
+ class_name = possible_self_or_cls.__class__.__name__
56
+
57
+ try:
58
+ result = func(*args, **kwargs)
59
+ duration = (time.perf_counter() - start) * 1000
60
+ if duration > self.config.slow_log_threshold_ms:
61
+ logger.log(
62
+ self.config.slow_log_level,
63
+ f"{class_name}.{func.__name__} -> Slow execution: took %.2fms",
64
+ duration,
65
+ )
66
+ # logger.warning("Slow execution: %s took %.2fms", func.__name__, duration)
67
+ else:
68
+ logger.info(
69
+ "Function %s%s executed successfully in %.2fms",
70
+ f"{class_name}." if class_name else "",
71
+ func.__name__,
72
+ duration,
73
+ extra={
74
+ "function_name": func.__name__,
75
+ "class_name": class_name,
76
+ "duration_ms": duration,
77
+ "func_args": args,
78
+ "func_kwargs": kwargs,
79
+ },
80
+ )
81
+ return result
82
+ except Exception as e:
83
+ duration = (time.perf_counter() - start) * 1000
84
+ logger.error(
85
+ "Function %s%s failed after %.2fms: %s",
86
+ f"{class_name}." if class_name else "",
87
+ func.__name__,
88
+ duration,
89
+ str(e),
90
+ exc_info=True,
91
+ extra={
92
+ "function_name": func.__name__,
93
+ "class_name": class_name,
94
+ "duration_ms": duration,
95
+ "func_args": args,
96
+ "func_kwargs": kwargs,
97
+ "error": str(e),
98
+ },
99
+ )
100
+ raise
101
+
102
+ return update_wrapper(wrapped, func)
@@ -0,0 +1,84 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyquerytracker
3
+ Version: 0.1.0
4
+ Summary: A lightweight, decorator-based query performance tracking library for Python applications. Monitor and analyze database query performance with ease.
5
+ Author-email: MuddyHope <daktarisun@gmail.com>
6
+ License: MIT
7
+ Project-URL: Repository, https://github.com/MuddyHope/pyquerytracker
8
+ Project-URL: Issues, https://github.com/MuddyHope/pyquerytracker/issues
9
+ Keywords: performance,database,query,decorator,tracking
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.11
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # 🐍 pyquerytracker
24
+
25
+ **pyquerytracker** is a lightweight Python utility to **track and analyze database query performance** using simple decorators. It enables developers to gain visibility into SQL execution time, log metadata, and export insights in JSON format — with optional FastAPI integration and scheduled reporting.
26
+
27
+ ---
28
+
29
+ ## 🚀 Features
30
+
31
+ - ✅ Easy-to-use decorator to track function execution (e.g., SQL queries)
32
+ - ✅ Capture runtime, function name, args, return values, and more
33
+
34
+ ## TODO Features
35
+ - ✅ Export logs to JSON or CSV
36
+ - ✅ FastAPI integration to expose tracked metrics via REST API
37
+ - ✅ Schedule periodic exports using `APScheduler`
38
+ - ✅ Plug-and-play with any Python database client (SQLAlchemy, psycopg2, etc.)
39
+ - ✅ Modular and extensible design
40
+
41
+ ---
42
+
43
+ ## 📦 Installation
44
+
45
+ ```bash
46
+ pip install pyquerytracker
47
+ ```
48
+
49
+ ## Usage
50
+ ### Basic Usage
51
+ ```python
52
+ import time
53
+ from pyquerytracker import TrackQuery
54
+
55
+ @TrackQuery()
56
+ def run_query():
57
+ time.sleep(0.3) # Simulate SQL execution
58
+ return "SELECT * FROM users;"
59
+
60
+ run_query()
61
+ ```
62
+ ### Output
63
+ ```bash
64
+ 2025-06-14 14:23:00,123 - pyquerytracker - INFO - Function run_query executed successfully in 305.12ms
65
+ ```
66
+
67
+ ### With Configure
68
+ ```
69
+ import logging
70
+ from pyquerytracker.config import configure
71
+
72
+ configure(
73
+ slow_log_threshold_ms=200, # Log queries slower than 200ms
74
+ slow_log_level=logging.DEBUG # Use DEBUG level for slow logs
75
+ )
76
+ ```
77
+
78
+ ### Output
79
+ ```bash
80
+ 2025-06-14 14:24:45,456 - pyquerytracker - WARNING - Slow execution: run_query took 501.87ms
81
+ ```
82
+
83
+
84
+
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ pyquerytracker/__init__.py
5
+ pyquerytracker/config.py
6
+ pyquerytracker/core.py
7
+ pyquerytracker.egg-info/PKG-INFO
8
+ pyquerytracker.egg-info/SOURCES.txt
9
+ pyquerytracker.egg-info/dependency_links.txt
10
+ pyquerytracker.egg-info/top_level.txt
11
+ tests/test_config.py
12
+ tests/test_core.py
@@ -0,0 +1 @@
1
+ pyquerytracker
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,44 @@
1
+ import logging
2
+
3
+ from pyquerytracker import TrackQuery, configure
4
+
5
+
6
+ def test_configure_basic(caplog):
7
+ configure(slow_log_threshold_ms=250)
8
+
9
+ class MyClass:
10
+ @TrackQuery()
11
+ def do_work(self, a, b):
12
+ import time
13
+
14
+ time.sleep(0.5)
15
+ return a * b
16
+
17
+ res = MyClass().do_work(2, 3) # noqa: F841
18
+ assert len(caplog.records) == 1
19
+ record = caplog.records[0]
20
+ assert record.levelname == "WARNING"
21
+ assert "MyClass" in record.message
22
+ assert "do_work" in record.message
23
+ assert "ms" in record.message
24
+
25
+
26
+ def test_configure_basic_with_loglevel(caplog):
27
+
28
+ configure(slow_log_threshold_ms=100, slow_log_level=logging.ERROR)
29
+
30
+ class MyClass:
31
+ @TrackQuery()
32
+ def do_slow_work(self, a, b):
33
+ import time
34
+
35
+ time.sleep(0.2)
36
+ return a * b
37
+
38
+ res = MyClass().do_slow_work(2, 3) # noqa: F841
39
+ assert len(caplog.records) == 1
40
+ record = caplog.records[0]
41
+ assert record.levelname == "ERROR"
42
+ assert "MyClass" in record.message
43
+ assert "do_slow_work" in record.message
44
+ assert "ms" in record.message
@@ -0,0 +1,72 @@
1
+ from pyquerytracker import TrackQuery
2
+ import pytest
3
+
4
+
5
+ def test_tracking_output(capsys):
6
+ @TrackQuery()
7
+ def fake_db_query():
8
+ return "done"
9
+
10
+ assert fake_db_query() == "done"
11
+
12
+
13
+ import logging # noqa: E402
14
+
15
+ logging.basicConfig(
16
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
17
+ )
18
+
19
+
20
+ def test_tracking_output_with_logging(caplog):
21
+ caplog.set_level("INFO")
22
+
23
+ @TrackQuery()
24
+ def fake_db_query():
25
+ return "done"
26
+
27
+ result = fake_db_query()
28
+ assert result == "done"
29
+
30
+ # Check the log records
31
+ assert len(caplog.records) == 1
32
+ record = caplog.records[0]
33
+ assert record.levelname == "INFO"
34
+ assert "Function fake_db_query executed successfully" in record.message
35
+ assert "ms" in record.message
36
+
37
+
38
+ def test_tracking_output_with_error(caplog):
39
+ caplog.set_level("ERROR")
40
+
41
+ @TrackQuery()
42
+ def failing_query():
43
+ raise ValueError("Test error")
44
+
45
+ with pytest.raises(ValueError):
46
+ failing_query()
47
+
48
+ # Check the log records
49
+ assert len(caplog.records) == 1
50
+ record = caplog.records[0]
51
+ assert record.levelname == "ERROR"
52
+ assert "Function failing_query failed" in record.message
53
+ assert "Test error" in record.message
54
+ assert "ms" in record.message
55
+
56
+
57
+ def test_tracking_with_class(caplog):
58
+ class MyClass:
59
+ @TrackQuery()
60
+ def do_work(self, a, b):
61
+ import time
62
+
63
+ time.sleep(0.09)
64
+ return a * b
65
+
66
+ res = MyClass().do_work(2, 3) # noqa: F841
67
+ assert len(caplog.records) == 1
68
+ record = caplog.records[0]
69
+ assert record.levelname == "INFO"
70
+ assert "MyClass" in record.message
71
+ assert "do_work" in record.message
72
+ assert "ms" in record.message