Skip to content

Commit

Permalink
Fix more ruff nags
Browse files Browse the repository at this point in the history
  • Loading branch information
tukiains committed Nov 22, 2023
1 parent a867c76 commit d7cf9c8
Show file tree
Hide file tree
Showing 13 changed files with 130 additions and 73 deletions.
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ repos:
rev: v3.1.0
hooks:
- id: prettier
- repo: https://github.com/pappasam/toml-sort
rev: v0.23.1
hooks:
- id: toml-sort-fix
55 changes: 40 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
[build-system]
requires = ["setuptools", "wheel", "Cython"]
requires = ["Cython", "setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name="rpgPy"
name = "rpgPy"
description = "Cython code for reading binary files from RPG cloud radar."
authors = [{name = "Simo Tukiainen", email = "[email protected]"}]
readme = "README.md"
license = {file = "LICENSE"}
requires-python = ">=3.8"
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"License :: OSI Approved :: MIT License",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering",
"Development Status :: 4 - Beta",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Scientific/Engineering",
]

dependencies = ["numpy", "cython", "netCDF4", "tqdm", "numba"]

dependencies = ["cython", "netCDF4", "numba", "numpy", "tqdm"]
dynamic = ["version"]

[project.optional-dependencies]
test = [
"pytest-flakefinder",
"mypy",
"types-tqdm",
"mypy",
"pytest-flakefinder",
"types-tqdm",
]
dev = ["pre-commit", "release-version"]

Expand All @@ -39,7 +37,7 @@ Changelog = "https://github.com/actris-cloudnet/rpgpy/blob/main/CHANGELOG.md"
check_untyped_defs = true

[[tool.mypy.overrides]]
module = ["Cython.Build", "setuptools", "netCDF4", "numba", "rpgpy.data"]
module = ["Cython.Build", "netCDF4", "numba", "rpgpy.data", "setuptools"]
ignore_missing_imports = true

[tool.release-version]
Expand All @@ -50,8 +48,35 @@ changelog = "CHANGELOG.md"
[tool.ruff]
extend-select = ["I"]

[tool.ruff.lint]
select = ["ALL"]
ignore = [
"ANN", # missing types, use mypy for this
"C9", # too complex, fix me later
"COM812", # Formatting
"D", # documentation
"DTZ00", # do not check timezone info
"FIX002", # TODOs
"INP",
"ISC001", # Formatter wants me
"N8", # uppercase variable names
"PD011", # false positive
"PERF", # try except in loop
"PLR", # too many arguments etc.
"PTH", # use pathlib, fix me later
"RUF002", # unicode in doc string
"S101", # use assert
"S60",
"TD002", # TODOs
"TD003", # TODOs
]

[tool.ruff.lint.extend-per-file-ignores]
"__init__.py" = ["F401"]

[tool.setuptools.dynamic]
version = {attr = "rpgpy.version.__version__"}

[tool.tomlsort]
trailing_comma_inline_array = true
sort_inline_arrays = true
10 changes: 7 additions & 3 deletions rpgpy/header.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
"""Module for reading RPG 94 GHz radar header."""
from pathlib import Path
from typing import Iterator
from __future__ import annotations

from typing import TYPE_CHECKING, Iterator

import numpy as np

from rpgpy import utils

if TYPE_CHECKING:
from pathlib import Path


def read_rpg_header(file_name: Path) -> tuple[dict, int]:
"""Reads header from RPG binary file.
Expand Down Expand Up @@ -33,7 +37,7 @@ def read(*fields):
header[name] = np.array(array, dtype=_get_dtype(array))

header: dict = {}
file = open(file_name, "rb")
file = open(file_name, "rb") # noqa: SIM115

read(("FileCode", "i4"), ("HeaderLen", "i4"))

Expand Down
14 changes: 10 additions & 4 deletions rpgpy/metadata.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from typing import NamedTuple


Expand Down Expand Up @@ -67,7 +69,8 @@ class Meta(NamedTuple):
"CompEna": Meta(
name="compression",
long_name="Compression",
comment="0=not compressed, 1=compressed, 2=compressed and polarimetric variables saved",
comment="0=not compressed, 1=compressed, 2=compressed and polarimetric "
"variables saved",
),
"AntiAlias": Meta(
name="anti_alias",
Expand Down Expand Up @@ -216,7 +219,8 @@ class Meta(NamedTuple):
"FFTWindow": Meta(
name="fft_window",
long_name="FFT Window",
comment="FFT window in use: 0=square, 1=parzen, 2=blackman, 3=welch, 4=slepian2, "
comment="FFT window in use: 0=square, 1=parzen, 2=blackman, 3=welch, "
"4=slepian2, "
"5=slepian3",
),
"FFTInputRng": Meta(
Expand All @@ -240,7 +244,8 @@ class Meta(NamedTuple):
"QF": Meta(
name="quality_flag",
long_name="Quality Flag",
comment="Bit 1=ADC saturation, Bit 2=spectral width too high, Bit 3=no transm. power "
comment="Bit 1=ADC saturation, Bit 2=spectral width too high, Bit 3=no "
"transm. power "
"leveling",
),
"RR": Meta(name="rain_rate", long_name="Rain Rate", units="mm/h"),
Expand Down Expand Up @@ -281,7 +286,8 @@ class Meta(NamedTuple):
"Status": Meta(
name="status_flag",
long_name="Status Flag",
comment="mitigation status flags: 0/1=heater switch (ON/OFF) 0/10=blower switch (ON/OFF)",
comment="mitigation status flags: 0/1=heater switch (ON/OFF) 0/10=blower "
"switch (ON/OFF)",
),
"TotSpec": Meta(
name="doppler_spectrum",
Expand Down
60 changes: 36 additions & 24 deletions rpgpy/nc.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Module for writing netCDF file."""
from __future__ import annotations

