Skip to content

Commit

Permalink
feat: add archive label and active status to ReviewModel
Browse files Browse the repository at this point in the history
  • Loading branch information
lwasser authored Jan 14, 2025
2 parents 383e10f + 8623834 commit 0e665f0
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 5 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

## [Unreleased]

* Fix: Parse archive and JOSS links to handle markdown links and validate DOI links are valid. Added python-doi as a dependency to ensure archive/DOI URLs fully resolve (@banesullivan)
* Add: new `active` status under `ReviewModel` which is set to `False` if the `"archived"` label is present on a review to mark the package as inactive (@banesullivan)

[v1.4] - 2024-11-22

## [v1.4] - 2024-11-22
* Fix: Parse archive and JOSS links to handle markdown links and validate DOI links are valid. Added python-doi as a dependency to ensure archive/DOI URLs fully resolve (@banesullivan)

Notes: it looks like i may have mistakenly bumped to 1.3.7 in august. rather than try to fix on pypi we will just go with it to ensure our release cycles are smooth given no one else uses this package except pyopensci.

Expand Down
1 change: 1 addition & 0 deletions src/pyosmeta/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ class ReviewModel(BaseModel):
partners: Optional[list[Partnerships]] = None
gh_meta: Optional[GhMeta] = None
labels: list[str] = Field(default_factory=list)
active: bool = True # To indicate if package is maintained or archived

@field_validator(
"date_accepted",
Expand Down
36 changes: 34 additions & 2 deletions src/pyosmeta/models/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
from __future__ import annotations

from datetime import datetime
from enum import Enum
from typing import Any, List, Literal, Optional, Union

from pydantic import AnyUrl, BaseModel, ConfigDict, Field
from pydantic import AnyUrl, BaseModel, ConfigDict, Field, model_validator


class User(BaseModel):
Expand Down Expand Up @@ -61,14 +62,45 @@ class ClosedBy(User): ...
class Owner(User): ...


class LabelType(str, Enum):
"""Enum for the different types of labels that can be assigned to an issue.
This enum is not meant to be exhaustive, but rather capture a few important
labels for life cycle of approved reviews.
For now, this only includes the "archived" label, which is used to mark
packages that are no longer maintained ("inactive"). The "archived" label
corresponds to setting ``active=False`` on the ReviewModel
"""

ARCHIVED = "archived"


class Labels(BaseModel):
name: str
id: Optional[int] = None
node_id: Optional[str] = None
url: Optional[AnyUrl] = None
name: Optional[str] = None
description: Optional[str] = None
color: Optional[str] = None
default: Optional[bool] = None
type: Optional[LabelType] = None

@model_validator(mode="before")
def parse_label_type(cls, data):
"""Parse the label type from the name before validation.
This will parse the label name into an available LabelType enum value.
Not all labels will have a corresponding LabelType, so this will
gracefully fail. This was implemented for assigning the LabelType.ARCHIVED
value to the "archived" label so that we can easily filter out archived
issues.
"""
try:
data["type"] = LabelType(data["name"])
except ValueError:
pass
return data


class Issue(BaseModel):
Expand Down
28 changes: 27 additions & 1 deletion src/pyosmeta/parse_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from pydantic import ValidationError

from pyosmeta.models import ReviewModel, ReviewUser
from pyosmeta.models.github import Issue
from pyosmeta.models.github import Issue, Labels, LabelType

from .github_api import GitHubAPI
from .utils_clean import clean_date_accepted_key
Expand Down Expand Up @@ -224,6 +224,31 @@ def _postprocess_meta(self, meta: dict, body: List[str]) -> dict:

return meta

def _postprocess_labels(self, meta: dict) -> dict:
"""
Process specific labels for attributes in the review model.
Presently, this method only checks if the review has the "archived"
(LabelType.ARCHIVED) label and sets the active attribute to False
if it does. We may add more label processing in the future.
The intention behind this is to assign specific ReviewModel attributes
based on the presence of certain labels in the review issue.
"""

def _is_archived(label: str | Labels) -> bool:
"""Internal helper to check if a label is the "archived" label"""
if isinstance(label, Labels):
return label.type == LabelType.ARCHIVED
return "archived" in label.lower()

# Check if the review has the "archived" label
if "labels" in meta and [
label for label in meta["labels"] if _is_archived(label)
]:
meta["active"] = False
return meta

def _parse_field(self, key: str, val: str) -> Any:
"""
Method dispatcher for parsing specific header fields.
Expand Down Expand Up @@ -280,6 +305,7 @@ def parse_issue(self, issue: Issue | str) -> ReviewModel:

# Finalize review model before casting
model = self._postprocess_meta(model, body)
model = self._postprocess_labels(model)

return ReviewModel(**model)

Expand Down
25 changes: 25 additions & 0 deletions tests/integration/test_parse_issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,28 @@ def test_parse_labels(issue_list, process_issues):
issue.labels = labels
review = process_issues.parse_issue(issue)
assert review.labels == ["6/pyOS-approved", "another_label"]
assert review.active

# Now add an archive label
label_inst = Labels(
id=1196238794,
node_id="MDU6TGFiZWwxMTk2MjM4Nzk0",
url="https://api.github.com/repos/pyOpenSci/software-submission/labels/archived",
name="archived",
description="",
color="006B75",
default=False,
)
labels = [label_inst, "another_label"]
for issue in issue_list:
issue.labels = labels
review = process_issues.parse_issue(issue)
assert not review.active

# Handle label with missing details
label_inst = Labels(name="test")
labels = [label_inst, "another_label"]
for issue in issue_list:
issue.labels = labels
review = process_issues.parse_issue(issue)
assert review.labels == ["test", "another_label"]

0 comments on commit 0e665f0

Please sign in to comment.