Skip to content

Commit ef7f196

Browse files
authored
Merge pull request #1 from IFRCGo/feat/setup-pre-commit-hooks
Setup pre-commit hooks for black, isort, flake8 and ruff
2 parents 753ada4 + 22d8892 commit ef7f196

File tree

16 files changed

+190
-198
lines changed

16 files changed

+190
-198
lines changed

.flake8

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[flake8]
2+
extend-ignore = C901, E203, E701
3+
max-line-length = 130
4+
exclude = .git,__pycache__,old,build,dist,
5+
max-comlpexity = 10

.github/workflows/lint.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Lints
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
10+
jobs:
11+
pre_commit_checks:
12+
name: Pre-Commit checks
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@main
17+
- uses: pre-commit/action@main

.pre-commit-config.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
default_language_version:
2+
python: python3
3+
4+
# NOTE: Update in .flake8 pyproject.toml as well
5+
exclude: |
6+
(?x)^(
7+
\.git|
8+
__pycache__|
9+
\.venv
10+
)
11+
12+
repos:
13+
- repo: https://github.com/psf/black
14+
rev: 24.3.0
15+
hooks:
16+
- id: black
17+
# args: ["--check"]
18+
19+
- repo: https://github.com/PyCQA/isort
20+
rev: 5.13.2
21+
hooks:
22+
- id: isort
23+
# args: ["--check"]
24+
25+
- repo: https://github.com/PyCQA/flake8
26+
rev: 7.0.0
27+
hooks:
28+
- id: flake8
29+
30+
- repo: https://github.com/astral-sh/ruff-pre-commit
31+
# Ruff version.
32+
rev: v0.8.4
33+
hooks:
34+
# Run the linter.
35+
- id: ruff
36+
args: [ --fix ]
37+
# Run the formatter.
38+
- id: ruff-format

pyproject.toml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module = ["jinja2"]
6565
ignore_missing_imports = true
6666

6767
[tool.ruff]
68-
line-length = 88
68+
line-length = 130
6969
lint.select = ["E", "F", "I"]
7070

7171
[tool.pytest.ini_options]
@@ -78,6 +78,35 @@ exclude = ["tests*"]
7878
[tool.setuptools.dynamic]
7979
version = { attr = "pystac_monty.extension.__version__" }
8080

