Skip to content

Commit

Permalink
🔀 Merge pull request #99 from davep/rework-tagdata
Browse files Browse the repository at this point in the history
Rework the tag counts
  • Loading branch information
davep authored Jan 13, 2025
2 parents 2130d00 + c982802 commit 1470fb0
Show file tree
Hide file tree
Showing 9 changed files with 61 additions and 93 deletions.
3 changes: 2 additions & 1 deletion src/braindrop/app/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
)
from .exit_state import ExitState
from .local import LocalData, local_data_file
from .raindrops import Raindrops
from .raindrops import Raindrops, TagCount
from .token import token_file

##############################################################################
Expand All @@ -22,6 +22,7 @@
"local_data_file",
"LocalData",
"Raindrops",
"TagCount",
"save_configuration",
"token_file",
"update_configuration",
Expand Down
45 changes: 41 additions & 4 deletions src/braindrop/app/data/raindrops.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

##############################################################################
# Python imports.
from typing import Counter, Iterable, Iterator
from dataclasses import dataclass
from typing import Callable, Counter, Iterable, Iterator

##############################################################################
# Typing extension imports.
Expand All @@ -19,10 +20,46 @@
Raindrop,
SpecialCollection,
Tag,
TagData,
)


##############################################################################
@dataclass(frozen=True)
class TagCount:
"""Holds count details of a tag."""

tag: Tag
"""The name of the tag."""
count: int
"""The number of Raindrops using this tag."""

@staticmethod
def the_tag() -> Callable[[TagCount], Tag]:
"""Returns a function for getting the tag from a `TagCount` instance.
Returns:
A function to get the tag of a `TagCount` instance.
"""

def _getter(data: TagCount) -> Tag:
return data.tag

return _getter

@staticmethod
def the_count() -> Callable[[TagCount], int]:
"""Returns a function for getting the count from a `TagCount` instance.
Returns:
A function to get the count of a `TagCount` instance.
"""

def _getter(data: TagCount) -> int:
return data.count

return _getter


##############################################################################
class Filter:
"""Base class for the raindrop filters."""
Expand Down Expand Up @@ -213,12 +250,12 @@ def description(self) -> str:
return f"{'; '.join((self._title, *filters))} ({len(self)})"

@property
def tags(self) -> list[TagData]:
def tags(self) -> list[TagCount]:
"""The list of unique tags found amongst the Raindrops."""
tags: list[Tag] = []
for raindrop in self:
tags.extend(set(raindrop.tags))
return [TagData(name, count) for name, count in Counter(tags).items()]
return [TagCount(name, count) for name, count in Counter(tags).items()]

def __and__(self, new_filter: Filter) -> Raindrops:
"""Get the raindrops that match a given filter.
Expand Down
5 changes: 2 additions & 3 deletions src/braindrop/app/providers/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

##############################################################################
# Local imports.
from ...raindrop import TagData
from ..data import Raindrops
from ..data import Raindrops, TagCount
from ..messages import ShowTagged
from .commands_provider import CommandHit, CommandHits, CommandsProvider

Expand Down Expand Up @@ -35,7 +34,7 @@ def commands(self) -> CommandHits:
command_prefix = (
"Also tagged" if self.active_collection.is_filtered else "Tagged"
)
for tag in sorted(self.active_collection.tags, key=TagData.the_tag()):
for tag in sorted(self.active_collection.tags, key=TagCount.the_tag()):
yield CommandHit(
f"{command_prefix} {tag.tag}",
f"{help_prefix} to Raindrops tagged with {tag.tag} (narrows down to {tag.count})",
Expand Down
7 changes: 4 additions & 3 deletions src/braindrop/app/suggestions/tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@

##############################################################################
# Local imports.
from ...raindrop import Raindrop, Tag, TagData
from ...raindrop import Raindrop, Tag
from ..data import TagCount


##############################################################################
class SuggestTags(Suggester):
"""A Textual `Input` suggester that suggests tags."""

def __init__(self, tags: Iterable[Tag | TagData], use_cache: bool = True) -> None:
def __init__(self, tags: Iterable[Tag | TagCount], use_cache: bool = True) -> None:
"""Initialise the suggester.
Args:
Expand All @@ -29,7 +30,7 @@ def __init__(self, tags: Iterable[Tag | TagData], use_cache: bool = True) -> Non
# being case-sensitive; so here we say we *are* going to be case
# sensitive and then in get_suggestion we'll handle it ourselves.
super().__init__(use_cache=use_cache, case_sensitive=True)
self._tags = [tag.tag if isinstance(tag, TagData) else tag for tag in tags]
self._tags = [tag.tag if isinstance(tag, TagCount) else tag for tag in tags]
"""The tags to take suggestions from."""

_SUGGESTABLE: Final[Pattern[str]] = re.compile(r".*[^,\s]$")
Expand Down
16 changes: 8 additions & 8 deletions src/braindrop/app/widgets/navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

##############################################################################
# Local imports.
from ...raindrop import API, Collection, SpecialCollection, Tag, TagData
from ...raindrop import API, Collection, SpecialCollection, Tag
from ..commands import ShowAll, ShowUnsorted, ShowUntagged
from ..data import LocalData, Raindrops
from ..data import LocalData, Raindrops, TagCount
from ..messages import ShowCollection, ShowTagged
from .extended_option_list import OptionListEx

