Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[python] Migrate to f-strings in python-package/lightgbm/sklearn.py #4188

Merged
merged 9 commits into from
Apr 19, 2021
18 changes: 9 additions & 9 deletions python-package/lightgbm/sklearn.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def __call__(self, preds, dataset):
elif argc == 3:
grad, hess = self.func(labels, preds, dataset.get_group())
else:
raise TypeError("Self-defined objective function should have 2 or 3 arguments, got %d" % argc)
raise TypeError(f"Self-defined objective function should have 2 or 3 arguments, got {argc}")
"""weighted for objective"""
weight = dataset.get_weight()
if weight is not None:
Expand Down Expand Up @@ -171,7 +171,7 @@ def __call__(self, preds, dataset):
elif argc == 4:
return self.func(labels, preds, dataset.get_weight(), dataset.get_group())
else:
raise TypeError("Self-defined eval function should have 2, 3 or 4 arguments, got %d" % argc)
raise TypeError(f"Self-defined eval function should have 2, 3 or 4 arguments, got {argc}")


# documentation templates for LGBMModel methods are shared between the classes in
Expand Down Expand Up @@ -719,10 +719,9 @@ def predict(self, X, raw_score=False, start_iteration=0, num_iteration=None,
X = _LGBMCheckArray(X, accept_sparse=True, force_all_finite=False)
n_features = X.shape[1]
if self._n_features != n_features:
raise ValueError("Number of features of the model must "
"match the input. Model n_features_ is %s and "
"input n_features is %s "
% (self._n_features, n_features))
raise ValueError(f"Number of features of the model must " \
f"match the input. Model n_features_ is {self._n_features} and " \
f"input n_features is {n_features} ")
akshitadixit marked this conversation as resolved.
Show resolved Hide resolved
akshitadixit marked this conversation as resolved.
Show resolved Hide resolved
return self._Booster.predict(X, raw_score=raw_score, start_iteration=start_iteration, num_iteration=num_iteration,
pred_leaf=pred_leaf, pred_contrib=pred_contrib, **kwargs)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the following lines within this PR as well

if hasattr(self, '_' + key):
setattr(self, '_' + key, value)

+ ' ' * 12 + 'The evaluation positions of the specified metric.\n'
+ ' ' * 8 + _early_stop + _after_early_stop)
(part about ' ' * x)
raise TypeError('{} should be dict or list'.format(name))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StrikerRUS do I only change the ' '*x part or do I also modify the concatenation taking place there into an f-string as below?

space = " "
    fit.__doc__ = (f"{_before_early_stop}" \
                  f"eval_at : iterable of int, optional (default=(1, 2, 3, 4, 5))\n" \
                  f"{space*12} The evaluation positions of the specified metric.\n" \
                  f"{space*8} {_early_stop} {_after_early_stop}")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I thought about only ' '*x part, but just saw that @jameslamb would prefer modifying concatenation as well: #4144 (comment). So, please modify it with concatenation.

BTW, there are some other places where concatenation can be eliminated with f-strings:

fit.__doc__ = _lgbmmodel_doc_fit.format(
X_shape="array-like or sparse matrix of shape = [n_samples, n_features]",
y_shape="array-like of shape = [n_samples]",
sample_weight_shape="array-like of shape = [n_samples] or None, optional (default=None)",
init_score_shape="array-like of shape = [n_samples] or None, optional (default=None)",
group_shape="array-like or None, optional (default=None)"
) + "\n\n" + _lgbmmodel_doc_custom_eval_note

_base_doc = LGBMModel.fit.__doc__
_base_doc = (_base_doc[:_base_doc.find('group :')] # type: ignore
+ _base_doc[_base_doc.find('eval_set :'):]) # type: ignore
_base_doc = (_base_doc[:_base_doc.find('eval_class_weight :')]
+ _base_doc[_base_doc.find('eval_init_score :'):])
fit.__doc__ = (_base_doc[:_base_doc.find('eval_group :')]
+ _base_doc[_base_doc.find('eval_metric :'):])

_base_doc = LGBMModel.fit.__doc__
_base_doc = (_base_doc[:_base_doc.find('group :')] # type: ignore
+ _base_doc[_base_doc.find('eval_set :'):]) # type: ignore
fit.__doc__ = (_base_doc[:_base_doc.find('eval_group :')]
+ _base_doc[_base_doc.find('eval_metric :'):])

_base_doc = LGBMModel.fit.__doc__
fit.__doc__ = (_base_doc[:_base_doc.find('eval_class_weight :')] # type: ignore
+ _base_doc[_base_doc.find('eval_init_score :'):]) # type: ignore

But I don't think we should replace concatenation with f-strings there because concatenation is more readable in those cases in my opinion. @jameslamb WDYT?

Also, please check the following comment about padding #4144 (comment).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I don't think we should replace concatenation with f-strings there because concatenation is more readable in those cases in my opinion

Yes I agree with you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I infer that no concatenations be migrated then.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, cases like the ones @StrikerRUS mentioned (where .format() was used to replace a shared template like _lgbmmodel_doc_fit or where there are just variables being added to each other but not string literals) do not need to be changed for this pull request

Expand Down Expand Up @@ -919,9 +918,10 @@ def predict_proba(self, X, raw_score=False, start_iteration=0, num_iteration=Non
"""Docstring is set after definition, using a template."""
result = super().predict(X, raw_score, start_iteration, num_iteration, pred_leaf, pred_contrib, **kwargs)
if callable(self._objective) and not (raw_score or pred_leaf or pred_contrib):
_log_warning("Cannot compute class probabilities or labels "
"due to the usage of customized objective function.\n"
"Returning raw scores instead.")
new_line = "\n"
akshitadixit marked this conversation as resolved.
Show resolved Hide resolved
_log_warning(f"Cannot compute class probabilities or labels " \
f"due to the usage of customized objective function.{new_line}" \
f"Returning raw scores instead.")
akshitadixit marked this conversation as resolved.
Show resolved Hide resolved
return result
elif self._n_classes > 2 or raw_score or pred_leaf or pred_contrib:
return result
Expand Down