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

refactor: Change linting to Ruff #978

Merged
merged 11 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions .flake8

This file was deleted.

33 changes: 17 additions & 16 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
default_stages: [pre-commit]
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-builtin-literals
- id: check-case-conflict
- id: check-docstring-first
- id: check-toml
- id: detect-private-key
- id: end-of-file-fixer
- id: check-builtin-literals
- id: check-case-conflict
- id: check-docstring-first
- id: check-toml
- id: detect-private-key
- id: end-of-file-fixer
exclude: (\.min\.js$|\.svg$)
- id: trailing-whitespace
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.3
hooks:
- id: flake8
- repo: https://github.com/hoxbro/clean_notebook
rev: v0.1.10
hooks:
- id: clean-notebook
- id: ruff
exclude: \.ipynb
- repo: https://github.com/hoxbro/clean_notebook
rev: v0.1.15
hooks:
- id: clean-notebook
6 changes: 3 additions & 3 deletions numbergen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import param


from param import __version__ # noqa: API import
from param import __version__

class TimeAware(param.Parameterized):
"""
Expand Down Expand Up @@ -763,5 +763,5 @@ def __call__(self):
else: return val


_public = list({_k for _k,_v in locals().items() if isinstance(_v,type) and issubclass(_v,NumberGenerator)})
__all__ = _public
_public = {_k for _k,_v in locals().items() if isinstance(_v,type) and issubclass(_v,NumberGenerator)}
__all__ = ["__version__", *_public]
4 changes: 2 additions & 2 deletions param/ipython.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def param_docstrings(self, info, max_col_len=100, only_changed=False):
contents = []
displayed_params = []
for name in self.sort_by_precedence(params):
if only_changed and not (name in changed):
if only_changed and name not in changed:
continue
displayed_params.append((name, params[name]))

Expand Down Expand Up @@ -155,7 +155,7 @@ def _build_table(self, info, order, max_col_len=40, only_changed=False):
ordering = self.sort_by_precedence(params)
for name in ordering:
p = params[name]
if only_changed and not (name in changed):
if only_changed and name not in changed:
continue

constant = 'C' if p.constant else 'V'
Expand Down
18 changes: 7 additions & 11 deletions param/parameterized.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# Allow this file to be used standalone if desired, albeit without JSON serialization
try:
from . import serializer
except ImportError:
except ModuleNotFoundError:
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not entirely sure about this one.

Copy link
Member Author

Choose a reason for hiding this comment

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

Tested it. Needs to be an ImportError

Suggested change
except ModuleNotFoundError:
except ImportError:

Copy link
Member Author

Choose a reason for hiding this comment

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

Though even with ImportError it still does not work...

❯ python -c "import param"  # with ModuleNotFoundError
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/shh/projects/holoviz/repos/param/param/__init__.py", line 4, in <module>
    from .depends import depends  # noqa: api import
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/shh/projects/holoviz/repos/param/param/depends.py", line 9, in <module>
    from .parameterized import (
  File "/home/shh/projects/holoviz/repos/param/param/parameterized.py", line 28, in <module>
    from . import serializer
ImportError: cannot import name 'serializer' from partially initialized module 'param' (most likely due to a circular import) (/home/shh/projects/holoviz/repos/param/param/__init__.py)

param on  refactor_ruff [$✘] via 🅒 holoviz
❯ python -c "import param"  # with ImportError
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/shh/projects/holoviz/repos/param/param/__init__.py", line 4, in <module>
    from .depends import depends  # noqa: api import
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/shh/projects/holoviz/repos/param/param/depends.py", line 9, in <module>
    from .parameterized import (
  File "/home/shh/projects/holoviz/repos/param/param/parameterized.py", line 1027, in <module>
    class Parameter(_ParameterBase):
  File "/home/shh/projects/holoviz/repos/param/param/parameterized.py", line 1170, in Parameter
    _serializers = {'json': serializer.JSONSerialization}
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'JSONSerialization'

Copy link
Member Author

@hoxbro hoxbro Nov 14, 2024

Choose a reason for hiding this comment

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

Should we remove the try/except here? Nobody has complained about it, and that line was changed in June of 2021.

Copy link
Member

Choose a reason for hiding this comment

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

From what I've heard, and IIRC, Param was designed to be used super easily by simply copy-pasting one or two files in a project, which works as it has no external dependency. It's likely it made people's lives easier 10/15 years ago, these days we expect users to pip/conda install their dependencies and in the vast majority of cases it works fine.
So I think that yes we should remove the try/except and generally lift the assumption that you can copy-paste some modules and it works, if it's baked in other places. I also wouldn't be surprised if one day we added some dependencies to Param (e.g. typing-extensions if we finally do some typing work in Param).

cc @philippjfr @jbednar @jlstevens

Copy link
Contributor

Choose a reason for hiding this comment

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

@maximlt is right in that param was originally designed to be easily vendored-in to any codebase. I personally have no strong feelings about this: while being easy to avoid an extra dependencies can be nice, it is also true that the majority of users will be using a package manager.

Copy link
Member Author

Choose a reason for hiding this comment

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

To be sure, the question right now is not about adding an extra dependency but about removing the try/except around the serializer import, which has been broken since 2021.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, was just confirming what Maxime said and given this import has been broken so long, the issue is rather moot!

Copy link
Member

Choose a reason for hiding this comment

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

I agree that it is no longer important to be able to paste in the two main Param files directly into a project. Param was first written before conda and even before pip, and adding a dependency was much more of a big issue in those days. Happy to see this and any similar try/excepts removed, when they depend only on files in param itself.

serializer = None

from collections import defaultdict, namedtuple, OrderedDict
Expand Down Expand Up @@ -67,7 +67,7 @@
try:
from .ipython import ParamPager, ipython_async_executor as async_executor
param_pager = ParamPager(metaclass=True) # Generates param description
except ImportError:
except ModuleNotFoundError:
from ._utils import async_executor
else:
from ._utils import async_executor
Expand Down Expand Up @@ -340,8 +340,6 @@ def edit_constant(parameterized):
p.constant = False
try:
yield
except:
raise
finally:
for (p, const) in zip(params, constants):
p.constant = const
Expand All @@ -359,8 +357,6 @@ def discard_events(parameterized):
list(parameterized.param._events))
try:
yield
except:
raise
finally:
parameterized.param._BATCH_WATCH = batch_watch
parameterized.param._state_watchers = watchers
Expand Down Expand Up @@ -1747,7 +1743,7 @@ def is_equal(cls, obj1, obj2):

@classmethod
def compare_iterator(cls, obj1, obj2):
if type(obj1) != type(obj2) or len(obj1) != len(obj2):
if type(obj1) is not type(obj2) or len(obj1) != len(obj2):
return False
for o1, o2 in zip(obj1, obj2):
if not cls.is_equal(o1, o2):
Expand All @@ -1756,7 +1752,7 @@ def compare_iterator(cls, obj1, obj2):

@classmethod
def compare_mapping(cls, obj1, obj2):
if type(obj1) != type(obj2) or len(obj1) != len(obj2): return False
if type(obj1) is not type(obj2) or len(obj1) != len(obj2): return False
for k in obj1:
if k in obj2:
if not cls.is_equal(obj1[k], obj2[k]):
Expand Down Expand Up @@ -2354,7 +2350,7 @@ def _update(self_, arg=Undefined, /, **kwargs):
raise ValueError(f"{k!r} is not a parameter of {self_.cls.__name__}")
try:
setattr(self_or_cls, k, v)
except:
except Exception:
self_._BATCH_WATCH = False
raise

Expand Down Expand Up @@ -2386,7 +2382,7 @@ def set_param(self_, *args,**kwargs):
"""
self_or_cls = self_.self_or_cls
if args:
if len(args) == 2 and not args[0] in kwargs and not kwargs:
if len(args) == 2 and args[0] not in kwargs and not kwargs:
kwargs[args[0]] = args[1]
else:
raise ValueError("Invalid positional arguments for %s.set_param" %
Expand Down Expand Up @@ -3388,7 +3384,7 @@ def __set_name(mcs, name, dict_):
"""
name_param = dict_.get("name", None)
if name_param is not None:
if not type(name_param) is String:
if type(name_param) is not String:
raise TypeError(
f"Parameterized class {name!r} cannot override "
f"the 'name' Parameter with type {type(name_param)}. "
Expand Down
4 changes: 2 additions & 2 deletions param/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,7 @@ def serialize(cls, value):
if not isinstance(v, (dt.datetime, dt.date)): # i.e np.datetime64
v = v.astype(dt.datetime)
# Separate date and datetime to deserialize to the right type.
if type(v) == dt.date:
if type(v) is dt.date:
v = v.strftime("%Y-%m-%d")
else:
v = v.strftime("%Y-%m-%dT%H:%M:%S.%f")
Expand Down Expand Up @@ -1958,7 +1958,7 @@ def _ensure_value_is_in_objects(self, val):
Subclasses can override if they support multiple items on a list,
to check each item instead.
"""
if not (val in self.objects):
if val not in self.objects:
self._objects.append(val)

def get_range(self):
Expand Down
4 changes: 2 additions & 2 deletions param/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def objectselector_schema(cls, p, safe=False):
schema = {'anyOf': allowed_types}
schema['enum'] = p.objects
return schema
except:
except Exception:
if safe is True:
msg = ('ObjectSelector cannot be guaranteed to be safe for '
'serialization due to unserializable type in objects')
Expand All @@ -267,7 +267,7 @@ def selector_schema(cls, p, safe=False):
schema = {'anyOf': allowed_types}
schema['enum'] = p.objects
return schema
except:
except Exception:
if safe is True:
msg = ('Selector cannot be guaranteed to be safe for '
'serialization due to unserializable type in objects')
Expand Down
16 changes: 9 additions & 7 deletions param/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@

__author__ = 'Jean-Luc Stevens'

import os, subprocess, json
import os
import subprocess
import json

def run_cmd(args, cwd=None):
kwargs = {}
Expand Down Expand Up @@ -192,7 +194,7 @@ def git_fetch(self, cmd='git', as_string=False):
output = self._output_from_file()
if output is not None:
self._update_from_vcs(output)
except: pass
except Exception: pass
if output is None:
# glob pattern (not regexp) matching vX.Y.Z* tags
output = run_cmd([cmd, 'describe', '--long', '--match',
Expand Down Expand Up @@ -251,7 +253,7 @@ def _output_from_file(self, entry='git_describe'):
vfile = os.path.join(os.path.dirname(self.fpath), '.version')
with open(vfile) as f:
return json.loads(f.read()).get(entry, None)
except: # File may be missing if using pip + git archive
except Exception: # File may be missing if using pip + git archive
return None


Expand Down Expand Up @@ -427,7 +429,7 @@ def setup_version(cls, setup_path, reponame, archive_commit=None,

if git_describe is not None:
info['git_describe'] = git_describe
except: pass
except Exception: pass

if git_describe is None:
extracted_directory_tag = Version.extract_directory_tag(setup_path, reponame)
Expand All @@ -436,7 +438,7 @@ def setup_version(cls, setup_path, reponame, archive_commit=None,
try:
with open(os.path.join(setup_path, pkgname, '.version'), 'w') as f:
f.write(json.dumps({'extracted_directory_tag':extracted_directory_tag}))
except:
except Exception:
print('Error in setup_version: could not write .version file.')


Expand All @@ -449,7 +451,7 @@ def setup_version(cls, setup_path, reponame, archive_commit=None,
try:
with open(os.path.join(setup_path, pkgname, '.version'), 'w') as f:
f.write(json.dumps(info))
except:
except Exception:
print('Error in setup_version: could not write .version file.')

return info['version_string']
Expand Down Expand Up @@ -517,7 +519,7 @@ def get_setupcfg_version():
"""
try:
import configparser
except ImportError:
except ModuleNotFoundError:
import ConfigParser as configparser # python2 (also prevents dict-like access)
hoxbro marked this conversation as resolved.
Show resolved Hide resolved
import re
cfg = "setup.cfg"
Expand Down
16 changes: 16 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,19 @@ asyncio_default_fixture_loop_scope="function"

[tool.coverage.report]
omit = ["param/version.py"]

[tool.ruff]
fix = true
include = ["*.py"]

[tool.ruff.lint]
select = ["W", "E", "F"]
ignore = [
"E402", # Module level import not at top of file
"E501", # Line too long
"E701", # Multiple statements on one line
"E712", # Comparison to true should be is
"E731", # Do not assign a lambda expression, use a def
"E741", # Ambiguous variable name
"F405", # From star imports
]
2 changes: 1 addition & 1 deletion tests/testclassselector.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def _check_defaults(self, p):
assert p.allow_None is True
assert p.instantiate is True
assert p.is_instance is True
assert p.class_ == dict
assert p.class_ is dict

def test_defaults_class(self):
class P(param.Parameterized):
Expand Down
4 changes: 2 additions & 2 deletions tests/testcomparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

try:
import numpy as np
except ImportError:
except ModuleNotFoundError:
np = None
try:
import pandas as pd
except ImportError:
except ModuleNotFoundError:
pd = None

_now = datetime.datetime.now()
Expand Down
2 changes: 1 addition & 1 deletion tests/testdateparam.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

try:
import numpy as np
except:
except ModuleNotFoundError:
np = None

from .utils import check_defaults
Expand Down
2 changes: 1 addition & 1 deletion tests/testdaterangeparam.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

try:
import numpy as np
except:
except ModuleNotFoundError:
np = None

# Assuming tests of range parameter cover most of what's needed to
Expand Down
8 changes: 4 additions & 4 deletions tests/testdefaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@

try:
import numpy # noqa
except ImportError:
except ModuleNotFoundError:
skip.append('Array')
try:
import pandas # noqa
except ImportError:
except ModuleNotFoundError:
skip.append('DataFrame')
skip.append('Series')

Expand Down Expand Up @@ -61,7 +61,7 @@ class P(param.Parameterized):

for slot in param.parameterized.get_all_slots(parameter):
# Handled in a special way, skip it
if type(parameter) == param.Composite and slot == 'objtype':
if type(parameter) is param.Composite and slot == 'objtype':
continue
assert getattr(P.param.p, slot) is not param.Undefined
# Handled in a special way, skip it
Expand All @@ -82,7 +82,7 @@ class P(param.Parameterized):

for slot in param.parameterized.get_all_slots(parameter):
# Handled in a special way, skip it
if type(parameter) == param.Composite and slot == 'objtype':
if type(parameter) is param.Composite and slot == 'objtype':
continue
assert getattr(inst.param.p, slot) is not param.Undefined
# Handled in a special way, skip it
Expand Down
Loading