Skip to content

Lint library code only with ruff check #1118

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

Merged
merged 23 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dfc0ead
Handle non-* unused import-related messages
roryyorke Jan 25, 2025
eb70132
Silence ruff warnings in __init__.py
roryyorke Feb 1, 2025
c135d2f
Make flatsys/__init__.py ruff-clean
roryyorke Feb 1, 2025
c6dbe07
Silence ruff warnings in matlab/__init__.py
roryyorke Feb 1, 2025
9427eec
Turn f-strings without format-parameters into normal strings (ruff)
roryyorke Feb 1, 2025
5ba2ad5
Fix ruff warnings in robust.py
roryyorke Feb 1, 2025
67fa35d
Apply ruff pyflakes rules to control library only
roryyorke Feb 1, 2025
44db126
Import `ControlArgument` in flatsys.py, with test
roryyorke Feb 1, 2025
7668d2c
Fix ruff "unused value" warnings
roryyorke Feb 1, 2025
ae5a702
Fixed ruff unused argument warning in acker
roryyorke Feb 1, 2025
f9c5b3b
Fix ruff shadowed symbol warning in xferfcn.py
roryyorke Feb 1, 2025
71ea2d7
Fix various ruff unknown symbol warnings
roryyorke Feb 1, 2025
d1ac450
Change _RLSortRoots in rlocus.py to placate ruff
roryyorke Feb 1, 2025
d8b8b2d
Remove unused import
roryyorke Feb 1, 2025
a032506
Silence ruff warning in phaseplot.py
roryyorke Feb 1, 2025
5421a63
Add ruff check Github Action workflow
roryyorke Feb 1, 2025
32ba227
Update docstring_test hashes
roryyorke Feb 2, 2025
b4776c4
Fix comment wording
roryyorke Feb 2, 2025
bd705f2
Remove pyflakes weirdness, use noqa instead
roryyorke Feb 2, 2025
76b2a34
Merge main into lint-lib-only
roryyorke Feb 2, 2025
ce13465
Update dlqe, lqe hashes in docstrings_test.py
roryyorke Feb 2, 2025
b333298
Remove import of unused ControlDimension
roryyorke Feb 2, 2025
18d3d59
Import missing StateSpace
roryyorke Feb 2, 2025
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
29 changes: 29 additions & 0 deletions .github/workflows/ruff-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# run ruff check on library source
# TODO: extend to tests, examples, benchmarks

name: ruff-check

on: [push, pull_request]

jobs:
ruff-check-linux:
# ruff *shouldn't* be sensitive to platform
runs-on: ubuntu-latest

steps:
- name: Checkout python-control
uses: actions/checkout@v3

- name: Setup environment
uses: actions/setup-python@v4
with:
python-version: 3.13 # todo: latest?

- name: Install ruff
run: |
python -m pip install --upgrade pip
python -m pip install ruff

- name: Run ruff check
run: |
ruff check
9 changes: 7 additions & 2 deletions control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@
# Import functions from within the control system library
# Note: the functions we use are specified as __all__ variables in the modules

# don't warn about `import *`
# ruff: noqa: F403
# don't warn about unknown names; they come via `import *`
# ruff: noqa: F405

# Input/output system modules
from .iosys import *
from .nlsys import *
Expand Down Expand Up @@ -106,8 +111,8 @@
from .sysnorm import *

# Allow access to phase_plane functions as ct.phaseplot.fcn or ct.pp.fcn
from . import phaseplot
from . import phaseplot as pp
from . import phaseplot as phaseplot
pp = phaseplot

# Exceptions
from .exception import *
Expand Down
5 changes: 2 additions & 3 deletions control/canonical.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@

import numpy as np

from numpy import zeros, zeros_like, shape, poly, iscomplex, vstack, hstack, \
transpose, empty, finfo, float64
from numpy.linalg import solve, matrix_rank, eig
from numpy import zeros_like, poly, transpose
from numpy.linalg import solve, matrix_rank

from scipy.linalg import schur

