diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb13c841..6be219ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,5 +21,5 @@ jobs: apt: - pandoc envs: | - - linux: py311 + - linux: py312 - linux: linkcheck diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2fd377a3..acd959a9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,38 +2,45 @@ ci: autofix_prs: false autoupdate_schedule: "quarterly" repos: - - repo: https://github.com/psf/black - rev: 24.3.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.3.7" hooks: - - id: black - - repo: https://github.com/PyCQA/isort - rev: 5.13.2 + - id: ruff + args: ["--fix", "--unsafe-fixes"] + - id: ruff-format + - repo: https://github.com/PyCQA/autoflake + rev: v2.3.1 hooks: - - id: isort + - id: autoflake + args: + [ + "--in-place", + "--remove-all-unused-imports", + "--remove-unused-variable", + ] + - repo: https://github.com/PyCQA/docformatter + rev: v1.7.5 + hooks: + - id: docformatter + args: ["--make-summary-multi-line", "--pre-summary-newline", "-ri"] - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier + types_or: [css, scss, javascript, rst, json, yaml, toml, markdown] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-ast - id: check-case-conflict - - id: trailing-whitespace - - id: mixed-line-ending - - id: end-of-file-fixer + - id: check-json + - id: check-toml - id: check-yaml - id: debug-statements - - repo: https://github.com/PyCQA/autoflake - rev: v2.3.1 - hooks: - - id: autoflake - args: - [ - "--in-place", - "--remove-all-unused-imports", - "--remove-unused-variable", - ] + - id: end-of-file-fixer + - id: mixed-line-ending + args: ["--fix=lf"] + - id: trailing-whitespace - repo: https://github.com/codespell-project/codespell rev: v2.2.6 hooks: diff --git a/conf.py b/conf.py index f33a5369..48fe3e5f 100644 --- a/conf.py +++ b/conf.py @@ -1,8 +1,8 @@ -import os import sys +from pathlib import Path from urllib.request import urlretrieve -sys.path.append(os.path.abspath("exts")) +sys.path.append(Path("exts").absolute().as_posix()) extensions = [ "cards", "myst_parser", @@ -51,17 +51,14 @@ ".tox/*", ] master_doc = "index" -project = "SunPy" -author = "SunPy Project" -copyright = "SunPy Project" +project = "sunpy.org" +author = "The SunPy Community" +copyright = "The SunPy Community" # NOQA: A001 show_sphinx = True version = "" release = "main" language = "en" - pygments_style = "sphinx" - - default_role = "obj" html_theme = "sunpy" html_title = "sunpy.org" @@ -71,11 +68,9 @@ "show_prev_next": False, "sst_is_root": True, } - html_css_files = [ "sunpy_org.css", ] - blog_sidebars = [ "ablog/postcard.html", "ablog/recentposts.html", @@ -83,7 +78,6 @@ "ablog/categories.html", "ablog/archives.html", ] - html_sidebars = { "*": [], "about": ["about-sidebar.html"], @@ -93,14 +87,12 @@ "blog": blog_sidebars, "blog/**": blog_sidebars, } - redirects = { "project/meetings": "about/meetings", "project/roles": "about/roles", "project": "about/project", "project/affiliated": "affiliated", } - # nbsphinx options nbsphinx_prolog = r""" {% set docname = env.doc2path(env.docname, base=None) %} @@ -123,18 +115,16 @@ ogp_image = "https://raw.githubusercontent.com/sunpy/sunpy-logo/master/generated/sunpy_logo_word.png" ogp_description_length = 300 ogp_type = "website" - urlretrieve( "https://raw.githubusercontent.com/sunpy/sunpy/main/sunpy/CITATION.rst", filename="CITATION.rst", ) - # These links have anchors that linkcheck does not like linkcheck_ignore = [ "https://app.element.io/#/room/#sunpy:openastronomy.org", ] linkcheck_anchors_ignore = [ - "/projects\?project=develop_sunkit-image", + r"/projects\?project=develop_sunkit-image", "the-executive", "acceptance-process-for-affiliated-packages", "detailed-description", diff --git a/exts/cards/__init__.py b/exts/cards/__init__.py index c6860e29..b17446d9 100644 --- a/exts/cards/__init__.py +++ b/exts/cards/__init__.py @@ -1,4 +1,3 @@ -import os from pathlib import Path from docutils import nodes @@ -15,9 +14,7 @@ def visit_card_node(self, node): key = title or node["github"] key = key.lower().replace(" ", "-") title = f"

