diff --git a/.github/workflows/lighthouse.yml b/.github/workflows/lighthouse.yml deleted file mode 100644 index aca328484..000000000 --- a/.github/workflows/lighthouse.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Lighthouse -on: [pull_request] - -jobs: - lighthouse: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Lighthouse - uses: foo-software/lighthouse-check-action@master - with: - urls: "https://docs.sunpy.org/en/stable/,https://docs.sunpy.org/projects/sunpy-sphinx-theme/latest/" diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index 5921833be..5c7ae1b83 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -32,5 +32,5 @@ jobs: RTD_AUTH_TOKEN: ${{ secrets.RTD_AUTH_TOKEN }} NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} run: | - python rebuild_all_rtd.py + python tools/rebuild_all_rtd.py http POST https://api.netlify.com/api/v1/sites/1ba3a6d4-f1ee-4524-bbec-3edc04720a48/builds "Authorization: Bearer $NETLIFY_AUTH_TOKEN" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 33c9bbb5d..707981125 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: autoupdate_schedule: "quarterly" repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.5.1" + rev: "v0.5.6" hooks: - id: ruff args: ["--fix", "--unsafe-fixes"] @@ -42,6 +42,6 @@ repos: args: ["--fix=lf"] - id: trailing-whitespace - repo: https://github.com/crate-ci/typos - rev: v1.23.1 + rev: v1.23.6 hooks: - id: typos diff --git a/MANIFEST.in b/MANIFEST.in index 71e45c3af..5da796080 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,10 +1,12 @@ -exclude rebuild_all_rtd.py exclude tox.ini exclude .gitignore exclude .pre-commit-config.yaml exclude .stylelintrc + prune .circleci/ prune .github/ prune docs/ prune examples/ +prune tools/ + recursive-include src/sunpy_sphinx_theme/sunpy/ * diff --git a/docs/_static/img/Stuart-Mumford.png b/docs/_static/img/Stuart-Mumford.png new file mode 100644 index 000000000..302927cfc Binary files /dev/null and b/docs/_static/img/Stuart-Mumford.png differ diff --git a/docs/cards.rst b/docs/cards.rst new file mode 100644 index 000000000..f97bfe238 --- /dev/null +++ b/docs/cards.rst @@ -0,0 +1,44 @@ +================ +Cards and Tables +================ + +This page covers the cards and tables that are used in the website. + +Cards +****** + +.. custom-card:: Stuart Mumford + :img_name: Stuart-Mumford.png + :github: cadair + :title: Lead Developer + :aff_name: Sheffield University + :aff_link: https://www.sheffield.ac.uk/ + :date: 17 March 2014 + + Stuart Mumford is the Python developer for the Daniel K. Inouye Solar Telescope Data Centre. He obtained a PhD in Numerical solar physics from Sheffield University in 2016, prior to his PhD he obtained a first class MPhys degree in Physics with Planetary and Space Physics from The University of Wales Aberystwyth, during which he spent 5 months studying at UNIS on Svalbard in the high arctic. + +Tables +****** + +.. list-table:: + :widths: 20, 80 + + * - **sunpy core** + - The core package for solar physics in Python. + + `Documentation `__, `Source code `__ + + |package_general| |integration_full| |docs_extensive| |tests_excellent| |duplication_none| |community_excellent| |dev_stable| + + **Maintainer**: `The SunPy Project`_ + + Version reviewed: `v1.1.4 `__ + +.. _The SunPy Project: https://sunpy.org/about/roles +.. |package_general| image:: https://img.shields.io/badge/Functionality-General_Package-brightgreen.svg +.. |integration_full| image:: https://img.shields.io/badge/Integration-Full-brightgreen.svg +.. |docs_extensive| image:: https://img.shields.io/badge/Documentation-Extensive-brightgreen.svg +.. |tests_excellent| image:: https://img.shields.io/badge/Testing-Excellent-brightgreen.svg +.. |duplication_none| image:: https://img.shields.io/badge/Duplication-None-brightgreen.svg +.. |community_excellent| image:: https://img.shields.io/badge/Community-Excellent-brightgreen.svg +.. |dev_stable| image:: https://img.shields.io/badge/Development_Status-Stable-brightgreen.svg diff --git a/docs/conf.py b/docs/conf.py index 73ccff265..97b600097 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -8,7 +8,7 @@ from pathlib import Path from sphinx_gallery.sorting import ExplicitOrder -from sunpy_sphinx_theme import SVG_ICON +from sunpy_sphinx_theme import SVG_ICON, _sunpy_static_path # Add the test package to the path so we can import it for automodapi sys.path.append(Path().absolute().as_posix()) @@ -67,6 +67,8 @@ "reproject": ("https://reproject.readthedocs.io/en/stable/", None), } html_theme = "sunpy" +html_static_path = [str(_sunpy_static_path), "_static"] +html_extra_path = ["_static/img"] html_theme_options = { "footer_links": [ ("Google", "https://google.com", 3), diff --git a/docs/index.rst b/docs/index.rst index 132101bbd..baae5ab3a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,6 +32,7 @@ The core changes between this theme and the `pydata-sphinx-theme` are: customizing colors web-components + cards .. grid-item-card:: :class-card: card diff --git a/docs/test_package/animals.py b/docs/test_package/animals.py index 13411348e..891f84fd5 100644 --- a/docs/test_package/animals.py +++ b/docs/test_package/animals.py @@ -46,7 +46,7 @@ class Animal: says_str = "A {name} says {sound}" - def __init__(self, name, sound, num_legs=5): + def __init__(self, name, sound, num_legs=5) -> None: """ Parameters ---------- @@ -61,7 +61,7 @@ def __init__(self, name, sound, num_legs=5): self.sound = sound self.num_legs = num_legs - def says(self, sound=None): + def says(self, sound=None) -> None: """ Prints what the animals name is and what sound it makes. @@ -87,11 +87,8 @@ def says(self, sound=None): msg = "Silent Animals are not supported!" raise NotImplementedError(msg) - out_sound = self.sound if sound is None else sound - print(self.says_str.format(name=self.name, sound=out_sound)) - -def function(): +def function() -> None: """ Prints what the animals name is and what sound it makes. @@ -132,10 +129,9 @@ def function(): ---------- * `A URL. `__ """ - print("A SOUND") -def a_really_long_function_name_just_to_see_what_happens(): +def a_really_long_function_name_just_to_see_what_happens() -> None: """ Prints what the animals name is and what sound it makes. @@ -176,4 +172,3 @@ def a_really_long_function_name_just_to_see_what_happens(): ---------- * `A URL. `__ """ - print("A SOUND") diff --git a/docs/test_package/timerange.py b/docs/test_package/timerange.py index eaedb27de..9934e1476 100644 --- a/docs/test_package/timerange.py +++ b/docs/test_package/timerange.py @@ -56,7 +56,7 @@ class TimeRange: """ - def __init__(self, a, b=None, format=None): # NOQA: A002 + def __init__(self, a, b=None, format=None) -> None: # NOQA: A002 # If a is a TimeRange object, copy attributes to new instance. self._t1 = None self._t2 = None @@ -238,7 +238,7 @@ def __ne__(self, other): return NotImplemented - def __repr__(self): + def __repr__(self) -> str: """ Returns a human-readable representation of `sunpy.time.TimeRange`. """ @@ -385,7 +385,7 @@ def previous(self): return self - def extend(self, dt_start, dt_end): + def extend(self, dt_start, dt_end) -> None: """ Extend the time range forwards and backwards. @@ -409,7 +409,7 @@ def get_dates(self): ] @add_common_docstring(**_variables_for_parse_time_docstring()) - def __contains__(self, time): + def __contains__(self, time) -> bool: """ Checks whether the given time lies within this range. Both limits are inclusive (i.e., ``__contains__(t1)`` and ``__contains__(t2)`` always diff --git a/examples/example_template.py b/examples/example_template.py index f596f6133..34c7414ce 100644 --- a/examples/example_template.py +++ b/examples/example_template.py @@ -63,7 +63,7 @@ # Comments in comment blocks remain nested in the text. -def dummy(): +def dummy() -> None: """ Dummy function to make sure docstrings don't get rendered as text. """ diff --git a/examples/section/example_template_subsection.py b/examples/section/example_template_subsection.py index 7c8e5b5d8..f58f28b52 100644 --- a/examples/section/example_template_subsection.py +++ b/examples/section/example_template_subsection.py @@ -65,7 +65,7 @@ # Comments in comment blocks remain nested in the text. -def dummy(): +def dummy() -> None: """ Dummy function to make sure docstrings don't get rendered as text. """ diff --git a/ruff.toml b/ruff.toml index 9b44a9fae..ed5726e5a 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,74 +1,64 @@ # Allow unused variables when underscore-prefixed. lint.dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" -target-version = "py39" +target-version = "py310" line-length = 120 -exclude=[ - ".git,", +extend-exclude=[ "__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", + "ALL", ] lint.extend-ignore = [ + "ANN001", # Missing type annotation for function argument + "ANN002", # Missing type annotation for variable + "ANN003", # Missing type annotation for keyword + "ANN201", # Missing return type annotation for public function + "ANN202", # Missing return type annotation for private function + "ANN204", # Missing return type annotation for special method + "ANN205", # Missing return type annotation for staticmethod + "ANN206", # Missing return type annotation for classmethod "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 + "D200", # One-line docstring should fit on one line + "D205", # 1 blank line required between summary line and description + "D400", # First line should end with a period + "D401", # First line should be in imperative mood + "D404", # First word of the docstring should not be "This" + "E501", # Line too long + "FIX002", # Line contains TODO, consider resolving the issue + "ISC001", # May cause conflicts when used with the formatter + "PLR2004", # Magic value used in comparison + "TD002", # Missing author in TODO + "TD003", # Missing issue link on the line following this TODO ] [lint.per-file-ignores] "examples/*.py" = [ - "INP001", # Part of an implicit namespace package + "B018", # Not print but display + "D400", # First line should end with a period, question mark, or exclamation point + "ERA001", # Commented out code + "INP001", # Implicit namespace package + "T201", # Use print ] "docs/conf.py" = [ - "INP001", # Part of an implicit namespace package + "D100", # Missing docstring in public module + "INP001", # conf.py is part of an implicit namespace package +] +"setup.py" = [ + "D100", # Missing docstring in public module +] +"test_*.py" = [ + "D100", # Missing docstring in public module + "D103", # Missing docstring in public function + "N806", # in function should be lowercase + "S101", # Use of `assert` detected +] +"sunpy_soar/version.py" = [ + "D100", # Missing docstring in public module +] +"sunpy_soar/conftest.py" = [ + "D100", # Missing docstring in public module ] [lint.pydocstyle] diff --git a/src/sunpy_sphinx_theme/__init__.py b/src/sunpy_sphinx_theme/__init__.py index 46cba1f48..d60a9eb9b 100644 --- a/src/sunpy_sphinx_theme/__init__.py +++ b/src/sunpy_sphinx_theme/__init__.py @@ -10,6 +10,8 @@ from pydata_sphinx_theme import utils from sphinx.application import Sphinx +from .cards import Card, _Card, depart_card_node, visit_card_node + __all__ = ["get_html_theme_path", "ON_RTD", "PNG_ICON", "SVG_ICON"] @@ -61,7 +63,7 @@ def default_navbar(): ] -def update_config(app): +def update_config(app) -> None: """ Update config with new default values and handle deprecated keys. """ @@ -139,7 +141,9 @@ def setup(app: Sphinx): theme_dir = get_html_theme_path() app.add_html_theme("sunpy", theme_dir) app.add_css_file("sunpy_style.css", priority=600) - + app.add_css_file("sunpy_cards.css", priority=600) + app.add_directive("custom-card", Card) + app.add_node(_Card, html=(visit_card_node, depart_card_node)) app.connect("builder-inited", update_config) app.connect("html-page-context", update_html_context) diff --git a/src/sunpy_sphinx_theme/cards.py b/src/sunpy_sphinx_theme/cards.py new file mode 100644 index 000000000..8986f0d5b --- /dev/null +++ b/src/sunpy_sphinx_theme/cards.py @@ -0,0 +1,86 @@ +""" +This provides the card extension from the website into the theme. +""" + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +__all__ = ["Card", "_Card", "visit_card_node", "depart_card_node"] + + +class _Card(nodes.General, nodes.Element): + pass + + +def visit_card_node(self, node) -> None: + title = node.get("title", "") + 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} +
+ {node['name']} +

