my.goodreads: cleanup, rename from my.reading.goodrads & use proper pip dependency
related:
- https://github.com/karlicoss/HPI/issues/79
- 10d8cc86a1
This commit is contained in:
parent
1cdef6f40a
commit
29384aef44
5 changed files with 123 additions and 83 deletions
|
@ -45,6 +45,9 @@ class bluemaestro:
|
||||||
class stackexchange:
|
class stackexchange:
|
||||||
export_path: Paths = ''
|
export_path: Paths = ''
|
||||||
|
|
||||||
|
class goodreads:
|
||||||
|
export_path: Paths = ''
|
||||||
|
|
||||||
class pinboard:
|
class pinboard:
|
||||||
export_dir: Paths = ''
|
export_dir: Paths = ''
|
||||||
|
|
||||||
|
|
102
my/goodreads.py
Normal file
102
my/goodreads.py
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
"""
|
||||||
|
[[https://www.goodreads.com][Goodreads]] statistics
|
||||||
|
"""
|
||||||
|
REQUIRES = [
|
||||||
|
'git+https://github.com/karlicoss/goodrexport',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from my.core import Paths
|
||||||
|
from my.config import goodreads as user_config
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class goodreads(user_config):
|
||||||
|
# paths[s]/glob to the exported JSON data
|
||||||
|
export_path: Paths
|
||||||
|
|
||||||
|
from my.core.cfg import make_config, Attrs
|
||||||
|
|
||||||
|
def _migration(attrs: Attrs) -> Attrs:
|
||||||
|
export_dir = 'export_dir'
|
||||||
|
if export_dir in attrs: # legacy name
|
||||||
|
attrs['export_path'] = attrs[export_dir]
|
||||||
|
from my.core.warnings import high
|
||||||
|
high(f'"{export_dir}" is deprecated! Please use "export_path" instead."')
|
||||||
|
return attrs
|
||||||
|
config = make_config(goodreads, migration=_migration)
|
||||||
|
|
||||||
|
#############################3
|
||||||
|
|
||||||
|
|
||||||
|
from my.core import get_files
|
||||||
|
from typing import Sequence, Iterator
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def inputs() -> Sequence[Path]:
|
||||||
|
return get_files(config.export_path)
|
||||||
|
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
|
||||||
|
from goodrexport import dal
|
||||||
|
|
||||||
|
|
||||||
|
def _dal() -> dal.DAL:
|
||||||
|
return dal.DAL(inputs())
|
||||||
|
|
||||||
|
|
||||||
|
def reviews() -> Iterator[dal.Review]:
|
||||||
|
return _dal().reviews()
|
||||||
|
|
||||||
|
|
||||||
|
# todo should be in DAL?
|
||||||
|
def books() -> Iterator[dal.Book]:
|
||||||
|
for r in reviews():
|
||||||
|
yield r.book
|
||||||
|
|
||||||
|
|
||||||
|
#######
|
||||||
|
# todo ok, not sure these really belong here...
|
||||||
|
|
||||||
|
from my.core.common import datetime_aware
|
||||||
|
@dataclass
|
||||||
|
class Event:
|
||||||
|
dt: datetime_aware
|
||||||
|
summary: str
|
||||||
|
eid: str
|
||||||
|
|
||||||
|
|
||||||
|
def events() -> Iterator[Event]:
|
||||||
|
for b in books():
|
||||||
|
yield Event(
|
||||||
|
dt=b.date_added,
|
||||||
|
summary=f'Added book "{b.title}"', # todo shelf?
|
||||||
|
eid=b.id
|
||||||
|
)
|
||||||
|
# todo finished? other updates?
|
||||||
|
|
||||||
|
|
||||||
|
def print_read_history() -> None:
|
||||||
|
def ddate(x):
|
||||||
|
if x is None:
|
||||||
|
return datetime.fromtimestamp(0, pytz.utc)
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
|
||||||
|
def key(b):
|
||||||
|
return ddate(b.date_started)
|
||||||
|
|
||||||
|
def fmtdt(dt):
|
||||||
|
if dt is None:
|
||||||
|
return dt
|
||||||
|
tz = pytz.timezone('Europe/London')
|
||||||
|
return dt.astimezone(tz)
|
||||||
|
for b in sorted(books(), key=key):
|
||||||
|
print(f"""
|
||||||
|
{b.title} by {', '.join(b.authors)}
|
||||||
|
started : {fmtdt(b.date_started)}
|
||||||
|
finished: {fmtdt(b.date_read)}
|
||||||
|
""")
|
86
my/reading/goodreads.py
Executable file → Normal file
86
my/reading/goodreads.py
Executable file → Normal file
|
@ -1,85 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
from my.core import warnings
|
||||||
from functools import lru_cache
|
|
||||||
from typing import NamedTuple
|
|
||||||
from datetime import datetime
|
|
||||||
import pytz
|
|
||||||
|
|
||||||
from my.config.repos.goodrexport import dal as goodrexport
|
warnings.medium('my.reading.goodreads is deprecated! Use my.goodreads instead!')
|
||||||
from my.config import goodreads as config
|
|
||||||
|
|
||||||
|
from ..goodreads import *
|
||||||
def get_model():
|
|
||||||
sources = list(sorted(config.export_dir.glob('*.xml')))
|
|
||||||
model = goodrexport.DAL(sources)
|
|
||||||
return model
|
|
||||||
|
|
||||||
|
|
||||||
def get_books():
|
|
||||||
model = get_model()
|
|
||||||
return [r.book for r in model.reviews()]
|
|
||||||
|
|
||||||
|
|
||||||
def test_books():
|
|
||||||
books = get_books()
|
|
||||||
assert len(books) > 10
|
|
||||||
|
|
||||||
|
|
||||||
class Event(NamedTuple):
|
|
||||||
dt: datetime
|
|
||||||
summary: str
|
|
||||||
eid: str
|
|
||||||
|
|
||||||
|
|
||||||
def get_events():
|
|
||||||
events = []
|
|
||||||
for b in get_books():
|
|
||||||
events.append(Event(
|
|
||||||
dt=b.date_added,
|
|
||||||
summary=f'Added book "{b.title}"', # TODO shelf?
|
|
||||||
eid=b.id
|
|
||||||
))
|
|
||||||
# TODO finished? other updates?
|
|
||||||
return sorted(events, key=lambda e: e.dt)
|
|
||||||
|
|
||||||
|
|
||||||
def print_read_history():
|
|
||||||
def ddate(x):
|
|
||||||
if x is None:
|
|
||||||
return datetime.fromtimestamp(0, pytz.utc)
|
|
||||||
else:
|
|
||||||
return x
|
|
||||||
|
|
||||||
def key(b):
|
|
||||||
return ddate(b.date_started)
|
|
||||||
|
|
||||||
def fmtdt(dt):
|
|
||||||
if dt is None:
|
|
||||||
return dt
|
|
||||||
tz = pytz.timezone('Europe/London')
|
|
||||||
return dt.astimezone(tz)
|
|
||||||
for b in sorted(get_books(), key=key):
|
|
||||||
print(f"""
|
|
||||||
{b.title} by {', '.join(b.authors)}
|
|
||||||
started : {fmtdt(b.date_started)}
|
|
||||||
finished: {fmtdt(b.date_read)}
|
|
||||||
""")
|
|
||||||
|
|
||||||
def test():
|
|
||||||
assert len(get_events()) > 20
|
|
||||||
|
|
||||||
|
|
||||||
# def main():
|
|
||||||
# import argparse
|
|
||||||
# p = argparse.ArgumentParser()
|
|
||||||
# sp = p.add_argument('mode', nargs='?')
|
|
||||||
# args = p.parse_args()
|
|
||||||
|
|
||||||
# if args.mode == 'history':
|
|
||||||
# print_read_history()
|
|
||||||
# else:
|
|
||||||
# assert args.mode is None
|
|
||||||
# for b in iter_books():
|
|
||||||
# print(b)
|
|
||||||
|
|
||||||
# if __name__ == '__main__':
|
|
||||||
# main()
|
|
||||||
|
|
13
tests/goodreads.py
Normal file
13
tests/goodreads.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from .common import skip_if_not_karlicoss as pytestmark
|
||||||
|
|
||||||
|
from more_itertools import ilen
|
||||||
|
|
||||||
|
|
||||||
|
def test_events() -> None:
|
||||||
|
from my.goodreads import events
|
||||||
|
assert ilen(events()) > 20
|
||||||
|
|
||||||
|
|
||||||
|
def test_books() -> None:
|
||||||
|
from my.goodreads import books
|
||||||
|
assert ilen(books()) > 10
|
2
tox.ini
2
tox.ini
|
@ -81,6 +81,7 @@ commands =
|
||||||
hpi module install my.pinboard
|
hpi module install my.pinboard
|
||||||
hpi module install my.arbtt
|
hpi module install my.arbtt
|
||||||
hpi module install my.coding.commits
|
hpi module install my.coding.commits
|
||||||
|
hpi module install my.goodreads
|
||||||
|
|
||||||
# todo fuck. -p my.github isn't checking the subpackages?? wtf...
|
# todo fuck. -p my.github isn't checking the subpackages?? wtf...
|
||||||
# guess it wants .pyi file??
|
# guess it wants .pyi file??
|
||||||
|
@ -101,6 +102,7 @@ commands =
|
||||||
-p my.calendar.holidays \
|
-p my.calendar.holidays \
|
||||||
-p my.arbtt \
|
-p my.arbtt \
|
||||||
-p my.coding.commits \
|
-p my.coding.commits \
|
||||||
|
-p my.goodreads \
|
||||||
--txt-report .coverage.mypy-misc \
|
--txt-report .coverage.mypy-misc \
|
||||||
--html-report .coverage.mypy-misc \
|
--html-report .coverage.mypy-misc \
|
||||||
{posargs}
|
{posargs}
|
||||||
|
|
Loading…
Add table
Reference in a new issue