Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6d148b7
version bump
XulbuX Dec 20, 2025
c4eaad7
everything as described in the `CHANGELOG.md` for `v1.9.3`
XulbuX Dec 20, 2025
1a8cb4f
OS specific functionality fixes
XulbuX Dec 20, 2025
54e9c04
define class-properties using `metaclass` and unnest simple nested me…
XulbuX Dec 20, 2025
f266f43
made some internal methods private & made internal classmethods stati…
XulbuX Dec 20, 2025
a72f946
- make all internal classes and methods be prefixed using only a sing…
XulbuX Dec 21, 2025
fdf9dea
adjust CHANGELOG changes order
XulbuX Dec 21, 2025
f8390f1
adjust CHANGELOG change descriptions
XulbuX Dec 21, 2025
549817f
unnest all nested methods in the `format_codes` module & linting
XulbuX Dec 21, 2025
47b460e
adjust docstrings and rename certain internal params to clarify their…
XulbuX Dec 21, 2025
ec71076
remove pointless TypeAlias' & unnest remaining nested methods in the …
XulbuX Dec 21, 2025
3a201a9
fix type error
XulbuX Dec 21, 2025
89efc34
add new attribute `is_positional` to `ArgResult` & correct internal m…
XulbuX Dec 21, 2025
337d272
linting
XulbuX Dec 22, 2025
9a85f2e
fix `AttributeError`s from GitHub Actions test run
XulbuX Dec 22, 2025
b0b6448
fix GitHub Actions run #2
XulbuX Dec 22, 2025
d20a046
fix GitHub Actions run #3
XulbuX Dec 22, 2025
c695572
fix GitHub Actions run #4
XulbuX Dec 22, 2025
d0859b6
fix GitHub Actions run #5
XulbuX Dec 22, 2025
3398c27
fix GitHub Actions run #6
XulbuX Dec 22, 2025
2525efd
fix GitHub Actions run #7
XulbuX Dec 22, 2025
68b53ec
fix GitHub Actions run #8
XulbuX Dec 22, 2025
5000103
fix GitHub Actions run #9
XulbuX Dec 22, 2025
d73e71b
fix GitHub Actions run #10
XulbuX Dec 22, 2025
e1a6890
fix GitHub Actions run #11
XulbuX Dec 22, 2025
b7df19a
remove redundant `@mypyc_attr(…)` decorators
XulbuX Dec 22, 2025
7ad3c68
add back `@mypyc_attr(…)` decorators that apparently aren't redundant…
XulbuX Dec 23, 2025
c9ea8dc
add missing import
XulbuX Dec 23, 2025
692e6ba
adjust `console` module tests mocking/patching to work with the `Cons…
XulbuX Dec 23, 2025
b4669b6
adjust `console` module tests mocking/patching to work with the `Cons…
XulbuX Dec 23, 2025
250232e
fix `'Console.get_args' is too complex` and other linting
XulbuX Dec 23, 2025
4b34217
add benchmarking results to `CHANGELOG.md` & adjust license file patt…
XulbuX Dec 23, 2025
3decd1c
make type corrections, add docstrings to dunder methods, rename const…
XulbuX Dec 24, 2025
a7c0e65
fix: no backslashes in f-string expression part
XulbuX Dec 24, 2025
0d8f478
fix `C901 '_ConsoleArgsParseHelper.process_positional_args' is too co…
XulbuX Dec 24, 2025
7ddb5ed
fix `C901 too complex` linting errors
XulbuX Dec 24, 2025
50696cb
fix `… == None` comparison
XulbuX Dec 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 4 additions & 22 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,33 +1,15 @@
# IDE & EDITOR SETTINGS
.vscode/
.python-version

# CREDENTIALS & CONFIGURATION
.env
.npmrc
.pypirc

# COMPILED FILES & CACHES
__pycache__/
__pypackages__/
.mypy_cache/
.pytest_cache/
*.py[cod]
*$py.class

# BUILD ARTIFACTS
*.egg-info/
build/
dist/
target/
wheels/
*.egg-info/
.Python
.pybuilder/
.pytype/
cython_debug/
__pypackages__/

# TESTING
.venv/
.pytest_cache/

# MISCELLANEOUS
.DS_Store
Thumbs.db
43 changes: 40 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,44 @@
# <br><b>Changelog</b><br>


<span id="v1-9-3" />

## ... `v1.9.3` Big Update 🚀

* Added a new method `Color.str_to_hsla()` to parse HSLA colors from strings.
* Changed the default syntax highlighting for `Data.to_str()` and therefore also `Data.print()` to use console default colors.
* Added the missing but needed dunder methods to the `Args` and `ArgResult` classes and the `rgba`, `hsla` and `hexa` color objects for better usability and type checking.
* Added three new methods to `Args`:
- `get()` returns the argument result for a given alias, or a default value if not found
- `existing()` yields only the existing arguments as tuples of `(alias, ArgResult)`
- `missing()` yields only the missing arguments as tuples of `(alias, ArgResult)`
* Added a new attribute `is_positional` to `ArgResult`, which indicates whether the argument is a positional argument or not.
* The `ArgResult` class now also has a `dict()` method, which returns the argument result as a dictionary.
* Added new properties `is_tty` and `supports_color` to the `Console` class, `home` to the `Path` class and `is_win` to the `System` class.
* Added the option to add format specifiers to the `{current}`, `{total}` and `{percentage}` placeholders in the `bar_format` and `limited_bar_format` of `ProgressBar`.
* Finally fixed the `C901 'Console.get_args' is too complex (39)` linting error by refactoring the method into its own helper class.
* Changed the string- and repr-representations of the `rgba` and `hsla` color objects and newly implemented it for the `Args` and `ArgResult` classes.
* Made internal, global constants, which's values never change, into `Final` constants for better type checking.
* The names of all internal classes and methods are all no longer prefixed with a double underscore (`__`), but a single underscore (`_`) instead.
* Changed all methods defined as `@staticmethod` to `@classmethod` where applicable, to improve inheritance capabilities.
* Adjusted the whole library's type hints to be way more strict and accurate, using `mypy` as static type checker.
* Change the class-property definitions to be defined via `metaclass` and using `@property` decorators, to make them compatible with `mypyc`.
* Unnest all the nested methods in the whole library for compatibility with `mypyc`.
* The library is now compiled using `mypyc` when installing, which makes it run significantly faster. Benchmarking results:
- Simple methods like data and color operations had a speed improvement of around 50%.
- Complex methods like console logging had a speed improvement of up to 230%!

**BREAKING CHANGES:**
* Renamed `Data.to_str()` to `Data.render()`, since that describes its functionality better (*especially with the syntax highlighting option*).
* Renamed the constant `ANSI.ESCAPED_CHAR` to `ANSI.CHAR_ESCAPED` for better consistency with the other constant names.
* Removed the general `Pattern` and `Match` type aliases from the `base.types` module (*they are pointless since you should always use a specific type and not "type1 OR typeB"*).
* Removed the `_` prefix from the param `_syntax_highlighting` in `Data.render()`, since it's no longer just for internal use.


<span id="v1-9-2" />

## 16.12.2025 `v1.9.2`

* Added a new class `LazyRegex` to the `regex` module, which is used to define regex patterns that are only compiled when they are used for the first time.
* Removed unnecessary character escaping in the precompiled regex patterns in the `console` module.
* Removed all the runtime type-checks that can also be checked using static type-checking tools, since you're supposed to use type checkers in modern python anyway, and to improve performance.
Expand All @@ -40,6 +75,7 @@
<span id="v1-9-1" />

## 26.11.2025 `v1.9.1`

* Unified the module and class docstring styles throughout the whole library.
* Moved the Protocol `ProgressUpdater` from the `console` module to the `types` module.
* Added throttling to the `ProgressBar` update methods to impact the actual process' performance as little as possible.
Expand All @@ -55,6 +91,7 @@
<span id="v1-9-0" />

## 21.11.2025 `v1.9.0` Big Update 🚀

* Standardized the docstrings for all public methods in the whole library to use the same style and structure.
* Replaced left over single quotes with double quotes for consistency.
* Fixed a bug inside `Data.remove_empty_items()`, where types other than strings where passed to `String.is_empty()`, which caused an exception.
Expand Down Expand Up @@ -194,7 +231,7 @@
## 17.06.2025 `v1.7.2`

* The `Console.w`, `Console.h` and `Console.wh` class properties now return a default size if there is no console, instead of throwing an error.
* It wasn't actually possible to use default console-colors (*e.g.* `"red"`, `"green"`, ...) for the color params in `Console.log()` so that option was completely removed again.
* It wasn't actually possible to use default console-colors (*e.g.* `"red"`, `"green"`, ) for the color params in `Console.log()` so that option was completely removed again.
* Upgraded the speed of `FormatCodes.to_ansi()` by adding the internal ability to skip the `default_color` validation.
* Fixed type hints for the whole library.
* Fixed a small bug in `Console.pause_exit()`, where the key, pressed to unpause wasn't suppressed, so it was written into the next console input after unpausing.
Expand All @@ -208,7 +245,7 @@
* Added a new method `Console.log_box_bordered()`, which does the same as `Console.log_box_filled()`, but with a border instead of a background color.
* The module `xx_format_codes` now treats the `[*]` to-default-color-reset as a normal full-reset, when no `default_color` is set, instead of just counting it as an invalid format code.
* Fixed bug where entering a color as HEX integer in the color params of the methods `Console.log()`, `Console.log_box_filled()` and `Console.log_box_bordered()` would not work, because it was not properly converted to a format code.
* You can now use default console colors (*e.g.* `"red"`, `"green"`, ...) for the color params in `Console.log()`.
* You can now use default console colors (*e.g.* `"red"`, `"green"`, ) for the color params in `Console.log()`.
* The methods `Console.log_box_filled()` and `Console.log_box_bordered()` no longer right-strip spaces, so you can make multiple log boxes the same width, by adding spaces to the end of the text.

**BREAKING CHANGES:**
Expand Down Expand Up @@ -774,7 +811,7 @@ from XulbuX import rgb, hsl, hexa
<thead>
<tr>
<th>Features</th>
<th>class, type, function, ...</th>
<th>class, type, function, </th>
</tr>
</thead>
<tbody>
Expand Down
18 changes: 14 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
[build-system]
requires = ["setuptools>=61.0"]
requires = [
"setuptools>=80.0.0",
"wheel>=0.45.0",
"mypy>=1.19.0",
"mypy-extensions>=1.1.0",
# TYPES FOR MyPy
"types-regex",
"types-keyboard",
"prompt_toolkit>=3.0.41",
]
build-backend = "setuptools.build_meta"

[project]
name = "xulbux"
version = "1.9.2"
version = "1.9.3"
authors = [{ name = "XulbuX", email = "xulbux.real@gmail.com" }]
maintainers = [{ name = "XulbuX", email = "xulbux.real@gmail.com" }]
description = "A Python library to simplify common programming tasks."
readme = "README.md"
license = "MIT"
license-files = ["LICEN[CS]E.*"]
license-files = ["LICENSE"]
requires-python = ">=3.10.0"
dependencies = [
"keyboard>=0.13.5",
"mypy-extensions>=1.1.0",
"prompt_toolkit>=3.0.41",
"regex>=2023.10.3",
]
Expand Down Expand Up @@ -139,7 +149,7 @@ ensure_newline_before_comments = true
max-complexity = 12
max-line-length = 127
select = ["E", "F", "W", "C90"]
extend-ignore = ["E203", "E266", "W503"]
extend-ignore = ["E203", "E266", "E502", "W503"]
per-file-ignores = ["__init__.py:F403,F405"]

[tool.setuptools]
Expand Down
20 changes: 20 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from mypyc.build import mypycify
from setuptools import setup
import os


def find_python_files(directory: str) -> list[str]:
python_files: list[str] = []
for root, _, files in os.walk(directory):
for file in files:
if file.endswith(".py"):
python_files.append(os.path.join(root, file))
return python_files


source_files = find_python_files("src/xulbux")

setup(
name="xulbux",
ext_modules=mypycify(source_files),
)
2 changes: 1 addition & 1 deletion src/xulbux/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.9.2"
__version__ = "1.9.3"

__author__ = "XulbuX"
__email__ = "xulbux.real@gmail.com"
Expand Down
96 changes: 49 additions & 47 deletions src/xulbux/base/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,98 +4,100 @@

from .types import FormattableString, AllTextChars

from typing import Final


class COLOR:
"""Hexadecimal color presets."""

WHITE = "#F1F2FF"
LIGHT_GRAY = "#B6B7C0"
GRAY = "#7B7C8D"
DARK_GRAY = "#67686C"
BLACK = "#202125"
RED = "#FF606A"
CORAL = "#FF7069"
ORANGE = "#FF876A"
TANGERINE = "#FF9962"
GOLD = "#FFAF60"
YELLOW = "#FFD260"
LIME = "#C9F16E"
GREEN = "#7EE787"
NEON_GREEN = "#4CFF85"
TEAL = "#50EAAF"
CYAN = "#3EDEE6"
ICE = "#77DBEF"
LIGHT_BLUE = "#60AAFF"
BLUE = "#8085FF"
LAVENDER = "#9B7DFF"
PURPLE = "#AD68FF"
MAGENTA = "#C860FF"
PINK = "#F162EF"
ROSE = "#FF609F"
WHITE: Final = "#F1F2FF"
LIGHT_GRAY: Final = "#B6B7C0"
GRAY: Final = "#7B7C8D"
DARK_GRAY: Final = "#67686C"
BLACK: Final = "#202125"
RED: Final = "#FF606A"
CORAL: Final = "#FF7069"
ORANGE: Final = "#FF876A"
TANGERINE: Final = "#FF9962"
GOLD: Final = "#FFAF60"
YELLOW: Final = "#FFD260"
LIME: Final = "#C9F16E"
GREEN: Final = "#7EE787"
NEON_GREEN: Final = "#4CFF85"
TEAL: Final = "#50EAAF"
CYAN: Final = "#3EDEE6"
ICE: Final = "#77DBEF"
LIGHT_BLUE: Final = "#60AAFF"
BLUE: Final = "#8085FF"
LAVENDER: Final = "#9B7DFF"
PURPLE: Final = "#AD68FF"
MAGENTA: Final = "#C860FF"
PINK: Final = "#F162EF"
ROSE: Final = "#FF609F"


class CHARS:
"""Character set constants for text validation and filtering."""

ALL = AllTextChars()
ALL: Final = AllTextChars()
"""Sentinel value indicating all characters are allowed."""

DIGITS = "0123456789"
DIGITS: Final = "0123456789"
"""Numeric digits: `0`-`9`"""
FLOAT_DIGITS = "." + DIGITS
FLOAT_DIGITS: Final = "." + DIGITS
"""Numeric digits with decimal point: `0`-`9` and `.`"""
HEX_DIGITS = "#" + DIGITS + "abcdefABCDEF"
HEX_DIGITS: Final = "#" + DIGITS + "abcdefABCDEF"
"""Hexadecimal digits: `0`-`9`, `a`-`f`, `A`-`F`, and `#`"""

