Skip to content
This repository was archived by the owner on Jan 30, 2022. It is now read-only.

Commit 39afab9

Browse files
committed
Big big refactor
1 parent 227d81f commit 39afab9

19 files changed

+4486
-1607
lines changed

.vscode/PythonImportHelper-v2-Completion.json

+1,498
Large diffs are not rendered by default.

hyp2rem/__main__.py

+138-145
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,138 @@
1-
# Copyright 2020 The Hyp2Rem Authors
2-
3-
# Use of this source code is governed by an MIT-style
4-
# license that can be found in the LICENSE file or at
5-
# https://opensource.org/licenses/MIT.
6-
7-
8-
"""Command line interface to sync Hypothes.is and RemNote.
9-
10-
This module provides a command line utility that retrieves newly created or
11-
updated annotations in a Hypothes.is group, compares them to existing Rem's in
12-
a RemNote account, and uploads them.
13-
14-
Note:
15-
For this module to work, it is recommended that you store your credentials
16-
as environment variables. See the package documentation for more
17-
information.
18-
"""
19-
20-
21-
import json
22-
from datetime import datetime
23-
from enum import Enum
24-
from typing import Optional
25-
26-
import log # type: ignore
27-
from typer import Option, Typer, echo
28-
29-
import hyp2rem.utils
30-
from hyp2rem import hypothesis as hyp
31-
32-
app = Typer()
33-
34-
35-
class SortOption(str, Enum):
36-
"""Sorting options supported by Hypothes.is API."""
37-
38-
created: str = "created"
39-
updated: str = "updated"
40-
41-
42-
@app.command()
43-
def main( # type: ignore
44-
hyp_group: Optional[str] = Option(
45-
None,
46-
help="Name of the Hypothes.is group where annotations are stored",
47-
show_default=False,
48-
),
49-
sort: SortOption = Option(
50-
SortOption.created, help="Metric to sort results by"
51-
),
52-
after: Optional[datetime] = Option(
53-
None,
54-
help="Search for annotations created ou updated after the given date",
55-
),
56-
hyp_key: str = Option(
57-
...,
58-
envvar="HYP_KEY",
59-
prompt=True,
60-
help="API key for Hypothes.is account",
61-
show_default=False,
62-
),
63-
rem_user: str = Option(
64-
...,
65-
envvar="REM_USER",
66-
prompt=True,
67-
help="User ID for RemNote account",
68-
show_default=False,
69-
),
70-
rem_key: str = Option(
71-
...,
72-
envvar="REM_KEY",
73-
prompt=True,
74-
help="API key for RemNote account",
75-
show_default=False,
76-
),
77-
uri: Optional[str] = Option(
78-
None,
79-
help="A web page address (URL) or a URN representing another kind "
80-
+ "of resource such as DOI (Digital Object Identifier) or a PDF "
81-
+ "fingerprint.",
82-
show_default=False,
83-
),
84-
quiet: bool = Option(
85-
False,
86-
help="Silences the output printed to the terminal.",
87-
),
88-
verbose: bool = Option(
89-
False,
90-
help="Increases the output printed to the terminal.",
91-
),
92-
debug: bool = Option(
93-
False,
94-
help="Print every step to the terminal, for debugging purposes.",
95-
),
96-
):
97-
"""
98-
Sync Hypothes.is annotations with Rem's in a RemNote account.
99-
"""
100-
# pylint: disable=too-many-locals
101-
if quiet:
102-
verbosity: int = 0 # Only errors (ERROR)
103-
elif verbose:
104-
verbosity = 2 # Errors, warnings and information (INFO)
105-
elif debug:
106-
verbosity = 3 # All possible output (DEBUG)
107-
else:
108-
verbosity = 1 # Errors and warnings (WARN) - Default
109-
log.reset()
110-
log.init(verbosity=verbosity)
111-
# get group id, if a group name was provided
112-
group_id = None
113-
if hyp_group is not None:
114-
group = hyp.get_group_by_name(key=hyp_key, name=hyp_group)
115-
if group is not None:
116-
group_id = group["id"]
117-
else:
118-
log.error(
119-
"Group name was set, but not found in server. Cannot proceed."
120-
)
121-
raise ValueError
122-
# `after` option back to ISO string
123-
if isinstance(after, datetime):
124-
after = after.isoformat() # type: ignore
125-
# fetch relevant annotations
126-
annotations = hyp.get_annotations(
127-
key=hyp_key,
128-
group=group_id,
129-
sort=sort,
130-
order="asc",
131-
search_after=after,
132-
uri=uri,
133-
)
134-
if verbosity > 2:
135-
echo(json.dumps(annotations, indent=4))
136-
for annotation in annotations:
137-
document = hyp2rem.utils.document_for_source(
138-
rem_key, rem_user, annotation
139-
)
140-
if verbosity > 2:
141-
echo(document)
142-
143-
144-
if __name__ == "__main__":
145-
app(prog_name="hyp2rem")
1+
# Copyright 2020 The Hyp2Rem Authors
2+
3+
# Use of this source code is governed by an MIT-style
4+
# license that can be found in the LICENSE file or at
5+
# https://opensource.org/licenses/MIT.
6+
7+
8+
"""Command line interface to sync Hypothes.is and RemNote.
9+
10+
This module provides a command line utility that retrieves newly created or
11+
updated annotations in a Hypothes.is group, compares them to existing Rem's in
12+
a RemNote account, and uploads them.
13+
14+
Note:
15+
For this module to work, it is recommended that you store your credentials
16+
as environment variables. See the package documentation for more
17+
information.
18+
"""
19+
20+
21+
from datetime import datetime
22+
from enum import Enum
23+
from typing import Literal, Optional
24+
25+
import log # type: ignore
26+
from dotenv import load_dotenv
27+
from typer import Option, Typer, echo
28+
29+
from hyp2rem.hyp2rem import Bridge
30+
from hyp2rem.hypothesis.clients import HypothesisV1Client
31+
from hyp2rem.remnote.clients import RemNoteV0Client
32+
33+
app = Typer()
34+
35+
36+
class SortOption(str, Enum):
37+
"""Sorting options supported by Hypothes.is API."""
38+
39+
CREATED: Literal["created"] = "created"
40+
UPDATED: Literal["updated"] = "updated"
41+
42+
43+
@app.command()
44+
def main( # type: ignore
45+
group: Optional[str] = Option( # TODO: Accept multiple groups
46+
None,
47+
help="Name of the Hypothes.is group where annotations are stored",
48+
show_default=False,
49+
),
50+
sort: SortOption = Option(
51+
SortOption.UPDATED,
52+
help="Metric to sort results by",
53+
case_sensitive=False,
54+
),
55+
after: Optional[datetime] = Option(
56+
None,
57+
help="Search for annotations created ou updated after the given date",
58+
),
59+
uri: Optional[str] = Option(
60+
None,
61+
help="A web page address (URL) or a URN representing another kind "
62+
+ "of resource whose annotations should be synced.",
63+
show_default=False,
64+
),
65+
hyp_key: str = Option(
66+
...,
67+
envvar="HYP_KEY",
68+
prompt=True,
69+
help="API key for Hypothes.is account",
70+
show_default=False,
71+
),
72+
rem_user: str = Option(
73+
...,
74+
envvar="REM_USER",
75+
prompt=True,
76+
help="User ID for RemNote account",
77+
show_default=False,
78+
),
79+
rem_key: str = Option(
80+
...,
81+
envvar="REM_KEY",
82+
prompt=True,
83+
help="API key for RemNote account",
84+
show_default=False,
85+
),
86+
quiet: bool = Option(
87+
False,
88+
help="Silences the output printed to the terminal.",
89+
),
90+
verbose: bool = Option(
91+
False,
92+
help="Increases the output printed to the terminal.",
93+
),
94+
debug: bool = Option(
95+
False,
96+
help="Print every step to the terminal, for debugging purposes.",
97+
),
98+
):
99+
"""
100+
Sync Hypothes.is annotations with Rem's in a RemNote account.
101+
"""
102+
# pylint: disable=too-many-locals
103+
104+
# set verbosity levels and initialize logs
105+
verbosity: int = 1 # Errors and warnings (WARN) - Default
106+
if quiet:
107+
verbosity = 0 # Only errors (ERROR)
108+
elif verbose:
109+
verbosity = 2 # Errors, warnings and information (INFO)
110+
elif debug:
111+
verbosity = 3 # All possible output (DEBUG)
112+
log.reset()
113+
log.init(verbosity=verbosity)
114+
115+
# set up Hypothes.is and RemNote connections
116+
hyp_client: HypothesisV1Client = HypothesisV1Client(
117+
group_name=group,
118+
sort=sort,
119+
order="asc",
120+
search_after=after,
121+
uri=uri,
122+
key=hyp_key,
123+
)
124+
rem_client: RemNoteV0Client = RemNoteV0Client(
125+
key=rem_key,
126+
user_id=rem_user,
127+
)
128+
129+
# set up Bridge object between fetched annotations and RemNote
130+
bridge: Bridge = Bridge(hyp_client, rem_client)
131+
bridge.sync_all()
132+
if verbosity > 1:
133+
echo(bridge.stats)
134+
135+
136+
if __name__ == "__main__":
137+
load_dotenv()
138+
app(prog_name="hyp2rem")

