separate sqlalchemystorage from __init__

This commit is contained in:
Jacob Mason 2010-07-15 13:25:12 -05:00
parent 1f2a52f45c
commit dc2f45208f
6 changed files with 229 additions and 130 deletions

View File

@ -0,0 +1,47 @@
.. _searchadapters:
.. currentmodule:: sphinx.websupport.search
Search Adapters
===============
To create a custom search adapter you will need to subclass the
:class:`~BaseSearch` class. Then create an instance of the new class
and pass that as the `search` keyword argument when you create the
:class:`~sphinx.websupport.WebSupport` object::
support = Websupport(srcdir=srcdir,
outdir=outdir,
search=MySearch())
For more information about creating a custom search adapter, please see
the documentation of the :class:`BaseSearch` class below.
.. class:: BaseSearch
Defines an interface for search adapters.
BaseSearch Methods
~~~~~~~~~~~~~~~~~~
The following methods are defined in the BaseSearch class. Some methods
do not need to be overridden, but some (
:meth:`~sphinx.websupport.search.BaseSearch.add_document` and
:meth:`~sphinx.websupport.search.BaseSearch.handle_query`) must be
overridden in your subclass. For a working example, look at the
built-in adapter for whoosh.
.. automethod:: sphinx.websupport.search.BaseSearch.init_indexing
.. automethod:: sphinx.websupport.search.BaseSearch.finish_indexing
.. automethod:: sphinx.websupport.search.BaseSearch.feed
.. automethod:: sphinx.websupport.search.BaseSearch.add_document
.. automethod:: sphinx.websupport.search.BaseSearch.query
.. automethod:: sphinx.websupport.search.BaseSearch.handle_query
.. automethod:: sphinx.websupport.search.BaseSearch.extract_context

View File

@ -0,0 +1,47 @@
.. _searchadapters:
.. currentmodule:: sphinx.websupport.search
Search Adapters
===============
To create a custom search adapter you will need to subclass the
:class:`~BaseSearch` class. Then create an instance of the new class
and pass that as the `search` keyword argument when you create the
:class:`~sphinx.websupport.WebSupport` object::
support = Websupport(srcdir=srcdir,
outdir=outdir,
search=MySearch())
For more information about creating a custom search adapter, please see
the documentation of the :class:`BaseSearch` class below.
.. class:: BaseSearch
Defines an interface for search adapters.
BaseSearch Methods
~~~~~~~~~~~~~~~~~~
The following methods are defined in the BaseSearch class. Some methods
do not need to be overridden, but some (
:meth:`~sphinx.websupport.search.BaseSearch.add_document` and
:meth:`~sphinx.websupport.search.BaseSearch.handle_query`) must be
overridden in your subclass. For a working example, look at the
built-in adapter for whoosh.
.. automethod:: sphinx.websupport.search.BaseSearch.init_indexing
.. automethod:: sphinx.websupport.search.BaseSearch.finish_indexing
.. automethod:: sphinx.websupport.search.BaseSearch.feed
.. automethod:: sphinx.websupport.search.BaseSearch.add_document
.. automethod:: sphinx.websupport.search.BaseSearch.query
.. automethod:: sphinx.websupport.search.BaseSearch.handle_query
.. automethod:: sphinx.websupport.search.BaseSearch.extract_context

View File

@ -12,4 +12,5 @@ into your web application. To learn more read the
web/quickstart
web/api
web/frontend
web/searchadapters
web/searchadapters
web/storagebackends

View File