{node['name']}

+

+ +
""" + self.body.append(body) + + +class Card(Directive): + has_content = True + required_arguments = 1 + optional_arguments = 6 + option_spec = { # NOQA: RUF012 + "img_name": directives.unchanged, + "title": directives.unchanged, + "github": directives.unchanged, + "aff_name": directives.unchanged, + "aff_link": directives.unchanged, + "date": directives.unchanged, + "desc": directives.unchanged, + } + + def run(self): + 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, + title=title, + github=github, + aff_name=aff_name, + aff_link=aff_link, + date=date, + desc=desc, + ) + self.state.nested_parse(self.content, 0, out) + return [out] diff --git a/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_cards.css b/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_cards.css new file mode 100644 index 000000000..5dd9e1283 --- /dev/null +++ b/src/sunpy_sphinx_theme/theme/sunpy/static/sunpy_cards.css @@ -0,0 +1,86 @@ +.card { + background-color: var(--pst-color-on-background); + box-shadow: 0 4px 8px 0; + margin: 0 auto; + } + + html[data-theme="light"] .card { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); + } + + html[data-theme="dark"] .card { + box-shadow: 0 4px 8px 0 rgba(150, 150, 150, 0.2); + } + + .card p { + text-align: center; + padding-top: 10px; + } + + .card img { + display: block; + margin: 0 auto; + max-width: 60%; + padding-top: 10px; + } + + .button { + border: none; + outline: 0; + display: inline-block; + padding: 5px 20px; + margin-bottom: 20px; + border-radius: 5px; + color: var(--sst-lighter-color); + background-color: var(--sst-accent-color-bright); + text-align: center; + cursor: pointer; + font-size: 16px; + } + + .button:hover { + background-color: var(--sst-darker-color); + } + + h4.modal-title { + margin-top: 0; + } + + .column { + display: inline-block; + width: 24%; + margin-bottom: 16px; + padding: 0 10px; + } + + .column > h4 { + text-align: center; + font-size: 1.2em; + line-height: 1.2em; + height: 3.6em; + } + + .section#sunpy-board { + margin-left: -15px; + margin-right: -15px; + margin-top: 30px; + } + + @media only screen and (max-width: 355px) { + .column { + width: 80%; + } + } + + @media only screen and (min-width: 356px) and (max-width: 680px) { + .column { + width: 45%; + } + } + + @media only screen and (max-width: 1000px) { + .card p { + text-align: center; + padding-top: 10px; + } + } \ No newline at end of file diff --git a/rebuild_all_rtd.py b/tools/rebuild_all_rtd.py similarity index 100% rename from rebuild_all_rtd.py rename to tools/rebuild_all_rtd.py