Expand Down
1 change: 0 additions & 1 deletion control/dtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"""

from .iosys import isctime
from .statesp import StateSpace

__all__ = ['sample_system', 'c2d']

Expand Down
6 changes: 3 additions & 3 deletions control/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def slycot_check():
global slycot_installed
if slycot_installed is None:
try:
import slycot
import slycot # noqa: F401
slycot_installed = True
except:
slycot_installed = False
Expand All @@ -85,7 +85,7 @@ def pandas_check():
global pandas_installed
if pandas_installed is None:
try:
import pandas
import pandas # noqa: F401
pandas_installed = True
except:
pandas_installed = False
Expand All @@ -98,7 +98,7 @@ def cvxopt_check():
global cvxopt_installed
if cvxopt_installed is None:
try:
import cvxopt
import cvxopt # noqa: F401
cvxopt_installed = True
except:
cvxopt_installed = False
Expand Down
18 changes: 10 additions & 8 deletions control/flatsys/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,17 @@
"""

# Basis function families
from .basis import BasisFamily
from .poly import PolyFamily
from .bezier import BezierFamily
from .bspline import BSplineFamily
from .basis import BasisFamily as BasisFamily
from .poly import PolyFamily as PolyFamily
from .bezier import BezierFamily as BezierFamily
from .bspline import BSplineFamily as BSplineFamily

# Classes
from .systraj import SystemTrajectory
from .flatsys import FlatSystem, flatsys
from .linflat import LinearFlatSystem
from .systraj import SystemTrajectory as SystemTrajectory
from .flatsys import FlatSystem as FlatSystem
from .flatsys import flatsys as flatsys
from .linflat import LinearFlatSystem as LinearFlatSystem

# Package functions
from .flatsys import point_to_point, solve_flat_ocp
from .flatsys import point_to_point as point_to_point
from .flatsys import solve_flat_ocp as solve_flat_ocp
2 changes: 1 addition & 1 deletion control/flatsys/bspline.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import numpy as np
from .basis import BasisFamily
from scipy.interpolate import BSpline, splev
from scipy.interpolate import BSpline

class BSplineFamily(BasisFamily):
"""B-spline basis functions.
Expand Down
2 changes: 1 addition & 1 deletion control/flatsys/flatsys.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import warnings
from .poly import PolyFamily
from .systraj import SystemTrajectory
from ..exception import ControlArgument
from ..nlsys import NonlinearIOSystem
from ..timeresp import _check_convert_array

Expand Down Expand Up @@ -245,7 +246,6 @@ def flatsys(*args, updfcn=None, outfcn=None, **kwargs):
"""
from .linflat import LinearFlatSystem
from ..statesp import StateSpace
from ..iosys import _process_iosys_keywords

if len(args) == 1 and isinstance(args[0], StateSpace):
# We were passed a linear system, so call linflat
Expand Down
4 changes: 2 additions & 2 deletions control/frdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
from warnings import warn

import numpy as np
from numpy import absolute, angle, array, empty, eye, imag, linalg, ones, \
real, sort, where
from numpy import absolute, array, empty, eye, imag, linalg, ones, \
real, sort
from scipy.interpolate import splev, splprep

from . import config
Expand Down
5 changes: 1 addition & 4 deletions control/freqplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import itertools
import math
import warnings
from os.path import commonprefix

import matplotlib as mpl
import matplotlib.pyplot as plt
Expand Down Expand Up @@ -760,13 +759,11 @@ def _make_line_label(response, output_index, input_index):
if plot_magnitude:
ax_mag.axhline(y=0 if dB else 1, color='k', linestyle=':',
zorder=-20)
mag_ylim = ax_mag.get_ylim()

if plot_phase:
ax_phase.axhline(y=phase_limit if deg else
math.radians(phase_limit),
color='k', linestyle=':', zorder=-20)
phase_ylim = ax_phase.get_ylim()