{title}

" if len(title) > 0 else "" - col_extra_class = "column-half" if title else "" - body = f"""
{title}
@@ -46,7 +43,6 @@ def depart_card_node(self, node):
""" - self.body.append(body) @@ -54,7 +50,7 @@ class Card(Directive): has_content = True required_arguments = 1 optional_arguments = 6 - option_spec = { + option_spec = { # NOQA: RUF012 "img_name": directives.unchanged, "title": directives.unchanged, "github": directives.unchanged, @@ -65,37 +61,14 @@ class Card(Directive): } def run(self): - if "title" in self.options: - title = self.options.get("title") - else: - title = "" - if "img_name" in self.options: - img_name = self.options.get("img_name") - else: - img_name = "sunpy_icon.svg" - if "github" in self.options: - github = self.options.get("github") - else: - github = "" - if "aff_name" in self.options: - aff_name = self.options.get("aff_name") - else: - aff_name = "" - if "aff_link" in self.options: - aff_link = self.options.get("aff_link") - else: - aff_link = "" - if "date" in self.options: - date = self.options.get("date") - else: - date = "" - if "desc" in self.options: - desc = self.options.get("desc") - else: - desc = "N/A" - + title = self.options.get("title") if "title" in self.options else "" + img_name = self.options.get("img_name") if "img_name" in self.options else "sunpy_icon.svg" + github = self.options.get("github") if "github" in self.options else "" + aff_name = self.options.get("aff_name") if "aff_name" in self.options else "" + aff_link = self.options.get("aff_link") if "aff_link" in self.options else "" + date = self.options.get("date") if "date" in self.options else "" + desc = self.options.get("desc") if "desc" in self.options else "N/A" name = " ".join(self.arguments) - out = card( name=name, img_name=img_name, @@ -106,26 +79,21 @@ def run(self): date=date, desc=desc, ) - self.state.nested_parse(self.content, 0, out) - return [out] def copy_asset_files(app, exc): - if exc is None: # build succeeded + if exc is None: # Build succeeded for path in (Path(__file__).parent / "static").glob("*"): - copy_asset(str(path), os.path.join(app.outdir, "_static")) + copy_asset(str(path), str(Path(app.outdir) / Path("_static"))) def setup(app): app.add_node(card, html=(visit_card_node, depart_card_node)) - app.add_css_file("cards.css") app.add_directive("custom-card", Card) - app.connect("build-finished", copy_asset_files) - return { "parallel_read_safe": True, "parallel_write_safe": True, diff --git a/exts/rawfiles.py b/exts/rawfiles.py index 3ee85e18..18dd05e4 100644 --- a/exts/rawfiles.py +++ b/exts/rawfiles.py @@ -1,12 +1,12 @@ -import os import shutil +from pathlib import Path def on_html_collect_pages(app): for f in app.builder.config.rawfiles: - src = os.path.join(app.srcdir, f) - dst = os.path.join(app.builder.outdir, f) - if os.path.isfile(src): + src = str(Path(app.srcdir) / Path(f)) + dst = str(Path(app.builder.outdir) / Path(f)) + if Path(src).is_file(): shutil.copy(src, dst) else: shutil.copytree(src, dst) diff --git a/github_submodule b/github_submodule index d3bbbe7e..00a91fca 160000 --- a/github_submodule +++ b/github_submodule @@ -1 +1 @@ -Subproject commit d3bbbe7e16d7d8df11bacb421abaeb4607657283 +Subproject commit 00a91fca5014c648fb9bd19f34b087f57be8774c diff --git a/posts/2024/2024-04-03-eclipse.ipynb b/posts/2024/2024-04-03-eclipse.ipynb index e7930fc0..c62828cd 100644 --- a/posts/2024/2024-04-03-eclipse.ipynb +++ b/posts/2024/2024-04-03-eclipse.ipynb @@ -456,7 +456,9 @@ "metadata": {}, "outputs": [], "source": [ - "eclipse_map.plot()\n", + "fig = plt.figure(figsize=(9,9))\n", + "ax = plt.subplot(projection=eclipse_map)\n", + "eclipse_map.plot(axes=ax)\n", "plt.show()" ] }, diff --git a/posts/2024/eclipse_helpers.py b/posts/2024/eclipse_helpers.py index 77c92d55..63a8fab0 100644 --- a/posts/2024/eclipse_helpers.py +++ b/posts/2024/eclipse_helpers.py @@ -6,7 +6,8 @@ def _convert_to_degress(value): """ - Helper function to convert the GPS coordinates stored in the EXIF to degrees + Helper function to convert the GPS coordinates stored in the EXIF to + degrees. """ d = value.values[0].num / value.values[0].den * u.degree m = value.values[1].num / value.values[1].den * u.arcminute @@ -17,7 +18,8 @@ def _convert_to_degress(value): def get_exif_location(exif_data): """ - Returns the latitude, longitude, and altitude, if available, from the provided exif_data + Returns the latitude, longitude, and altitude, if available, from the + provided exif_data. """ lat = None lon = None @@ -48,16 +50,12 @@ def get_camera_metadata(tags): camera_metadata = {} if "EXIF ExposureTime" in tags: exposure_tag = tags["EXIF ExposureTime"] - camera_metadata["exposure_time"] = ( - exposure_tag.values[0].num / exposure_tag.values[0].den * u.s - ) + camera_metadata["exposure_time"] = exposure_tag.values[0].num / exposure_tag.values[0].den * u.s if "Image Artist" in tags: camera_metadata["author"] = tags["Image Artist"].values if "EXIF DateTimeOriginal" in tags: datetime_str = tags["EXIF DateTimeOriginal"].values.replace(" ", ":").split(":") - camera_metadata["time"] = parse_time( - f"{'-'.join(datetime_str[:3])} {':'.join(datetime_str[3:])}" - ) + camera_metadata["time"] = parse_time(f"{'-'.join(datetime_str[:3])} {':'.join(datetime_str[3:])}") if "Image Model" in tags: camera_metadata["camera_model"] = tags["Image Model"].values diff --git a/requirements.txt b/requirements.txt index 1af32ae9..bd234410 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,23 +1,21 @@ -# RC versions are needed as netfily does not support modern python -ablog>=0.11.0rc1 -sunpy-sphinx-theme>=2.0.0 +ablog>=0.11.0 ipykernel ipython jupyter_client myst-parser nbsphinx sphinx -sphinxext-opengraph -sphinx-design sphinx_reredirects +sphinx-design sphinxcontrib-youtube +sphinxext-opengraph +sunpy-sphinx-theme>=2.0.0 -# eclipse notebooks +# Eclipse notebook +astropy exifread -numpy +ipywidgets matplotlib -astropy +numpy scikit-image sunpy[map,net] -photutils -ipywidgets diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..1209f362 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,83 @@ +# Allow unused variables when underscore-prefixed. +lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" +target-version = "py39" +line-length = 120 +exclude=[ + ".git,", + "__pycache__", + "build", + "tools/**", +] +lint.select = [ + "A", + "ARG", + "ASYNC", + "B", + "BLE", + "C4", + "COM", + "DTZ", + "E", + "EM", + "ERA", + "EXE", + "F", + "FBT", + "FLY", + "G", + "I", + "ICN", + "INP", + "INT", + "ISC", + "LOG", + "NPY", + "PERF", + "PGH", + "PIE", + "PLE", + "PT", + "PTH", + "PYI", + "Q", + "RET", + "RSE", + "RUF", + "SIM", + "SLF", + "SLOT", + "T10", + "T20", + "TCH", + "TID", + "TRIO", + "TRY", + "UP", + "W", + "YTT", +] +lint.extend-ignore = [ + "COM812", # May cause conflicts when used with the formatter + "E501", # Line too long + "ISC001", # May cause conflicts when used with the formatter + "T201", # Print statements +] + +[lint.per-file-ignores] +"exts/rawfiles.py" = [ + "INP001", # Part of an implicit namespace package +] +"posts/2024/eclipse_helpers.py" = [ + "INP001", # Part of an implicit namespace package +] +"docs/conf.py" = [ + "INP001", # Part of an implicit namespace package +] + +[lint.pydocstyle] +convention = "numpy" + +[format] +docstring-code-format = true +indent-style = "space" +quote-style = "double" diff --git a/tox.ini b/tox.ini index dafb33e6..31584a9e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] minversion = 4.0 envlist = - py{39,310,311} + py{39,310,311,312} codestyle linkcheck