@ -18,7 +18,7 @@ from jinja2 import Environment, FileSystemLoader
from sphinx.application import Sphinx
from sphinx.util.osutil import ensuredir
from sphinx.websupport.search import BaseSearch, search_adapters
from sphinx.websupport import comments as sphinxcomments
from sphinx.websupport.comments import StorageBackend
class WebSupportApp(Sphinx):
def __init__(self, *args, **kwargs):
@ -46,17 +46,18 @@ class WebSupport(object):
self._init_comments(comments)
def _init_comments(self, comments):
if isinstance(comments, sphinxcomments.CommentBackend):
if isinstance(comments, StorageBackend):
self.comments = comments
else:
# If a CommentBackend isn't provided, use the default
# If a StorageBackend isn't provided, use the default
# SQLAlchemy backend with an SQLite db.
from sphinx.websupport.comments import SQLAlchemyComments
from sphinx.websupport.comments.sqlalchemystorage \
import SQLAlchemyStorage
from sqlalchemy import create_engine
db_path = path.join(self.outdir, 'comments', 'comments.db')
ensuredir(path.dirname(db_path))
engine = create_engine('sqlite:///%s' % db_path)
self.comments = SQLAlchemyComments(engine)
self.comments = SQLAlchemyStorage(engine)
def _init_templating(self):
import sphinx
@ -93,8 +94,7 @@ class WebSupport(object):
self.outdir, doctreedir, 'websupport',
search=self.search,
comments=self.comments)
# TODO:
# Hook comments into Sphinx signals.
self.comments.pre_build()
app.build()
self.comments.post_build()

View File

@ -1,12 +1,5 @@
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sphinx.websupport.comments.db import Base, Node, Comment, Vote
Session = sessionmaker()
class CommentBackend(object):
class StorageBackend(object):
def pre_build(self):
pass
@ -22,117 +15,3 @@ class CommentBackend(object):
def get_comments(self, parent_id):
raise NotImplemented
class SQLAlchemyComments(CommentBackend):
def __init__(self, engine):
self.engine = engine
Base.metadata.bind = engine
Base.metadata.create_all()
Session.configure(bind=engine)
self.session = Session()
def pre_build(self):
self.current_pk = None
def add_node(self, document, line, source, treeloc):
node = Node(document, line, source, treeloc)
self.session.add(node)
if self.current_pk is None:
self.session.commit()
self.current_pk = node.id
else:
self.current_pk += 1
return self.current_pk
def post_build(self):
self.session.commit()
def add_comment(self, parent_id, text, displayed,
username, rating, time):
time = time or datetime.now()
id = parent_id[1:]
if parent_id[0] == 's':
node = self.session.query(Node).filter(Node.id == id).first()
comment = Comment(text, displayed, username, rating,
time, node=node)
elif parent_id[0] == 'c':
parent = self.session.query(Comment).filter(Comment.id == id).first()
comment = Comment(text, displayed, username, rating,
time, parent=parent)
self.session.add(comment)
self.session.commit()
return self.serializable(comment)
def get_comments(self, parent_id, user_id):
parent_id = parent_id[1:]
node = self.session.query(Node).filter(Node.id == parent_id).first()
comments = []
for comment in node.comments:
comments.append(self.serializable(comment, user_id))
return comments
def process_vote(self, comment_id, user_id, value):
vote = self.session.query(Vote).filter(
Vote.comment_id == comment_id).filter(
Vote.user_id == user_id).first()
comment = self.session.query(Comment).filter(
Comment.id == comment_id).first()
if vote is None:
vote = Vote(comment_id, user_id, value)
comment.rating += value
else:
comment.rating += value - vote.value
vote.value = value
self.session.add(vote)
self.session.commit()
def serializable(self, comment, user_id=None):
delta = datetime.now() - comment.time
time = {'year': comment.time.year,
'month': comment.time.month,
'day': comment.time.day,
'hour': comment.time.hour,
'minute': comment.time.minute,
'second': comment.time.second,
'iso': comment.time.isoformat(),
'delta': self.pretty_delta(delta)}
vote = ''
if user_id is not None:
vote = self.session.query(Vote).filter(
Vote.comment_id == comment.id).filter(
Vote.user_id == user_id).first()
if vote is not None:
vote = vote.value
return {'text': comment.text,
'username': comment.username or 'Anonymous',
'id': comment.id,
'rating': comment.rating,
'age': delta.seconds,
'time': time,
'vote': vote or 0,
'node': comment.node.id if comment.node else None,
'parent': comment.parent.id if comment.parent else None,
'children': [self.serializable(child, user_id)
for child in comment.children]}
def pretty_delta(self, delta):
days = delta.days
seconds = delta.seconds
hours = seconds / 3600
minutes = seconds / 60
if days == 0:
dt = (minutes, 'minute') if hours == 0 else (hours, 'hour')
else:
dt = (days, 'day')
return '%s %s ago' % dt if dt[0] == 1 else '%s %ss ago' % dt

