Skip to content

Commit b6da693

Browse files
authored
Add logging decorator, test and test for yaml_file (#1178)
add a logging decorator (logit) and its associated pytest add a pytest for yaml_file
1 parent bf06289 commit b6da693

File tree

4 files changed

+151
-4
lines changed

4 files changed

+151
-4
lines changed

ush/python/pygw/src/pygw/logger.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import sys
6+
from functools import wraps
67
from pathlib import Path
78
from typing import Union, List
89
import logging
@@ -222,3 +223,47 @@ def add_file_handler(cls, logfile_path: Union[str, Path],
222223
handler.setFormatter(logging.Formatter(_format))
223224

224225
return handler
226+
227+
228+
def logit(logger, name=None, message=None):
229+
"""
230+
Add logging to a function.
231+
Parameters
232+
----------
233+
logger : Logger
234+
Logger object
235+
name : str
236+
Name of the module to be logged
237+
default: __module__
238+
message : str
239+
Name of the function to be logged
240+
default: __name__
241+
"""
242+
243+
def decorate(func):
244+
245+
log_name = name if name else func.__module__
246+
log_msg = message if message else log_name + "." + func.__name__
247+
248+
@wraps(func)
249+
def wrapper(*args, **kwargs):
250+
251+
passed_args = [repr(aa) for aa in args]
252+
passed_kwargs = [f"{kk}={repr(vv)}" for kk, vv in list(kwargs.items())]
253+
call_msg = 'BEGIN: ' + log_msg + f"( {', '.join(passed_args + passed_kwargs)} )"
254+
255+
# Begin the logging with printing input arguments
256+
logger.debug(call_msg)
257+
258+
# Call the function
259+
retval = func(*args, **kwargs)
260+
261+
# Close the logging with printing the return val
262+
ret_msg = ' END: ' + log_msg + f" returning {retval}"
263+
logger.debug(ret_msg)
264+
265+
return retval
266+
267+
return wrapper
268+
269+
return decorate

ush/python/pygw/src/pygw/yaml_file.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,17 @@ class YAMLFile(AttrDict):
1717

1818
def __init__(self, path=None, data=None):
1919
super().__init__()
20+
2021
if path and data:
21-
print("Ignoring 'data' and using 'path' argument") # TODO: use logging
22-
if path:
22+
print("Ignoring 'data' and using 'path' argument")
23+
24+
config = None
25+
if path is not None:
2326
config = parse_yaml(path=path)
24-
elif data:
27+
elif data is not None:
2528
config = parse_yaml(data=data)
2629

27-
if config:
30+
if config is not None:
2831
self.update(config)
2932

3033
def save(self, target):

ush/python/pygw/src/tests/test_logger.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from pygw.logger import Logger
2+
from pygw.logger import logit
23

34
level = 'debug'
45
number_of_log_msgs = 5
@@ -40,3 +41,27 @@ def test_logger(tmp_path):
4041
lev = line.split('-')[3].strip().lower()
4142
message = line.split(':')[-1].strip()
4243
assert reference[lev] == message
44+
45+
46+
def test_logit(tmp_path):
47+
48+
logger = Logger('test_logit', level=level, colored_log=True)
49+
50+
@logit(logger)
51+
def add(x, y):
52+
return x + y
53+
54+
@logit(logger)
55+
def usedict(n, j=0, k=1):
56+
return n + j + k
57+
58+
@logit(logger, 'example')
59+
def spam():
60+
print('Spam!')
61+
62+
add(2, 3)
63+
usedict(2, 3)
64+
usedict(2, k=3)
65+
spam()
66+
67+
assert True
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import os
2+
from pygw.yaml_file import YAMLFile
3+
4+
host_yaml = """
5+
host:
6+
hostname: test_host
7+
host_user: !ENV ${USER}
8+
"""
9+
10+
conf_yaml = """
11+
config:
12+
config_file: !ENV ${TMP_PATH}/config.yaml
13+
user: !ENV ${USER}
14+
host_file: !INC ${TMP_PATH}/host.yaml
15+
"""
16+
17+
tmpl_yaml = """
18+
config:
19+
config_file: !ENV ${TMP_PATH}/config.yaml
20+
user: !ENV ${USER}
21+
host_file: !INC ${TMP_PATH}/host.yaml
22+
tmpl:
23+
cdate: '{{PDY}}{{cyc}}'
24+
homedir: $(user)
25+
"""
26+
# Note the quotes ' ' around {{ }}. These quotes are necessary otherwise YAMLFile will fail parsing
27+
28+
29+
def test_yaml_file(tmp_path):
30+
31+
# Create temporary yaml files w/ tags
32+
config_file_path = tmp_path / 'config.yaml'
33+
with open(config_file_path, 'w') as conf_file:
34+
conf_file.write(conf_yaml)
35+
36+
with open(tmp_path / 'host.yaml', 'w') as host_file:
37+
host_file.write(host_yaml)
38+
39+
# Set env. variable
40+
os.environ['TMP_PATH'] = str(tmp_path)
41+
conf = YAMLFile(path=config_file_path)
42+
43+
# Write out yaml file
44+
yaml_out = tmp_path / 'output.yaml'
45+
conf.save(yaml_out)
46+
47+
# Read in the yaml file and compare w/ conf
48+
yaml_in = YAMLFile(path=str(yaml_out))
49+
50+
assert yaml_in == conf
51+
52+
53+
def test_yaml_file_with_templates(tmp_path):
54+
55+
# Create temporary yaml files w/ tags
56+
tmpl_file_path = tmp_path / 'tmpl.yaml'
57+
with open(tmpl_file_path, 'w') as tmpl_file:
58+
tmpl_file.write(tmpl_yaml)
59+
60+
with open(tmp_path / 'host.yaml', 'w') as host_file:
61+
host_file.write(host_yaml)
62+
63+
# Set env. variable
64+
os.environ['TMP_PATH'] = str(tmp_path)
65+
conf = YAMLFile(path=tmpl_file_path)
66+
67+
# Write out yaml file
68+
yaml_out = tmp_path / 'tmpl_output.yaml'
69+
conf.save(yaml_out)
70+
71+
# Read in the yaml file and compare w/ conf
72+
yaml_in = YAMLFile(path=yaml_out)
73+
74+
assert yaml_in == conf

0 commit comments

Comments
 (0)