##// END OF EJS Templates
deps: removed pinned deps in favor of moving them back into the requirements.txt file itself
super-admin -
r1058:2b749a9a python3
parent child Browse files
Show More
@@ -1,93 +1,93 b''
1 1
2 2 # set by: PATH_TO_OUTDATED_PACKAGES=/some/path/outdated_packages.py
3 3 OUTDATED_PACKAGES = ${PATH_TO_OUTDATED_PACKAGES}
4 4
5 5 .PHONY: clean
6 6 ## Cleanup compiled and cache py files
7 7 clean:
8 8 make test-clean
9 9 find . -type f \( -iname '*.c' -o -iname '*.pyc' -o -iname '*.so' -o -iname '*.orig' \) -exec rm '{}' ';'
10 10
11 11
12 12 .PHONY: test
13 13 ## run test-clean and tests
14 14 test:
15 15 make test-clean
16 16 make test-only
17 17
18 18
19 19 .PHONY:test-clean
20 20 ## run test-clean and tests
21 21 test-clean:
22 22 rm -rf coverage.xml htmlcov junit.xml pylint.log result
23 23 find . -type d -name "__pycache__" -prune -exec rm -rf '{}' ';'
24 24 find . -type f \( -iname '.coverage.*' \) -exec rm '{}' ';'
25 25
26 26
27 27 .PHONY: test-only
28 28 ## Run tests only without cleanup
29 29 test-only:
30 30 PYTHONHASHSEED=random \
31 31 py.test -x -vv -r xw -p no:sugar \
32 32 --cov-report=term-missing --cov-report=html --cov=vcsserver vcsserver
33 33
34 34
35 35
36 36 .PHONY: pip-packages
37 37 ## Show outdated packages
38 38 pip-packages:
39 39 python ${OUTDATED_PACKAGES}
40 40
41 41
42 42 .PHONY: sdist
43 43 ## Build sdist
44 44 sdist:
45 45 python setup.py sdist
46 46
47 47 .PHONY: dev-env
48 48 ## Build sdist
49 49 dev-env:
50 pip install -r requirements.txt -r requirements_pinned.txt -r requirements_debug.txt -r requirements_test.txt
50 pip install -r requirements.txt -r requirements_debug.txt -r requirements_test.txt
51 51 pip install -e .
52 52
53 53 # Default command on calling make
54 54 .DEFAULT_GOAL := show-help
55 55
56 56 .PHONY: show-help
57 57 show-help:
58 58 @echo "$$(tput bold)Available rules:$$(tput sgr0)"
59 59 @echo
60 60 @sed -n -e "/^## / { \
61 61 h; \
62 62 s/.*//; \
63 63 :doc" \
64 64 -e "H; \
65 65 n; \
66 66 s/^## //; \
67 67 t doc" \
68 68 -e "s/:.*//; \
69 69 G; \
70 70 s/\\n## /---/; \
71 71 s/\\n/ /g; \
72 72 p; \
73 73 }" ${MAKEFILE_LIST} \
74 74 | LC_ALL='C' sort --ignore-case \
75 75 | awk -F '---' \
76 76 -v ncol=$$(tput cols) \
77 77 -v indent=19 \
78 78 -v col_on="$$(tput setaf 6)" \
79 79 -v col_off="$$(tput sgr0)" \
80 80 '{ \
81 81 printf "%s%*s%s ", col_on, -indent, $$1, col_off; \
82 82 n = split($$2, words, " "); \
83 83 line_length = ncol - indent; \
84 84 for (i = 1; i <= n; i++) { \
85 85 line_length -= length(words[i]) + 1; \
86 86 if (line_length <= 0) { \
87 87 line_length = ncol - indent - length(words[i]) - 1; \
88 88 printf "\n%*s ", -indent, " "; \
89 89 } \
90 90 printf "%s ", words[i]; \
91 91 } \
92 92 printf "\n"; \
93 93 }'
@@ -1,42 +1,62 b''
1 1 ## dependencies
2 2
3 3 configobj==5.0.8
4 4
5 5 dogpile.cache==1.1.8
6 6
7 7 decorator==5.1.1
8 8 dulwich==0.21.3
9 9 hg-evolve==11.0.0
10 10
11 11 mercurial==6.3.3
12 12 msgpack-python==0.5.6
13 13 more-itertools==9.1.0
14 14
15 15 pastedeploy==3.0.1
16 16 pyramid==2.0.1
17 17 pygit2==1.11.1
18 18
19 19 repoze.lru==0.7
20 20 redis==4.5.1
21 21 simplejson==3.18.3
22 22 subvertpy==0.11.0
23 23
24 24 translationstring==1.4
25 25 webob==1.8.7
26 26 zope.deprecation==4.4.0
27 27 zope.interface==5.5.2
28 28
29 29 ## http servers
30 30 #gevent==20.6.0
31 31 #greenlet==0.4.16
32 32 gunicorn==20.1.0
33 33 waitress==2.1.2
34 34
35 # contains not directly required libraries we want to pin the version.
36
37 atomicwrites==1.4.1
38 attrs==22.2.0
39 contextlib2==21.6.0
40 cffi==1.15.1
41 hupper==1.11
42 importlib-metadata==6.0.0
43 packaging==23.0
44 pathlib2==2.3.7.post1
45 pygments==2.14.0
46 pyparsing==3.0.9
47 psutil==5.9.4
48 pluggy==1.0.0
49 scandir==1.10.0
50 setproctitle==1.3.2
51 venusian==3.0.0
52 wcwidth==0.2.6
53 toml==0.10.2
54
35 55 ## test related requirements
36 56 -r requirements_test.txt
37 57
38 58 ## uncomment to add the debug libraries
39 59 #ipdb==0.13.2
40 60 #ipython==7.15.0
41 61
42 62 #-r requirements_debug.txt
@@ -1,243 +1,243 b''
1 1 '''
2 2 This library is provided to allow standard python logging
3 3 to output log data as JSON formatted strings
4 4 '''
5 5 import logging
6 6 import json
7 7 import re
8 8 from datetime import date, datetime, time, tzinfo, timedelta
9 9 import traceback
10 10 import importlib
11 11
12 12 from inspect import istraceback
13 13
14 14 from collections import OrderedDict
15 15
16 16
17 17 def _inject_req_id(record, *args, **kwargs):
18 18 return record
19 19
20 20
21 21 ExceptionAwareFormatter = logging.Formatter
22 22
23 23
24 24 ZERO = timedelta(0)
25 25 HOUR = timedelta(hours=1)
26 26
27 27
28 28 class UTC(tzinfo):
29 29 """UTC"""
30 30
31 31 def utcoffset(self, dt):
32 32 return ZERO
33 33
34 34 def tzname(self, dt):
35 35 return "UTC"
36 36
37 37 def dst(self, dt):
38 38 return ZERO
39 39
40 40 utc = UTC()
41 41
42 42
43 43 # skip natural LogRecord attributes
44 44 # http://docs.python.org/library/logging.html#logrecord-attributes
45 45 RESERVED_ATTRS = (
46 46 'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
47 47 'funcName', 'levelname', 'levelno', 'lineno', 'module',
48 48 'msecs', 'message', 'msg', 'name', 'pathname', 'process',
49 49 'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName')
50 50
51 51
52 52 def merge_record_extra(record, target, reserved):
53 53 """
54 54 Merges extra attributes from LogRecord object into target dictionary
55 55
56 56 :param record: logging.LogRecord
57 57 :param target: dict to update
58 58 :param reserved: dict or list with reserved keys to skip
59 59 """
60 60 for key, value in record.__dict__.items():
61 61 # this allows to have numeric keys
62 62 if (key not in reserved
63 63 and not (hasattr(key, "startswith")
64 64 and key.startswith('_'))):
65 65 target[key] = value
66 66 return target
67 67
68 68
69 69 class JsonEncoder(json.JSONEncoder):
70 70 """
71 71 A custom encoder extending the default JSONEncoder
72 72 """
73 73
74 74 def default(self, obj):
75 75 if isinstance(obj, (date, datetime, time)):
76 76 return self.format_datetime_obj(obj)
77 77
78 78 elif istraceback(obj):
79 79 return ''.join(traceback.format_tb(obj)).strip()
80 80
81 81 elif type(obj) == Exception \
82 82 or isinstance(obj, Exception) \
83 83 or type(obj) == type:
84 84 return str(obj)
85 85
86 86 try:
87 87 return super(JsonEncoder, self).default(obj)
88 88
89 89 except TypeError:
90 90 try:
91 91 return str(obj)
92 92
93 93 except Exception:
94 94 return None
95 95
96 96 def format_datetime_obj(self, obj):
97 97 return obj.isoformat()
98 98
99 99
100 100 class JsonFormatter(ExceptionAwareFormatter):
101 101 """
102 102 A custom formatter to format logging records as json strings.
103 103 Extra values will be formatted as str() if not supported by
104 104 json default encoder
105 105 """
106 106
107 107 def __init__(self, *args, **kwargs):
108 108 """
109 109 :param json_default: a function for encoding non-standard objects
110 110 as outlined in http://docs.python.org/2/library/json.html
111 111 :param json_encoder: optional custom encoder
112 112 :param json_serializer: a :meth:`json.dumps`-compatible callable
113 113 that will be used to serialize the log record.
114 114 :param json_indent: an optional :meth:`json.dumps`-compatible numeric value
115 115 that will be used to customize the indent of the output json.
116 116 :param prefix: an optional string prefix added at the beginning of
117 117 the formatted string
118 118 :param json_indent: indent parameter for json.dumps
119 119 :param json_ensure_ascii: ensure_ascii parameter for json.dumps
120 120 :param reserved_attrs: an optional list of fields that will be skipped when
121 121 outputting json log record. Defaults to all log record attributes:
122 122 http://docs.python.org/library/logging.html#logrecord-attributes
123 123 :param timestamp: an optional string/boolean field to add a timestamp when
124 124 outputting the json log record. If string is passed, timestamp will be added
125 125 to log record using string as key. If True boolean is passed, timestamp key
126 126 will be "timestamp". Defaults to False/off.
127 127 """
128 128 self.json_default = self._str_to_fn(kwargs.pop("json_default", None))
129 129 self.json_encoder = self._str_to_fn(kwargs.pop("json_encoder", None))
130 130 self.json_serializer = self._str_to_fn(kwargs.pop("json_serializer", json.dumps))
131 131 self.json_indent = kwargs.pop("json_indent", None)
132 132 self.json_ensure_ascii = kwargs.pop("json_ensure_ascii", True)
133 133 self.prefix = kwargs.pop("prefix", "")
134 134 reserved_attrs = kwargs.pop("reserved_attrs", RESERVED_ATTRS)
135 135 self.reserved_attrs = dict(list(zip(reserved_attrs, reserved_attrs)))
136 136 self.timestamp = kwargs.pop("timestamp", True)
137 137
138 138 # super(JsonFormatter, self).__init__(*args, **kwargs)
139 139 logging.Formatter.__init__(self, *args, **kwargs)
140 140 if not self.json_encoder and not self.json_default:
141 141 self.json_encoder = JsonEncoder
142 142
143 143 self._required_fields = self.parse()
144 144 self._skip_fields = dict(list(zip(self._required_fields,
145 self._required_fields)))
145 self._required_fields)))
146 146 self._skip_fields.update(self.reserved_attrs)
147 147
148 148 def _str_to_fn(self, fn_as_str):
149 149 """
150 150 If the argument is not a string, return whatever was passed in.
151 151 Parses a string such as package.module.function, imports the module
152 152 and returns the function.
153 153
154 154 :param fn_as_str: The string to parse. If not a string, return it.
155 155 """
156 156 if not isinstance(fn_as_str, str):
157 157 return fn_as_str
158 158
159 159 path, _, function = fn_as_str.rpartition('.')
160 160 module = importlib.import_module(path)
161 161 return getattr(module, function)
162 162
163 163 def parse(self):
164 164 """
165 165 Parses format string looking for substitutions
166 166
167 167 This method is responsible for returning a list of fields (as strings)
168 168 to include in all log messages.
169 169 """
170 170 standard_formatters = re.compile(r'\((.+?)\)', re.IGNORECASE)
171 171 return standard_formatters.findall(self._fmt)
172 172
173 173 def add_fields(self, log_record, record, message_dict):
174 174 """
175 175 Override this method to implement custom logic for adding fields.
176 176 """
177 177 for field in self._required_fields:
178 178 log_record[field] = record.__dict__.get(field)
179 179 log_record.update(message_dict)
180 180 merge_record_extra(record, log_record, reserved=self._skip_fields)
181 181
182 182 if self.timestamp:
183 183 key = self.timestamp if type(self.timestamp) == str else 'timestamp'
184 184 log_record[key] = datetime.fromtimestamp(record.created, tz=utc)
185 185
186 186 def process_log_record(self, log_record):
187 187 """
188 188 Override this method to implement custom logic
189 189 on the possibly ordered dictionary.
190 190 """
191 191 return log_record
192 192
193 193 def jsonify_log_record(self, log_record):
194 194 """Returns a json string of the log record."""
195 195 return self.json_serializer(log_record,
196 196 default=self.json_default,
197 197 cls=self.json_encoder,
198 198 indent=self.json_indent,
199 199 ensure_ascii=self.json_ensure_ascii)
200 200
201 201 def serialize_log_record(self, log_record):
202 202 """Returns the final representation of the log record."""
203 203 return "%s%s" % (self.prefix, self.jsonify_log_record(log_record))
204 204
205 205 def format(self, record):
206 206 """Formats a log record and serializes to json"""
207 207 message_dict = {}
208 208 # FIXME: logging.LogRecord.msg and logging.LogRecord.message in typeshed
209 209 # are always type of str. We shouldn't need to override that.
210 210 if isinstance(record.msg, dict):
211 211 message_dict = record.msg
212 212 record.message = None
213 213 else:
214 214 record.message = record.getMessage()
215 215 # only format time if needed
216 216 if "asctime" in self._required_fields:
217 217 record.asctime = self.formatTime(record, self.datefmt)
218 218
219 219 # Display formatted exception, but allow overriding it in the
220 220 # user-supplied dict.
221 221 if record.exc_info and not message_dict.get('exc_info'):
222 222 message_dict['exc_info'] = self.formatException(record.exc_info)
223 223 if not message_dict.get('exc_info') and record.exc_text:
224 224 message_dict['exc_info'] = record.exc_text
225 225 # Display formatted record of stack frames
226 226 # default format is a string returned from :func:`traceback.print_stack`
227 227 try:
228 228 if record.stack_info and not message_dict.get('stack_info'):
229 229 message_dict['stack_info'] = self.formatStack(record.stack_info)
230 230 except AttributeError:
231 231 # Python2.7 doesn't have stack_info.
232 232 pass
233 233
234 234 try:
235 235 log_record = OrderedDict()
236 236 except NameError:
237 237 log_record = {}
238 238
239 239 _inject_req_id(record, with_prefix=False)
240 240 self.add_fields(log_record, record, message_dict)
241 241 log_record = self.process_log_record(log_record)
242 242
243 243 return self.serialize_log_record(log_record)
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now