# Annotate the phase margin (if it exists)
if plot_phase and pm != float('inf') and Wcp != float('nan'):
Expand Down Expand Up @@ -2222,7 +2219,7 @@ def gangof4_plot(
See :class:`ControlPlot` for more detailed information.

"""
if len(args) == 1 and isinstance(arg, FrequencyResponseData):
if len(args) == 1 and isinstance(args[0], FrequencyResponseData):
if any([kw is not None
for kw in [omega, omega_limits, omega_num, Hz]]):
raise ValueError(
Expand Down
1 change: 0 additions & 1 deletion control/iosys.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import re
from copy import deepcopy
from warnings import warn

import numpy as np

Expand Down
3 changes: 2 additions & 1 deletion control/lti.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import numpy as np
import math

from numpy import real, angle, abs
# todo: override built-in abs
from numpy import real, abs
from warnings import warn
from . import config
from .iosys import InputOutputSystem
Expand Down
1 change: 0 additions & 1 deletion control/margins.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
import numpy as np
import scipy as sp
from . import xferfcn
from .lti import evalfr
from .iosys import issiso
from . import frdata
from . import freqplot
Expand Down
2 changes: 1 addition & 1 deletion control/mateqn.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

import warnings
import numpy as np
from numpy import copy, eye, dot, finfo, inexact, atleast_2d
from numpy import eye, finfo, inexact

import scipy as sp
from scipy.linalg import eigvals, solve
Expand Down
3 changes: 3 additions & 0 deletions control/matlab/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@

"""

# Silence unused imports (F401), * imports (F403), unknown symbols (F405)
# ruff: noqa: F401, F403, F405

# Import MATLAB-like functions that are defined in other packages
from scipy.signal import zpk2ss, ss2zpk, tf2zpk, zpk2tf
from numpy import linspace, logspace
Expand Down
2 changes: 1 addition & 1 deletion control/modelsimp.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ def balanced_reduction(sys, orders, method='truncate', alpha=None):

# check if orders is a list or a scalar
try:
order = iter(orders)
iter(orders)
except TypeError: # if orders is a scalar
orders = [orders]

Expand Down
3 changes: 1 addition & 2 deletions control/nichols.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from .ctrlplot import ControlPlot, _get_line_labels, _process_ax_keyword, \
_process_legend_keywords, _process_line_labels, _update_plot_title
from .ctrlutil import unwrap
from .freqplot import _default_frequency_range, _freqplot_defaults
from .lti import frequency_response
from .statesp import StateSpace
from .xferfcn import TransferFunction
Expand Down Expand Up @@ -137,7 +136,7 @@ def nichols_plot(

# Decide on the system name and label
sysname = response.sysname if response.sysname is not None \
else f"Unknown-{idx_sys}"
else f"Unknown-sys_{idx}"
label_ = sysname if label is None else label[idx]

# Generate the plot
Expand Down
24 changes: 11 additions & 13 deletions control/nlsys.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@

"""

import copy
from warnings import warn

import numpy as np
import scipy as sp

from . import config
from .iosys import InputOutputSystem, _parse_spec, _process_iosys_keywords, \
_process_signal_list, common_timebase, iosys_repr, isctime, isdtime
common_timebase, iosys_repr, isctime, isdtime
from .timeresp import _check_convert_array, _process_time_response, \
TimeResponseData, TimeResponseList

Expand Down Expand Up @@ -211,7 +210,7 @@ def __mul__(self, other):
"can't multiply systems with incompatible inputs and outputs")

# Make sure timebase are compatible
dt = common_timebase(other.dt, self.dt)
common_timebase(other.dt, self.dt)

# Create a new system to handle the composition
inplist = [(0, i) for i in range(other.ninputs)]
Expand Down Expand Up @@ -243,7 +242,7 @@ def __rmul__(self, other):
"inputs and outputs")

# Make sure timebase are compatible
dt = common_timebase(self.dt, other.dt)
common_timebase(self.dt, other.dt)

# Create a new system to handle the composition
inplist = [(0, i) for i in range(self.ninputs)]
Expand Down Expand Up @@ -811,7 +810,7 @@ def cxn_string(signal, gain, first):
return (" - " if not first else "-") + \
f"{abs(gain)} * {signal}"

out += f"\nConnections:\n"
out += "\nConnections:\n"
for i in range(len(input_list)):
first = True
cxn = f"{input_list[i]} <- "
Expand All @@ -831,7 +830,7 @@ def cxn_string(signal, gain, first):
cxn, width=78, initial_indent=" * ",
subsequent_indent=" ")) + "\n"

out += f"\nOutputs:\n"
out += "\nOutputs:\n"
for i in range(len(self.output_labels)):
first = True
cxn = f"{self.output_labels[i]} <- "
Expand Down Expand Up @@ -2474,8 +2473,7 @@ def interconnect(
`outputs`, for more natural naming of SISO systems.

"""
from .statesp import LinearICSystem, StateSpace, _convert_to_statespace
from .xferfcn import TransferFunction
from .statesp import LinearICSystem, StateSpace

dt = kwargs.pop('dt', None) # bypass normal 'dt' processing
name, inputs, outputs, states, _ = _process_iosys_keywords(kwargs)
Expand Down Expand Up @@ -2537,7 +2535,7 @@ def interconnect(
# This includes signal lists such as ('sysname', ['sig1', 'sig2', ...])
# as well as slice-based specifications such as 'sysname.signal[i:j]'.
#
dprint(f"Pre-processing connections:")
dprint("Pre-processing connections:")
new_connections = []
for connection in connections:
dprint(f" parsing {connection=}")
Expand Down Expand Up @@ -2576,7 +2574,7 @@ def interconnect(
#
dprint(f"Pre-processing input connections: {inplist}")
if not isinstance(inplist, list):
dprint(f" converting inplist to list")
dprint(" converting inplist to list")
inplist = [inplist]
new_inplist, new_inputs = [], [] if inplist_none else inputs

Expand Down Expand Up @@ -2639,7 +2637,7 @@ def interconnect(
else:
if isinstance(connection, list):
# Passed a list => create input map
dprint(f" detected input list")
dprint(" detected input list")
signal_list = []
for spec in connection:
isys, indices, gain = _parse_spec(syslist, spec, 'input')
Expand All @@ -2665,7 +2663,7 @@ def interconnect(
#
dprint(f"Pre-processing output connections: {outlist}")
if not isinstance(outlist, list):
dprint(f" converting outlist to list")
dprint(" converting outlist to list")
outlist = [outlist]
new_outlist, new_outputs = [], [] if outlist_none else outputs
for iout, connection in enumerate(outlist):
Expand Down Expand Up @@ -2742,7 +2740,7 @@ def _find_output_or_input_signal(spec):

if isinstance(connection, list):
# Passed a list => create input map
dprint(f" detected output list")
dprint(" detected output list")
signal_list = []
for spec in connection:
signal_list += _find_output_or_input_signal(spec)
Expand Down
7 changes: 3 additions & 4 deletions control/optimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
import time

from . import config
from .exception import ControlNotImplemented
from .iosys import _process_indices, _process_labels, \
from .iosys import _process_labels, \
_process_control_disturbance_indices


Expand Down Expand Up @@ -163,7 +162,7 @@ def __init__(
if trajectory_method is None:
trajectory_method = 'collocation' if sys.isctime() else 'shooting'
elif trajectory_method not in _optimal_trajectory_methods:
raise NotImplementedError(f"Unkown method {method}")
raise NotImplementedError(f"Unknown method {trajectory_method}")

self.shooting = trajectory_method in {'shooting'}
self.collocation = trajectory_method in {'collocation'}
Expand Down Expand Up @@ -1106,7 +1105,7 @@ def solve_ocp(
# Process (legacy) method keyword
if kwargs.get('method'):
method = kwargs.pop('method')
if method not in optimal_methods:
if method not in _optimal_trajectory_methods:
if kwargs.get('minimize_method'):
raise ValueError("'minimize_method' specified more than once")
warnings.warn(
Expand Down
Loading
Loading