diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c2fb38c867..693d8fd9f7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -46,7 +46,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -57,7 +57,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -71,4 +71,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000000..88ebb91427 --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,33 @@ +name: linting + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + pre-job: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@master + with: + concurrent_skipping: 'same_content' + skip_after_successful_duplicate: 'false' + do_not_skip: '["workflow_dispatch", "schedule"]' + linting: + needs: pre-job + runs-on: ubuntu-latest + if: ${{ needs.pre-job.outputs.should_skip != 'true' }} + steps: + - name: Cancel Previous Runs + uses: styfle/cancel-workflow-action@0.9.1 + with: + access_token: ${{ github.token }} + - uses: actions/checkout@v2 + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - uses: pre-commit/action@v3.0.0 diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 1c131a7c9d..c0dd6b1ead 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -247,39 +247,22 @@ An example: Code Style ---------- -ACT follows PEP8 coding standards. To make sure your code follows the -PEP8 style, you can use a variety of tools that can check for you. Two -popular PEP8 check modules are flake8 and pylint. (Note: ACT's continuous -integration uses flake8). +Py-ART uses pre-commit for linting, which applies a variety of pep8 and other +code style rules. For more on pep8 style: - https://www.python.org/dev/peps/pep-0008/ -To install flake8:: +To install pre-commit hooks for the Py-ART repo:: - conda install -c conda-forge flake8 + pre-commit install -To use flake8:: +Afterwards, pre-commit will run on every commit to the repository. It will +re-format files as neccessary. - flake8 path/to/code/to/check.py - -To install pylint:: - - conda install pylint - -To use pylint:: - - pylint path/to/code/to/check.py - -Both of these tools are highly configurable to suit a user's taste. Refer to -the tools documentation for details on this process. - -- https://flake8.pycqa.org/en/latest/ -- https://www.pylint.org/ - -Naming Convenction ----------------------------------------- +Naming Convention +----------------- Discovery ~~~~~~~~~ diff --git a/README.rst b/README.rst index d828e20b3c..3efac0f6fe 100644 --- a/README.rst +++ b/README.rst @@ -38,16 +38,14 @@ Please report any issues or feature requests by sumitting an `Issue `_ has been provided that explains the changes and how to work with the new syntax. -To test out the release candidate 2.0.0-rc.0 of ACT, use:: +The new release is available on both PyPI and conda-forge. - pip install git+https://github.com/ARM-DOE/ACT.git@v2.0.0-rc.0 - -Please report any bugs of the release candidate to the Issue Tracker mentioned in +Please report any bugs of the 2.0 release to the Issue Tracker mentioned in the Important Links section below. Important Links diff --git a/act/__init__.py b/act/__init__.py index 81ae36fd04..56ee9cb5be 100644 --- a/act/__init__.py +++ b/act/__init__.py @@ -14,7 +14,7 @@ register_matplotlib_converters() # Import early so these classes are available to the object -from .qc import QCFilter, QCTests, clean +from .qc import QCFilter, QCTests, clean # noqa # Import the lazy loaded modules submodules = [ diff --git a/act/io/hysplit.py b/act/io/hysplit.py index 35fc96710a..0579b3ef00 100644 --- a/act/io/hysplit.py +++ b/act/io/hysplit.py @@ -95,7 +95,8 @@ def read_hysplit(filename, base_year=2000): var_list.append(variable) input_df = pd.read_csv( - filename, sep='\s+', index_col=False, names=var_list, skiprows=12) # noqa W605 + filename, sep=r'\s+', index_col=False, names=var_list, skiprows=12 + ) # noqa W605 input_df['year'] = base_year + input_df['year'] input_df['time'] = pd.to_datetime( input_df[["year", "month", "day", "hour", "minute"]], format='%y%m%d%H%M' diff --git a/act/plotting/__init__.py b/act/plotting/__init__.py index 814fa43f0a..1e8bad1732 100644 --- a/act/plotting/__init__.py +++ b/act/plotting/__init__.py @@ -17,10 +17,10 @@ import lazy_loader as lazy # Load colormaps -import cmweather +import cmweather # noqa # Eagerly load in common -from . import common +from . import common # noqa __getattr__, __dir__, __all__ = lazy.attach( __name__, diff --git a/act/utils/data_utils.py b/act/utils/data_utils.py index 38853c2439..d664f5a356 100644 --- a/act/utils/data_utils.py +++ b/act/utils/data_utils.py @@ -35,8 +35,13 @@ def __init__(self, ds): self._ds = ds def change_units( - self, variables=None, desired_unit=None, skip_variables=None, skip_standard=True, - verbose=False, raise_error=False + self, + variables=None, + desired_unit=None, + skip_variables=None, + skip_standard=True, + verbose=False, + raise_error=False, ): """ Parameters @@ -111,10 +116,14 @@ def change_units( np.core._exceptions.UFuncTypeError, ): if raise_error: - raise ValueError(f"Unable to convert '{var_name}' to units of '{desired_unit}'.") + raise ValueError( + f"Unable to convert '{var_name}' to units of '{desired_unit}'." + ) elif verbose: - print(f"\n Unable to convert '{var_name}' to units of '{desired_unit}'. " - f"Skipping unit converstion for '{var_name}'.\n") + print( + f"\n Unable to convert '{var_name}' to units of '{desired_unit}'. " + f"Skipping unit converstion for '{var_name}'.\n" + ) return self._ds diff --git a/continuous_integration/environment_actions.yml b/continuous_integration/environment_actions.yml index 0443eb0502..279ed58f14 100644 --- a/continuous_integration/environment_actions.yml +++ b/continuous_integration/environment_actions.yml @@ -24,11 +24,12 @@ dependencies: - coveralls - pandas - shapely - - pip - lazy_loader - cmweather - arm-test-data - moviepy + - ruff + - pip - pip: - mpl2nc - metpy diff --git a/docs/source/conf.py b/docs/source/conf.py index a906959a32..d04bc24fb6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -91,7 +91,7 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -import act +import act # noqa # The short X.Y version. version = act.__version__ diff --git a/examples/plotting/plot_daytime_averages.py b/examples/plotting/plot_daytime_averages.py index 6beff17c1b..ef77de0179 100644 --- a/examples/plotting/plot_daytime_averages.py +++ b/examples/plotting/plot_daytime_averages.py @@ -33,7 +33,7 @@ ds = ds.where(ds['sun_variable'] == 1) # Take daily mean using xarray features -ds = ds.resample(time='1d', skipna=True, keep_attrs=True).mean() +ds = ds.resample(time='1d', skipna=True).mean() # Creat Plot Display display = act.plotting.TimeSeriesDisplay(ds, figsize=(15, 10)) diff --git a/examples/plotting/plot_scatter.py b/examples/plotting/plot_scatter.py index 5a32477e67..e3a7fc14f4 100644 --- a/examples/plotting/plot_scatter.py +++ b/examples/plotting/plot_scatter.py @@ -32,7 +32,7 @@ 'ground_speed', m_field='ambient_temp', marker='x', - cbar_label=r'Ambient Temperature ($^\circ$C)', # noqa W605 + cbar_label=r'Ambient Temperature ($^\circ$C)', # noqa W605 ) # Set the range of the field on the x-axis @@ -47,7 +47,7 @@ display.axes[0].plot(ds['true_airspeed'], p(ds['true_airspeed']), 'r', linewidth=2) # Display the line equation -display.axes[0].text(45, 135, "y = {:.3f}x + ({:.3f})".format(z[0], z[1]), color='r', fontsize=12) +display.axes[0].text(45, 135, f"y = {z[0]:.3f}x + ({z[1]:.3f})", color='r', fontsize=12) # Calculate Pearson Correlation Coefficient cc_conc = pearsonr(ds['true_airspeed'], ds['ground_speed']) diff --git a/examples/qc/plot_arm_qc.py b/examples/qc/plot_arm_qc.py index d8abc6dd26..91d43645a0 100644 --- a/examples/qc/plot_arm_qc.py +++ b/examples/qc/plot_arm_qc.py @@ -145,7 +145,7 @@ # to give to other users. # There is a file in the same directory called sgpmfrsr7nchE11.b1.yaml with times of # incorrect or suspect values that can be read and applied to the Dataset. -from act.qc.add_supplemental_qc import apply_supplemental_qc +from act.qc.add_supplemental_qc import apply_supplemental_qc # noqa apply_supplemental_qc(ds, 'sgpmfrsr7nchE11.b1.yaml') diff --git a/pyproject.toml b/pyproject.toml index 06353c6682..6f4440c460 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,3 +6,9 @@ ignore = ["act/io/arm.py"] [tool.check-manifest] ignore = ["docs/*", "ci/*"] + +[tool.ruff] +target-version = "py39" +ignore = [ + "E501", +] diff --git a/tests/plotting/test_geodisplay.py b/tests/plotting/test_geodisplay.py index 035c2ed998..f1d11b57ff 100644 --- a/tests/plotting/test_geodisplay.py +++ b/tests/plotting/test_geodisplay.py @@ -7,6 +7,7 @@ from act.tests import sample_files try: + import cartopy # noqa CARTOPY_AVAILABLE = True except ImportError: CARTOPY_AVAILABLE = False diff --git a/tests/plotting/test_xsectiondisplay.py b/tests/plotting/test_xsectiondisplay.py index aa73154905..dbcb1896a8 100644 --- a/tests/plotting/test_xsectiondisplay.py +++ b/tests/plotting/test_xsectiondisplay.py @@ -7,6 +7,7 @@ from act.tests import sample_files try: + import cartopy # noqa CARTOPY_AVAILABLE = True except ImportError: CARTOPY_AVAILABLE = False diff --git a/tests/qc/test_qcfilter.py b/tests/qc/test_qcfilter.py index 01a0adf643..99311ec589 100644 --- a/tests/qc/test_qcfilter.py +++ b/tests/qc/test_qcfilter.py @@ -13,7 +13,7 @@ from act.tests import EXAMPLE_MET1, EXAMPLE_METE40, EXAMPLE_IRT25m20s try: - import scikit_posthocs + import scikit_posthocs # noqa SCIKIT_POSTHOCS_AVAILABLE = True except ImportError: diff --git a/tests/retrievals/test_sp2_retrievals.py b/tests/retrievals/test_sp2_retrievals.py index e22db09722..b5bf49f927 100644 --- a/tests/retrievals/test_sp2_retrievals.py +++ b/tests/retrievals/test_sp2_retrievals.py @@ -4,7 +4,7 @@ import act try: - import pysp2 + import pysp2 # noqa PYSP2_AVAILABLE = True except ImportError: diff --git a/tests/utils/test_data_utils.py b/tests/utils/test_data_utils.py index ec1a0a920e..27facdee3c 100644 --- a/tests/utils/test_data_utils.py +++ b/tests/utils/test_data_utils.py @@ -152,8 +152,10 @@ def test_convert_units(): with redirect_stdout(f): ds.utils.change_units('home_signal_15', 'not_a_real_unit_string', verbose=True) s = f.getvalue() - assert s.strip() == f"Unable to convert '{var_name}' to units of '{unit}'. Skipping unit converstion for '{var_name}'." - + assert ( + s.strip() + == f"Unable to convert '{var_name}' to units of '{unit}'. Skipping unit converstion for '{var_name}'." + ) ds.close() del ds diff --git a/tests/utils/test_io_utils.py b/tests/utils/test_io_utils.py index 44bb2d1c01..23393e6bbd 100644 --- a/tests/utils/test_io_utils.py +++ b/tests/utils/test_io_utils.py @@ -12,7 +12,8 @@ from act.tests import sample_files try: - import moviepy.video.io.ImageSequenceClip + import moviepy.video.io.ImageSequenceClip # noqa + MOVIEPY_AVAILABLE = True except ImportError: MOVIEPY_AVAILABLE = False