Skip to content

Commit f99e86a

Browse files
committed
update escaping and safety mechanisms as well as test cases
1 parent c1cae3c commit f99e86a

File tree

4 files changed

+206
-267
lines changed

4 files changed

+206
-267
lines changed

logstyles/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# logstyles/__init__.py
2+
from os import times
23

34
from .base_formats import BASE_FORMATS
45
from .formatter import create_formatter
@@ -29,7 +30,7 @@ def get_formatter(theme_name, format_name, delimiter=None, included_parts=None,
2930
base_format = base_format.copy()
3031
base_format['delimiter'] = delimiter
3132

32-
return create_formatter(theme, base_format)
33+
return create_formatter(theme, base_format, delimiter, included_parts)
3334

3435
@staticmethod
3536
def list_themes():

logstyles/formatter.py

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
11
# logstyles/formatter.py
22
import threading
3-
43
from .utils import hex_to_ansi, reset_code
54

5+
# logstyles/formatter.py
66
def escape_angle_brackets(text):
7-
"""Escapes '<' and '>' characters in the given text."""
8-
return text.replace('<', '\\<').replace('>', '\\>')
7+
"""Escapes '<' and '>' characters in the given text using HTML entities."""
8+
return text.replace('<', '&lt;').replace('>', '&gt;')
9+
910

11+
# logstyles/formatter.py
1012
def create_formatter(theme, base_format, delimiter=None, override_included_parts=None):
1113
timestamp_format = theme.get('timestamp_format', '%Y-%m-%d %H:%M:%S')
1214
styles = theme['styles']
1315
delimiter = delimiter or base_format['delimiter']
1416
parts_order = base_format['parts_order']
1517

16-
included_parts = [
17-
part.replace('_part', '') for part in parts_order
18-
]
19-
18+
# Determine which parts to include
2019
if override_included_parts is not None:
2120
included_parts = override_included_parts
21+
else:
22+
included_parts = [
23+
part.replace('_part', '') for part in parts_order
24+
]
25+
26+
# Filter parts_order based on included_parts
27+
parts_order = [p for p in parts_order if p.replace('_part', '') in included_parts]
28+
remaining_parts = [p for p in included_parts if f"{p}_part" not in parts_order]
29+
parts_order.extend(f"{p}_part" for p in remaining_parts)
30+
2231

2332
# Default and maximum widths for fields
2433
field_widths_config = {
@@ -55,31 +64,35 @@ def formatter(record):
5564

5665
fields = {}
5766

58-
# Prepare field values
59-
for part in parts_order:
60-
part_key = part.replace('_part', '')
61-
if part_key == 'time' and 'time' in included_parts:
62-
fields['time'] = time_str
63-
elif part_key == 'level' and 'level' in included_parts:
64-
fields['level'] = level_name
65-
elif part_key == 'module' and 'module' in included_parts:
66-
module_name = escape_angle_brackets(record['module'])
67-
fields['module'] = module_name
68-
elif part_key == 'function' and 'function' in included_parts:
69-
function_name = escape_angle_brackets(record['function'])
70-
fields['function'] = function_name
71-
elif part_key == 'line' and 'line' in included_parts:
72-
line_str = str(record['line'])
73-
fields['line'] = line_str
74-
elif part_key == 'thread_name' and 'thread_name' in included_parts:
75-
thread_name = escape_angle_brackets(record['thread'].name)
76-
fields['thread_name'] = thread_name
77-
elif part_key == 'process_name' and 'process_name' in included_parts:
78-
process_name = escape_angle_brackets(record['process'].name)
79-
fields['process_name'] = process_name
80-
elif part_key == 'message' and 'message' in included_parts:
81-
message = escape_angle_brackets(record['message'])
82-
fields['message'] = message
67+
# Retrieve values, prioritizing record['extra'] for custom fields
68+
# Only set fields if they are included
69+
if 'time' in included_parts:
70+
fields['time'] = time_str
71+
if 'level' in included_parts:
72+
fields['level'] = level_name
73+
74+
# For fields that can be overridden by extra:
75+
if 'module' in included_parts:
76+
module_name = escape_angle_brackets(record['extra'].get('module', record['module']))
77+
fields['module'] = module_name
78+
if 'function' in included_parts:
79+
function_name = escape_angle_brackets(record['extra'].get('function', record['function']))
80+
fields['function'] = function_name
81+
if 'line' in included_parts:
82+
line_val = record['extra'].get('line', record['line'])
83+
line_str = escape_angle_brackets(str(line_val))
84+
fields['line'] = line_str
85+
if 'thread_name' in included_parts:
86+
thread_val = record['extra'].get('thread_name', record['thread'].name)
87+
thread_name = escape_angle_brackets(thread_val)
88+
fields['thread_name'] = thread_name
89+
if 'process_name' in included_parts:
90+
process_val = record['extra'].get('process_name', record['process'].name)
91+
process_name = escape_angle_brackets(process_val)
92+
fields['process_name'] = process_name
93+
if 'message' in included_parts:
94+
message = escape_angle_brackets(record['message'])
95+
fields['message'] = message
8396

8497
# Update current field widths up to maximums
8598
with field_widths_lock:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
setup(
1616
name="logstyles", # Required
17-
version="0.1.4", # Required
17+
version="0.1.5", # Required
1818
description="A logging styling library for Loguru with customizable themes and formats.", # Required
1919
long_description=README, # Optional
2020
long_description_content_type="text/markdown", # Optional (see note above)

0 commit comments

Comments
 (0)