81+
[tool.black]
82+
line-length = 130
83+
target-version = ['py39']
84+
include = '\.pyi?$'
85+
exclude = '''
86+
/(
87+
\.git
88+
| \.tox
89+
| \.venv
90+
| \.db
91+
| _build
92+
| buck-out
93+
| build
94+
| dist
95+
| docs
96+
)/
97+
'''
98+
# NOTE: Update in .pre-commit-config.yaml as well
99+
extend-exclude = "^.*\\b(migrations)\\b.*$ (__pycache__|.+/+.+/+migrations/+.*)"
100+
101+
[tool.isort]
102+
profile = "black"
103+
multi_line_output = 3
104+
# NOTE: Update in .pre-commit-config.yaml as well
105+
skip = [
106+
"**/__pycache__",
107+
".venv/",
108+
]
109+
81110
[tool.uv]
82111
dev-dependencies = [
83112
"codespell<2.3",

pystac_monty/extension.py

Lines changed: 26 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,22 @@
44

55
from abc import ABC
66
from collections.abc import Mapping
7-
from datetime import datetime
8-
from typing import Any, Dict, Generic, Iterator, Literal, TypeVar, Union, cast
7+
from typing import Any, Generic, Iterator, Literal, TypeVar, Union, cast
98

109
import pystac
1110
import pystac.extensions
1211
import pystac.extensions.ext
1312
from pystac.extensions import item_assets
1413
from pystac.extensions.base import ExtensionManagementMixin, PropertiesExtension
1514
from pystac.extensions.hooks import ExtensionHooks
16-
from pystac.utils import StringEnum, get_opt, get_required, map_opt, str_to_datetime
15+
from pystac.utils import StringEnum, get_opt, get_required, map_opt
1716

1817
from pystac_monty.hazard_profiles import HazardProfiles
1918
from pystac_monty.paring import Pairing
2019

2120
__version__ = "0.1.0"
2221

23-
T = TypeVar(
24-
"T", pystac.Collection, pystac.Item, pystac.Asset, item_assets.AssetDefinition
25-
)
22+
T = TypeVar("T", pystac.Collection, pystac.Item, pystac.Asset, item_assets.AssetDefinition)
2623

2724
SCHEMA_URI = "https://ifrcgo.github.io/monty/v0.1.0/schema.json"
2825

@@ -158,8 +155,8 @@ def __init__(self) -> None:
158155
MontyImpactExposureCategory.AID_CONTRIBUTIONS_NON_INFLATION_ADJUSTED: "Aid Contributions Non-Inflation-Adjusted",
159156
MontyImpactExposureCategory.AID_CONTRIBUTIONS_UNSPECIFIED: "Aid Contributions (Unspecified-Inflation-Adjustment)",
160157
MontyImpactExposureCategory.RECONSTRUCTION_COSTS_INFLATION_ADJUSTED: "Reconstruction Costs Inflation-Adjusted",
161-
MontyImpactExposureCategory.RECONSTRUCTION_COSTS_NON_INFLATION_ADJUSTED: "Reconstruction Costs Non-Inflation-Adjusted",
162-
MontyImpactExposureCategory.RECONSTRUCTION_COSTS_UNSPECIFIED: "Reconstruction Costs (Unspecified-Inflation-Adjustment)",
158+
MontyImpactExposureCategory.RECONSTRUCTION_COSTS_NON_INFLATION_ADJUSTED: "Reconstruction Costs Non-Inflation-Adjusted", # noqa: E501
159+
MontyImpactExposureCategory.RECONSTRUCTION_COSTS_UNSPECIFIED: "Reconstruction Costs (Unspecified-Inflation-Adjustment)", # noqa: E501
163160
MontyImpactExposureCategory.INSURED_COSTS_INFLATION_ADJUSTED: "Insured Costs Inflation-Adjusted",
164161
MontyImpactExposureCategory.INSURED_COSTS_NON_INFLATION_ADJUSTED: "Insured Costs Non-Inflation-Adjusted",
165162
MontyImpactExposureCategory.INSURED_COSTS_UNSPECIFIED: "Insured Costs (Unspecified-Inflation-Adjustment)",
@@ -173,11 +170,11 @@ def __init__(self) -> None:
173170
MontyImpactExposureCategory.TOTAL_DIRECT_COSTS_NON_INFLATION_ADJUSTED: "Total Direct Costs Non-Inflation-Adjusted",
174171
MontyImpactExposureCategory.TOTAL_DIRECT_COSTS_UNSPECIFIED: "Total Direct Costs (Unspecified-Inflation-Adjustment)",
175172
MontyImpactExposureCategory.TOTAL_INDIRECT_COSTS_INFLATION_ADJUSTED: "Total Indirect Costs Inflation-Adjusted",
176-
MontyImpactExposureCategory.TOTAL_INDIRECT_COSTS_NON_INFLATION_ADJUSTED: "Total Indirect Costs Non-Inflation-Adjusted",
177-
MontyImpactExposureCategory.TOTAL_INDIRECT_COSTS_UNSPECIFIED: "Total Indirect Costs (Unspecified-Inflation-Adjustment)",
173+
MontyImpactExposureCategory.TOTAL_INDIRECT_COSTS_NON_INFLATION_ADJUSTED: "Total Indirect Costs Non-Inflation-Adjusted", # noqa: E501
174+
MontyImpactExposureCategory.TOTAL_INDIRECT_COSTS_UNSPECIFIED: "Total Indirect Costs (Unspecified-Inflation-Adjustment)", # noqa: E501
178175
MontyImpactExposureCategory.CATTLE: "Cattle",
179176
MontyImpactExposureCategory.ALERTSCORE: "Alertscore",
180-
MontyImpactExposureCategory.IFRC_AID_CONTRIBUTIONS_UNSPECIFIED: "IFRC Aid Contributions (Unspecified-Inflation-Adjustment)",
177+
MontyImpactExposureCategory.IFRC_AID_CONTRIBUTIONS_UNSPECIFIED: "IFRC Aid Contributions (Unspecified-Inflation-Adjustment)", # noqa: E501
181178
}
182179

183180
def __getitem__(self, key: MontyImpactExposureCategory) -> str:
@@ -245,7 +242,7 @@ def __init__(self) -> None:
245242
MontyImpactType.LOSS_COST: "Loss (Cost)",
246243
MontyImpactType.HOMELESS: "Homeless",
247244
MontyImpactType.INTERNALLY_DISPLACED_PERSONS: "Internally Displaced Persons (IDPs)",
248-
MontyImpactType.REFUGEES_ASYLUM_SEEKERS_EXTERNALLY_DISPLACED_PERSONS: "Refugees, Asylum Seekers and Externally Displaced Persons",
245+
MontyImpactType.REFUGEES_ASYLUM_SEEKERS_EXTERNALLY_DISPLACED_PERSONS: "Refugees, Asylum Seekers and Externally Displaced Persons", # noqa: E501
249246
MontyImpactType.DISPLACED_PERSONS: "Displaced Persons (Internal & External)",
250247
MontyImpactType.ALERTSCORE: "Alertscore",
251248
}
@@ -340,9 +337,7 @@ def to_dict(self) -> dict[str, Any]:
340337