LOWERCASE = "abcdefghijklmnopqrstuvwxyz"
LOWERCASE: Final = "abcdefghijklmnopqrstuvwxyz"
"""Lowercase ASCII letters: `a`-`z`"""
LOWERCASE_EXTENDED = LOWERCASE + "äëïöüÿàèìòùáéíóúýâêîôûãñõåæç"
LOWERCASE_EXTENDED: Final = LOWERCASE + "äëïöüÿàèìòùáéíóúýâêîôûãñõåæç"
"""Lowercase ASCII letters with diacritic marks."""
UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
UPPERCASE: Final = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"""Uppercase ASCII letters: `A`-`Z`"""
UPPERCASE_EXTENDED = UPPERCASE + "ÄËÏÖÜÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÅÆÇß"
UPPERCASE_EXTENDED: Final = UPPERCASE + "ÄËÏÖÜÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÅÆÇß"
"""Uppercase ASCII letters with diacritic marks."""

LETTERS = LOWERCASE + UPPERCASE
LETTERS: Final = LOWERCASE + UPPERCASE
"""All ASCII letters: `a`-`z` and `A`-`Z`"""
LETTERS_EXTENDED = LOWERCASE_EXTENDED + UPPERCASE_EXTENDED
LETTERS_EXTENDED: Final = LOWERCASE_EXTENDED + UPPERCASE_EXTENDED
"""All ASCII letters with diacritic marks."""