import glob
import logging
import os
import uuid
from pathlib import Path
from typing import TYPE_CHECKING

import netCDF4
import numpy as np
Expand All @@ -15,6 +17,9 @@
from rpgpy import read_rpg, utils, version
from rpgpy.spcutil import spectra2moments

if TYPE_CHECKING:
from pathlib import Path

SKIP_ME = ("ProgName", "CustName", "HAlts", "TAlts", "StartTime", "StopTime")


Expand Down Expand Up @@ -84,16 +89,18 @@ def rpg2nc(
_append_data(f, data, metadata)
_create_global_attributes(f, header, global_attr)
f.close()
logging.info(f"Created new file: {output_file}")
msg = f"Created new file: {output_file}"
logging.info(msg)


def rpg2nc_multi(
file_directory: Path | str | None = None,
output_directory: Path | str | None = None,
global_attr: dict | None = None,
base_name: str | None = None,
*,
include_lv0: bool = True,
recursive: bool = True,
base_name: str | None = None,
global_attr: dict | None = None,
) -> list:
"""Converts several RPG binary files individually.
Expand Down Expand Up @@ -122,18 +129,21 @@ def rpg2nc_multi(
new_files = []
file_directory = utils.str2path(file_directory)
output_directory = utils.str2path(output_directory)
for filepath in _generator_files(file_directory, include_lv0, recursive):
logging.info(f"Converting {filepath}")
for filepath in _generator_files(
file_directory, include_lv0=include_lv0, recursive=recursive
):
msg = f"Converting {filepath}"
logging.info(msg)
try:
prefix = f"{base_name}_" if base_name is not None else ""
new_filename = f"{output_directory}/{prefix}{_new_filename(filepath)}"
rpg2nc(filepath, new_filename, global_attr)
new_files.append(new_filename)
except IndexError as err:
logging.warning(
f"############### File {filepath} has not been converted: {err}",
)
logging.info(f"Converted {len(new_files)} files")
msg = f"############### File {filepath} has not been converted: {err}"
logging.warning(msg)
msg = f"Converted {len(new_files)} files"
logging.info(msg)
return new_files


Expand All @@ -144,11 +154,8 @@ def _check_header_consistency(f: netCDF4.Dataset, header: dict) -> None:
try:
assert_array_almost_equal(array, f.variables[key])
except AssertionError:
print(
"Warning: inconsistent header data in " + key,
array,
f.variables[key][:],
)
msg = f"Inconsistent header data in {key}, {array}, {f.variables[key]}"
logging.warning(msg)


def _create_dimensions(f: netCDF4.Dataset, header: dict, level: int) -> None:
Expand Down Expand Up @@ -189,13 +196,13 @@ def _append_data(f: netCDF4.Dataset, data: dict, metadata: dict) -> None:
for key, array in data.items():
if key in SKIP_ME:
continue
key = metadata[key].name
name = metadata[key].name
if array.ndim == 1:
f.variables[key][ind0:ind1] = array
f.variables[name][ind0:ind1] = array
elif array.ndim == 2:
f.variables[key][ind0:ind1, :] = array
f.variables[name][ind0:ind1, :] = array
else:
f.variables[key][ind0:ind1, :, :] = array
f.variables[name][ind0:ind1, :, :] = array


def _get_dtype(array: np.ndarray) -> str:
Expand All @@ -209,14 +216,16 @@ def _get_rpg_files(path_to_files: Path) -> tuple[list, int]:
files = glob.glob(str(path_to_files))
files.sort()
if not files:
raise RuntimeError("No proper RPG binary files found")
msg = f"No RPG binary files found in {path_to_files}"
raise RuntimeError(msg)
extension = [file[-4:] for file in files]
if all(ext.lower() == ".lv1" for ext in extension):
level = 1
elif all(ext.lower() == ".lv0" for ext in extension):
level = 0
else:
raise RuntimeError("No consistent RPG level (0 or 1) files found.")
msg = "No consistent RPG level (0 or 1) files found."
raise RuntimeError(msg)
return files, level


Expand All @@ -228,7 +237,9 @@ def _get_dim(f: netCDF4.Dataset, array: np.ndarray) -> tuple:
file_dims = f.dimensions
for length in array.shape:
try:
dim = [key for key in file_dims.keys() if file_dims[key].size == length][0]
dim = next(
(key for key in file_dims if file_dims[key].size == length), None
)
except IndexError:
dim = "time"
variable_size.append(dim)
Expand Down Expand Up @@ -259,11 +270,12 @@ def _get_measurement_date(file: netCDF4.Dataset) -> list:
date_times = utils.rpg_seconds2datetime64(time, time_ms)
dates = np.unique(date_times.astype("datetime64[D]"))
if len(np.unique(dates)) > 1:
raise RuntimeError("More than one date in the file")
msg = "More than one date in the file"
raise RuntimeError(msg)
return str(dates[0]).split("-")


def _generator_files(dir_name: Path, include_lv0: bool, recursive: bool):
def _generator_files(dir_name: Path, *, include_lv0: bool, recursive: bool):
includes = (".lv1",) if include_lv0 is False else (".lv0", "lv1")
if recursive is False:
for file in os.listdir(str(dir_name)):
Expand Down
17 changes: 10 additions & 7 deletions rpgpy/spcutil.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import numpy as np
from numba import jit

Expand All @@ -11,16 +13,16 @@ def spectra2moments(
) -> dict:
"""Calculates radar moments from the main peak.
This routine calculates the radar moments: reflectivity, mean Doppler velocity, spectrum
width, skewness and kurtosis from compressed level 0 spectrum files (NoiseFactor > 0)
of the 94 GHz RPG cloud radar. Considering only the largest peak.
This routine calculates the radar moments: reflectivity, mean Doppler velocity,
spectrum width, skewness and kurtosis from compressed level 0 spectrum files
(NoiseFactor > 0) of the 94 GHz RPG cloud radar. Considering only the largest peak.
Args:
----
data: Level 0 nD variables.
header: Level 0 metadata.
spec_var: Name of the spectral variable. Possible names are 'TotSpec', 'VSpec', and 'HSpec'.
fill_value: Clear sky fill value.
spec_var: Name of the spectral variable. Possible names are 'TotSpec', 'VSpec',
and 'HSpec'. fill_value: Clear sky fill value.
n_points_min: Minimum number of points in a valid spectral line.
Returns:
Expand Down Expand Up @@ -66,7 +68,7 @@ def spectra2moments(
key: moments[:, :, i]
for i, key in enumerate(["Ze", "MeanVel", "SpecWidth", "Skewn", "Kurt"])
}
for key in output.keys():
for key in output:
output[key][no_signal] = fill_value
return output

Expand Down Expand Up @@ -113,7 +115,8 @@ def radar_moment_calculation(signal: np.ndarray, vel_bins: np.ndarray) -> np.nda

@jit(nopython=True, fastmath=True)
def find_peak_edges(signal: np.ndarray) -> tuple[int, int]:
"""Returns the indices of left and right edge of the main signal peak in a Doppler spectra.
"""Returns the indices of left and right edge of the main signal peak in a Doppler
spectra.
Args:
----
Expand Down
8 changes: 6 additions & 2 deletions rpgpy/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import datetime
import os
from pathlib import Path
Expand Down Expand Up @@ -76,7 +78,8 @@ def get_rpg_file_type(header: dict) -> tuple[int, float]:
Returns:
-------
tuple: 2-element tuple containing Level (0 or 1) and Version (1.0, 2.0, 3.5 or 4.0).
tuple: 2-element tuple containing Level (0 or 1) and Version (1.0, 2.0, 3.5
or 4.0).
Raises:
------
Expand All @@ -96,7 +99,8 @@ def get_rpg_file_type(header: dict) -> tuple[int, float]:
return 1, 3.5
if file_code == 889348:
return 1, 4.0
raise RuntimeError(f"Unsupported RPG binary file. File code: {file_code}")
msg = f"Unknown file type. File code: {file_code}"
raise RuntimeError(msg)


def isscalar(array) -> bool:
Expand Down
Loading

0 comments on commit d7cf9c8

Please sign in to comment.