hyp2rem/exceptions.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Copyright 2020 The Hyp2Rem Authors
2+
3+
# Use of this source code is governed by an MIT-style
4+
# license that can be found in the LICENSE file or at
5+
# https://opensource.org/licenses/MIT.
6+
7+
"""Exceptions for use in Hyp2Rem package and sub-packages."""
8+
9+
10+
class ParentNotSyncedError(ValueError):
11+
"""A Rem's parent is missing or is outdated."""
12+
13+
def __init__(
14+
self,
15+
message: str = "Cannot create or update an annotation whose parent has"
16+
+ "not been synced yet or is out-of-date.",
17+
):
18+
self.message = message
19+
super().__init__(self.message)
20+
21+
22+
class SiblingNotSyncedError(ValueError):
23+
"""A Rem's older sibling is missing or outdated."""
24+
25+
def __init__(
26+
self,
27+
message: str = "Cannot create or update an annotation whose older "
28+
+ "sibling has not been synced yet or is out-of-date.",
29+
):
30+
self.message = message
31+
super().__init__(self.message)
32+
33+
34+
class MissingAuthorizationTokenError(TypeError):
35+
"""Credentials for accessing a web service are not available."""
36+
37+
def __init__(
38+
self,
39+
message: str = "Could not find one or more credentials required to"
40+
+ "access the specified resource.",
41+
):
42+
self.message = message
43+
super().__init__(self.message)

0 commit comments

Comments
 (0)