341338
@staticmethod
342339
def from_dict(d: dict[str, Any]) -> HazardDetail:
343-
cluster: str = get_required(
344-
d.get(HAZDET_CLUSTER_PROP), "hazard_detail", HAZDET_CLUSTER_PROP
345-
)
340+
cluster: str = get_required(d.get(HAZDET_CLUSTER_PROP), "hazard_detail", HAZDET_CLUSTER_PROP)
346341

347342
return HazardDetail(cluster)
348343

@@ -405,7 +400,7 @@ def value(self) -> float:
405400
ITEM_IMPACT_DETAIL_PROP,
406401
IMPDET_VALUE_PROP,
407402
)
408-
403+
409404
@value.setter
410405
def value(self, v: float) -> None:
411406
self.properties[IMPDET_VALUE_PROP] = v
@@ -433,18 +428,13 @@ def to_dict(self) -> dict[str, Any]:
433428

434429
@staticmethod
435430
def from_dict(d: dict[str, Any]) -> ImpactDetail:
436-
category: str = get_required(
437-
d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP
438-
)
439-
type: str = get_required(
440-
d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP
441-
)
442-
value: float = get_required(
443-
d.get(IMPDET_VALUE_PROP), "impact_detail", IMPDET_VALUE_PROP
444-
)
431+
category: str = get_required(d.get(IMPDET_CATEGORY_PROP), "impact_detail", IMPDET_CATEGORY_PROP)
432+
type: str = get_required(d.get(IMPDET_TYPE_PROP), "impact_detail", IMPDET_TYPE_PROP)
433+
value: float = get_required(d.get(IMPDET_VALUE_PROP), "impact_detail", IMPDET_VALUE_PROP)
445434

446435
return ImpactDetail(category, type, value)
447436

