diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2f821a42..d167ca5a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,3 +34,10 @@ repos: rev: 22.3.0 hooks: - id: black + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.11 + hooks: + # Run the linter. + - id: ruff-check + # The formatter could be run in the future + #- id: ruff-format diff --git a/doc/source/conf.py b/doc/source/conf.py index f5691bbc..9cc34581 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -9,13 +9,14 @@ # full list see the documentation: # http://www.sphinx-doc.org/en/master/config +import importlib.util import os import sys from datetime import datetime +from importlib.metadata import version as get_version import jsonschema2md -import fusesoc from fusesoc.capi2.json_schema import capi2_schema from fusesoc.utils import yaml_read @@ -34,8 +35,6 @@ copyright = f"2018-{datetime.now().year}, Olof Kindgren" author = "Olof Kindgren" -from importlib.metadata import version as get_version - # The full version, including alpha/beta/rc tags. release: str = get_version("fusesoc") @@ -109,11 +108,9 @@ # or # - apt-get install python-sphinx-rtd-theme -try: - import sphinx_rtd_theme - +if importlib.util.find_spec("sphinx_rtd_theme") is not None: html_theme = "sphinx_rtd_theme" -except ImportError: +else: sys.stderr.write( "Warning: The Sphinx 'sphinx_rtd_theme' HTML theme was " + "not found. Make sure you have the theme installed to produce pretty " diff --git a/fusesoc/capi2/core.py b/fusesoc/capi2/core.py index e570dc6b..49fe8af5 100644 --- a/fusesoc/capi2/core.py +++ b/fusesoc/capi2/core.py @@ -133,7 +133,7 @@ def export(self, dst_dir, flags={}): _abs_f = os.path.join(root, f) _rel_f = os.path.normpath(os.path.relpath(_abs_f, dst_dir)) - if not _rel_f in [os.path.normpath(x) for x in src_files]: + if _rel_f not in [os.path.normpath(x) for x in src_files]: os.remove(_abs_f) def _get_script_names(self, flags): @@ -148,7 +148,7 @@ def _get_script_names(self, flags): if scripts: hooks[hook] = [] for script in scripts: - if not script in cd_scripts: + if script not in cd_scripts: raise SyntaxError( "Script '{}', requested by target '{}', was not found".format( script, target_name @@ -276,10 +276,10 @@ def get_files(self, flags): attributes = { k: v for k, v in attributes.items() - if (type(v) == bool and v == True) - or (type(v) == str and len(v)) > 0 - or (type(v) == list and len(v)) > 0 - or (type(v) == dict and len(v)) > 0 + if (isinstance(v, bool) and v is True) + or (isinstance(v, str) and len(v) > 0) + or (isinstance(v, list) and len(v) > 0) + or (isinstance(v, dict) and len(v) > 0) } _src_files.append(attributes) @@ -302,7 +302,7 @@ def get_virtuals(self, flags={}): def get_parameters(self, flags={}, ext_parameters={}): def _parse_param_value(name, datatype, default): if datatype == "bool": - if type(default) == str: + if isinstance(default, str): if default.lower() == "true": return True elif default.lower() == "false": @@ -312,12 +312,12 @@ def _parse_param_value(name, datatype, default): raise SyntaxError(_s.format(self.name, default, p)) return default elif datatype == "int": - if type(default) == int: + if isinstance(default, int): return default else: return int(default, 0) elif datatype == "real": - if type(default) == float: + if isinstance(default, float): return default else: return float(default) @@ -332,11 +332,11 @@ def _parse_param(flags, name, core_param): core_param["description"] if "description" in core_param else "" ) - if not datatype in ["bool", "file", "int", "real", "str"]: + if datatype not in ["bool", "file", "int", "real", "str"]: _s = "{} : Invalid datatype '{}' for parameter {}" raise SyntaxError(_s.format(self.name, datatype, p)) - if not paramtype in [ + if paramtype not in [ "cmdlinearg", "generic", "plusarg", @@ -384,7 +384,6 @@ def _parse_param(flags, name, core_param): # ...or in any of its dependencies elif p in ext_parameters: parameters[p] = ext_parameters[p] - datatype = parameters[p]["datatype"] else: raise SyntaxError( @@ -402,7 +401,7 @@ def _parse_param(flags, name, core_param): # If default is a string and it is empty it should be deleted if ( "default" in parameters[p] - and type(parameters[p]["default"]) == str + and isinstance(parameters[p]["default"], str) and len(parameters[p]["default"]) == 0 ): del parameters[p]["default"] @@ -420,7 +419,7 @@ def get_toplevel(self, flags): if "toplevel" in target: toplevel = target["toplevel"] self._debug(f"Matched toplevel {toplevel}") - return " ".join(toplevel) if type(toplevel) == list else toplevel + return " ".join(toplevel) if isinstance(toplevel, list) else toplevel else: s = "{} : Target '{}' has no toplevel" raise SyntaxError(s.format(self.name, target_name)) @@ -436,9 +435,9 @@ def get_ttptttg(self, flags): _ttptttg = [] if "generate" in target: for f in target["generate"]: - if type(f) == str: + if isinstance(f, str): _ttptttg.append({"name": f, "params": {}}) - elif type(f) == dict: + elif isinstance(f, dict): for k, v in f.items(): _ttptttg.append({"name": k, "params": v}) @@ -447,7 +446,7 @@ def get_ttptttg(self, flags): for gen in _ttptttg: gen_name = gen["name"] cd_generate = self._coredata.get_generate(flags) - if not gen_name in cd_generate: + if gen_name not in cd_generate: raise SyntaxError( "Generator instance '{}', requested by target '{}', was not found".format( gen_name, target_name @@ -500,7 +499,7 @@ def _get_vpi(self, flags): vpi[vpi_name] = { "src_files": files, "inc_files": incfiles, - "libs": [l for l in libs], + "libs": [lib for lib in libs], } return vpi @@ -535,12 +534,12 @@ def info(self, trustfile): cd_target = self._coredata.get_targets({}) if cd_target: - l = max(len(x) for x in cd_target) + maxlen = max(len(x) for x in cd_target) targets = "" for t in sorted(cd_target): targets += "{} : {}\n".format( - t.ljust(l), + t.ljust(maxlen), cd_target[t]["description"] if "description" in cd_target[t] else "", @@ -620,7 +619,7 @@ def _get_filesets(self, flags): cd_filesets = self._coredata.get_filesets(flags) for fs in target.get("filesets", []): - if not fs in cd_filesets: + if fs not in cd_filesets: raise SyntaxError( "{} : Fileset '{}', requested by target '{}', was not found".format( self.name, fs, target_name @@ -686,7 +685,7 @@ def sig_status(self, trustfile): ok = True except RuntimeError: return "*" # Signature is not for this core (should not happen) - except: + except Exception: return "!" # Other signature checking error if ok: return "good" diff --git a/fusesoc/capi2/coredata.py b/fusesoc/capi2/coredata.py index 295e80e9..802c3889 100644 --- a/fusesoc/capi2/coredata.py +++ b/fusesoc/capi2/coredata.py @@ -17,23 +17,22 @@ def __init__(self, capi_data): self._append_lists(self._capi_data) def _expand_use(self, data, flags): - if type(data) == dict: + if isinstance(data, dict): remove = [] append = {} for k, v in data.items(): # Only run expand() if a string contains a "?" to avoid # issues with strings containing for instance parentheses - if type(v) == str and len(v) > 0 and "?" in v: + if isinstance(v, str) and len(v) > 0 and "?" in v: data[k] = Exprs(v).expand(flags) - if type(k) == str and "?" in k: + if isinstance(k, str) and "?" in k: expanded_k = Exprs(k).expand(flags) if len(expanded_k) == 0: remove.append(k) elif expanded_k != k: append[expanded_k] = v remove.append(k) - - if type(v) == dict or type(v) == list: + if isinstance(v, (dict, list)): self._expand_use(data[k], flags) for i in remove: @@ -41,33 +40,35 @@ def _expand_use(self, data, flags): data.update(append) - if type(data) == list: + if isinstance(data, list): remove = [] for idx, i in enumerate(data): - if type(i) == str and len(i) > 0 and "?" in i: + if isinstance(i, str) and len(i) > 0 and "?" in i: expanded = Exprs(i).expand(flags) if i != expanded: if len(expanded) > 0: data[idx] = expanded else: remove.append(idx) - elif type(i) == dict or type(i) == list: + elif isinstance(i, (dict, list)): self._expand_use(i, flags) for i in reversed(remove): data.pop(i) def _append_lists(self, data): - if type(data) == list: + if isinstance(data, list): for i in data: self._append_lists(i) - if type(data) == dict: + if isinstance(data, dict): data_append = {} for k, v in data.items(): if k.endswith("_append"): _k = k[:-7] - if type(v) == list and (not _k in data or type(data[_k]) == list): + if isinstance(v, list) and ( + _k not in data or isinstance(data[_k], list) + ): if _k in data: # If for instance default target is included for several other # targets we need to create a copy to avoid modifying the source @@ -106,11 +107,11 @@ def _setup_file(self, file, fs): d["logical_name"] = fs["logical_name"] # If we already have values for the file attributes we overwrite the defaults - if type(file) == dict: + if isinstance(file, dict): for k in file.keys(): d.update(file[k]) file_name = k - elif type(file) == str: + elif isinstance(file, str): file_name = file return {file_name: d} @@ -121,7 +122,7 @@ def _setup_fileset(self, data, flags): for file in fs.get("files", []): files.append(self._setup_file(file, fs)) - if not "depend" in fs: + if "depend" not in fs: fs["depend"] = [] fs["files"] = files diff --git a/fusesoc/capi2/exprs.py b/fusesoc/capi2/exprs.py index 1ae0165b..29b29154 100644 --- a/fusesoc/capi2/exprs.py +++ b/fusesoc/capi2/exprs.py @@ -87,7 +87,7 @@ def _get_parser(): + Suppress(")") ) exprs <<= OneOrMore(conditional ^ word) - conditional.setParseAction(_cond_parse_action) + conditional.set_parse_action(_cond_parse_action) _PARSER = exprs return _PARSER @@ -138,7 +138,7 @@ def _parse(string): """ try: - raw_ast = _get_parser().parseString(string, parseAll=True) + raw_ast = _get_parser().parse_string(string, parse_all=True) except ParseException as err: raise ValueError( f"Invalid syntax for string: {err}. Parsed text was {string!r}." diff --git a/fusesoc/capi2/generator.py b/fusesoc/capi2/generator.py index 67145788..1e80331b 100644 --- a/fusesoc/capi2/generator.py +++ b/fusesoc/capi2/generator.py @@ -26,27 +26,27 @@ def __init__(self, data=None, resolve_env_vars=False): def add_files( self, files, fileset="rtl", targets=["default"], file_type="", logical_name="" ): - if not fileset in self.filesets: + if fileset not in self.filesets: self.filesets[fileset] = {"files": []} self.filesets[fileset]["files"] = files self.filesets[fileset]["file_type"] = file_type self.filesets[fileset]["logical_name"] = logical_name for target in targets: - if not target in self.targets: + if target not in self.targets: self.targets[target] = {"filesets": []} - if not fileset in self.targets[target]["filesets"]: + if fileset not in self.targets[target]["filesets"]: self.targets[target]["filesets"].append(fileset) def add_parameter(self, parameter, data={}, targets=["default"]): self.parameters[parameter] = data for target in targets: - if not target in self.targets: + if target not in self.targets: self.targets[target] = {} - if not "parameters" in self.targets[target]: + if "parameters" not in self.targets[target]: self.targets[target]["parameters"] = [] - if not parameter in self.targets[target]["parameters"]: + if parameter not in self.targets[target]["parameters"]: self.targets[target]["parameters"].append(parameter) def write(self): diff --git a/fusesoc/config.py b/fusesoc/config.py index 88993415..305ed2f7 100644 --- a/fusesoc/config.py +++ b/fusesoc/config.py @@ -222,7 +222,7 @@ def ignored_dirs(self): @ignored_dirs.setter def ignored_dirs(self, val): self._set_default_section( - "ignored_dirs", " ".join(val) if type(val) == list else val + "ignored_dirs", " ".join(val) if isinstance(val, list) else val ) @property diff --git a/fusesoc/coremanager.py b/fusesoc/coremanager.py index 3049f5b8..86d9b14b 100644 --- a/fusesoc/coremanager.py +++ b/fusesoc/coremanager.py @@ -364,7 +364,7 @@ def eq_vln(this, that): transaction = solver.solve(request) except SatisfiabilityError as e: raise DependencyError(top_core.name, msg=e.unsat.to_string(pool)) - except NoPackageFound as e: + except NoPackageFound: raise DependencyError(top_core.name) virtual_selection = {} @@ -416,7 +416,7 @@ def __init__(self, config, library_manager=None): self.db = CoreDB() self._lm = ( LibraryManager(config.library_root) - if library_manager == None + if library_manager is None else library_manager ) self.core2parser = Core2Parser( @@ -427,7 +427,7 @@ def find_cores(self, library, ignored_dirs): found_cores = [] path = os.path.expanduser(library.location) exclude = {".git"} - if os.path.isdir(path) == False: + if not os.path.isdir(path): raise OSError(path + " is not a directory") logger.debug("Checking for cores in " + path) visited = set() @@ -498,9 +498,9 @@ def _detect_capi_version(self, core_file) -> int: """ try: with open(core_file) as f: - l = f.readline().split() - if l: - first_line = l[0] + lines = f.readline().split() + if lines: + first_line = lines[0] else: first_line = "" if first_line == "CAPI=1": @@ -523,7 +523,7 @@ def _detect_capi_version(self, core_file) -> int: core_file ) ) - except Exception as error: + except Exception: error_msg = f"Unable to determine CAPI version from core file {core_file}" logger.warning(error_msg) return -1 diff --git a/fusesoc/edalizer.py b/fusesoc/edalizer.py index 2a31ed3d..1411adbf 100644 --- a/fusesoc/edalizer.py +++ b/fusesoc/edalizer.py @@ -13,8 +13,8 @@ from fusesoc import utils from fusesoc.capi2.coreparser import Core2Parser -from fusesoc.coremanager import DependencyError -from fusesoc.utils import merge_dict +from fusesoc.core import Core +from fusesoc.utils import Launcher, merge_dict from fusesoc.vlnv import Vlnv logger = logging.getLogger(__name__) @@ -346,13 +346,13 @@ def _build_parser(self, backend_class, edam): _description = param.get("description", "No description") _paramtype = param["paramtype"] if _paramtype in paramtypes: - if not _paramtype in param_groups: + if _paramtype not in param_groups: param_groups[_paramtype] = parser.add_argument_group( _descr[_paramtype] ) default = None - if not param.get("default") is None: + if param.get("default") is not None: try: if param["datatype"] == "bool": default = param["default"] @@ -360,7 +360,7 @@ def _build_parser(self, backend_class, edam): default = [ typedict[param["datatype"]]["type"](param["default"]) ] - except KeyError as e: + except KeyError: pass try: param_groups[_paramtype].add_argument( @@ -438,7 +438,7 @@ def add_parsed_args(self, backend_class, parsed_args): elif key in backend_members: tool_options[key] = value elif key in backend_lists: - if not key in tool_options: + if key not in tool_options: tool_options[key] = [] tool_options[key] += value.split(" ") elif key in self.edam["parameters"]: @@ -488,7 +488,7 @@ def _parse_flow_options(self, backend_class, backendargs, edam): # on the command line if value is None: continue - _value = value[0] if type(value) == list else value + _value = value[0] if isinstance(value, list) else value # If flow option is a list, we split up the parsed string if "list" in available_flow_options[key]: @@ -516,7 +516,7 @@ def parse_args(self, backend_class, backendargs): for key, value in sorted(vars(parsed_args).items()): if value is None: continue - _value = value[0] if type(value) == list else value + _value = value[0] if isinstance(value, list) else value args_dict[key] = _value self.add_parsed_args(backend_class, args_dict) @@ -526,14 +526,10 @@ def to_yaml(self, edam_file): return utils.yaml_fwrite(edam_file, self.edam) -from fusesoc.core import Core -from fusesoc.utils import Launcher - - class Ttptttg: def __init__(self, ttptttg, core, generators, work_root, resolve_env_vars=False): generator_name = ttptttg["generator"] - if not generator_name in generators: + if generator_name not in generators: raise RuntimeError( "Could not find generator '{}' requested by {}".format( generator_name, core.name @@ -590,7 +586,7 @@ def _sha256_file_input_hexdigest(self): hash = hashlib.sha256() for f in input_files: - if type(f) == list: + if isinstance(f, list): files = f else: files = [f] @@ -645,7 +641,9 @@ def is_cacheable(self): return self.is_input_cacheable() or self.is_generator_cacheable() def acquire_cache_lock(self): - have_lock = False + pass + # TODO: Implement cache locking + # have_lock = False # while not have_lock: # if @@ -696,7 +694,7 @@ def generate(self): shutil.rmtree(generator_cwd, ignore_errors=True) try: self._run(generator_cwd) - except: + except Exception: # If the generator invocation failed for any reason, its output # directory is removed. While this is bad for debugging failing # generators, it at least prevents the next FuseSoC-run to diff --git a/fusesoc/filters/autotype.py b/fusesoc/filters/autotype.py index 9fb2eb9c..9bdf979b 100644 --- a/fusesoc/filters/autotype.py +++ b/fusesoc/filters/autotype.py @@ -29,7 +29,7 @@ def run(self, edam, work_root): ".rdl": "systemRDL", } for f in edam["files"]: - if not "file_type" in f: + if "file_type" not in f: fn = f["name"] (_, ext) = os.path.splitext(fn) ft = type_map.get(ext, "") diff --git a/fusesoc/filters/spdxgen.py b/fusesoc/filters/spdxgen.py index a7826c4a..6220301e 100755 --- a/fusesoc/filters/spdxgen.py +++ b/fusesoc/filters/spdxgen.py @@ -10,7 +10,7 @@ try: import nanoid -except: +except ImportError: print( "Filter spdxgen needs the nanoid python package, please install it and try again." ) diff --git a/fusesoc/filters/splitlib.py b/fusesoc/filters/splitlib.py index 2ffb7a11..ad71a50b 100644 --- a/fusesoc/filters/splitlib.py +++ b/fusesoc/filters/splitlib.py @@ -1,5 +1,4 @@ import logging -import os logger = logging.getLogger(__name__) @@ -18,6 +17,6 @@ def run(self, edam, work_root): edam["library_dependencies"] = libdeps for f in edam["files"]: - if not "logical_name" in f: + if "logical_name" not in f: f["logical_name"] = flatten_vlnv(f["core"]) return edam diff --git a/fusesoc/fusesoc.py b/fusesoc/fusesoc.py index 5f163fc1..48ebe0b2 100644 --- a/fusesoc/fusesoc.py +++ b/fusesoc/fusesoc.py @@ -6,11 +6,10 @@ import os from importlib import import_module -from fusesoc.config import Config from fusesoc.coremanager import CoreManager, DependencyError from fusesoc.edalizer import Edalizer from fusesoc.librarymanager import Library, LibraryManager -from fusesoc.utils import Launcher, setup_logging, yaml_fread +from fusesoc.utils import setup_logging, yaml_fread from fusesoc.vlnv import Vlnv try: @@ -36,7 +35,7 @@ def _register_libraries(self): for library in self.config.libraries + cores_root_libs: try: self.add_library(library) - except (RuntimeError, OSError) as e: + except (RuntimeError, OSError): try: temporary_lm = LibraryManager(self.config.library_root) # try to initialize library @@ -146,7 +145,7 @@ def get_backend(self, core, flags, backendargs=[]): try: backend_class = get_edatool(flags["tool"]) except ImportError: - raise RuntimeError(f"Backend {tool!r} not found") + raise RuntimeError(f"Backend {flags['tool']!r} not found") edalizer = Edalizer( toplevel=core.name, diff --git a/fusesoc/librarymanager.py b/fusesoc/librarymanager.py index b1eb13e0..4d084ae0 100644 --- a/fusesoc/librarymanager.py +++ b/fusesoc/librarymanager.py @@ -20,7 +20,7 @@ def __init__( sync_version=None, auto_sync=True, ): - if sync_type and not sync_type in ["local", "git", "url"]: + if sync_type and sync_type not in ["local", "git", "url"]: raise ValueError( "Library {} ({}) Invalid sync-type '{}'".format( name, location, sync_type @@ -41,35 +41,35 @@ def __init__( self.auto_sync = auto_sync def update(self, force=False): - def l(s): + def lib(s): return self.name + " : " + s if self.sync_type == "local": - logger.info(l("sync-type is local. Ignoring update")) + logger.info(lib("sync-type is local. Ignoring update")) return if not (self.auto_sync or force): - logger.info(l("auto-sync disabled. Ignoring update")) + logger.info(lib("auto-sync disabled. Ignoring update")) return provider = get_provider(self.sync_type) if not os.path.exists(self.location): - logger.info(l(f"{self.location} does not exist. Trying a checkout")) + logger.info(lib(f"{self.location} does not exist. Trying a checkout")) try: provider.init_library(self) - except RuntimeError as e: + except RuntimeError: # Keep old behavior of logging a warning if there is a library # in `fusesoc.conf`, but the directory does not exist for some # reason and it could not be initialized. - logger.warning(l(f"{self.location} does not exist. Ignoring update")) + logger.warning(lib(f"{self.location} does not exist. Ignoring update")) return try: - logger.info(l("Updating...")) + logger.info(lib("Updating...")) provider.update_library(self) except RuntimeError as e: - logger.error(l("Failed to update library: " + str(e))) + logger.error(lib("Failed to update library: " + str(e))) class LibraryManager: diff --git a/fusesoc/lockfile.py b/fusesoc/lockfile.py index abc507bd..0d72a844 100644 --- a/fusesoc/lockfile.py +++ b/fusesoc/lockfile.py @@ -79,7 +79,7 @@ def load_lockfile(filepath: pathlib.Path): raise SyntaxError(f"Core {vln} defined multiple times in lock file") core["name"] = vlnv else: - raise SyntaxError(f"Core definition without a name") + raise SyntaxError("Core definition without a name") cores[vlnv] = core lockfile = { "cores": cores, diff --git a/fusesoc/main.py b/fusesoc/main.py index fde273a3..13ad88a6 100644 --- a/fusesoc/main.py +++ b/fusesoc/main.py @@ -22,13 +22,6 @@ except ImportError: __version__ = "unknown" -# Check if this is run from a local installation -fusesocdir = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "..") -) -if os.path.exists(os.path.join(fusesocdir, "fusesoc")): - sys.path[0:0] = [fusesocdir] - import logging from fusesoc.config import Config @@ -39,30 +32,30 @@ logger = logging.getLogger(__name__) -def _get_core(cm, name): +def _get_core(cm, core_name): matches = set() - if not ":" in name: + if ":" not in core_name: for core in cm.get_cores(): - (v, l, n, _) = core.split(":") - if n.lower() == name.lower(): - matches.add(f"{v}:{l}:{n}") + (vendor, library, name, _) = core.split(":") + if name.lower() == core_name.lower(): + matches.add(f"{vendor}:{library}:{name}") if len(matches) == 1: - name = matches.pop() + core_name = matches.pop() elif len(matches) > 1: - _s = f"'{name}' is ambiguous. Potential matches: " + _s = f"'{core_name}' is ambiguous. Potential matches: " _s += ", ".join(f"'{x}'" for x in matches) logger.error(_s) exit(1) core = None try: - core = cm.get_core(name) + core = cm.get_core(core_name) except RuntimeError as e: logger.error(str(e)) exit(1) except DependencyError as e: logger.error( - f"{name!r} or any of its dependencies requires {e.value!r}, but " + f"{core_name!r} or any of its dependencies requires {e.value!r}, but " "this core was not found" ) exit(1) diff --git a/fusesoc/parser/coreparser.py b/fusesoc/parser/coreparser.py index b8c24cc8..e76d1b71 100644 --- a/fusesoc/parser/coreparser.py +++ b/fusesoc/parser/coreparser.py @@ -3,7 +3,6 @@ # SPDX-License-Identifier: BSD-2-Clause import fastjsonschema -import yaml from fusesoc import utils @@ -34,16 +33,16 @@ def __init__( raise SyntaxError(f"\nError parsing JSON Schema: {e}") def _set_additional_properties(self, schema, val): - if type(schema) == list: + if isinstance(schema, list): for i in schema: self._set_additional_properties(i, val) - if type(schema) == dict: + if isinstance(schema, dict): for k, v in schema.items(): - if k == "additionalProperties" and type(v) == bool: + if k == "additionalProperties" and isinstance(v, bool): schema[k] = val - if type(v) == dict or type(v) == list: + if isinstance(v, (dict, list)): self._set_additional_properties(v, val) def read(self, core_file, validate_core=True): diff --git a/fusesoc/provider/git.py b/fusesoc/provider/git.py index bb1af4b1..3b8cd95a 100644 --- a/fusesoc/provider/git.py +++ b/fusesoc/provider/git.py @@ -3,8 +3,6 @@ # SPDX-License-Identifier: BSD-2-Clause import logging -import os.path -import shutil import subprocess from fusesoc.provider.provider import Provider @@ -67,7 +65,7 @@ def _checkout(self, local_dir): try: args = ["clone", "-q", "--no-single-branch", repo, local_dir] Launcher("git", args).run() - except: + except Exception: raise e if version: args = ["-C", local_dir, "checkout", "-q", version] diff --git a/fusesoc/provider/opencores.py b/fusesoc/provider/opencores.py index 2bd60bd6..92b93f67 100644 --- a/fusesoc/provider/opencores.py +++ b/fusesoc/provider/opencores.py @@ -3,7 +3,6 @@ # SPDX-License-Identifier: BSD-2-Clause import logging -import sys from fusesoc.provider.provider import Provider from fusesoc.utils import Launcher, cygpath, is_mingw diff --git a/fusesoc/provider/provider.py b/fusesoc/provider/provider.py index 2a1f7498..19e3e2b3 100644 --- a/fusesoc/provider/provider.py +++ b/fusesoc/provider/provider.py @@ -6,13 +6,12 @@ import os import shutil import stat +from importlib import import_module from fusesoc.utils import Launcher logger = logging.getLogger(__name__) -from importlib import import_module - def get_provider(name): return getattr(import_module(f"fusesoc.provider.{name}"), name.capitalize()) @@ -23,7 +22,7 @@ def __init__(self, config, core_root, files_root): self.config = config self.core_root = core_root self.files_root = files_root - self.cachable = not (config.get("cachable", "") == False) + self.cachable = config.get("cachable", "") is not False self.patches = config.get("patches", []) def clean_cache(self): diff --git a/fusesoc/provider/url.py b/fusesoc/provider/url.py index eec7315c..e20ebbc9 100644 --- a/fusesoc/provider/url.py +++ b/fusesoc/provider/url.py @@ -9,8 +9,6 @@ import tarfile import zipfile -logger = logging.getLogger(__name__) - if sys.version_info[0] >= 3: import urllib.request as urllib from urllib.error import HTTPError, URLError @@ -21,6 +19,8 @@ from fusesoc.provider.provider import Provider +logger = logging.getLogger(__name__) + _HAS_TAR_FILTER = hasattr(tarfile, "tar_filter") # Requires Python 3.12 diff --git a/fusesoc/signature.py b/fusesoc/signature.py index 83650c2e..e6a676cb 100644 --- a/fusesoc/signature.py +++ b/fusesoc/signature.py @@ -3,7 +3,6 @@ # Licensed under the 2-Clause BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-2-Clause -import base64 import logging import os import shutil @@ -32,7 +31,7 @@ def sign(core, key_file_name, old_sig_file): signatory = key_parts[2].strip() core_canonical = core.signed_data() - if shutil.which("ssh-keygen") == None: + if shutil.which("ssh-keygen") is None: raise RuntimeError("ssh-keygen not found in $PATH") cmd = ["ssh-keygen", "-Y", "sign", "-f", key_file_name, "-n", "file"] @@ -80,17 +79,17 @@ def verify(core_obj, trust_file_name, sig_file_name): logger.debug("with trustfile: " + trust_file_name) core_canonical = core_obj.signed_data() sig_data = utils.yaml_fread(sig_file_name) - if not "coresig" in sig_data: + if "coresig" not in sig_data: raise RuntimeError("Signature file missing coresig member.") if not isinstance(sig_data["coresig"], dict): raise RuntimeError("coresig object in signature is not an object.") - if not "name" in sig_data["coresig"]: + if "name" not in sig_data["coresig"]: raise RuntimeError("Signature file missing name member in coresig object.") if sig_data["coresig"]["name"] != str(core_obj.name): raise RuntimeError( "Signature file and core file must have the same 'name' field." ) - if shutil.which("ssh-keygen") == None: + if shutil.which("ssh-keygen") is None: raise RuntimeError("ssh-keygen not found in $PATH") user_results = {} diff --git a/fusesoc/utils.py b/fusesoc/utils.py index bcb27320..313d644f 100644 --- a/fusesoc/utils.py +++ b/fusesoc/utils.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: BSD-2-Clause import logging +import os import subprocess import sys import warnings @@ -59,9 +60,6 @@ def cygpath(win_path): return path.decode("ascii").strip() -import os - - def unique_dirs(file_list): return list({os.path.dirname(f) for f in file_list}) @@ -117,7 +115,7 @@ def _formatwarning(message, category, filename, lineno, line=None): # Format FutureWarnings, which are intended for end users, in a way # that strips out all code references, which are meaningless to an end # user. - if category == FutureWarning: + if category is FutureWarning: return message return _formatwarning_orig(message, category, filename, lineno, line) diff --git a/fusesoc/vlnv.py b/fusesoc/vlnv.py index cfe00a4e..30cb0f20 100644 --- a/fusesoc/vlnv.py +++ b/fusesoc/vlnv.py @@ -173,8 +173,11 @@ def compare_relation(vlvn_a: Vlnv, relation: str, vlvn_b: Vlnv): """Compare two VLVNs with the provided relation. Returns boolan.""" from okonomiyaki.versions import EnpkgVersion + def version_str(v): + return f"{v.version}-{v.revision}" + valid_version = False - version_str = lambda v: f"{v.version}-{v.revision}" + if vlvn_a.vln_str() == vlvn_b.vln_str(): ver_a = EnpkgVersion.from_string(version_str(vlvn_a)) ver_b = EnpkgVersion.from_string(version_str(vlvn_b)) diff --git a/pyproject.toml b/pyproject.toml index d216fd4a..e3c0ca6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,3 +59,9 @@ envlist = py3 deps = pytest commands = pytest """ + +[tool.ruff] +line-length = 88 +indent-width = 4 + +target-version = "py37" diff --git a/tests/test_capi2.py b/tests/test_capi2.py index 09029b08..8b24df4e 100644 --- a/tests/test_capi2.py +++ b/tests/test_capi2.py @@ -38,14 +38,13 @@ def test_files_out_of_hierarchy(): def test_empty_core(): import os - import tempfile from fusesoc.capi2.coreparser import Core2Parser from fusesoc.core import Core core_file = os.path.join(tests_dir, "capi2_cores", "misc", "empty.core") with pytest.raises(SyntaxError) as excinfo: - core = Core(Core2Parser(), core_file) + Core(Core2Parser(), core_file) assert "Error validating" in str(excinfo.value) @@ -127,8 +126,6 @@ def test_capi2_export_no_overwrite(): "vpifile", ] - result = [] - # Export and check all dst files are equal to src files core.export(export_root) for f in expected: @@ -282,7 +279,7 @@ def test_capi2_type_check(): core_file = os.path.join(tests_dir, "capi2_cores", "misc", "typecheck.core") with pytest.raises(SyntaxError) as excinfo: - core = Core(Core2Parser(), core_file) + Core(Core2Parser(), core_file) assert "Error validating" in str(excinfo.value) @@ -427,14 +424,14 @@ def test_capi2_get_parameters(): } result = core.get_parameters(flags) assert expected == result - assert str == type(result["param2"]["datatype"]) - assert str == type(result["param2"]["default"]) - assert str == type(result["param2"]["description"]) - assert str == type(result["param2"]["paramtype"]) - assert int == type(result["intparam"]["default"]) - assert bool == type(result["boolfalse"]["default"]) - assert bool == type(result["booltrue"]["default"]) - assert float == type(result["realpi"]["default"]) + assert isinstance(result["param2"]["datatype"], str) + assert isinstance(result["param2"]["default"], str) + assert isinstance(result["param2"]["description"], str) + assert isinstance(result["param2"]["paramtype"], str) + assert isinstance(result["intparam"]["default"], int) + assert isinstance(result["boolfalse"]["default"], bool) + assert isinstance(result["booltrue"]["default"], bool) + assert isinstance(result["realpi"]["default"], float) flags["target"] = "empty" expected = {"int0": int0, "emptystr": emptystr} @@ -691,7 +688,7 @@ def test_core2parser(): parser = Core2Parser(allow_additional_properties=False) assert parser.get_version() == 2 - assert parser.get_allow_additional_properties() == False + assert parser.get_allow_additional_properties() is False assert parser.get_preamble() == "CAPI=2:" expected = { @@ -731,7 +728,7 @@ def test_core2parser(): assert "Error validating" in str(excinfo.value) parser = Core2Parser(allow_additional_properties=True) - assert parser.get_allow_additional_properties() == True + assert parser.get_allow_additional_properties() is True expected = { "name": "::withadditionalproperties:0", diff --git a/tests/test_config.py b/tests/test_config.py index d6544141..5905aa8d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,6 +6,7 @@ import os.path import tempfile +import pytest from test_common import cache_root, cores_root, library_root from fusesoc.config import Config @@ -43,9 +44,6 @@ def test_config(): assert conf.library_root == library_root -import pytest - - @pytest.mark.parametrize("from_cli", [False, True]) @pytest.mark.parametrize("from_config", [False, True]) def test_config_filters(from_cli, from_config): diff --git a/tests/test_edalizer.py b/tests/test_edalizer.py index 3124c453..c7ba3c47 100644 --- a/tests/test_edalizer.py +++ b/tests/test_edalizer.py @@ -4,8 +4,6 @@ def test_apply_filters(caplog): - import logging - import pytest from fusesoc.edalizer import Edalizer @@ -211,11 +209,6 @@ def test_generators(): ], "license": "MIT", }, - "::generators:0": { - "core_file": "generators.core", - "dependencies": [], - "license": None, - }, "::generate-testgenerate_without_params:0": { "core_file": "generated.core", "dependencies": [], diff --git a/tests/test_libraries.py b/tests/test_libraries.py index 9348fa2c..3716d616 100644 --- a/tests/test_libraries.py +++ b/tests/test_libraries.py @@ -13,7 +13,6 @@ from fusesoc.config import Config from fusesoc.fusesoc import Fusesoc -from fusesoc.librarymanager import Library build_root = "test_build_root" @@ -61,7 +60,6 @@ def test_library_add(caplog): import tempfile from fusesoc.coremanager import CoreManager - from fusesoc.librarymanager import LibraryManager from fusesoc.main import add_library with tempfile.TemporaryDirectory() as td: @@ -141,9 +139,7 @@ def test_library_add(caplog): sync-uri = https://github.com/fusesoc/fusesoc-cores sync-version = capi2 sync-type = git -auto-sync = true""".format( - cm._lm.library_root - ) +auto-sync = true""" add_library(cm, args) @@ -177,8 +173,6 @@ def test_library_update(caplog): conf = Config(tcf.name) - args = Namespace() - Fusesoc.init_logging(False, False) fs = Fusesoc(conf) @@ -236,8 +230,6 @@ def test_library_update_with_initialize(caplog): conf = Config(tcf.name) - args = Namespace() - Fusesoc.init_logging(False, False) fs = Fusesoc(conf) diff --git a/tests/test_lockfile.py b/tests/test_lockfile.py index 6fb03e86..26fb676e 100644 --- a/tests/test_lockfile.py +++ b/tests/test_lockfile.py @@ -2,7 +2,6 @@ # Licensed under the 2-Clause BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-2-Clause -import os import pathlib import pytest diff --git a/tests/test_provider.py b/tests/test_provider.py index 629e5184..657e87bd 100644 --- a/tests/test_provider.py +++ b/tests/test_provider.py @@ -59,7 +59,7 @@ def test_github_provider(): assert fref.read() == fgen.read(), f -@pytest.mark.skipif(shutil.which("svn") == None, reason="Subversion not installed") +@pytest.mark.skipif(shutil.which("svn") is None, reason="Subversion not installed") def test_svn_provider(): cache_root = tempfile.mkdtemp("svn_") core = Core( diff --git a/tests/test_signatures.py b/tests/test_signatures.py index a353a9df..fd8617d1 100644 --- a/tests/test_signatures.py +++ b/tests/test_signatures.py @@ -3,8 +3,6 @@ # SPDX-License-Identifier: BSD-2-Clause import os -import shutil -from pathlib import Path import pytest from test_common import tests_dir diff --git a/tests/test_vlnv.py b/tests/test_vlnv.py index 76ecfcdb..93057c08 100644 --- a/tests/test_vlnv.py +++ b/tests/test_vlnv.py @@ -2,8 +2,6 @@ # Licensed under the 2-Clause BSD License, see LICENSE for details. # SPDX-License-Identifier: BSD-2-Clause -import pytest - from fusesoc.vlnv import Vlnv, compare_relation