diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d017208 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,72 @@ +# 🀝 Contributing to PyQueryTracker + +Welcome! πŸ‘‹ +Thank you for considering a contribution to **PyQueryTracker** β€” a lightweight and extensible query tracking library for Python applications. + +We appreciate all kinds of contributions, from code and documentation to bug reports and feature ideas. This guide will help you get started. + +--- + +## πŸš€ Project Overview + +**PyQueryTracker** provides a Python decorator to track and analyze query performance in web applications. It’s designed to be easy to integrate into FastAPI, support customizable exporters, and work well in production and development environments. + +--- + + +## Assumptions + +1. **You're familiar with [GitHub](https://github.com) and the [Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)(PR) workflow.** + +## How to Contribute + +1. Make sure that the contribution you want to make is explained or detailed in a GitHub issue! Find an [existing issue](https://github.com/MuddyHope/pyquerytracker/issues/) or [open a new one](https://github.com/MuddyHope/pyquerytracker/issues/new). +2. Once done, [fork the pyquerytracker repository](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) in your own GitHub account. Ask a maintainer if you want your issue to be checked before making a PR. +3. [Create a new Git branch](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-and-deleting-branches-within-your-repository). +4. Review the necessary checks that describes the steps to maintain the repository. +5. Make the changes on your branch. +6. Submit the branch as a PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) pointing to the `main` branch of the main meilisearch-python repository. A maintainer should comment and/or review your Pull Request within a few days. Although depending on the circumstances, it may take longer.
+ +We do not enforce a naming convention for the PRs, but **please use something descriptive of your changes**, having in mind that the title of your PR will be automatically added to the next + + +## 🧠 How You Can Contribute + +Here are some ways you can help: + +- πŸ› Report bugs or suggest improvements via [Issues](https://github.com/MuddyHope/pyquerytracker/issues) +- πŸ“Š Build new exporters (JSON, CSV, Prometheus) +- βš™οΈ Integrate with frameworks like FastAPI, Flask +- πŸ§ͺ Expand test coverage with Pytest +- πŸ“– Improve documentation or add examples +- 🧰 Create a CLI wrapper for runtime stats inspection + +--- + +## πŸ› οΈ Development Setup + +### Clone the repo + +```bash +git clone https://github.com/MuddyHope/pyquerytracker.git +cd pyquerytracker +``` + +### Pushing your changes +```bash +git checkout -b feature/your-feature-name +``` + + +### Running Tests and Linting +```bash +cd pyquerytracker +pip install -e . + +pytest tests/ + +# Linting +black . +isort . + +``` diff --git a/pyquerytracker/performance_exporter.py b/pyquerytracker/performance_exporter.py new file mode 100644 index 0000000..4480983 --- /dev/null +++ b/pyquerytracker/performance_exporter.py @@ -0,0 +1,17 @@ +import time +import functools + +class BuiltinPerformanceExporter: + def __init__(self, output_func=print): + self.output_func = output_func + + def track(self, func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + start = time.perf_counter() + result = func(*args, **kwargs) + end = time.perf_counter() + elapsed_ms = (end - start) * 1000 + self.output_func(f"Function '{func.__name__}' executed in {elapsed_ms:.2f} ms") + return result + return wrapper diff --git a/tests/test_performance_exporter.py b/tests/test_performance_exporter.py new file mode 100644 index 0000000..d77fb51 --- /dev/null +++ b/tests/test_performance_exporter.py @@ -0,0 +1,37 @@ +import time +import re +import pytest +from pyquerytracker.performance_exporter import BuiltinPerformanceExporter + +def test_track_decorator_outputs_execution_time(capsys): + exporter = BuiltinPerformanceExporter() + + @exporter.track + def dummy_function(): + time.sleep(0.1) + + dummy_function() + + # Capture the output + captured = capsys.readouterr() + output = captured.out.strip() + + # Assert output format (basic check) + assert output.startswith("Function 'dummy_function' executed in ") + + # Extract the ms part and check it's within reasonable range + match = re.search(r'executed in ([\d\.]+) ms', output) + assert match is not None + elapsed_ms = float(match.group(1)) + + assert 90 <= elapsed_ms <= 200 # Allowing some tolerance + +def test_track_decorator_returns_original_value(): + exporter = BuiltinPerformanceExporter() + + @exporter.track + def add(a, b): + return a + b + + result = add(3, 5) + assert result == 8