veronix 1.0.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,7 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 - 2026-10-25
4
+ - First public release by 1tz.raj
5
+ - Colourful console logging with 7 levels (TRACE → CRITICAL)
6
+ - File logging with rotation, JSON mode, timer, `@log_calls`, banner/rule
7
+ - CLI: `veronix demo | info | levels | log`
veronix-1.0.0/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ VERONIX PROPRIETARY LICENSE - ALL RIGHTS RESERVED
2
+
3
+ Copyright (c) 2026 1tz.raj (GitHub: 7rzraj). All rights reserved.
4
+
5
+ 1. GRANT. You may install Veronix with "pip install veronix" and use it, free
6
+ of charge, in personal, educational and commercial projects, including as a
7
+ dependency of your own software.
8
+
9
+ 2. RESTRICTIONS. Without prior written permission from the author you may NOT:
10
+ a) republish, re-upload or redistribute Veronix (original or modified, in
11
+ source or binary form) on PyPI, GitHub, any package index, website,
12
+ marketplace or any other platform;
13
+ b) sell, sublicense, rent or claim Veronix as your own work;
14
+ c) rename, rebrand or fork it into a competing or look-alike package;
15
+ d) remove or alter copyright notices, author credits or this license.
16
+
17
+ 3. ENFORCEMENT. Any republication or unauthorised copying is copyright
18
+ infringement. The author may file takedown notices (e.g. DMCA) with PyPI,
19
+ GitHub and hosting providers and pursue legal remedies.
20
+
21
+ 4. NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
22
+ THE AUTHOR IS NOT LIABLE FOR ANY CLAIM OR DAMAGES ARISING FROM ITS USE.
23
+
24
+ Contact: Instagram @1tz.raj_ | GitHub @7rzraj | Discord 1tz.raj
@@ -0,0 +1,2 @@
1
+ include LICENSE README.md CHANGELOG.md
2
+ recursive-include src/veronix py.typed
veronix-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: veronix
3
+ Version: 1.0.0
4
+ Summary: Clean, professional and colourful console logging for Python - by 1tz.raj
5
+ Author: 1tz.raj
6
+ Maintainer: 1tz.raj
7
+ License: VERONIX PROPRIETARY LICENSE - ALL RIGHTS RESERVED
8
+
9
+ Copyright (c) 2026 1tz.raj (GitHub: 7rzraj). All rights reserved.
10
+
11
+ 1. GRANT. You may install Veronix with "pip install veronix" and use it, free
12
+ of charge, in personal, educational and commercial projects, including as a
13
+ dependency of your own software.
14
+
15
+ 2. RESTRICTIONS. Without prior written permission from the author you may NOT:
16
+ a) republish, re-upload or redistribute Veronix (original or modified, in
17
+ source or binary form) on PyPI, GitHub, any package index, website,
18
+ marketplace or any other platform;
19
+ b) sell, sublicense, rent or claim Veronix as your own work;
20
+ c) rename, rebrand or fork it into a competing or look-alike package;
21
+ d) remove or alter copyright notices, author credits or this license.
22
+
23
+ 3. ENFORCEMENT. Any republication or unauthorised copying is copyright
24
+ infringement. The author may file takedown notices (e.g. DMCA) with PyPI,
25
+ GitHub and hosting providers and pursue legal remedies.
26
+
27
+ 4. NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
28
+ THE AUTHOR IS NOT LIABLE FOR ANY CLAIM OR DAMAGES ARISING FROM ITS USE.
29
+
30
+ Contact: Instagram @1tz.raj_ | GitHub @7rzraj | Discord 1tz.raj
31
+
32
+ Project-URL: Homepage, https://github.com/7rzraj/veronix
33
+ Project-URL: Documentation, https://github.com/7rzraj/veronix#readme
34
+ Project-URL: Source, https://github.com/7rzraj/veronix
35
+ Project-URL: Issues, https://github.com/7rzraj/veronix/issues
36
+ Project-URL: Changelog, https://github.com/7rzraj/veronix/blob/main/CHANGELOG.md
37
+ Project-URL: Developer, https://github.com/7rzraj
38
+ Project-URL: Instagram, https://instagram.com/1tz.raj_
39
+ Keywords: logging,logger,colorful logs,console logging,python logger,colored terminal,ansi colors,veronix,1tz.raj,7rzraj,cli logging
40
+ Classifier: Development Status :: 5 - Production/Stable
41
+ Classifier: Intended Audience :: Developers
42
+ Classifier: License :: Other/Proprietary License
43
+ Classifier: Operating System :: OS Independent
44
+ Classifier: Programming Language :: Python :: 3
45
+ Classifier: Programming Language :: Python :: 3.8
46
+ Classifier: Programming Language :: Python :: 3.9
47
+ Classifier: Programming Language :: Python :: 3.10
48
+ Classifier: Programming Language :: Python :: 3.11
49
+ Classifier: Programming Language :: Python :: 3.12
50
+ Classifier: Programming Language :: Python :: 3.13
51
+ Classifier: Topic :: System :: Logging
52
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
53
+ Classifier: Typing :: Typed
54
+ Requires-Python: >=3.8
55
+ Description-Content-Type: text/markdown
56
+ License-File: LICENSE
57
+ Dynamic: license-file
58
+
59
+ <div align="center">
60
+
61
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/banner.png" alt="Veronix - colourful Python logging by 1tz.raj" width="100%">
62
+
63
+ [![PyPI](https://img.shields.io/pypi/v/veronix?color=blue)](https://pypi.org/project/veronix/)
64
+ [![Python](https://img.shields.io/pypi/pyversions/veronix)](https://pypi.org/project/veronix/)
65
+ [![CI](https://github.com/7rzraj/veronix/actions/workflows/ci.yml/badge.svg)](https://github.com/7rzraj/veronix/actions)
66
+ [![License](https://img.shields.io/badge/license-Proprietary-red)](LICENSE)
67
+ [![Downloads](https://img.shields.io/pypi/dm/veronix)](https://pypi.org/project/veronix/)
68
+
69
+ Made with ❤️ by **[1tz.raj](https://github.com/7rzraj)**
70
+
71
+ </div>
72
+
73
+ <div align="center">
74
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/demo-screenshot.png" alt="Veronix demo output in terminal" width="85%">
75
+ </div>
76
+
77
+ ---
78
+
79
+ ## 📦 Installation
80
+
81
+ ```bash
82
+ pip install veronix
83
+ ```
84
+
85
+ ## 🚀 Usage
86
+
87
+ ```python
88
+ import veronix
89
+
90
+ veronix.info("Server started", port=8000)
91
+ veronix.success("Database connected")
92
+ veronix.warning("Disk almost full")
93
+ veronix.error("Payment failed", order_id=1042)
94
+ veronix.critical("System down!")
95
+ ```
96
+
97
+ ### Levels
98
+ `TRACE` · `DEBUG` · `INFO` · `SUCCESS` · `WARNING` · `ERROR` · `CRITICAL`
99
+
100
+ ### Configure
101
+
102
+ ```python
103
+ veronix.configure(level="DEBUG", file="logs/app.log") # save to file (auto-rotating)
104
+ veronix.configure(json_mode=True) # JSON logs
105
+ ```
106
+
107
+ ### Named loggers
108
+
109
+ ```python
110
+ api = veronix.get_logger("api")
111
+ api.info("GET /users 200")
112
+ ```
113
+
114
+ ### Timer, decorator, exceptions
115
+
116
+ ```python
117
+ with veronix.timer("db query"):
118
+ run_query()
119
+
120
+ @veronix.log_calls
121
+ def work(): ...
122
+
123
+ try:
124
+ 1 / 0
125
+ except ZeroDivisionError:
126
+ veronix.exception("Something broke") # prints full traceback
127
+ ```
128
+
129
+ ### Banner & divider
130
+
131
+ ```python
132
+ veronix.banner("My App v1.0")
133
+ veronix.rule("Startup")
134
+ ```
135
+
136
+ ## 💻 Command line
137
+
138
+ | Command | What it does |
139
+ |---|---|
140
+ | `veronix demo` | See all colours and levels |
141
+ | `veronix info` | Developer and package details |
142
+ | `veronix levels` | List log levels |
143
+ | `veronix log "text" -l ERROR` | Print one log line |
144
+ | `veronix --version` | Show version |
145
+
146
+ ## ✨ Features
147
+ - Auto colour detection (respects `NO_COLOR` / `FORCE_COLOR`), works on Windows, Linux, macOS
148
+ - Zero dependencies
149
+ - File logging with rotation, JSON output, thread-safe
150
+ - Fully typed (`py.typed`)
151
+
152
+ ## 👨‍💻 Developer
153
+
154
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/avatar.png" width="110" align="right" alt="1tz.raj">
155
+
156
+ | | |
157
+ |---|---|
158
+ | **Name** | 1tz.raj |
159
+ | **GitHub** | [@7rzraj](https://github.com/7rzraj) |
160
+ | **Instagram** | [@1tz.raj_](https://instagram.com/1tz.raj_) |
161
+ | **Discord** | `1tz.raj` |
162
+ | **Project** | https://github.com/7rzraj/veronix |
163
+
164
+ ## ⚠️ Copyright Notice
165
+
166
+ © 2026 **1tz.raj**. All rights reserved.
167
+ You may **use** Veronix freely, but you may **not republish, re-upload, rebrand or redistribute** it
168
+ (on PyPI, GitHub or anywhere else). Violations will result in a copyright takedown (DMCA).
169
+ See [LICENSE](LICENSE).
170
+
171
+ <sub>Keywords: veronix, 1tz.raj, 7rzraj, python logging, colorful logger, console logger, pip install veronix</sub>
@@ -0,0 +1,113 @@
1
+ <div align="center">
2
+
3
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/banner.png" alt="Veronix - colourful Python logging by 1tz.raj" width="100%">
4
+
5
+ [![PyPI](https://img.shields.io/pypi/v/veronix?color=blue)](https://pypi.org/project/veronix/)
6
+ [![Python](https://img.shields.io/pypi/pyversions/veronix)](https://pypi.org/project/veronix/)
7
+ [![CI](https://github.com/7rzraj/veronix/actions/workflows/ci.yml/badge.svg)](https://github.com/7rzraj/veronix/actions)
8
+ [![License](https://img.shields.io/badge/license-Proprietary-red)](LICENSE)
9
+ [![Downloads](https://img.shields.io/pypi/dm/veronix)](https://pypi.org/project/veronix/)
10
+
11
+ Made with ❤️ by **[1tz.raj](https://github.com/7rzraj)**
12
+
13
+ </div>
14
+
15
+ <div align="center">
16
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/demo-screenshot.png" alt="Veronix demo output in terminal" width="85%">
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## 📦 Installation
22
+
23
+ ```bash
24
+ pip install veronix
25
+ ```
26
+
27
+ ## 🚀 Usage
28
+
29
+ ```python
30
+ import veronix
31
+
32
+ veronix.info("Server started", port=8000)
33
+ veronix.success("Database connected")
34
+ veronix.warning("Disk almost full")
35
+ veronix.error("Payment failed", order_id=1042)
36
+ veronix.critical("System down!")
37
+ ```
38
+
39
+ ### Levels
40
+ `TRACE` · `DEBUG` · `INFO` · `SUCCESS` · `WARNING` · `ERROR` · `CRITICAL`
41
+
42
+ ### Configure
43
+
44
+ ```python
45
+ veronix.configure(level="DEBUG", file="logs/app.log") # save to file (auto-rotating)
46
+ veronix.configure(json_mode=True) # JSON logs
47
+ ```
48
+
49
+ ### Named loggers
50
+
51
+ ```python
52
+ api = veronix.get_logger("api")
53
+ api.info("GET /users 200")
54
+ ```
55
+
56
+ ### Timer, decorator, exceptions
57
+
58
+ ```python
59
+ with veronix.timer("db query"):
60
+ run_query()
61
+
62
+ @veronix.log_calls
63
+ def work(): ...
64
+
65
+ try:
66
+ 1 / 0
67
+ except ZeroDivisionError:
68
+ veronix.exception("Something broke") # prints full traceback
69
+ ```
70
+
71
+ ### Banner & divider
72
+
73
+ ```python
74
+ veronix.banner("My App v1.0")
75
+ veronix.rule("Startup")
76
+ ```
77
+
78
+ ## 💻 Command line
79
+
80
+ | Command | What it does |
81
+ |---|---|
82
+ | `veronix demo` | See all colours and levels |
83
+ | `veronix info` | Developer and package details |
84
+ | `veronix levels` | List log levels |
85
+ | `veronix log "text" -l ERROR` | Print one log line |
86
+ | `veronix --version` | Show version |
87
+
88
+ ## ✨ Features
89
+ - Auto colour detection (respects `NO_COLOR` / `FORCE_COLOR`), works on Windows, Linux, macOS
90
+ - Zero dependencies
91
+ - File logging with rotation, JSON output, thread-safe
92
+ - Fully typed (`py.typed`)
93
+
94
+ ## 👨‍💻 Developer
95
+
96
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/avatar.png" width="110" align="right" alt="1tz.raj">
97
+
98
+ | | |
99
+ |---|---|
100
+ | **Name** | 1tz.raj |
101
+ | **GitHub** | [@7rzraj](https://github.com/7rzraj) |
102
+ | **Instagram** | [@1tz.raj_](https://instagram.com/1tz.raj_) |
103
+ | **Discord** | `1tz.raj` |
104
+ | **Project** | https://github.com/7rzraj/veronix |
105
+
106
+ ## ⚠️ Copyright Notice
107
+
108
+ © 2026 **1tz.raj**. All rights reserved.
109
+ You may **use** Veronix freely, but you may **not republish, re-upload, rebrand or redistribute** it
110
+ (on PyPI, GitHub or anywhere else). Violations will result in a copyright takedown (DMCA).
111
+ See [LICENSE](LICENSE).
112
+
113
+ <sub>Keywords: veronix, 1tz.raj, 7rzraj, python logging, colorful logger, console logger, pip install veronix</sub>
@@ -0,0 +1,55 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "veronix"
7
+ dynamic = ["version"]
8
+ description = "Clean, professional and colourful console logging for Python - by 1tz.raj"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "1tz.raj" }]
13
+ maintainers = [{ name = "1tz.raj" }]
14
+ keywords = [
15
+ "logging", "logger", "colorful logs", "console logging", "python logger",
16
+ "colored terminal", "ansi colors", "veronix", "1tz.raj", "7rzraj", "cli logging",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 5 - Production/Stable",
20
+ "Intended Audience :: Developers",
21
+ "License :: Other/Proprietary License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.8",
25
+ "Programming Language :: Python :: 3.9",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Topic :: System :: Logging",
31
+ "Topic :: Software Development :: Libraries :: Python Modules",
32
+ "Typing :: Typed",
33
+ ]
34
+ dependencies = []
35
+
36
+ [project.urls]
37
+ Homepage = "https://github.com/7rzraj/veronix"
38
+ Documentation = "https://github.com/7rzraj/veronix#readme"
39
+ Source = "https://github.com/7rzraj/veronix"
40
+ Issues = "https://github.com/7rzraj/veronix/issues"
41
+ Changelog = "https://github.com/7rzraj/veronix/blob/main/CHANGELOG.md"
42
+ Developer = "https://github.com/7rzraj"
43
+ Instagram = "https://instagram.com/1tz.raj_"
44
+
45
+ [project.scripts]
46
+ veronix = "veronix.cli:main"
47
+
48
+ [tool.setuptools.dynamic]
49
+ version = { attr = "veronix.__about__.__version__" }
50
+
51
+ [tool.setuptools.packages.find]
52
+ where = ["src"]
53
+
54
+ [tool.setuptools.package-data]
55
+ veronix = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Package metadata for Veronix (single source of truth)."""
4
+
5
+ __title__ = "veronix"
6
+ __version__ = "1.0.0"
7
+ __description__ = "Clean, professional and colourful console logging for Python."
8
+ __author__ = "1tz.raj"
9
+ __license__ = "Veronix Proprietary License (All Rights Reserved)"
10
+ __copyright__ = "Copyright (c) 2026 1tz.raj. All rights reserved."
11
+ __url__ = "https://github.com/7rzraj/veronix"
12
+
13
+ __instagram__ = "https://instagram.com/1tz.raj_"
14
+ __github__ = "https://github.com/7rzraj"
15
+ __discord__ = "1tz.raj"
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """
4
+ Veronix - clean, professional and colourful console logging for Python.
5
+
6
+ pip install veronix
7
+
8
+ import veronix
9
+ veronix.info("Hello from Veronix")
10
+
11
+ Developer : 1tz.raj
12
+ GitHub : https://github.com/7rzraj
13
+ Instagram : https://instagram.com/1tz.raj_
14
+ Discord : 1tz.raj
15
+ """
16
+
17
+ from .__about__ import (__author__, __copyright__, __description__, __license__,
18
+ __url__, __version__)
19
+ from .levels import (CRITICAL, DEBUG, ERROR, INFO, SUCCESS, TRACE, WARNING)
20
+ from .logger import (Logger, banner, configure, critical, debug, error, exception,
21
+ get_logger, info, log_calls, rule, success, timer, trace,
22
+ warn, warning)
23
+
24
+ __all__ = [
25
+ "Logger", "get_logger", "configure", "trace", "debug", "info", "success",
26
+ "warning", "warn", "error", "critical", "exception", "banner", "rule",
27
+ "timer", "log_calls", "TRACE", "DEBUG", "INFO", "SUCCESS", "WARNING",
28
+ "ERROR", "CRITICAL", "__version__", "__author__",
29
+ ]
@@ -0,0 +1,6 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ import sys
4
+ from .cli import main
5
+
6
+ sys.exit(main())
@@ -0,0 +1,80 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Command line interface: ``veronix --help``."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import argparse
8
+ import sys
9
+
10
+ from . import __about__ as about
11
+ from .levels import LEVEL_NAMES, resolve_level
12
+ from .logger import Logger
13
+ from .colors import style, supports_color
14
+
15
+
16
+ def _demo() -> None:
17
+ log = Logger("demo", level="TRACE", color=None)
18
+ log.banner(f"VERONIX v{about.__version__}")
19
+ log.trace("Trace: very detailed information")
20
+ log.debug("Debug: variable x = 42")
21
+ log.info("Info: server started", port=8000, env="prod")
22
+ log.success("Success: database connected")
23
+ log.warning("Warning: disk usage at 91%")
24
+ log.error("Error: could not reach payment API")
25
+ log.critical("Critical: system is going down!")
26
+ try:
27
+ 1 / 0
28
+ except ZeroDivisionError:
29
+ log.exception("Exception caught with traceback")
30
+ log.rule("done")
31
+
32
+
33
+ def _info() -> None:
34
+ c = supports_color()
35
+ rows = [("Package", about.__title__), ("Version", about.__version__),
36
+ ("Developer", about.__author__), ("Install", "pip install veronix"),
37
+ ("GitHub", about.__github__), ("Instagram", about.__instagram__),
38
+ ("Discord", about.__discord__), ("License", about.__license__)]
39
+ print(style(f"\n {about.__title__.upper()} - {about.__description__}\n", "bright_cyan", bold=True, enabled=c))
40
+ for k, v in rows:
41
+ print(f" {style((k + ':').ljust(12), 'yellow', bold=True, enabled=c)} {v}")
42
+ print()
43
+
44
+
45
+ def main(argv=None) -> int:
46
+ p = argparse.ArgumentParser(prog="veronix", description=about.__description__)
47
+ p.add_argument("-V", "--version", action="version", version=f"veronix {about.__version__}")
48
+ sub = p.add_subparsers(dest="cmd")
49
+ sub.add_parser("demo", help="show every log level in colour")
50
+ sub.add_parser("info", help="show developer and package details")
51
+ sub.add_parser("levels", help="list available log levels")
52
+ lg = sub.add_parser("log", help="print a single log line")
53
+ lg.add_argument("message")
54
+ lg.add_argument("-l", "--level", default="INFO")
55
+ lg.add_argument("-n", "--name", default="cli")
56
+ lg.add_argument("-f", "--file", help="also write the log to this file")
57
+ lg.add_argument("--json", action="store_true", help="JSON output")
58
+ args = p.parse_args(argv)
59
+
60
+ if args.cmd == "demo":
61
+ _demo()
62
+ elif args.cmd == "info":
63
+ _info()
64
+ elif args.cmd == "levels":
65
+ for num, name in sorted(LEVEL_NAMES.items()):
66
+ Logger("levels", level=0, show_time=False, show_name=False).log(num, f"{name} ({num})")
67
+ elif args.cmd == "log":
68
+ try:
69
+ lvl = resolve_level(args.level)
70
+ except ValueError as exc:
71
+ print(exc, file=sys.stderr)
72
+ return 2
73
+ Logger(args.name, level=0, file=args.file, json_mode=args.json).log(lvl, args.message)
74
+ else:
75
+ p.print_help()
76
+ return 0
77
+
78
+
79
+ if __name__ == "__main__":
80
+ sys.exit(main())
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """ANSI colour helpers with automatic terminal detection."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import os
8
+ import sys
9
+
10
+ RESET = "\033[0m"
11
+ BOLD = "\033[1m"
12
+ DIM = "\033[2m"
13
+ ITALIC = "\033[3m"
14
+
15
+ FG = {
16
+ "black": 30, "red": 31, "green": 32, "yellow": 33,
17
+ "blue": 34, "magenta": 35, "cyan": 36, "white": 37,
18
+ "gray": 90, "bright_red": 91, "bright_green": 92, "bright_yellow": 93,
19
+ "bright_blue": 94, "bright_magenta": 95, "bright_cyan": 96, "bright_white": 97,
20
+ }
21
+ BG = {
22
+ "red": 41, "green": 42, "yellow": 43, "blue": 44,
23
+ "magenta": 45, "cyan": 46, "white": 47, "gray": 100,
24
+ "bright_red": 101, "bright_green": 102, "bright_blue": 104,
25
+ }
26
+
27
+ # Enable ANSI escape processing on modern Windows consoles.
28
+ if os.name == "nt": # pragma: no cover
29
+ os.system("")
30
+
31
+
32
+ def supports_color(stream=None) -> bool:
33
+ """Return True if ``stream`` (default: stdout) should receive colours.
34
+
35
+ Respects the ``NO_COLOR`` and ``FORCE_COLOR`` environment variables.
36
+ """
37
+ if os.environ.get("NO_COLOR"):
38
+ return False
39
+ if os.environ.get("FORCE_COLOR"):
40
+ return True
41
+ stream = stream or sys.stdout
42
+ if os.environ.get("TERM") == "dumb":
43
+ return False
44
+ isatty = getattr(stream, "isatty", None)
45
+ return bool(isatty and isatty())
46
+
47
+
48
+ def style(text: str, fg: str | None = None, bg: str | None = None,
49
+ bold: bool = False, dim: bool = False, enabled: bool = True) -> str:
50
+ """Wrap ``text`` in ANSI codes. Returns plain text if ``enabled`` is False."""
51
+ if not enabled:
52
+ return text
53
+ codes = []
54
+ if bold:
55
+ codes.append("1")
56
+ if dim:
57
+ codes.append("2")
58
+ if fg in FG:
59
+ codes.append(str(FG[fg]))
60
+ if bg in BG:
61
+ codes.append(str(BG[bg]))
62
+ if not codes:
63
+ return text
64
+ return f"\033[{';'.join(codes)}m{text}{RESET}"
@@ -0,0 +1,61 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Console, plain-text and JSON formatters."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import json
8
+ from datetime import datetime
9
+
10
+ from .colors import style
11
+ from .levels import LEVEL_NAMES, LEVEL_STYLES
12
+
13
+
14
+ def _extras(extra: dict) -> str:
15
+ return " ".join(f"{k}={v!r}" if isinstance(v, str) else f"{k}={v}" for k, v in extra.items())
16
+
17
+
18
+ def format_console(rec: dict, color: bool, show_time: bool, show_name: bool, time_format: str) -> str:
19
+ lv = rec["levelno"]
20
+ badge_fg, badge_bg, msg_fg = LEVEL_STYLES.get(lv, ("white", "gray", "white"))
21
+ parts = []
22
+ if show_time:
23
+ ts = datetime.fromtimestamp(rec["time"]).strftime(time_format)
24
+ parts.append(style(ts, "gray", enabled=color))
25
+ parts.append(style(f" {rec['level']:<8} ", badge_fg, badge_bg, bold=True, enabled=color))
26
+ if show_name:
27
+ parts.append(style(rec["name"], "magenta", enabled=color))
28
+ msg = style(rec["message"], msg_fg, bold=lv >= 40, enabled=color)
29
+ if rec["extra"]:
30
+ msg += " " + style(_extras(rec["extra"]), "gray", enabled=color)
31
+ parts.append(msg)
32
+ line = style(" | ", "gray", enabled=color).join(parts)
33
+ if rec.get("traceback"):
34
+ line += "\n" + style(rec["traceback"].rstrip(), "red", dim=True, enabled=color)
35
+ return line
36
+
37
+
38
+ def format_plain(rec: dict, time_format: str) -> str:
39
+ ts = datetime.fromtimestamp(rec["time"]).strftime(time_format)
40
+ line = f"{ts} | {rec['level']:<8} | {rec['name']} | {rec['message']}"
41
+ if rec["extra"]:
42
+ line += " " + _extras(rec["extra"])
43
+ if rec.get("traceback"):
44
+ line += "\n" + rec["traceback"].rstrip()
45
+ return line
46
+
47
+
48
+ def format_json(rec: dict) -> str:
49
+ data = {
50
+ "time": datetime.fromtimestamp(rec["time"]).isoformat(),
51
+ "level": rec["level"],
52
+ "name": rec["name"],
53
+ "message": rec["message"],
54
+ **rec["extra"],
55
+ }
56
+ if rec.get("traceback"):
57
+ data["traceback"] = rec["traceback"]
58
+ return json.dumps(data, default=str, ensure_ascii=False)
59
+
60
+
61
+ __all__ = ["format_console", "format_plain", "format_json", "LEVEL_NAMES"]
@@ -0,0 +1,39 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Thread-safe rotating file writer."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import os
8
+ import threading
9
+
10
+
11
+ class RotatingFileWriter:
12
+ """Append lines to a file and rotate it when it grows too large."""
13
+
14
+ def __init__(self, path: str, max_bytes: int = 5_000_000, backups: int = 3):
15
+ self.path = path
16
+ self.max_bytes = max_bytes
17
+ self.backups = backups
18
+ self._lock = threading.Lock()
19
+ folder = os.path.dirname(os.path.abspath(path))
20
+ os.makedirs(folder, exist_ok=True)
21
+
22
+ def _rotate(self) -> None:
23
+ for i in range(self.backups - 1, 0, -1):
24
+ src, dst = f"{self.path}.{i}", f"{self.path}.{i + 1}"
25
+ if os.path.exists(src):
26
+ os.replace(src, dst)
27
+ if self.backups > 0 and os.path.exists(self.path):
28
+ os.replace(self.path, f"{self.path}.1")
29
+
30
+ def write(self, line: str) -> None:
31
+ with self._lock:
32
+ try:
33
+ if self.max_bytes and os.path.exists(self.path) \
34
+ and os.path.getsize(self.path) >= self.max_bytes:
35
+ self._rotate()
36
+ with open(self.path, "a", encoding="utf-8") as fh:
37
+ fh.write(line + "\n")
38
+ except OSError:
39
+ pass # logging must never crash the application
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Log level definitions."""
4
+
5
+ from __future__ import annotations
6
+
7
+ TRACE = 5
8
+ DEBUG = 10
9
+ INFO = 20
10
+ SUCCESS = 25
11
+ WARNING = 30
12
+ ERROR = 40
13
+ CRITICAL = 50
14
+
15
+ LEVEL_NAMES = {
16
+ TRACE: "TRACE", DEBUG: "DEBUG", INFO: "INFO", SUCCESS: "SUCCESS",
17
+ WARNING: "WARNING", ERROR: "ERROR", CRITICAL: "CRITICAL",
18
+ }
19
+ NAME_TO_LEVEL = {v: k for k, v in LEVEL_NAMES.items()}
20
+ NAME_TO_LEVEL["WARN"] = WARNING
21
+
22
+ # level -> (badge foreground, badge background, message foreground)
23
+ LEVEL_STYLES = {
24
+ TRACE: ("white", "gray", "gray"),
25
+ DEBUG: ("black", "cyan", "cyan"),
26
+ INFO: ("white", "blue", "bright_blue"),
27
+ SUCCESS: ("black", "green", "bright_green"),
28
+ WARNING: ("black", "yellow", "bright_yellow"),
29
+ ERROR: ("white", "red", "bright_red"),
30
+ CRITICAL: ("bright_white", "bright_red", "bright_red"),
31
+ }
32
+
33
+
34
+ def resolve_level(level) -> int:
35
+ """Convert a level name (``"info"``) or number into an int."""
36
+ if isinstance(level, int):
37
+ return level
38
+ key = str(level).strip().upper()
39
+ if key not in NAME_TO_LEVEL:
40
+ raise ValueError(f"Unknown log level: {level!r}")
41
+ return NAME_TO_LEVEL[key]
@@ -0,0 +1,192 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ """Core Logger class and module-level convenience API."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import functools
8
+ import sys
9
+ import threading
10
+ import time
11
+ import traceback
12
+ from contextlib import contextmanager
13
+
14
+ from .colors import supports_color, style
15
+ from .formatter import format_console, format_json, format_plain
16
+ from .handlers import RotatingFileWriter
17
+ from .levels import (CRITICAL, DEBUG, ERROR, INFO, SUCCESS, TRACE, WARNING,
18
+ LEVEL_NAMES, resolve_level)
19
+
20
+
21
+ class Logger:
22
+ """A lightweight, colourful logger.
23
+
24
+ >>> log = Logger("app", level="DEBUG")
25
+ >>> log.info("Server started", port=8000)
26
+ """
27
+
28
+ def __init__(self, name: str = "veronix", level="INFO", *, color=None,
29
+ show_time: bool = True, show_name: bool = True, file: str | None = None,
30
+ json_mode: bool = False, stream=None, max_bytes: int = 5_000_000,
31
+ backups: int = 3, time_format: str = "%Y-%m-%d %H:%M:%S"):
32
+ self.name = name
33
+ self.level = resolve_level(level)
34
+ self.color = color # None = auto-detect
35
+ self.show_time = show_time
36
+ self.show_name = show_name
37
+ self.json_mode = json_mode
38
+ self.stream = stream # None = sys.stdout at call time
39
+ self.time_format = time_format
40
+ self._lock = threading.Lock()
41
+ self._file = RotatingFileWriter(file, max_bytes, backups) if file else None
42
+
43
+ # ------------------------------------------------------------ config
44
+ def configure(self, **kw) -> "Logger":
45
+ """Change settings at runtime (level, color, file, json_mode, ...)."""
46
+ if "level" in kw:
47
+ self.level = resolve_level(kw.pop("level"))
48
+ if "file" in kw:
49
+ path = kw.pop("file")
50
+ self._file = RotatingFileWriter(
51
+ path, kw.pop("max_bytes", 5_000_000), kw.pop("backups", 3)) if path else None
52
+ for key, value in kw.items():
53
+ if not hasattr(self, key):
54
+ raise TypeError(f"Unknown option: {key}")
55
+ setattr(self, key, value)
56
+ return self
57
+
58
+ def set_level(self, level) -> None:
59
+ self.level = resolve_level(level)
60
+
61
+ def child(self, name: str) -> "Logger":
62
+ """Create a logger that shares this logger's settings."""
63
+ new = Logger(f"{self.name}.{name}", self.level, color=self.color,
64
+ show_time=self.show_time, show_name=self.show_name,
65
+ json_mode=self.json_mode, stream=self.stream,
66
+ time_format=self.time_format)
67
+ new._file = self._file
68
+ return new
69
+
70
+ # ------------------------------------------------------------ core
71
+ def log(self, level, message, *args, exc_info: bool = False, **extra) -> None:
72
+ levelno = resolve_level(level)
73
+ if levelno < self.level:
74
+ return
75
+ message = str(message)
76
+ if args:
77
+ try:
78
+ message = message % args
79
+ except (TypeError, ValueError):
80
+ message = " ".join([message, *map(str, args)])
81
+ tb = traceback.format_exc() if exc_info and sys.exc_info()[0] else None
82
+ rec = {"time": time.time(), "levelno": levelno,
83
+ "level": LEVEL_NAMES.get(levelno, f"L{levelno}"),
84
+ "name": self.name, "message": message, "extra": extra, "traceback": tb}
85
+
86
+ stream = self.stream or sys.stdout
87
+ use_color = supports_color(stream) if self.color is None else self.color
88
+ with self._lock:
89
+ try:
90
+ if self.json_mode:
91
+ stream.write(format_json(rec) + "\n")
92
+ else:
93
+ stream.write(format_console(rec, use_color, self.show_time,
94
+ self.show_name, self.time_format) + "\n")
95
+ stream.flush()
96
+ except (OSError, ValueError):
97
+ pass
98
+ if self._file:
99
+ self._file.write(format_json(rec) if self.json_mode
100
+ else format_plain(rec, self.time_format))
101
+
102
+ def trace(self, msg, *a, **k): self.log(TRACE, msg, *a, **k)
103
+ def debug(self, msg, *a, **k): self.log(DEBUG, msg, *a, **k)
104
+ def info(self, msg, *a, **k): self.log(INFO, msg, *a, **k)
105
+ def success(self, msg, *a, **k): self.log(SUCCESS, msg, *a, **k)
106
+ def warning(self, msg, *a, **k): self.log(WARNING, msg, *a, **k)
107
+ warn = warning
108
+ def error(self, msg, *a, **k): self.log(ERROR, msg, *a, **k)
109
+ def critical(self, msg, *a, **k): self.log(CRITICAL, msg, *a, **k)
110
+
111
+ def exception(self, msg, *a, **k):
112
+ """Log an ERROR with the current traceback (use inside ``except``)."""
113
+ k["exc_info"] = True
114
+ self.log(ERROR, msg, *a, **k)
115
+
116
+ # ------------------------------------------------------------ extras
117
+ def banner(self, text: str, fg: str = "bright_cyan", width: int = 0) -> None:
118
+ """Print a framed banner (console only)."""
119
+ stream = self.stream or sys.stdout
120
+ c = supports_color(stream) if self.color is None else self.color
121
+ width = max(width, len(text) + 4)
122
+ bar = "=" * width
123
+ stream.write(style(bar, fg, enabled=c) + "\n"
124
+ + style(text.center(width), fg, bold=True, enabled=c) + "\n"
125
+ + style(bar, fg, enabled=c) + "\n")
126
+ stream.flush()
127
+
128
+ def rule(self, title: str = "", width: int = 60) -> None:
129
+ """Print a horizontal divider line."""
130
+ stream = self.stream or sys.stdout
131
+ c = supports_color(stream) if self.color is None else self.color
132
+ line = f" {title} ".center(width, "-") if title else "-" * width
133
+ stream.write(style(line, "gray", enabled=c) + "\n")
134
+ stream.flush()
135
+
136
+ @contextmanager
137
+ def timer(self, label: str = "task", level=SUCCESS):
138
+ """Time a block of code: ``with log.timer("db query"): ...``"""
139
+ start = time.perf_counter()
140
+ try:
141
+ yield
142
+ finally:
143
+ self.log(level, f"{label} finished in {time.perf_counter() - start:.3f}s")
144
+
145
+ def log_calls(self, func=None, *, level=DEBUG):
146
+ """Decorator that logs calls, results and exceptions of a function."""
147
+ def decorate(fn):
148
+ @functools.wraps(fn)
149
+ def wrapper(*args, **kwargs):
150
+ self.log(level, f"calling {fn.__name__}()")
151
+ start = time.perf_counter()
152
+ try:
153
+ result = fn(*args, **kwargs)
154
+ except Exception:
155
+ self.exception(f"{fn.__name__}() raised an exception")
156
+ raise
157
+ self.log(level, f"{fn.__name__}() returned in {time.perf_counter() - start:.4f}s")
158
+ return result
159
+ return wrapper
160
+ return decorate(func) if func else decorate
161
+
162
+
163
+ # ---------------------------------------------------------------- default API
164
+ _default = Logger("veronix")
165
+ _loggers: dict = {}
166
+
167
+
168
+ def get_logger(name: str = "veronix", **kwargs) -> Logger:
169
+ """Return a named logger (cached). Extra kwargs apply on first creation."""
170
+ if name not in _loggers:
171
+ _loggers[name] = Logger(name, **kwargs)
172
+ return _loggers[name]
173
+
174
+
175
+ def configure(**kwargs) -> Logger:
176
+ """Configure the default logger used by ``veronix.info()`` etc."""
177
+ return _default.configure(**kwargs)
178
+
179
+
180
+ def trace(msg, *a, **k): _default.trace(msg, *a, **k)
181
+ def debug(msg, *a, **k): _default.debug(msg, *a, **k)
182
+ def info(msg, *a, **k): _default.info(msg, *a, **k)
183
+ def success(msg, *a, **k): _default.success(msg, *a, **k)
184
+ def warning(msg, *a, **k): _default.warning(msg, *a, **k)
185
+ warn = warning
186
+ def error(msg, *a, **k): _default.error(msg, *a, **k)
187
+ def critical(msg, *a, **k): _default.critical(msg, *a, **k)
188
+ def exception(msg, *a, **k): _default.exception(msg, *a, **k)
189
+ def banner(text, **k): _default.banner(text, **k)
190
+ def rule(title="", **k): _default.rule(title, **k)
191
+ def timer(label="task", **k): return _default.timer(label, **k)
192
+ def log_calls(func=None, **k): return _default.log_calls(func, **k)
File without changes
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: veronix
3
+ Version: 1.0.0
4
+ Summary: Clean, professional and colourful console logging for Python - by 1tz.raj
5
+ Author: 1tz.raj
6
+ Maintainer: 1tz.raj
7
+ License: VERONIX PROPRIETARY LICENSE - ALL RIGHTS RESERVED
8
+
9
+ Copyright (c) 2026 1tz.raj (GitHub: 7rzraj). All rights reserved.
10
+
11
+ 1. GRANT. You may install Veronix with "pip install veronix" and use it, free
12
+ of charge, in personal, educational and commercial projects, including as a
13
+ dependency of your own software.
14
+
15
+ 2. RESTRICTIONS. Without prior written permission from the author you may NOT:
16
+ a) republish, re-upload or redistribute Veronix (original or modified, in
17
+ source or binary form) on PyPI, GitHub, any package index, website,
18
+ marketplace or any other platform;
19
+ b) sell, sublicense, rent or claim Veronix as your own work;
20
+ c) rename, rebrand or fork it into a competing or look-alike package;
21
+ d) remove or alter copyright notices, author credits or this license.
22
+
23
+ 3. ENFORCEMENT. Any republication or unauthorised copying is copyright
24
+ infringement. The author may file takedown notices (e.g. DMCA) with PyPI,
25
+ GitHub and hosting providers and pursue legal remedies.
26
+
27
+ 4. NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
28
+ THE AUTHOR IS NOT LIABLE FOR ANY CLAIM OR DAMAGES ARISING FROM ITS USE.
29
+
30
+ Contact: Instagram @1tz.raj_ | GitHub @7rzraj | Discord 1tz.raj
31
+
32
+ Project-URL: Homepage, https://github.com/7rzraj/veronix
33
+ Project-URL: Documentation, https://github.com/7rzraj/veronix#readme
34
+ Project-URL: Source, https://github.com/7rzraj/veronix
35
+ Project-URL: Issues, https://github.com/7rzraj/veronix/issues
36
+ Project-URL: Changelog, https://github.com/7rzraj/veronix/blob/main/CHANGELOG.md
37
+ Project-URL: Developer, https://github.com/7rzraj
38
+ Project-URL: Instagram, https://instagram.com/1tz.raj_
39
+ Keywords: logging,logger,colorful logs,console logging,python logger,colored terminal,ansi colors,veronix,1tz.raj,7rzraj,cli logging
40
+ Classifier: Development Status :: 5 - Production/Stable
41
+ Classifier: Intended Audience :: Developers
42
+ Classifier: License :: Other/Proprietary License
43
+ Classifier: Operating System :: OS Independent
44
+ Classifier: Programming Language :: Python :: 3
45
+ Classifier: Programming Language :: Python :: 3.8
46
+ Classifier: Programming Language :: Python :: 3.9
47
+ Classifier: Programming Language :: Python :: 3.10
48
+ Classifier: Programming Language :: Python :: 3.11
49
+ Classifier: Programming Language :: Python :: 3.12
50
+ Classifier: Programming Language :: Python :: 3.13
51
+ Classifier: Topic :: System :: Logging
52
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
53
+ Classifier: Typing :: Typed
54
+ Requires-Python: >=3.8
55
+ Description-Content-Type: text/markdown
56
+ License-File: LICENSE
57
+ Dynamic: license-file
58
+
59
+ <div align="center">
60
+
61
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/banner.png" alt="Veronix - colourful Python logging by 1tz.raj" width="100%">
62
+
63
+ [![PyPI](https://img.shields.io/pypi/v/veronix?color=blue)](https://pypi.org/project/veronix/)
64
+ [![Python](https://img.shields.io/pypi/pyversions/veronix)](https://pypi.org/project/veronix/)
65
+ [![CI](https://github.com/7rzraj/veronix/actions/workflows/ci.yml/badge.svg)](https://github.com/7rzraj/veronix/actions)
66
+ [![License](https://img.shields.io/badge/license-Proprietary-red)](LICENSE)
67
+ [![Downloads](https://img.shields.io/pypi/dm/veronix)](https://pypi.org/project/veronix/)
68
+
69
+ Made with ❤️ by **[1tz.raj](https://github.com/7rzraj)**
70
+
71
+ </div>
72
+
73
+ <div align="center">
74
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/demo-screenshot.png" alt="Veronix demo output in terminal" width="85%">
75
+ </div>
76
+
77
+ ---
78
+
79
+ ## 📦 Installation
80
+
81
+ ```bash
82
+ pip install veronix
83
+ ```
84
+
85
+ ## 🚀 Usage
86
+
87
+ ```python
88
+ import veronix
89
+
90
+ veronix.info("Server started", port=8000)
91
+ veronix.success("Database connected")
92
+ veronix.warning("Disk almost full")
93
+ veronix.error("Payment failed", order_id=1042)
94
+ veronix.critical("System down!")
95
+ ```
96
+
97
+ ### Levels
98
+ `TRACE` · `DEBUG` · `INFO` · `SUCCESS` · `WARNING` · `ERROR` · `CRITICAL`
99
+
100
+ ### Configure
101
+
102
+ ```python
103
+ veronix.configure(level="DEBUG", file="logs/app.log") # save to file (auto-rotating)
104
+ veronix.configure(json_mode=True) # JSON logs
105
+ ```
106
+
107
+ ### Named loggers
108
+
109
+ ```python
110
+ api = veronix.get_logger("api")
111
+ api.info("GET /users 200")
112
+ ```
113
+
114
+ ### Timer, decorator, exceptions
115
+
116
+ ```python
117
+ with veronix.timer("db query"):
118
+ run_query()
119
+
120
+ @veronix.log_calls
121
+ def work(): ...
122
+
123
+ try:
124
+ 1 / 0
125
+ except ZeroDivisionError:
126
+ veronix.exception("Something broke") # prints full traceback
127
+ ```
128
+
129
+ ### Banner & divider
130
+
131
+ ```python
132
+ veronix.banner("My App v1.0")
133
+ veronix.rule("Startup")
134
+ ```
135
+
136
+ ## 💻 Command line
137
+
138
+ | Command | What it does |
139
+ |---|---|
140
+ | `veronix demo` | See all colours and levels |
141
+ | `veronix info` | Developer and package details |
142
+ | `veronix levels` | List log levels |
143
+ | `veronix log "text" -l ERROR` | Print one log line |
144
+ | `veronix --version` | Show version |
145
+
146
+ ## ✨ Features
147
+ - Auto colour detection (respects `NO_COLOR` / `FORCE_COLOR`), works on Windows, Linux, macOS
148
+ - Zero dependencies
149
+ - File logging with rotation, JSON output, thread-safe
150
+ - Fully typed (`py.typed`)
151
+
152
+ ## 👨‍💻 Developer
153
+
154
+ <img src="https://raw.githubusercontent.com/7rzraj/veronix/main/assets/avatar.png" width="110" align="right" alt="1tz.raj">
155
+
156
+ | | |
157
+ |---|---|
158
+ | **Name** | 1tz.raj |
159
+ | **GitHub** | [@7rzraj](https://github.com/7rzraj) |
160
+ | **Instagram** | [@1tz.raj_](https://instagram.com/1tz.raj_) |
161
+ | **Discord** | `1tz.raj` |
162
+ | **Project** | https://github.com/7rzraj/veronix |
163
+
164
+ ## ⚠️ Copyright Notice
165
+
166
+ © 2026 **1tz.raj**. All rights reserved.
167
+ You may **use** Veronix freely, but you may **not republish, re-upload, rebrand or redistribute** it
168
+ (on PyPI, GitHub or anywhere else). Violations will result in a copyright takedown (DMCA).
169
+ See [LICENSE](LICENSE).
170
+
171
+ <sub>Keywords: veronix, 1tz.raj, 7rzraj, python logging, colorful logger, console logger, pip install veronix</sub>
@@ -0,0 +1,21 @@
1
+ CHANGELOG.md
2
+ LICENSE
3
+ MANIFEST.in
4
+ README.md
5
+ pyproject.toml
6
+ src/veronix/__about__.py
7
+ src/veronix/__init__.py
8
+ src/veronix/__main__.py
9
+ src/veronix/cli.py
10
+ src/veronix/colors.py
11
+ src/veronix/formatter.py
12
+ src/veronix/handlers.py
13
+ src/veronix/levels.py
14
+ src/veronix/logger.py
15
+ src/veronix/py.typed
16
+ src/veronix.egg-info/PKG-INFO
17
+ src/veronix.egg-info/SOURCES.txt
18
+ src/veronix.egg-info/dependency_links.txt
19
+ src/veronix.egg-info/entry_points.txt
20
+ src/veronix.egg-info/top_level.txt
21
+ tests/test_veronix.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ veronix = veronix.cli:main
@@ -0,0 +1 @@
1
+ veronix
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2026 1tz.raj. All rights reserved.
2
+
3
+ import io
4
+ import json
5
+ import os
6
+ import tempfile
7
+ import unittest
8
+
9
+ import veronix
10
+ from veronix import Logger
11
+
12
+
13
+ class TestVeronix(unittest.TestCase):
14
+ def make(self, **kw):
15
+ buf = io.StringIO()
16
+ return Logger("t", stream=buf, color=False, **kw), buf
17
+
18
+ def test_levels_filter(self):
19
+ log, buf = self.make(level="WARNING")
20
+ log.info("hidden")
21
+ log.error("shown")
22
+ out = buf.getvalue()
23
+ self.assertNotIn("hidden", out)
24
+ self.assertIn("shown", out)
25
+
26
+ def test_color_codes(self):
27
+ buf = io.StringIO()
28
+ Logger("t", stream=buf, color=True).success("ok")
29
+ self.assertIn("\033[", buf.getvalue())
30
+
31
+ def test_no_color(self):
32
+ log, buf = self.make()
33
+ log.info("plain")
34
+ self.assertNotIn("\033[", buf.getvalue())
35
+
36
+ def test_extra_and_format_args(self):
37
+ log, buf = self.make()
38
+ log.info("user %s", "raj", id=7)
39
+ self.assertIn("user raj", buf.getvalue())
40
+ self.assertIn("id=7", buf.getvalue())
41
+
42
+ def test_json_and_file(self):
43
+ with tempfile.TemporaryDirectory() as d:
44
+ path = os.path.join(d, "app.log")
45
+ log, buf = self.make(file=path, json_mode=True)
46
+ log.info("hello", a=1)
47
+ data = json.loads(open(path, encoding="utf-8").read().strip())
48
+ self.assertEqual(data["message"], "hello")
49
+ self.assertEqual(data["a"], 1)
50
+
51
+ def test_exception(self):
52
+ log, buf = self.make()
53
+ try:
54
+ 1 / 0
55
+ except ZeroDivisionError:
56
+ log.exception("boom")
57
+ self.assertIn("ZeroDivisionError", buf.getvalue())
58
+
59
+ def test_timer_and_decorator(self):
60
+ log, buf = self.make(level="DEBUG")
61
+ with log.timer("job"):
62
+ pass
63
+
64
+ @log.log_calls
65
+ def f():
66
+ return 1
67
+
68
+ self.assertEqual(f(), 1)
69
+ self.assertIn("job finished", buf.getvalue())
70
+ self.assertIn("calling f()", buf.getvalue())
71
+
72
+ def test_bad_level(self):
73
+ with self.assertRaises(ValueError):
74
+ Logger(level="nope")
75
+
76
+ def test_public_api(self):
77
+ self.assertTrue(callable(veronix.info))
78
+ self.assertEqual(veronix.__author__, "1tz.raj")
79
+
80
+
81
+ if __name__ == "__main__":
82
+ unittest.main()