SPECIAL_ASCII = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
SPECIAL_ASCII: Final = " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
"""Standard ASCII special characters and symbols."""
SPECIAL_ASCII_EXTENDED = SPECIAL_ASCII + "ø£Ø×ƒªº¿®¬½¼¡«»░▒▓│┤©╣║╗╝¢¥┐└┴┬├─┼╚╔╩╦╠═╬¤ðÐı┘┌█▄¦▀µþÞ¯´≡­±‗¾¶§÷¸°¨·¹³²■ "
SPECIAL_ASCII_EXTENDED: Final = SPECIAL_ASCII + "ø£Ø×ƒªº¿®¬½¼¡«»░▒▓│┤©╣║╗╝¢¥┐└┴┬├─┼╚╔╩╦╠═╬¤ðÐı┘┌█▄¦▀µþÞ¯´≡­±‗¾¶§÷¸°¨·¹³²■ "
"""Standard and extended ASCII special characters."""
STANDARD_ASCII = DIGITS + LETTERS + SPECIAL_ASCII
STANDARD_ASCII: Final = DIGITS + LETTERS + SPECIAL_ASCII
"""All standard ASCII characters (letters, digits, and symbols)."""
FULL_ASCII = DIGITS + LETTERS_EXTENDED + SPECIAL_ASCII_EXTENDED
FULL_ASCII: Final = DIGITS + LETTERS_EXTENDED + SPECIAL_ASCII_EXTENDED
"""Complete ASCII character set including extended characters."""


