5
5
import json
6
6
import os
7
7
import warnings
8
- from tempfile import NamedTemporaryFile
9
8
from collections import OrderedDict
9
+ from functools import wraps
10
+ from logging import Logger
11
+ from tempfile import NamedTemporaryFile
10
12
11
13
import numpy as np
12
14
import scipy .sparse
15
17
from .libpath import find_lib_path
16
18
17
19
20
+ class _DummyLogger :
21
+ def info (self , msg ):
22
+ print (msg )
23
+
24
+ def warning (self , msg ):
25
+ warnings .warn (msg , stacklevel = 3 )
26
+
27
+
28
+ _LOGGER = _DummyLogger ()
29
+
30
+
31
+ def register_logger (logger ):
32
+ """Register custom logger.
33
+
34
+ Parameters
35
+ ----------
36
+ logger : logging.Logger
37
+ Custom logger.
38
+ """
39
+ if not isinstance (logger , Logger ):
40
+ raise TypeError ("Logger should inherit logging.Logger class" )
41
+ global _LOGGER
42
+ _LOGGER = logger
43
+
44
+
45
+ def _normalize_native_string (func ):
46
+ """Join log messages from native library which come by chunks."""
47
+ msg_normalized = []
48
+
49
+ @wraps (func )
50
+ def wrapper (msg ):
51
+ nonlocal msg_normalized
52
+ if msg .strip () == '' :
53
+ msg = '' .join (msg_normalized )
54
+ msg_normalized = []
55
+ return func (msg )
56
+ else :
57
+ msg_normalized .append (msg )
58
+
59
+ return wrapper
60
+
61
+
62
+ def _log_info (msg ):
63
+ _LOGGER .info (msg )
64
+
65
+
66
+ def _log_warning (msg ):
67
+ _LOGGER .warning (msg )
68
+
69
+
70
+ @_normalize_native_string
71
+ def _log_native (msg ):
72
+ _LOGGER .info (msg )
73
+
74
+
18
75
def _log_callback (msg ):
19
- """Redirect logs from native library into Python console ."""
20
- print ("{0:s}" .format (msg .decode ('utf-8' )), end = '' )
76
+ """Redirect logs from native library into Python."""
77
+ _log_native ("{0:s}" .format (msg .decode ('utf-8' )))
21
78
22
79
23
80
def _load_lib ():
@@ -329,8 +386,8 @@ def convert_from_sliced_object(data):
329
386
"""Fix the memory of multi-dimensional sliced object."""
330
387
if isinstance (data , np .ndarray ) and isinstance (data .base , np .ndarray ):
331
388
if not data .flags .c_contiguous :
332
- warnings . warn ("Usage of np.ndarray subset (sliced data) is not recommended "
333
- "due to it will double the peak memory cost in LightGBM." )
389
+ _log_warning ("Usage of np.ndarray subset (sliced data) is not recommended "
390
+ "due to it will double the peak memory cost in LightGBM." )
334
391
return np .copy (data )
335
392
return data
336
393
@@ -620,7 +677,7 @@ def predict(self, data, start_iteration=0, num_iteration=-1,
620
677
preds , nrow = self .__pred_for_np2d (data .to_numpy (), start_iteration , num_iteration , predict_type )
621
678
else :
622
679
try :
623
- warnings . warn ('Converting data to scipy sparse matrix.' )
680
+ _log_warning ('Converting data to scipy sparse matrix.' )
624
681
csr = scipy .sparse .csr_matrix (data )
625
682
except BaseException :
626
683
raise TypeError ('Cannot predict data for type {}' .format (type (data ).__name__ ))
@@ -1103,9 +1160,9 @@ def _lazy_init(self, data, label=None, reference=None,
1103
1160
.co_varnames [:getattr (self .__class__ , '_lazy_init' ).__code__ .co_argcount ])
1104
1161
for key , _ in params .items ():
1105
1162
if key in args_names :
1106
- warnings . warn ('{0} keyword has been found in `params` and will be ignored.\n '
1107
- 'Please use {0} argument of the Dataset constructor to pass this parameter.'
1108
- .format (key ))
1163
+ _log_warning ('{0} keyword has been found in `params` and will be ignored.\n '
1164
+ 'Please use {0} argument of the Dataset constructor to pass this parameter.'
1165
+ .format (key ))
1109
1166
# user can set verbose with params, it has higher priority
1110
1167
if not any (verbose_alias in params for verbose_alias in _ConfigAliases .get ("verbosity" )) and silent :
1111
1168
params ["verbose" ] = - 1
@@ -1126,7 +1183,7 @@ def _lazy_init(self, data, label=None, reference=None,
1126
1183
if categorical_indices :
1127
1184
for cat_alias in _ConfigAliases .get ("categorical_feature" ):
1128
1185
if cat_alias in params :
1129
- warnings . warn ('{} in param dict is overridden.' .format (cat_alias ))
1186
+ _log_warning ('{} in param dict is overridden.' .format (cat_alias ))
1130
1187
params .pop (cat_alias , None )
1131
1188
params ['categorical_column' ] = sorted (categorical_indices )
1132
1189
@@ -1172,7 +1229,7 @@ def _lazy_init(self, data, label=None, reference=None,
1172
1229
self .set_group (group )
1173
1230
if isinstance (predictor , _InnerPredictor ):
1174
1231
if self ._predictor is None and init_score is not None :
1175
- warnings . warn ("The init_score will be overridden by the prediction of init_model." )
1232
+ _log_warning ("The init_score will be overridden by the prediction of init_model." )
1176
1233
self ._set_init_score_by_predictor (predictor , data )
1177
1234
elif init_score is not None :
1178
1235
self .set_init_score (init_score )
@@ -1314,7 +1371,7 @@ def construct(self):
1314
1371
if self .reference is not None :
1315
1372
reference_params = self .reference .get_params ()
1316
1373
if self .get_params () != reference_params :
1317
- warnings . warn ('Overriding the parameters from Reference Dataset.' )
1374
+ _log_warning ('Overriding the parameters from Reference Dataset.' )
1318
1375
self ._update_params (reference_params )
1319
1376
if self .used_indices is None :
1320
1377
# create valid
@@ -1583,11 +1640,11 @@ def set_categorical_feature(self, categorical_feature):
1583
1640
self .categorical_feature = categorical_feature
1584
1641
return self ._free_handle ()
1585
1642
elif categorical_feature == 'auto' :
1586
- warnings . warn ('Using categorical_feature in Dataset.' )
1643
+ _log_warning ('Using categorical_feature in Dataset.' )
1587
1644
return self
1588
1645
else :
1589
- warnings . warn ('categorical_feature in Dataset is overridden.\n '
1590
- 'New categorical_feature is {}' .format (sorted (list (categorical_feature ))))
1646
+ _log_warning ('categorical_feature in Dataset is overridden.\n '
1647
+ 'New categorical_feature is {}' .format (sorted (list (categorical_feature ))))
1591
1648
self .categorical_feature = categorical_feature
1592
1649
return self ._free_handle ()
1593
1650
else :
@@ -1840,8 +1897,8 @@ def get_data(self):
1840
1897
elif isinstance (self .data , DataTable ):
1841
1898
self .data = self .data [self .used_indices , :]
1842
1899
else :
1843
- warnings . warn ("Cannot subset {} type of raw data.\n "
1844
- "Returning original raw data" .format (type (self .data ).__name__ ))
1900
+ _log_warning ("Cannot subset {} type of raw data.\n "
1901
+ "Returning original raw data" .format (type (self .data ).__name__ ))
1845
1902
self .need_slice = False
1846
1903
if self .data is None :
1847
1904
raise LightGBMError ("Cannot call `get_data` after freed raw data, "
@@ -2011,10 +2068,10 @@ def add_features_from(self, other):
2011
2068
old_self_data_type )
2012
2069
err_msg += ("Set free_raw_data=False when construct Dataset to avoid this"
2013
2070
if was_none else "Freeing raw data" )
2014
- warnings . warn (err_msg )
2071
+ _log_warning (err_msg )
2015
2072
self .feature_name = self .get_feature_name ()
2016
- warnings . warn ("Reseting categorical features.\n "
2017
- "You can set new categorical features via ``set_categorical_feature`` method" )
2073
+ _log_warning ("Reseting categorical features.\n "
2074
+ "You can set new categorical features via ``set_categorical_feature`` method" )
2018
2075
self .categorical_feature = "auto"
2019
2076
self .pandas_categorical = None
2020
2077
return self
@@ -2834,7 +2891,7 @@ def model_from_string(self, model_str, verbose=True):
2834
2891
self .handle ,
2835
2892
ctypes .byref (out_num_class )))
2836
2893
if verbose :
2837
- print ('Finished loading model, total used %d iterations' % int (out_num_iterations .value ))
2894
+ _log_info ('Finished loading model, total used %d iterations' % int (out_num_iterations .value ))
2838
2895
self .__num_class = out_num_class .value
2839
2896
self .pandas_categorical = _load_pandas_categorical (model_str = model_str )
2840
2897
return self
0 commit comments