Skip to content

Commit cfd3bd3

Browse files
authored
feat: add Ruff linting workflow and update deps for improved code quality
feat: add Ruff linting workflow and update deps for improved code quality
2 parents 2643ba1 + 4e7a960 commit cfd3bd3

22 files changed

Lines changed: 284 additions & 76 deletions
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
name: UV Build - Pylint Lint
1+
name: UV Build - Ruff Lint
22

33
on:
44
pull_request:
55
branches:
66
- '*'
77

88
jobs:
9-
pylint-lint:
9+
ruff-lint:
1010
runs-on: ubuntu-latest
1111
permissions:
1212
contents: read
@@ -40,10 +40,10 @@ jobs:
4040
- name: Install dependencies
4141
run: uv sync
4242

43-
- name: Run pylint
43+
- name: Run Ruff
4444
run: |
45-
uv run -- pylint src
46-
uv run -- pylint tests
45+
uv run ruff check src
46+
uv run ruff check tests
4747
4848
- name: Save uv caches
4949
if: steps.cache-restore.outputs.cache-hit != 'true'
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
{
2+
"@context": [
3+
"https://geojson.org/geojson-ld/geojson-context.jsonld",
4+
{
5+
"@version": "1.1",
6+
"wx": "https://api.weather.gov/ontology#",
7+
"s": "https://schema.org/",
8+
"geo": "http://www.opengis.net/ont/geosparql#",
9+
"unit": "http://codes.wmo.int/common/unit/",
10+
"@vocab": "https://api.weather.gov/ontology#",
11+
"geometry": {
12+
"@id": "s:GeoCoordinates",
13+
"@type": "geo:wktLiteral"
14+
},
15+
"city": "s:addressLocality",
16+
"state": "s:addressRegion",
17+
"distance": {
18+
"@id": "s:Distance",
19+
"@type": "s:QuantitativeValue"
20+
},
21+
"bearing": {
22+
"@type": "s:QuantitativeValue"
23+
},
24+
"value": {
25+
"@id": "s:value"
26+
},
27+
"unitCode": {
28+
"@id": "s:unitCode",
29+
"@type": "@id"
30+
},
31+
"forecastOffice": {
32+
"@type": "@id"
33+
},
34+
"forecastGridData": {
35+
"@type": "@id"
36+
},
37+
"publicZone": {
38+
"@type": "@id"
39+
},
40+
"county": {
41+
"@type": "@id"
42+
}
43+
}
44+
],
45+
"id": "https://api.weather.gov/points/29.8249,-95.4543",
46+
"type": "Feature",
47+
"geometry": {
48+
"type": "Point",
49+
"coordinates": [-95.4543, 29.8249]
50+
},
51+
"properties": {
52+
"@id": "https://api.weather.gov/points/29.8249,-95.4543",
53+
"@type": "wx:Point",
54+
"cwa": "HGX",
55+
"type": "land",
56+
"forecastOffice": "https://api.weather.gov/offices/HGX",
57+
"gridId": "HGX",
58+
"gridX": 60,
59+
"gridY": 97,
60+
"forecast": "https://api.weather.gov/gridpoints/HGX/60,97/forecast",
61+
"forecastHourly": "https://api.weather.gov/gridpoints/HGX/60,97/forecast/hourly",
62+
"forecastGridData": "https://api.weather.gov/gridpoints/HGX/60,97",
63+
"observationStations": "https://api.weather.gov/gridpoints/HGX/60,97/stations",
64+
"relativeLocation": {
65+
"type": "Feature",
66+
"geometry": {
67+
"type": "Point",
68+
"coordinates": [-95.488497, 29.790849]
69+
},
70+
"properties": {
71+
"city": "Hilshire Village",
72+
"state": "TX",
73+
"distance": {
74+
"unitCode": "wmoUnit:m",
75+
"value": 5022.1983814209
76+
},
77+
"bearing": {
78+
"unitCode": "wmoUnit:degree_(angle)",
79+
"value": 41
80+
}
81+
}
82+
},
83+
"forecastZone": "https://api.weather.gov/zones/forecast/TXZ213",
84+
"county": "https://api.weather.gov/zones/county/TXC201",
85+
"fireWeatherZone": "https://api.weather.gov/zones/fire/TXZ213",
86+
"timeZone": "America/Chicago",
87+
"radarStation": "KHGX",
88+
"astronomicalData": {
89+
"sunrise": "2026-02-12T07:02:22-06:00",
90+
"sunset": "2026-02-12T18:09:37-06:00",
91+
"transit": "2026-02-12T12:36:00-06:00",
92+
"civilTwilightBegin": "2026-02-12T06:39:09-06:00",
93+
"civilTwilightEnd": "2026-02-12T18:32:51-06:00",
94+
"nauticalTwilightBegin": "2026-02-12T06:11:00-06:00",
95+
"nauticalTwilightEnd": "2026-02-12T19:00:59-06:00",
96+
"astronomicalTwilightBegin": "2026-02-12T05:43:07-06:00",
97+
"astronomicalTwilightEnd": "2026-02-12T19:28:52-06:00"
98+
},
99+
"nwr": {
100+
"transmitter": "KGG68",
101+
"sameCode": "048201",
102+
"areaBroadcast": "https://api.weather.gov/radio/KGG68/broadcast",
103+
"pointBroadcast": "https://api.weather.gov/points/29.8249,-95.4543/radio"
104+
}
105+
}
106+
}