Expand Down Expand Up @@ -102,7 +102,7 @@ def prompt(self) -> RenderableType:
class TagView(Option):
"""Option for showing a tag."""

def __init__(self, tag: TagData) -> None:
def __init__(self, tag: TagCount) -> None:
"""Initialise the object.
Args:
Expand All @@ -126,7 +126,7 @@ def prompt(self) -> RenderableType:
return prompt

@property
def tag_data(self) -> TagData:
def tag_data(self) -> TagCount:
"""The tag data."""
return self._tag

Expand Down Expand Up @@ -306,7 +306,7 @@ def _main_navigation(self) -> None:
)

@staticmethod
def _by_name(tags: list[TagData]) -> list[TagData]:
def _by_name(tags: list[TagCount]) -> list[TagCount]:
"""Return a given list of tags sorted by tag name.
Args:
Expand All @@ -315,10 +315,10 @@ def _by_name(tags: list[TagData]) -> list[TagData]:
Returns:
The sorted list of tags.
"""
return sorted(tags, key=TagData.the_tag())
return sorted(tags, key=TagCount.the_tag())

@staticmethod
def _by_count(tags: list[TagData]) -> list[TagData]:
def _by_count(tags: list[TagCount]) -> list[TagCount]:
"""Return a given list of tags sorted by count.
Args:
Expand All @@ -327,7 +327,7 @@ def _by_count(tags: list[TagData]) -> list[TagData]:
Returns:
The sorted list of tags.
"""
return sorted(tags, key=TagData.the_count(), reverse=True)
return sorted(tags, key=TagCount.the_count(), reverse=True)

def _show_tags_for(self, collection: Raindrops) -> None:
"""Show tags relating a given collection.
Expand Down
3 changes: 1 addition & 2 deletions src/braindrop/raindrop/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .collection import Collection, SpecialCollection
from .raindrop import Raindrop, RaindropType
from .suggestions import Suggestions
from .tag import Tag, TagData
from .tag import Tag
from .time_tools import get_time
from .user import Group, User

Expand All @@ -22,7 +22,6 @@
"SpecialCollection",
"Suggestions",
"Tag",
"TagData",
"User",
]

Expand Down
15 changes: 0 additions & 15 deletions src/braindrop/raindrop/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
from .collection import Collection, SpecialCollection
from .raindrop import Raindrop
from .suggestions import Suggestions
from .tag import TagData
from .user import User


Expand Down Expand Up @@ -346,20 +345,6 @@ def gndn(_: int) -> None:
count_update(len(raindrops))
return raindrops

async def tags(self, collection: int | None = None) -> list[TagData]:
"""Get a list of tags.
Args:
collection: The optional collection to get the tags for.
Returns:
A list of tags.
"""
_, tags = await self._items_of(
self._get, "/tags" if collection is None else f"/tags/{collection}"
)
return [TagData.from_json(tag) for tag in tags or []]

async def add_raindrop(self, raindrop: Raindrop) -> Raindrop | None:
"""Add a raindrop.
Expand Down
54 changes: 0 additions & 54 deletions src/braindrop/raindrop/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@

##############################################################################
# Python imports.
from dataclasses import dataclass
from functools import total_ordering
from typing import Any, Callable


##############################################################################
Expand Down Expand Up @@ -90,56 +88,4 @@ def __len__(self) -> int:
return len(self._tag)


##############################################################################
@dataclass(frozen=True)
class TagData:
"""Holds details of a tag."""

tag: Tag
"""The name of the tag."""
count: int
"""The number of Raindrops using this tag."""

@staticmethod
def from_json(data: dict[str, Any]) -> TagData:
"""Create a tag from JSON-sourced data.
Args:
data: The data to create the object from.
Returns:
A fresh `TagData` instance.
"""
return TagData(
tag=Tag(data["_id"]),
count=data.get("count", 0),
)

@staticmethod
def the_tag() -> Callable[[TagData], Tag]:
"""Returns a function for getting the tag from a `TagData` instance.
Returns:
A function to get the tag of a `TagData` instance.
"""

def _getter(data: TagData) -> Tag:
return data.tag

return _getter

@staticmethod
def the_count() -> Callable[[TagData], int]:
"""Returns a function for getting the count from a `TagData` instance.
Returns:
A function to get the count of a `TagData` instance.
"""

def _getter(data: TagData) -> int:
return data.count

return _getter


### tag.py ends here
6 changes: 3 additions & 3 deletions tests/unit/test_raindrops.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

##############################################################################
# Local imports.
from braindrop.app.data import Raindrops
from braindrop.raindrop import Raindrop, Tag, TagData
from braindrop.app.data import Raindrops, TagCount
from braindrop.raindrop import Raindrop, Tag


##############################################################################
Expand Down Expand Up @@ -43,7 +43,7 @@ def test_found_tags() -> None:
repeat = 2
assert Raindrops(
raindrops=[Raindrop(tags=[Tag(tag)]) for tag in expecting * repeat]
).tags == list(TagData(Tag(tag), repeat) for tag in expecting)
).tags == list(TagCount(Tag(tag), repeat) for tag in expecting)


##############################################################################
Expand Down

0 comments on commit 1470fb0

Please sign in to comment.