Skip to content
Snippets Groups Projects
Commit 0230da34 authored by Johann Jacobsohn's avatar Johann Jacobsohn
Browse files

lint

parent 0b0e44d1
No related branches found
No related tags found
No related merge requests found
[pydocstyle]
ignore = D104,D105,D107,D203,D204,D213
# D104: Missing docstring in public package
# D105 Missing docstring in magic method
# D107 Missing docstring in __init__
# D203 1 blank line required before class docstring
# D204 1 blank line required after class docstring (found 0)
# D213 Multi-line docstring summary should start at the second line
\ No newline at end of file
[MESSAGES CONTROL]
disable=no-self-use,too-many-instance-attributes
good-names=id, i
""""Paper surfer - browse papers posted on the mattermost channel.
"""Paper surfer - browse papers posted on the mattermost channel.
UI:
......@@ -16,6 +16,7 @@ from functools import partial
import json
import time
import os
import sys
import requests
import mattermostdriver
import urwid
......@@ -28,7 +29,7 @@ class ConfigError(Exception):
@dataclass
class PostDTO:
""""Encapsulate Mattermost Posts."""
"""Encapsulate Mattermost Posts."""
id: str
message: str
reporter: str
......@@ -40,7 +41,7 @@ class PostDTO:
@dataclass
class PaperDTO:
""""Encapsulate Paper meta data."""
"""Encapsulate Paper meta data."""
author: str
authors: str
title: str
......@@ -52,20 +53,24 @@ class PaperDTO:
class Bibtex:
"""Interface for bibtex string."""
def entry_from_doi(self, doi):
"""Get bibtex string for doi."""
return Doi().get_bibtex(doi)
def bib_from_dois(self, dois):
"""Get bibtex string for mulitple dois."""
return "\n".join([Doi().get_bibtex(doi) for doi in dois])
class Doi:
"""Interface w/ the doi.org api"""
"""Interface w/ the doi.org api."""
def get_doi_link(self, doi):
"""Assemble doi link."""
return f"http://doi.org/{doi}"
def load_doi_data(self, doi):
"""Load data for doi."""
headers = {
'Accept': 'application/json',
}
......@@ -73,7 +78,7 @@ class Doi:
headers=headers).content
def parse_doi_json(self, jsoncontent):
"""Tranform doi json to PaperDTO"""
"""Tranform doi json to PaperDTO."""
info = json.loads(jsoncontent)
with open("debug.json", "w") as file:
......@@ -87,8 +92,7 @@ class Doi:
if "author" in info
else "Authors N/A")
title = (info['title']
if "title" in info
and isinstance(info['title'], str)
if "title" in info and isinstance(info['title'], str)
else "Title N/A")
journal = (info['publisher']
if "publisher" in info
......@@ -105,12 +109,14 @@ class Doi:
slug)
def get_bibtex(self, doi):
"""Get bibtex string for doi."""
headers = {
'Accept': 'text/bibliography; style=bibtex',
}
return requests.get(f'http://dx.doi.org/{doi}', headers=headers).text
def get_info(self, doi):
"""Get information for doi."""
try:
jsoncontent = self.load_doi_data(doi)
data = self.parse_doi_json(jsoncontent)
......@@ -132,6 +138,7 @@ class Doi:
class Mattermost:
"""Provide a simplified interaction w/ mattermost api."""
def __init__(self, url, channelname, username, password):
self.msgs = []
self.mattermost = mattermostdriver.Driver({
'url': url,
'login_id': username,
......@@ -155,13 +162,14 @@ class Mattermost:
self.reporters = {}
def get_channel(self, channelname):
""""Try to find the paper channel by display name."""
mm = self.mattermost
teams = [team["id"] for team in mm.teams.get_user_teams("me")]
"""Try to find the paper channel by display name."""
teamapi = self.mattermost.teams
channelapi = self.mattermost.channels
teams = [team["id"] for team in teamapi.get_user_teams("me")]
channels = []
for team in teams:
teamchannels = [channel for channel
in mm.channels.get_channels_for_user("me", team)
in channelapi.get_channels_for_user("me", team)
if channel["display_name"] == channelname]
channels.extend(teamchannels)
......@@ -171,22 +179,20 @@ class Mattermost:
raise ConfigError
return channels[0]["id"]
def get_reporter(self, id):
def get_reporter(self, userid):
"""Load user from mattermost api and cache."""
if id not in self.reporters:
self.reporters[id] = self.mattermost.users.get_user(id)["username"]
userapi = self.mattermost.users
if userid not in self.reporters:
self.reporters[userid] = userapi.get_user(userid)["username"]
return self.reporters[id]
return self.reporters[userid]
def retrieve_all_messages(self):
"""Retrieve all messages from mattermost, unfiltered for papers."""
posts = self.mattermost.posts.get_posts_for_channel(self.channel)
return [PostDTO(
id=m['id'],
message=m['message'],
return [PostDTO(id=m['id'], message=m['message'],
reporter=self.get_reporter(m['user_id']),
doi=Doi().extract_doi(m['message']),
)
doi=Doi().extract_doi(m['message']),)
for m in posts['posts'].values()]
def filter_incoming(self, posts):
......@@ -200,6 +206,7 @@ class Mattermost:
return self.msgs
def check_doi_exits(self, doi):
"""Check for doi in current paper list."""
doi_needle = Doi().extract_doi(doi)
msg_found = [msg for msg in self.msgs
if Doi().extract_doi(msg.doi) == doi_needle]
......@@ -212,12 +219,15 @@ class Mattermost:
or needle.lower() in m.reporter.lower()]
def post(self, message):
"""Post message to thread."""
self.mattermost.posts.create_post({"channel_id": self.channel,
"message": message})
class PrettyButton(urwid.WidgetWrap):
"""Prettified urwid Button."""
def __init__(self, label, on_press=None, user_data=None):
self.label = ""
self.text = urwid.Text("")
self.set_label(label)
self.widget = urwid.AttrMap(self.text, '', 'highlight')
......@@ -226,21 +236,26 @@ class PrettyButton(urwid.WidgetWrap):
self._hidden_btn = urwid.Button(f"hidden {self.label}",
on_press, user_data)
super(self.__class__, self).__init__(self.widget)
super().__init__(self.widget)
def selectable(self):
"""Make button selectable."""
return True
def keypress(self, *args, **kw):
"""Handle keypresses."""
return self._hidden_btn.keypress(*args, **kw)
def mouse_event(self, *args, **kw):
"""Handle mouse events."""
return self._hidden_btn.mouse_event(*args, **kw)
def get_label(self):
"""Return current input label."""
return self.label
def set_label(self, label):
"""Return current input label."""
self.label = label
self.text.set_text(f"[ {label} ]")
......@@ -308,16 +323,19 @@ class Papersurfer:
self.mainloop.run()
def h_unhandled_input(self, key):
"""Handle keyboard input not otherwise handled."""
if key == "esc":
raise urwid.ExitMainLoop()
def load_list(self, _loop, _data):
"""Load and display paper list."""
body = [self.list_item(paper) for paper in self.mtm.retrieve()]
self.listcontent.clear()
self.listcontent.extend(body)
self.mainloop.widget = self.top
def loading_indicator(self):
"""Create loading indicator dialog."""
body_text = urwid.Text("Loading...", align='center')
body_filler = urwid.Filler(body_text, valign='middle')
body_padding = urwid.Padding(
......@@ -329,6 +347,7 @@ class Papersurfer:
return urwid.Frame(body_padding)
def details_popup(self, paper):
"""Create Dialog with paper details."""
header_text = urwid.Text(('banner', 'Paper details'), align='center')
header = urwid.AttrMap(header_text, 'banner')
......@@ -391,7 +410,7 @@ class Papersurfer:
return pile
def updscrn(self):
""""Update (redraw) screen."""
"""Update (redraw) screen."""
self.mainloop.draw_screen()
def onchange(self, _, needle):
......@@ -402,6 +421,7 @@ class Papersurfer:
for paper in self.mtm.get_filtered(needle)])
def running_export(self, state):
"""Set exporting state."""
btn = self.exportbutton
label = btn.get_label()
running_indicator = " (running...)"
......@@ -422,6 +442,7 @@ class Papersurfer:
self.running_export(False)
def export_to_bibtex(self):
"""Export current filtered list to bibtex file."""
papers = self.mtm.get_filtered(self.filter)
dois = [paper.doi for paper in papers]
string = Bibtex().bib_from_dois(dois)
......@@ -455,13 +476,15 @@ class Papersurfer:
self.mainloop.widget = self.details_popup(paper)
def h_close_dialog(self, _):
"""Handle close dialog button."""
self.close_dialog()
def close_dialog(self):
"""Close currently open dialog."""
self.mainloop.widget = self.top
def open_submit_paper(self, _):
"""Open submit paper dialog."""
self._pile = urwid.Pile(
[
PostDialog(self.mtm, close=self.h_close_dialog)
......@@ -494,7 +517,6 @@ def get_config_file_paths():
>>> type(get_config_file_paths())
<class 'list'>
"""
env = os.environ
xdg_home = None
if 'XDG_CONFIG_HOME' in env:
......@@ -517,6 +539,7 @@ def get_config_file_paths():
def interactive_configuration():
"""Query user for credentials."""
url = input("Mattermost URL (eg. mattermost.example.net): ")
channel = input("Channel (eg. Paper Club): ")
username = input("Username (same as mattermost login, "
......@@ -526,7 +549,8 @@ def interactive_configuration():
class PostDialog(urwid.WidgetWrap):
"""
"""Dialog to submit a new paper to mattermost thread.
UI:
DOI: [ _________________]
Generated Message:
......@@ -535,6 +559,8 @@ class PostDialog(urwid.WidgetWrap):
[Submit] [Close]
"""
def __init__(self, mattermost, close):
self.doi = None
self.msg = None
self.mattermost = mattermost
self.close = close
self.doi_input = urwid.Edit("Doi: ")
......@@ -558,21 +584,21 @@ class PostDialog(urwid.WidgetWrap):
right=1
)
body = urwid.LineBox(body_padding)
frame = urwid.Frame(
body,
header=urwid.Text("Submit new paper to list"),
)
frame = urwid.Frame(body,
header=urwid.Text("Submit new paper to list"))
self.widget = frame
super(self.__class__, self).__init__(self.widget)
super().__init__(self.widget)
def submit(self, _):
"""Submit post to thread."""
if not self.mattermost.check_doi_exits(self.doi):
self.mattermost.post(self.msg)
self.close(_)
def create_mgs(self, paper):
"""Format post message."""
msg = f"""\
{paper.title}
{paper.authors}
......@@ -581,6 +607,7 @@ class PostDialog(urwid.WidgetWrap):
return msg
def h_input(self, _, doi):
"""Handle doi input field."""
self.doi_result.set_text("... loading ...")
self.doi = None
self.msg = None
......@@ -602,8 +629,8 @@ class PostDialog(urwid.WidgetWrap):
def parse_args():
"""Parse command line arguments and config file."""
parser = configargparse.ArgParser()
parser._default_config_files = get_config_file_paths()
parser = configargparse.ArgParser(
default_config_files=get_config_file_paths())
parser.add("-w", "--write-out-config-file",
help="takes the current command line args and writes them out "
"to a config file at the given path",
......@@ -630,7 +657,7 @@ def parse_args():
Mattermost(url, channel, username, password)
except ConfigError:
print("Failed to validate configuration, exiting.")
exit(1)
sys.exit(1)
options.url = url
options.channel = channel
......@@ -648,7 +675,7 @@ def parse_args():
time.sleep(2)
else:
parser.print_help()
exit(0)
sys.exit(0)
return options
......@@ -661,12 +688,14 @@ def just_papers(url, channel, username, password):
def just_bibtex(url, channel, username, password):
"""Retrieve and dump bibtext formated data, unfiltered."""
posts = Mattermost(url, channel, username, password).retrieve()
dois = [post.doi for post in posts]
print(Bibtex().bib_from_dois(dois))
def main():
"""Run main program."""
opt = parse_args()
if opt.dump_posts:
just_papers(opt.url, opt.channel, opt.username, opt.password)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment