Skip to content

Commit f30ee91

Browse files
fix: Handle percent signs in arguments' help text.
1 parent afaf052 commit f30ee91

5 files changed

Lines changed: 107 additions & 24 deletions

File tree

CHANGELOG.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,67 @@ Help this project by [Donation](DONATE.md)
66
Changes
77
-------
88

9+
### v3.3.2
10+
11+
Handle percent signs in arguments' help text.
12+
13+
In the older versions, if you had a percent sign in the help text of an argument, it
14+
would cause an error when you try to show the help. This is because the argparse
15+
module uses percent signs for string formatting, and it would try to format the help
16+
text as a string, which would fail if there are any percent signs in it.
17+
18+
The workaround for this issue was to escape the percent signs by doubling them, but it
19+
was not a good solution. Now, in v3.3.2, log21 handles percent signs in arguments' help
20+
text properly, so you can use percent signs without any issues.
21+
22+
#### Example (works before and after v3.3.2)
23+
24+
```python
25+
import log21
26+
27+
28+
def show_percentage(a: float, b: float, /) -> None:
29+
"""Takes two numbers and returns the percentage of a in b. E.g. if a is 50 and b is
30+
200, the percentage would be 25.00%.
31+
32+
:param a: The first number. (a %% b)
33+
:param b: The second number. (a %% b)
34+
:return: The percentage of a in b.
35+
"""
36+
if b == 0:
37+
raise log21.ArgumentError("b cannot be zero.")
38+
percentage = (a / b) * 100
39+
print(f"{a} is {percentage:.2f}% of {b}.")
40+
41+
42+
if __name__ == "__main__":
43+
log21.argumentify(show_percentage)
44+
```
45+
46+
#### Example (Works only after v3.3.2)
47+
48+
```python
49+
import log21
50+
51+
52+
def show_percentage(a: float, b: float, /) -> None:
53+
"""Takes two numbers and returns the percentage of a in b. E.g. if a is 50 and b is
54+
200, the percentage would be 25.00%.
55+
56+
:param a: The first number. (a % b)
57+
:param b: The second number. (a % b)
58+
:return: The percentage of a in b.
59+
"""
60+
if b == 0:
61+
raise log21.ArgumentError("b cannot be zero.")
62+
percentage = (a / b) * 100
63+
print(f"{a} is {percentage:.2f}% of {b}.")
64+
65+
66+
if __name__ == "__main__":
67+
log21.argumentify(show_percentage)
68+
```
69+
970
### v3.3.1
1071

1172
Get rid of `invalid NoneType value` error message.

README.md

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,45 +69,65 @@ pip install git+https://github.com/MPCodeWriter21/log21
6969
Changelog
7070
---------
7171

72-
### v3.3.1
72+
### v3.3.2
7373

74-
Get rid of `invalid NoneType value` error message.
74+
Handle percent signs in arguments' help text.
7575

76-
In the previous versions, if you used an optional union type such as `int | float | None`
77-
which ended with `None`, you'd get an error saying `invalid NoneType value` that didn't
78-
make any sense to the user. The code has been updated to use the name of the last
79-
non-None type for the error message in these situations.
76+
In the older versions, if you had a percent sign in the help text of an argument, it
77+
would cause an error when you try to show the help. This is because the argparse
78+
module uses percent signs for string formatting, and it would try to format the help
79+
text as a string, which would fail if there are any percent signs in it.
8080

81-
#### Example
81+
The workaround for this issue was to escape the percent signs by doubling them, but it
82+
was not a good solution. Now, in v3.3.2, log21 handles percent signs in arguments' help
83+
text properly, so you can use percent signs without any issues.
84+
85+
#### Example (works before and after v3.3.2)
8286

8387
```python
8488
import log21
85-
from log21.helper_types import FileSize
8689

8790

88-
def main(min_size: FileSize | None = None, max_size: FileSize | None = None) -> None:
89-
log21.info("Min Size: %s, Max Size: %s", args=(min_size, max_size))
91+
def show_percentage(a: float, b: float, /) -> None:
92+
"""Takes two numbers and returns the percentage of a in b. E.g. if a is 50 and b is
93+
200, the percentage would be 25.00%.
94+
95+
:param a: The first number. (a %% b)
96+
:param b: The second number. (a %% b)
97+
:return: The percentage of a in b.
98+
"""
99+
if b == 0:
100+
raise log21.ArgumentError("b cannot be zero.")
101+
percentage = (a / b) * 100
102+
print(f"{a} is {percentage:.2f}% of {b}.")
103+
90104

91105
if __name__ == "__main__":
92-
log21.argumentify(main)
106+
log21.argumentify(show_percentage)
93107
```
94108

95-
Before v3.3.1:
109+
#### Example (Works only after v3.3.2)
110+
111+
```python
112+
import log21
96113

97-
```shell
98-
$ python test.py -m Hello
99-
usage: test.py [-h] [--min-size MIN_SIZE] [--max-size MAX_SIZE]
100114

101-
test.py: error: argument --min-size/-m: invalid NoneType value: 'Hello'
102-
```
115+
def show_percentage(a: float, b: float, /) -> None:
116+
"""Takes two numbers and returns the percentage of a in b. E.g. if a is 50 and b is
117+
200, the percentage would be 25.00%.
103118
104-
With v3.3.1 update:
119+
:param a: The first number. (a % b)
120+
:param b: The second number. (a % b)
121+
:return: The percentage of a in b.
122+
"""
123+
if b == 0:
124+
raise log21.ArgumentError("b cannot be zero.")
125+
percentage = (a / b) * 100
126+
print(f"{a} is {percentage:.2f}% of {b}.")
105127

106-
```shell
107-
$ python test.py -m Hello
108-
usage: test.py [-h] [--min-size MIN_SIZE] [--max-size MAX_SIZE]
109128

110-
test.py: error: argument --min-size/-m: invalid FileSize value: 'Hello'
129+
if __name__ == "__main__":
130+
log21.argumentify(show_percentage)
111131
```
112132

113133
[Full CHANGELOG](https://github.com/MPCodeWriter21/log21/blob/master/CHANGELOG.md)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ dependencies = [
2323
"webcolors",
2424
"docstring-parser"
2525
]
26-
version = "3.3.1"
26+
version = "3.3.2"
2727

2828
[build-system]
2929
requires = ["uv_build>=0.8.15,<0.9.0"]

src/log21/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
# yapf: enable
3434

3535
__author__ = 'CodeWriter21 (Mehrad Pooryoussof)'
36-
__version__ = '3.3.1'
36+
__version__ = '3.3.2'
3737
__github__ = 'https://GitHub.com/MPCodeWriter21/log21'
3838
__all__ = [
3939
'ColorizingStreamHandler', 'DecolorizingFileHandler', 'ColorizingFormatter',

src/log21/argparse.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,10 @@ def _format_action(self, action) -> str:
171171
# collect the pieces of the action help
172172
parts = [action_header]
173173

174+
percent_pattern = _re.compile(r'([%]{2}|[%])')
174175
# if there was help for the action, add lines of help text
175176
if action.help:
177+
action.help = percent_pattern.sub("%%", action.help)
176178
help_text = _gc(self.colors['help']) + self._expand_help(action)
177179
help_lines = self._split_lines(help_text, help_width)
178180
parts.append('%*s%s\n' % (indent_first, '', help_lines[0]))

0 commit comments

Comments
 (0)