[gpapers] 3 new revisions pushed by marcelCo...@gmail.com on 2012-06-25 22:25 GMT

6 views
Skip to first unread message

codesite...@google.com

unread,
Jun 25, 2012, 6:25:31 PM6/25/12
to gpapers...@googlegroups.com
3 new revisions:

Revision: 068efdf03108
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:07:43 2012
Log: replace desktop.open with Gtk.show_uri
http://code.google.com/p/gpapers/source/detail?r=068efdf03108

Revision: 11a62e97f6d1
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:31:55 2012
Log: add support for the arxiv preprint server (contributed by Gordon
Ball)
http://code.google.com/p/gpapers/source/detail?r=11a62e97f6d1

Revision: 1ed2c3f7da27
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:50:30 2012
Log: fix arxiv icon size
http://code.google.com/p/gpapers/source/detail?r=1ed2c3f7da27

==============================================================================
Revision: 068efdf03108
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:07:43 2012
Log: replace desktop.open with Gtk.show_uri
http://code.google.com/p/gpapers/source/detail?r=068efdf03108

Deleted:
/gpapers/desktop.py
Modified:
/gpapers/__init__.py
/gpapers/gPapers/models.py

=======================================
--- /gpapers/desktop.py Thu Apr 5 14:13:17 2012
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Simple desktop integration for Python. This module provides desktop
environment
-detection and resource opening support for a selection of common and
-standardised desktop environments.
-
-Copyright (C) 2005, 2006 Paul Boddie <pa...@boddie.org.uk>
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA
-
---------
-
-Desktop Detection
------------------
-
-To detect a specific desktop environment, use the get_desktop function.
-To detect whether the desktop environment is standardised (according to the
-proposed DESKTOP_LAUNCH standard), use the is_standard function.
-
-Opening URLs
-------------
-
-To open a URL in the current desktop environment, relying on the automatic
-detection of that environment, use the desktop.open function as follows:
-
-desktop.open("http://www.python.org")
-
-To override the detected desktop, specify the desktop parameter to the open
-function as follows:
-
-desktop.open("http://www.python.org", "KDE") # Insists on KDE
-desktop.open("http://www.python.org", "GNOME") # Insists on GNOME
-
-Without overriding using the desktop parameter, the open function will
attempt
-to use the "standard" desktop opening mechanism which is controlled by the
-DESKTOP_LAUNCH environment variable as described below.
-
-The DESKTOP_LAUNCH Environment Variable
----------------------------------------
-
-The DESKTOP_LAUNCH environment variable must be shell-quoted where
appropriate,
-as shown in some of the following examples:
-
-DESKTOP_LAUNCH="kdialog --msgbox" Should present any opened URLs in
- their entirety in a KDE message
box.
- (Command "kdialog" plus parameter.)
-DESKTOP_LAUNCH="my\ opener" Should run the "my opener" program
to
- open URLs.
- (Command "my opener", no
parameters.)
-DESKTOP_LAUNCH="my\ opener --url" Should run the "my opener" program
to
- open URLs.
- (Command "my opener" plus
parameter.)
-
-Details of the DESKTOP_LAUNCH environment variable convention can be found
here:
-http://lists.freedesktop.org/archives/xdg/2004-August/004489.html
-"""
-
-__version__ = "0.2.3"
-
-import os
-import sys
-
-try:
- import subprocess
- def _run(cmd, shell, wait):
- opener = subprocess.Popen(cmd, shell=shell)
- if wait: opener.wait()
- return opener.pid
-
-except ImportError:
- import popen2
- def _run(cmd, shell, wait):
- opener = popen2.Popen3(cmd)
- if wait: opener.wait()
- return opener.pid
-
-import commands
-
-def get_desktop():
-
- """
- Detect the current desktop environment, returning the name of the
- environment. If no environment could be detected, None is returned.
- """
-
- if os.environ.has_key("KDE_FULL_SESSION") or \
- os.environ.has_key("KDE_MULTIHEAD"):
- return "KDE"
- elif os.environ.has_key("GNOME_DESKTOP_SESSION_ID") or \
- os.environ.has_key("GNOME_KEYRING_SOCKET"):
- return "GNOME"
- elif sys.platform == "darwin":
- return "Mac OS X"
- elif hasattr(os, "startfile"):
- return "Windows"
- else:
- return None
-
-def is_standard():
-
- """
- Return whether the current desktop supports standardised application
- launching.
- """
-
- return os.environ.has_key("DESKTOP_LAUNCH")
-
-def open(url, desktop=None, wait=0):
-
- """
- Open the 'url' in the current desktop's preferred file browser. If the
- optional 'desktop' parameter is specified then attempt to use that
- particular desktop environment's mechanisms to open the 'url' instead
of
- guessing or detecting which environment is being used.
-
- Suggested values for 'desktop' are "standard", "KDE", "GNOME", "Mac OS
X",
- "Windows" where "standard" employs a DESKTOP_LAUNCH environment
variable to
- open the specified 'url'. DESKTOP_LAUNCH should be a command, possibly
- followed by arguments, and must have any special characters
shell-escaped.
-
- The process identifier of the "opener" (ie. viewer, editor, browser or
- program) associated with the 'url' is returned by this function. If the
- process identifier cannot be determined, None is returned.
-
- An optional 'wait' parameter is also available for advanced usage and,
if
- 'wait' is set to a true value, this function will wait for the
launching
- mechanism to complete before returning (as opposed to immediately
returning
- as is the default behaviour).
- """
-
- # Attempt to detect a desktop environment.
-
- detected = get_desktop()
-
- # Start with desktops whose existence can be easily tested.
-
- if (desktop is None or desktop == "standard") and is_standard():
- arg = "".join([os.environ["DESKTOP_LAUNCH"], commands.mkarg(url)])
- return _run(arg, 1, wait)
-
- elif (desktop is None or desktop == "Windows") and detected
== "Windows":
- # NOTE: This returns None in current implementations.
- return os.startfile(url)
-
- # Test for desktops where the overriding is not verified.
-
- elif (desktop or detected) == "KDE":
- cmd = ["kfmclient", "exec", url]
-
- elif (desktop or detected) == "GNOME":
- cmd = ["gnome-open", url]
-
- elif (desktop or detected) == "Mac OS X":
- cmd = ["open", url]
-
- # Finish with an error where no suitable desktop was identified.
-
- else:
- raise OSError, "Desktop not supported (neither DESKTOP_LAUNCH nor
os.startfile could be used)"
-
- return _run(cmd, 0, wait)
-
-# vim: tabstop=4 expandtab shiftwidth=4
=======================================
--- /gpapers/__init__.py Sun Jun 24 06:26:42 2012
+++ /gpapers/__init__.py Mon Jun 25 13:07:43 2012
@@ -26,6 +26,7 @@
import os
import sys
import thread
+import time
import traceback

from gi.repository import Gio
@@ -47,7 +48,6 @@

from gpapers.logger import log_level_debug, log_warn, log_info, log_debug
from gpapers.importer import bibtex, pdf_file
-import gpapers.desktop
from gpapers.gPapers.models import *
import gpapers.importer as importer
from gpapers.importer import pango_escape
@@ -1681,7 +1681,8 @@
url = paper.import_url
if not url:
url = 'http://dx.doi.org/' + paper.doi
- button.connect('clicked', lambda x: desktop.open(url))
+ button.connect('clicked',
+ lambda x: Gtk.show_uri(None, url,
Gdk.CURRENT_TIME))
paper_information_toolbar.insert(button, -1)
if paper.id != -1:
button = Gtk.ToolButton(stock_id=Gtk.STOCK_REFRESH)
@@ -1888,7 +1889,7 @@
stdout.readlines()
stdout.close()
time.sleep(.1)
- desktop.open(file)
+ Gtk.show_uri(None, 'file://' + file, Gdk.CURRENT_TIME)

def update_bookmark_pane_from_paper(self, paper):
toolbar_bookmarks = self.ui.get_object('toolbar_bookmarks')
=======================================
--- /gpapers/gPapers/models.py Sun Jun 24 05:30:19 2012
+++ /gpapers/gPapers/models.py Mon Jun 25 13:07:43 2012
@@ -21,8 +21,10 @@
from django.db import models
import django.core.files.base

-from gpapers import desktop
-from gpapers.logger import log_debug
+from gi.repository import Gtk
+from gi.repository import Gdk
+
+from gpapers.logger import log_debug, log_error

class Publisher(models.Model):

@@ -178,9 +180,12 @@

def open(self):
if self.full_text and os.path.isfile(self.full_text.path):
- desktop.open(self.full_text.path)
- self.read_count = self.read_count + 1
- self.save()
+ uri = 'file://' + self.full_text.path
+ if Gtk.show_uri(None, uri, Gdk.CURRENT_TIME):
+ self.read_count = self.read_count + 1
+ self.save()
+ else:
+ log_error('Failed to open %s' % uri)

class Admin:
list_display = ('id', 'doi', 'title')

==============================================================================
Revision: 11a62e97f6d1
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:31:55 2012
Log: add support for the arxiv preprint server (contributed by Gordon
Ball)
http://code.google.com/p/gpapers/source/detail?r=11a62e97f6d1

Added:
/gpapers/icons/favicon_arxiv.ico
/gpapers/importer/arxiv.py
Modified:
/README
/gpapers/__init__.py
/gpapers/importer/__init__.py

=======================================
--- /dev/null
+++ /gpapers/icons/favicon_arxiv.ico Mon Jun 25 13:31:55 2012
Binary file, no diff available.
=======================================
--- /dev/null
+++ /gpapers/importer/arxiv.py Mon Jun 25 13:31:55 2012
@@ -0,0 +1,155 @@
+# gPapers
+# Copyright (C) 2007-2009 Derek Anderson
+# 2012 Derek Anderson, Marcel Stimberg, and Gordon
Ball
+#
+# This file is part of gPapers.
+#
+# gPapers is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# gPapers is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with gPapers. If not, see <http://www.gnu.org/licenses/>.
+import re
+import datetime
+import urllib
+
+from gi.repository import Soup
+import feedparser
+
+from gpapers.importer import SimpleWebSearchProvider, soup_session
+from gpapers.logger import log_debug, log_error
+
+BASE_URL = 'http://export.arxiv.org/api/query?'
+SORT_BY = "lastUpdatedDate"
+SORT_ORDER = "descending"
+MAX_RESULTS = 100
+
+class ArxivSearch(SimpleWebSearchProvider):
+ """
+ A search provider/importer for the arXiv.org e-print archive,
+ covering physics, mathematics, computer science, etc.
+
+ Implements searches using the API documented at
+ http://arxiv.org/help/api/user-manual
+ """
+
+ name = u'arXiv' #X -> \u03a7
+ label = 'arxiv'
+ icon = 'favicon_arxiv.ico'
+ unique_key = 'import_url'
+
+ def prepare_search_message(self, search_string):
+
+ #if the query already uses arXiv syntax, don't add an
+ #"all:" query on the front
+ if not re.match("^(ti|au|abs|co|jr|cat|rn|id):\w+", search_string):
+ search_string = 'all:' + search_string
+
+ uri_string = BASE_URL + urllib.urlencode({'sortBy': SORT_BY,
+ 'sortOrder': SORT_ORDER,
+ 'max_results':
MAX_RESULTS,
+ 'search_query':
search_string})
+
+ log_debug("arxiv: requesting %s" % uri_string)
+ return Soup.Message.new(method='GET', uri_string=uri_string)
+
+ def parse_response(self, response):
+ """
+ Parse the arXiv response, which is in Atom XML format.
+
+ The feed provides itself provides more-or-less all the
+ information required without needing any extra requests.
+ """
+
+ papers = []
+ try:
+ parsed = feedparser.parse(response)
+ except Exception as ex:
+ log_error("arxiv: error while parsing response: %s" % ex[0])
+ return papers
+
+ log_debug("arxiv: received response containing %d results" %
len(parsed.entries))
+ for entry in parsed.entries:
+ paper = {}
+
+ try:
+ paper['title'] = entry['title']
+ for link in entry['links']:
+ if link.get('title', None) == 'pdf':
+ paper['import_url'] = link['href']
+ break
+
+ paper['authors'] = [a['name'] for a in entry['authors']]
+ if 'arxiv_journal_ref' in entry:
+ paper['journal'] = entry['arxiv_journal_ref']
+ if 'arxiv_doi' in entry:
+ paper['doi'] = entry['arxiv_doi']
+ if 'arxiv_comment' in entry:
+ paper['notes'] = entry['arxiv_comment']
+ paper['year'] = entry['published_parsed'].tm_year
+ paper['arxiv_id'] = entry['id']
+ paper['url'] = entry['id']
+ paper['abstract'] = entry['summary'].replace('\n', ' ')
+ if 'arxiv_primary_category' in entry:
+ paper['arxiv_type'] =
entry['arxiv_primary_category'].get('term', '')
+
+ paper['created'] =
datetime.datetime(year=entry['published_parsed'].tm_year,
+
month=entry['published_parsed'].tm_mon,
+
day=entry['published_parsed'].tm_mday)
+ paper['updated'] =
datetime.datetime(year=entry['updated_parsed'].tm_year,
+
month=entry['updated_parsed'].tm_mon,
+
day=entry['updated_parsed'].tm_mday)
+
+ paper['data'] = paper #messy
+
+ papers += [paper]
+ except Exception as ex:
+ log_error("arxiv: error while reading item: %s" % ex[0])
+
+ return papers
+
+ def import_paper_after_search(self, data, callback):
+ """
+ FIXME: Inconsistent signature for this function.
+
+ gpapers.__init__:1702
+ button.connect('clicked',
+ lambda x:
paper.provider.import_paper_after_search(paper.data,
+
self.document_imported))
+
+ gpapers.importer.__init__:625
+ def import_paper_after_search(self, data, paper, callback)
+
+ Nowehere appears to call the latter form, but it seems more
sensible -
+ otherwise I have to set paper['data'] = paper otherwise I don't
seem to
+ be able to return appropriate info to the callback.
+
+ I am not clear on the correct delegation of operations here
- "import_url"
+ is already supplied by the initial search operation, but it appears
+ necessary to download it ourselves here or it doesn't get done.
+
+ Note that arxiv returns 403 forbidden if no user-agent is set.
+ """
+
+ if 'import_url' in data:
+ message = Soup.Message.new(method='GET',
uri_string=data['import_url'])
+
+ def mycallback(session, message, user_data):
+ if message.status_code == Soup.KnownStatusCode.OK:
+ log_debug("arxiv: received pdf length %s" %
message.response_body.length)
+ callback(data,
message.response_body.flatten().get_data(), user_data)
+ else:
+ log_error("arxiv: got status %s while trying to fetch
PDF" % (message.status_code))
+ callback(data, None, user_data)
+
+ log_debug("arxiv: trying to fetch %s" % data['import_url'])
+ soup_session.queue_message(message, mycallback, (self.label,
data['arxiv_id']))
+ else:
+ callback(data, None, self.label)
=======================================
--- /README Sun Jun 24 05:30:58 2012
+++ /README Mon Jun 25 13:31:55 2012
@@ -13,12 +13,10 @@
python-django: 1.3.1-4ubuntu1
python-pdfminer: 20110515+dfsg-1
python-beautifulsoup: 3.2.0-2build1
+python-feedparser: 5.1-0ubuntu3.1

In addition, gPapers contains code from the following sources:

-desktop
- http://pypi.python.org/pypi/desktop
- Written by Paul Boddie, published under LGPLv3
pyparsing parser for BibTeX
http://pastebin.com/ZzU19NLJ
Written by Matthew Brett, published under a simplified BSD license
@@ -31,6 +29,7 @@
Google Scholar: http://scholar.google.com/
Pubmed: http://www.ncbi.nlm.nih.gov/pubmed/
JSTOR's Data for Research (DfR) service: http://dfr.jstor.org
+arXiv.org e-Print archive: http://arxiv.org

The DOI service for resolving DOIs and downloading metadata:
http://dx.doi.org/

=======================================
--- /gpapers/__init__.py Mon Jun 25 13:07:43 2012
+++ /gpapers/__init__.py Mon Jun 25 13:31:55 2012
@@ -20,6 +20,8 @@
# You should have received a copy of the GNU General Public License
# along with gPapers. If not, see <http://www.gnu.org/licenses/>.

+__version__ = '0.5dev'
+
from datetime import datetime, timedelta, date
import math
import mimetypes
@@ -51,7 +53,7 @@
from gpapers.gPapers.models import *
import gpapers.importer as importer
from gpapers.importer import pango_escape
-from gpapers.importer import pubmed, google_scholar, jstor
+from gpapers.importer import pubmed, google_scholar, jstor, arxiv

log_level_debug()

@@ -74,7 +76,6 @@
GRAPH_ICON = GdkPixbuf.Pixbuf.new_from_file(os.path.join(BASE_DIR, 'icons',
'drawing.png'))

-__version__ = '0.5dev'

GObject.threads_init()

@@ -586,7 +587,8 @@
def __init__(self):
self.search_providers = {'pubmed' : pubmed.PubMedSearch(),
'google_scholar' :
google_scholar.GoogleScholarSearch(),
- 'jstor' : jstor.JSTORSearch()}
+ 'jstor' : jstor.JSTORSearch(),
+ 'arxiv' : arxiv.ArxivSearch()}
self.displayed_paper = None
self.ui = Gtk.Builder()
self.ui.add_from_file(os.path.join(BASE_DIR, 'data', 'ui.xml'))
=======================================
--- /gpapers/importer/__init__.py Sun Jun 24 05:30:19 2012
+++ /gpapers/importer/__init__.py Mon Jun 25 13:31:55 2012
@@ -32,6 +32,7 @@
from django.template import defaultfilters
import BeautifulSoup

+import gpapers
from gpapers.logger import *
from gpapers.gPapers.models import Paper

@@ -41,6 +42,8 @@
p_doi = re.compile('doi *: *(10.[a-z0-9]+/[a-z0-9.]+)', re.IGNORECASE)

soup_session = Soup.SessionAsync()
+#arXiv disallows requests if no user-agent is set
+soup_session.set_property("user-agent", "gPapers/%s" % gpapers.__version__)


def _decode_htmlentities(string):

==============================================================================
Revision: 1ed2c3f7da27
Author: Marcel Stimberg <marcel...@gmail.com>
Date: Mon Jun 25 13:50:30 2012
Log: fix arxiv icon size
http://code.google.com/p/gpapers/source/detail?r=1ed2c3f7da27

Modified:
/gpapers/__init__.py

=======================================
--- /gpapers/__init__.py Mon Jun 25 13:31:55 2012
+++ /gpapers/__init__.py Mon Jun 25 13:50:30 2012
@@ -1087,9 +1087,9 @@

for _, provider in self.search_providers.iteritems():
# FIXME: Load them in the providers
- provider_icon =
GdkPixbuf.Pixbuf.new_from_file(os.path.join(BASE_DIR,
- 'icons',
-
provider.icon))
+ icon_fname = os.path.join(BASE_DIR, 'icons', provider.icon)
+ provider_icon =
GdkPixbuf.Pixbuf.new_from_file_at_size(icon_fname,
+ 16, 16)
#FIXME
self.left_pane_model.append(None, (provider.name,
provider_icon, -1, False, provider.label))
for playlist in Playlist.objects.filter(parent=provider.label):
Reply all
Reply to author
Forward
0 new messages