View File

@ -0,0 +1,125 @@
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from sphinx.websupport.comments import StorageBackend
from sphinx.websupport.comments.db import Base, Node, Comment, Vote
Session = sessionmaker()
class SQLAlchemyStorage(StorageBackend):
def __init__(self, engine):
self.engine = engine
Base.metadata.bind = engine
Base.metadata.create_all()
Session.configure(bind=engine)
def pre_build(self):
self.build_session = Session()
def add_node(self, document, line, source, treeloc):
node = Node(document, line, source, treeloc)
self.build_session.add(node)
self.build_session.flush()
return node.id
def post_build(self):
self.build_session.commit()
self.build_session.close()
def add_comment(self, parent_id, text, displayed,
username, rating, time):
time = time or datetime.now()
session = Session()
id = parent_id[1:]
if parent_id[0] == 's':
node = session.query(Node).filter(Node.id == id).first()
comment = Comment(text, displayed, username, rating,
time, node=node)
elif parent_id[0] == 'c':
parent = session.query(Comment).filter(Comment.id == id).first()
comment = Comment(text, displayed, username, rating,
time, parent=parent)
session.add(comment)
session.commit()
comment = self.serializable(session, comment)
session.close()
return comment
def get_comments(self, parent_id, user_id):
parent_id = parent_id[1:]
session = Session()
node = session.query(Node).filter(Node.id == parent_id).first()
comments = []
for comment in node.comments:
comments.append(self.serializable(session, comment, user_id))
session.close()
return comments
def process_vote(self, comment_id, user_id, value):
session = Session()
vote = session.query(Vote).filter(
Vote.comment_id == comment_id).filter(
Vote.user_id == user_id).first()
comment = session.query(Comment).filter(
Comment.id == comment_id).first()
if vote is None:
vote = Vote(comment_id, user_id, value)
comment.rating += value
else:
comment.rating += value - vote.value
vote.value = value
session.add(vote)
session.commit()
session.close()
def serializable(self, session, comment, user_id=None):
delta = datetime.now() - comment.time
time = {'year': comment.time.year,
'month': comment.time.month,
'day': comment.time.day,
'hour': comment.time.hour,
'minute': comment.time.minute,
'second': comment.time.second,
'iso': comment.time.isoformat(),
'delta': self.pretty_delta(delta)}
vote = ''
if user_id is not None:
vote = session.query(Vote).filter(
Vote.comment_id == comment.id).filter(
Vote.user_id == user_id).first()
if vote is not None:
vote = vote.value
return {'text': comment.text,
'username': comment.username or 'Anonymous',
'id': comment.id,
'rating': comment.rating,
'age': delta.seconds,
'time': time,
'vote': vote or 0,
'node': comment.node.id if comment.node else None,
'parent': comment.parent.id if comment.parent else None,
'children': [self.serializable(session, child, user_id)
for child in comment.children]}
def pretty_delta(self, delta):
days = delta.days
seconds = delta.seconds
hours = seconds / 3600
minutes = seconds / 60
if days == 0:
dt = (minutes, 'minute') if hours == 0 else (hours, 'hour')
else:
dt = (days, 'day')
return '%s %s ago' % dt if dt[0] == 1 else '%s %ss ago' % dt