From 5051a0c15fc2c4a871114c641fcff3b34dae5187 Mon Sep 17 00:00:00 2001 From: Paul Makepeace Date: Mon, 25 Apr 2011 01:08:53 -0400 Subject: [PATCH] Add {Starred,Flagged}Facet, and {star,flag}_row. Allow get_rows to have a facets param. Add remove_rows(). --- google/refine.py | 38 +++++++++++++++++++++++++++++++++++++- google/test/test_engine.py | 10 +++++++++- google/test/test_refine.py | 27 ++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/google/refine.py b/google/refine.py index 6595440..1b61906 100644 --- a/google/refine.py +++ b/google/refine.py @@ -79,6 +79,22 @@ class TextFacet(Facet): self.selection = [] +class StarredFacet(TextFacet): + def __init__(self, selection=None): + if selection is not None and not isinstance(selection, bool): + raise ValueError('selection must be True or False.') + super(StarredFacet, self).__init__('', + expression='row.starred', selection=selection) + + +class FlaggedFacet(TextFacet): + def __init__(self, selection=None): + if selection is not None and not isinstance(selection, bool): + raise ValueError('selection must be True or False.') + super(FlaggedFacet, self).__init__('', + expression='row.flagged', selection=selection) + + # Capitalize 'From' to get around python's reserved word. class NumericFacet(Facet): def __init__(self, column, From=None, to=None, select_blank=True, select_error=True, select_non_numeric=True, select_numeric=True, **options): @@ -401,12 +417,19 @@ class RefineProject: {'engine': self.engine.as_json()}) return FacetsResponse(response) - def get_rows(self, start=0, limit=10): + def get_rows(self, facets=None, start=0, limit=10): + if facets: + self.engine = Engine(facets) response = self.do_json('get-rows', { 'sorting': "{'criteria': []}", 'engine': self.engine.as_json(), 'start': start, 'limit': limit}) return RowsResponse(response) + def remove_rows(self, facets=None): + if facets: + self.engine = Engine(facets) + return self.do_json('remove-rows', {'engine': self.engine.as_json()}) + def text_transform(self, column, expression, on_error='set-to-blank', repeat=False, repeat_count=10): response = self.do_json('text-transform', { @@ -457,3 +480,16 @@ class RefineProject: return [[{'value': x['v'], 'count': x['c']} for x in cluster] for cluster in response] + def annotate_one_row(self, row, annotation, state=True): + if annotation not in ('starred', 'flagged'): + raise ValueError('annotation must be one of starred or flagged') + state = 'true' if state == True else 'false' + return self.do_json('annotate-one-row', {'row': row.index, + annotation: state}) + + def flag_row(self, row, flagged=True): + return self.annotate_one_row(row, 'flagged', flagged) + + def star_row(self, row, starred=True): + return self.annotate_one_row(row, 'starred', starred) + diff --git a/google/test/test_engine.py b/google/test/test_engine.py index 0ba9c26..e328e92 100644 --- a/google/test/test_engine.py +++ b/google/test/test_engine.py @@ -13,7 +13,8 @@ import os import sys import unittest import urllib -from google.refine import Facet, TextFacet, NumericFacet, Engine, FacetsResponse +from google.refine import TextFacet, NumericFacet, StarredFacet, FlaggedFacet +from google.refine import Engine, FacetsResponse class FacetTest(unittest.TestCase): def test_init(self): @@ -24,6 +25,13 @@ class FacetTest(unittest.TestCase): facet = NumericFacet('column name', From=1, to=5) self.assertEqual(facet.to, 5) self.assertEqual(facet.From, 1) + facet = StarredFacet() + self.assertEqual(facet.expression, 'row.starred') + facet = StarredFacet(True) + self.assertEqual(facet.selection[0]['v']['v'], True) + facet = FlaggedFacet(False) + self.assertEqual(facet.selection[0]['v']['v'], False) + self.assertRaises(ValueError, FlaggedFacet, 'false') # no strings def test_serialize(self): engine = Engine() diff --git a/google/test/test_refine.py b/google/test/test_refine.py index 85d0f20..1e28490 100644 --- a/google/test/test_refine.py +++ b/google/test/test_refine.py @@ -11,7 +11,7 @@ import sys import os import unittest from google.refine import REFINE_HOST, REFINE_PORT -from google.refine import NumericFacet, TextFacet, Engine +from google.refine import NumericFacet, TextFacet, StarredFacet, Engine from google.refine import RefineServer, Refine, RefineProject from google.refine import to_camel, from_camel @@ -235,6 +235,31 @@ class TutorialTestEditing(RefineTestCase): response = self.project.compute_facets() self.assertEqual(len(response.facets[0].choices), 65) + # Section "4. Row and Column Editing" + # Test doesn't strictly follow the tutorial as the "Browse this + # cluster" performs a text facet which the server can't complete + # as it busts its max facet count. The useful work is done with + # get_rows(). Also, we can facet & select in one; the UI can't. + # {1}, {2}, {3}, {4} + clusters = self.project.compute_clusters('Candidate Name') + for cluster in clusters[0:3]: # just do a few + for match in cluster: + # {2} + if match['value'].endswith(', '): + response = self.project.get_rows( + TextFacet('Candidate Name', match['value'])) + self.assertEqual(len(response.rows), 1) + for row in response.rows: + response = self.project.star_row(row) + self.assertTrue(str(row.index + 1) in + response['historyEntry']['description']) + # {5}, {6}, {7} + response = self.project.compute_facets(StarredFacet(True)) + self.assertEqual(len(response.facets[0].choices), 2) # true & false + self.assertEqual(response.facets[0].choices[True].count, 3) + response = self.project.remove_rows() + self.assertTrue('3 rows' in response['historyEntry']['description']) + if __name__ == '__main__': unittest.main() \ No newline at end of file