437+
448438
class MontyExtension(
449439
Generic[T],
450440
PropertiesExtension,
@@ -492,9 +482,7 @@ def apply(
492482
@property
493483
def correlation_id(self) -> str:
494484
"""A unique correlation identifier for the event of the data."""
495-
result = get_required(
496-
self._get_property(ITEM_CORR_ID_PROP, str), self, ITEM_CORR_ID_PROP
497-
)
485+
result = get_required(self._get_property(ITEM_CORR_ID_PROP, str), self, ITEM_CORR_ID_PROP)
498486
return result
499487

500488
@correlation_id.setter
@@ -529,23 +517,19 @@ def hazard_codes(self, v: list[str] | None) -> None:
529517
@property
530518
def hazard_detail(self) -> HazardDetail | None:
531519
"""The details of the hazard."""
532-
result = map_opt(
533-
self._get_property(ITEM_HAZARD_DETAIL_PROP, dict), HazardDetail
534-
)
520+
result = map_opt(self._get_property(ITEM_HAZARD_DETAIL_PROP, dict), HazardDetail)
535521
return result
536522

537523
@hazard_detail.setter
538524
def hazard_detail(self, v: HazardDetail | None) -> None:
539525
self._set_property(ITEM_HAZARD_DETAIL_PROP, map_opt(lambda x: x.to_dict(), v))
540-
526+
541527
@property
542528
def impact_detail(self) -> ImpactDetail | None:
543529
"""The details of the impact."""
544-
result = map_opt(
545-
self._get_property(ITEM_IMPACT_DETAIL_PROP, dict), ImpactDetail
546-
)
530+
result = map_opt(self._get_property(ITEM_IMPACT_DETAIL_PROP, dict), ImpactDetail)
547531
return result
548-
532+
549533
@impact_detail.setter
550534
def impact_detail(self, v: ImpactDetail | None) -> None:
551535
self._set_property(ITEM_IMPACT_DETAIL_PROP, map_opt(lambda x: x.to_dict(), v))
@@ -560,9 +544,7 @@ def episode_number(self, v: int) -> None:
560544
self.properties[ITEM_EPISODE_NUMBER_PROP] = v
561545

562546
def compute_and_set_correlation_id(self, hazard_profiles: HazardProfiles) -> None:
563-
correlation_id = self.pairing.generate_correlation_id(
564-
self.item, hazard_profiles
565-
)
547+
correlation_id = self.pairing.generate_correlation_id(self.item, hazard_profiles)
566548
self.correlation_id = correlation_id
567549

568550
@classmethod
@@ -595,9 +577,7 @@ def ext(cls, obj: T, add_if_missing: bool = False) -> MontyExtension[T]:
595577

596578
@staticmethod
597579
def enable_extension() -> None:
598-
pystac.extensions.ext.ItemExt.monty = property(
599-
lambda self: MontyExtension.ext(self)
600-
)
580+
pystac.extensions.ext.ItemExt.monty = property(lambda self: MontyExtension.ext(self))
601581

602582

603583
class CollectionMontyExtension(MontyExtension[pystac.Collection]):
@@ -638,24 +618,15 @@ def __init__(self, item: pystac.Item):
638618

639619
def is_source_event(self) -> bool:
640620
"""Indicates if the item is a source event."""
641-
return (
642-
MontyRoles.SOURCE in self.item.properties["roles"]
643-
and MontyRoles.EVENT in self.item.properties["roles"]
644-
)
621+
return MontyRoles.SOURCE in self.item.properties["roles"] and MontyRoles.EVENT in self.item.properties["roles"]
645622

646623
def is_source_hazard(self) -> bool:
647624
"""Indicates if the item is a source hazard."""
648-
return (
649-
MontyRoles.SOURCE in self.item.properties["roles"]
650-
and MontyRoles.HAZARD in self.item.properties["roles"]
651-
)
652-
625+
return MontyRoles.SOURCE in self.item.properties["roles"] and MontyRoles.HAZARD in self.item.properties["roles"]
626+
653627
def is_source_impact(self) -> bool:
654628
"""Indicates if the item is a source impact."""
655-
return (
656-
MontyRoles.SOURCE in self.item.properties["roles"]
657-
and MontyRoles.IMPACT in self.item.properties["roles"]
658-
)
629+
return MontyRoles.SOURCE in self.item.properties["roles"] and MontyRoles.IMPACT in self.item.properties["roles"]
659630

660631
def __repr__(self) -> str:
661632
return f"<ItemMontyExtension Item id={self.item.id}>"

pystac_monty/hazard_profiles.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class HazardProfiles:
77
impact_information_profile_path = "ImpactInformationProfiles.csv"
88
impact_information_profile_data = None
9-
9+
1010
# free impact_information_profile_data when the object is destroyed
1111
def __del__(self):
1212
if self.impact_information_profile_data:
@@ -16,7 +16,7 @@ def __del__(self):
1616

1717
def get_profiles(self) -> df.DataFrame:
1818
if self.impact_information_profile_data is None:
19-
with importlib.resources.open_binary('pystac_monty', self.impact_information_profile_path) as f:
19+
with importlib.resources.open_binary("pystac_monty", self.impact_information_profile_path) as f:
2020
self.impact_information_profile_data = df.read_csv(f)
2121
return self.impact_information_profile_data
2222

@@ -28,7 +28,7 @@ def get_cluster_code(self, hazard_code: str | list[str]) -> str:
2828
for c in codes:
2929
cluster_code = None
3030
try:
31-
cluster_code = profiles.loc[profiles['name'] == c, "link_group"].values[-1]
31+
cluster_code = profiles.loc[profiles["name"] == c, "link_group"].values[-1]
3232
except IndexError:
3333
if not cluster_code and c.__len__() == 2:
3434
cluster_code = c
@@ -38,5 +38,3 @@ def get_cluster_code(self, hazard_code: str | list[str]) -> str:
3838
raise ValueError("No cluster code found for hazard code")
3939
# return the majority item cluster code in the list
4040
return max(set(cluster_codes), key=cluster_codes.count)
41-
42-

pystac_monty/paring.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
class Pairing:
7-
87
def generate_correlation_id(self, item: Item, hazard_profiles: HazardProfiles) -> str:
98
# Get the necessary properties for creating the correlation id
109
hazards = item.properties.get("monty:hazard_codes", [])

pystac_monty/sources/common.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1-
21
from dataclasses import dataclass
32
from typing import Any
43

54

65
@dataclass
76
class MontyDataSource:
8-
9-
source_url : str
10-
data : Any
11-
7+
source_url: str
8+
data: Any
9+
1210
def __init__(self, source_url: str, data: Any):
1311
self.source_url = source_url
1412

1513
def get_source_url(self) -> str:
1614
return self.source_url
17-
15+
1816
def get_data(self) -> Any:
19-
return self.data
17+
return self.data

0 commit comments

Comments
 (0)