Skip to content

Commit 5b4e85e

Browse files
CopilotIntegerAlex
andcommitted
fix: license mismatch, import shadowing, packaging, AsyncLogger shutdown, magic numbers, CONTRIBUTING.md
Co-authored-by: IntegerAlex <84370725+IntegerAlex@users.noreply.github.com>
1 parent b8ffcbc commit 5b4e85e

6 files changed

Lines changed: 80 additions & 117 deletions

File tree

CONTRIBUTING.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Contributing to Kakashi
2+
3+
Thank you for your interest in contributing! The following guidelines will help you get started.
4+
5+
## Reporting Issues
6+
7+
- Search [existing issues](https://github.com/IntegerAlex/kakashi/issues) before opening a new one.
8+
- Include a minimal, reproducible example and your Python version when reporting bugs.
9+
10+
## Development Setup
11+
12+
```bash
13+
# Clone the repository
14+
git clone https://github.com/IntegerAlex/kakashi.git
15+
cd kakashi
16+
17+
# Install with development dependencies
18+
pip install -e ".[dev]"
19+
```
20+
21+
## Running Tests
22+
23+
```bash
24+
pytest
25+
```
26+
27+
## Code Style
28+
29+
- Format code with [black](https://black.readthedocs.io/): `black .`
30+
- Lint with [flake8](https://flake8.pycqa.org/): `flake8 kakashi/`
31+
- Type-check with [mypy](https://mypy.readthedocs.io/): `mypy kakashi/`
32+
33+
## Submitting a Pull Request
34+
35+
1. Fork the repository and create a feature branch from `main`.
36+
2. Write tests for any new functionality.
37+
3. Ensure all tests, lint, and type checks pass.
38+
4. Open a pull request with a clear description of the change.
39+
40+
## License
41+
42+
By contributing you agree that your code will be released under the project's [LGPL-2.1 license](LICENSE).

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
235235

236236
## 📄 License
237237

238-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
238+
This project is licensed under the GNU Lesser General Public License v2.1 (LGPL-2.1) - see the [LICENSE](LICENSE) file for details.
239239

240240
## ⚖️ Legal Disclaimers
241241

__init__.py

Lines changed: 0 additions & 12 deletions
This file was deleted.

kakashi/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
from .core.logger import (
4343
Logger, AsyncLogger, LogFormatter,
4444
get_logger, get_async_logger, clear_logger_cache,
45-
shutdown_async_logging
45+
shutdown_async_logging,
46+
LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR, LOG_LEVEL_CRITICAL,
4647
)
4748

4849
# ============================================================================
@@ -99,6 +100,13 @@
99100
"get_async_logger", # Async logger entry point
100101
"clear_logger_cache",
101102
"shutdown_async_logging",
103+
104+
# ---- LOG LEVEL CONSTANTS ----
105+
"LOG_LEVEL_DEBUG",
106+
"LOG_LEVEL_INFO",
107+
"LOG_LEVEL_WARNING",
108+
"LOG_LEVEL_ERROR",
109+
"LOG_LEVEL_CRITICAL",
102110

103111
# ---- CORE DATA STRUCTURES ----
104112
"LogRecord",

kakashi/core/logger.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- Professional, maintainable code structure
1313
"""
1414

15+
import atexit
1516
import threading
1617
import time
1718
import sys
@@ -21,12 +22,22 @@
2122
# Pre-computed constants for fast access
2223
_LEVEL_NAMES = {
2324
10: 'DEBUG',
24-
20: 'INFO',
25+
20: 'INFO',
2526
30: 'WARNING',
2627
40: 'ERROR',
2728
50: 'CRITICAL'
2829
}
2930

31+
# Named log-level constants (use these instead of bare integers)
32+
LOG_LEVEL_DEBUG = 10
33+
LOG_LEVEL_INFO = 20
34+
LOG_LEVEL_WARNING = 30
35+
LOG_LEVEL_ERROR = 40
36+
LOG_LEVEL_CRITICAL = 50
37+
38+
# Wait time (seconds) for AsyncLogger.close() best-effort flush
39+
_ASYNC_CLOSE_WAIT_SECS = 0.05
40+
3041
# Thread-local storage for lock-free operation
3142
_thread_local = threading.local()
3243

@@ -146,7 +157,7 @@ class Logger:
146157

147158
__slots__ = ('name', 'min_level', 'formatter')
148159

149-
def __init__(self, name: str, min_level: int = 20):
160+
def __init__(self, name: str, min_level: int = LOG_LEVEL_INFO):
150161
self.name = name
151162
self.min_level = min_level
152163
self.formatter = LogFormatter()
@@ -236,12 +247,19 @@ class AsyncLogger:
236247
- Superior throughput vs sync logging
237248
"""
238249

239-
def __init__(self, name: str, min_level: int = 20):
250+
def __init__(self, name: str, min_level: int = LOG_LEVEL_INFO):
240251
self.name = name
241252
self.min_level = min_level
242-
253+
243254
# Ensure async worker is running
244255
_ensure_async_worker()
256+
257+
def close(self) -> None:
258+
"""Flush pending messages and release resources for this logger instance."""
259+
# Draining items belonging to this logger from the queue would require
260+
# restructuring the shared queue, so we do a best-effort flush by
261+
# waiting briefly for the background worker to catch up.
262+
time.sleep(_ASYNC_CLOSE_WAIT_SECS)
245263

246264
def _log_async(self, level: int, message: str, fields: Optional[Dict[str, Any]] = None) -> None:
247265
"""True asynchronous logging - non-blocking enqueue."""
@@ -302,7 +320,7 @@ def flush(self) -> None:
302320
_cache_lock = threading.RLock()
303321

304322

305-
def get_logger(name: str, min_level: int = 20) -> Logger:
323+
def get_logger(name: str, min_level: int = LOG_LEVEL_INFO) -> Logger:
306324
"""
307325
Get a high-performance logger instance with minimal lock contention.
308326
@@ -324,7 +342,7 @@ def get_logger(name: str, min_level: int = 20) -> Logger:
324342
return logger
325343

326344

327-
def get_async_logger(name: str, min_level: int = 20) -> AsyncLogger:
345+
def get_async_logger(name: str, min_level: int = LOG_LEVEL_INFO) -> AsyncLogger:
328346
"""
329347
Get an asynchronous logger instance with minimal lock contention.
330348
@@ -366,3 +384,7 @@ def shutdown_async_logging() -> None:
366384
# Wait for worker to finish (with timeout)
367385
_async_worker.join(timeout=1.0)
368386
_async_worker = None
387+
388+
389+
# Ensure buffered async messages are flushed when the interpreter exits
390+
atexit.register(shutdown_async_logging)

setup.py

Lines changed: 0 additions & 97 deletions
This file was deleted.

0 commit comments

Comments
 (0)