data/weather/sample.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@
4242
}
4343
}
4444
],
45-
"id": "https://api.weather.gov/points/29.8249,-95.4543",
45+
"id": "https://api.weather.gov/points/29.8253,-95.4546",
4646
"type": "Feature",
4747
"geometry": {
4848
"type": "Point",
49-
"coordinates": [-95.4543, 29.8249]
49+
"coordinates": [-95.4546, 29.8253]
5050
},
5151
"properties": {
52-
"@id": "https://api.weather.gov/points/29.8249,-95.4543",
52+
"@id": "https://api.weather.gov/points/29.8253,-95.4546",
5353
"@type": "wx:Point",
5454
"cwa": "HGX",
5555
"type": "land",
@@ -72,11 +72,11 @@
7272
"state": "TX",
7373
"distance": {
7474
"unitCode": "wmoUnit:m",
75-
"value": 5022.1983814209
75+
"value": 5036.9691995333
7676
},
7777
"bearing": {
7878
"unitCode": "wmoUnit:degree_(angle)",
79-
"value": 41
79+
"value": 40
8080
}
8181
}
8282
},
@@ -86,21 +86,21 @@
8686
"timeZone": "America/Chicago",
8787
"radarStation": "KHGX",
8888
"astronomicalData": {
89-
"sunrise": "2026-02-12T07:02:22-06:00",
90-
"sunset": "2026-02-12T18:09:37-06:00",
91-
"transit": "2026-02-12T12:36:00-06:00",
92-
"civilTwilightBegin": "2026-02-12T06:39:09-06:00",
93-
"civilTwilightEnd": "2026-02-12T18:32:51-06:00",
94-
"nauticalTwilightBegin": "2026-02-12T06:11:00-06:00",
95-
"nauticalTwilightEnd": "2026-02-12T19:00:59-06:00",
96-
"astronomicalTwilightBegin": "2026-02-12T05:43:07-06:00",
97-
"astronomicalTwilightEnd": "2026-02-12T19:28:52-06:00"
89+
"sunrise": "2026-02-14T07:00:41-06:00",
90+
"sunset": "2026-02-14T18:11:11-06:00",
91+
"transit": "2026-02-14T12:35:56-06:00",
92+
"civilTwilightBegin": "2026-02-14T06:37:31-06:00",
93+
"civilTwilightEnd": "2026-02-14T18:34:21-06:00",
94+
"nauticalTwilightBegin": "2026-02-14T06:09:27-06:00",
95+
"nauticalTwilightEnd": "2026-02-14T19:02:25-06:00",
96+
"astronomicalTwilightBegin": "2026-02-14T05:41:37-06:00",
97+
"astronomicalTwilightEnd": "2026-02-14T19:30:15-06:00"
9898
},
9999
"nwr": {
100100
"transmitter": "KGG68",
101101
"sameCode": "048201",
102102
"areaBroadcast": "https://api.weather.gov/radio/KGG68/broadcast",
103-
"pointBroadcast": "https://api.weather.gov/points/29.8249,-95.4543/radio"
103+
"pointBroadcast": "https://api.weather.gov/points/29.8253,-95.4546/radio"
104104
}
105105
}
106106
}

pyproject.toml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ dependencies = [
1515
"pydantic-extra-types>=2.11.0",
1616
"pydantic-settings>=2.12.0",
1717
"pyfiglet>=1.0.4",
18-
"pylint>=4.0.4",
1918
"pylint-pydantic>=0.4.1",
2019
"pytest>=9.0.2",
2120
"rich>=14.3.2",
21+
"ruff>=0.15.1",
2222
]
2323

