From 21d1c49eadb69d710998dc851b5fefb1a5fdbe1a Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 9 May 2014 13:08:08 -0400 Subject: [PATCH] Parsing dates should work. --- bitshift/query/__init__.py | 37 +++++++++++++++++++++++++++++++++---- bitshift/query/nodes.py | 28 ++++++++++++++-------------- setup.py | 3 ++- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/bitshift/query/__init__.py b/bitshift/query/__init__.py index 3705860..e5844f1 100644 --- a/bitshift/query/__init__.py +++ b/bitshift/query/__init__.py @@ -3,9 +3,13 @@ This subpackage contains code to parse search queries received from the frontend into trees that can be used by the database backend. """ +from __future__ import unicode_literals from shlex import split -from .nodes import * ## TODO +from dateutil.parser import parse as parse_date + +from .nodes import (String, Regex, Text, Language, Author, Date, Symbol, + BinaryOp, UnaryOp) from .tree import Tree from ..languages import LANGS @@ -15,6 +19,7 @@ class QueryParseException(Exception): """Raised by parse_query() when a query is invalid.""" pass + class _QueryParser(object): """Wrapper class with methods to parse queries. Used as a singleton.""" @@ -31,28 +36,52 @@ class _QueryParser(object): } def _parse_language(self, term): + """Parse part of a query into a language node and return it.""" ## TODO: look up language ID return Language(0) def _parse_author(self, term): - pass + """Parse part of a query into an author node and return it.""" + return Author(self._parse_literal(term)) + + def _parse_date(self, term, type_): + """Parse part of a query into a date node and return it.""" + if term.startswith(("before:", "b:")): + relation = Date.BEFORE + dtstr = term.split(":", 1)[1] + elif term.startswith(("after:", "a:")): + relation = Date.AFTER + dtstr = term.split(":", 1)[1] + else: + raise QueryParseException('Bad relation for date: "%s"' % term) + try: + dt = parse_date(dtstr) + except (TypeError, ValueError): + raise QueryParseException('Bad datetime for date: "%s"' % dtstr) + return Date(type_, relation, dt) def _parse_modified(self, term): - pass + """Parse part of a query into a date modified node and return it.""" + return self._parse_date(term, Date.MODIFY) def _parse_created(self, term): - pass + """Parse part of a query into a date created node and return it.""" + return self._parse_date(term, Date.CREATE) def _parse_symbol(self, term): + """Parse part of a query into a symbol node and return it.""" pass def _parse_function(self, term): + """Parse part of a query into a function node and return it.""" pass def _parse_class(self, term): + """Parse part of a query into a class node and return it.""" pass def _parse_variable(self, term): + """Parse part of a query into a variable node and return it.""" pass def _parse_literal(self, literal): diff --git a/bitshift/query/nodes.py b/bitshift/query/nodes.py index ff9d21b..8ac3684 100644 --- a/bitshift/query/nodes.py +++ b/bitshift/query/nodes.py @@ -1,6 +1,6 @@ from ..languages import LANGS -__all__ = ["String", "Regex", "Text", "Language", "Date", "Author", "Symbol", +__all__ = ["String", "Regex", "Text", "Language", "Author", "Date", "Symbol", "BinaryOp", "UnaryOp"] class _Node(object): @@ -80,6 +80,19 @@ class Language(_Node): return "Language({0})".format(LANGS[self.lang]) +class Author(_Node): + """Represents a author node. + + Searches in the author_name field (full-text search). + """ + + def __init__(self, name): + self.name = name + + def __repr__(self): + return "Author({0})".format(self.name) + + class Date(_Node): """Represents a date node. @@ -108,19 +121,6 @@ class Date(_Node): return tm.format(types[self.type], relations[self.relation], self.date) -class Author(_Node): - """Represents a author node. - - Searches in the author_name field (full-text search). - """ - - def __init__(self, name): - self.name = name - - def __repr__(self): - return "Author({0})".format(self.name) - - class Symbol(_Node): """Represents a symbol node. diff --git a/setup.py b/setup.py index 48d4c42..5ab7a7c 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,8 @@ setup( packages = find_packages(), install_requires = [ "Flask>=0.10.1", "pygments>=1.6", "requests>=2.2.0", - "beautifulsoup4>=3.2.1", "oursql>=0.9.3.1", "mmh3>=2.3"], + "beautifulsoup4>=3.2.1", "oursql>=0.9.3.1", "mmh3>=2.3", + "python-dateutil>=2.2"], author = "Benjamin Attal, Ben Kurtovic, Severyn Kozak", license = "MIT", url = "https://github.com/earwig/bitshift"