class ANSI:
"""Constants and utilities for ANSI escape code sequences."""

ESCAPED_CHAR = "\\x1b"
CHAR_ESCAPED: Final = r"\x1b"
"""Printable ANSI escape character."""
CHAR = "\x1b"
CHAR: Final = "\x1b"
"""ANSI escape character."""
START = "["
START: Final = "["
"""Start of an ANSI escape sequence."""
SEP = ";"
SEP: Final = ";"
"""Separator between ANSI escape sequence parts."""
END = "m"
END: Final = "m"
"""End of an ANSI escape sequence."""

@classmethod
def seq(cls, placeholders: int = 1) -> FormattableString:
"""Generates an ANSI escape sequence with the specified number of placeholders."""
return cls.CHAR + cls.START + cls.SEP.join(["{}" for _ in range(placeholders)]) + cls.END

SEQ_COLOR: FormattableString = CHAR + START + "38" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
SEQ_COLOR: Final[FormattableString] = CHAR + START + "38" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
"""ANSI escape sequence with three placeholders for setting the RGB text color."""
SEQ_BG_COLOR: FormattableString = CHAR + START + "48" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
SEQ_BG_COLOR: Final[FormattableString] = CHAR + START + "48" + SEP + "2" + SEP + "{}" + SEP + "{}" + SEP + "{}" + END
"""ANSI escape sequence with three placeholders for setting the RGB background color."""

COLOR_MAP: tuple[str, ...] = (
COLOR_MAP: Final[tuple[str, ...]] = (
########### DEFAULT CONSOLE COLOR NAMES ############
"black",
"red",
Expand All @@ -108,7 +110,7 @@ def seq(cls, placeholders: int = 1) -> FormattableString:
)
"""The standard terminal color names."""

CODES_MAP: dict[str | tuple[str, ...], int] = {
CODES_MAP: Final[dict[str | tuple[str, ...], int]] = {
################# SPECIFIC RESETS ##################
"_": 0,
("_bold", "_b"): 22,
Expand Down
5 changes: 5 additions & 0 deletions src/xulbux/base/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
This module contains all custom exception classes used throughout the library.
"""

from mypy_extensions import mypyc_attr

#
################################################## FILE ##################################################


@mypyc_attr(native_class=False)
class SameContentFileExistsError(FileExistsError):
"""Raised when attempting to create a file that already exists with identical content."""
...
Expand All @@ -13,6 +17,7 @@ class SameContentFileExistsError(FileExistsError):
################################################## PATH ##################################################


@mypyc_attr(native_class=False)
class PathNotFoundError(FileNotFoundError):
"""Raised when a file system path does not exist or cannot be accessed."""
...
Loading