2424
[project.optional-dependencies]
@@ -45,3 +45,14 @@ source = ["src"]
4545

4646
[tool.coverage.report]
4747
omit = ["tests/*"]
48+
49+
[tool.ruff]
50+
line-length = 88
51+
exclude = ["__pycache__", "build", "dist", ".venv"]
52+
53+
[tool.ruff.lint]
54+
select = ["E", "F", "W", "C", "B", "I", "N", "D", "UP", "T", "A"]
55+
ignore = []
56+
57+
[tool.ruff.lint.per-file-ignores]
58+
"tests/*" = ["F401"]

src/sample_python_app/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Sample Python app package initialization."""

src/sample_python_app/core/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""
2-
Export core modules for use in other modules.
3-
"""
1+
"""Export core modules for use in other modules."""
42

53
from sample_python_app.core.config import settings, weather_settings
64
from sample_python_app.core.data_loader import fetch_astronomical_data_from_api

src/sample_python_app/core/config.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""
2-
Main configuration file for the API
3-
"""
1+
"""Main configuration file for the API."""
42

53
from zoneinfo import ZoneInfo
64

@@ -35,6 +33,7 @@ class Settings(BaseSettings):
3533

3634
@property
3735
def tz(self) -> ZoneInfo:
36+
"""Return the configured timezone info."""
3837
return ZoneInfo(self.TIMEZONE)
3938

4039

src/sample_python_app/core/data_loader.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""
2-
Handles loading and validating weather.gov astronomical data from file.
3-
"""
1+
"""Handles loading and validating weather.gov astronomical data from file."""
42

53
import httpx
64
from pydantic import ValidationError
@@ -10,6 +8,20 @@
108

119

1210
def fetch_astronomical_data_from_api(lat: float, lon: float):
11+
"""Fetch and validate astronomical data from weather.gov API for given coordinates.
12+
13+
Args:
14+
lat (float): Latitude of the location.
15+
lon (float): Longitude of the location.
16+
17+
Returns:
18+
AstronomicalData: Validated astronomical data from API response.
19+
20+
Raises:
21+
ValidationError: If the API response fails validation.
22+
httpx.HTTPError: If the API request fails.
23+
24+
"""
1325
logger = setup_logger(mode="silent")
1426
url = f"https://api.weather.gov/points/{lat},{lon}"
1527
headers = {"User-Agent": "(myweatherapp.com, contact@myweatherapp.com)"}

src/sample_python_app/core/display.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"""
2-
Handles formatting and displaying astronomical data using rich and pyfiglet.
3-
"""
1+
"""Handles formatting and displaying astronomical data using rich and pyfiglet."""
42

53
from pyfiglet import Figlet
64
from rich.console import Console
@@ -10,6 +8,15 @@
108

119

1210
def display_astronomical_data(astro):
11+
"""Format and display astronomical data using rich and pyfiglet.
12+
13+
Args:
14+
astro: AstronomicalData object containing sunrise, sunset, and formatted values.
15+
16+
Returns:
17+
None
18+
19+
"""
1320
logger = setup_logger(mode="silent")
1421
console = Console()
1522
header = Figlet(font="small", width=100).renderText("Astronomical Data")

src/sample_python_app/core/logging.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
"""
2-
Loguru logger configuration for python-app-template.
3-
"""
1+
"""Loguru logger configuration for python-app-template."""
2+
3+
import sys
44

55
from loguru import logger
66

@@ -13,8 +13,22 @@
1313

1414

1515
def setup_logger(mode="normal"):
16+
"""Configure and return a Loguru logger instance.
17+
18+
Args:
19+
mode (str, optional): Logging mode. "normal" for console and file logging,
20+
"silent" for file logging only. Defaults to "normal".
21+
22+
Returns:
23+
logger: Configured Loguru logger instance.
24+
25+
"""
1626
logger.remove()
1727
if mode == "silent":
28+
# Log errors to the console even in silent mode
29+
logger.add(
30+
sink=lambda msg: sys.stdout.write(msg), format=log_format, level="ERROR"
31+
)
1832
logger.add(
1933
"app.log",
2034
format=log_format,
@@ -24,7 +38,9 @@ def setup_logger(mode="normal"):
2438
compression="zip",
2539
)
2640
else:
27-
logger.add(sink=lambda msg: print(msg, end=""), format=log_format, level="INFO")
41+
logger.add(
42+
sink=lambda msg: sys.stdout.write(msg), format=log_format, level="INFO"
43+
)
2844
logger.add(
2945
"app.log",
3046
format=log_format,

0 commit comments

Comments
 (0)