From 7c4779b45d37b3712d2cdf4c5f5797bda2e99e94 Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:34:09 +0200 Subject: [PATCH 1/7] Add .ropeproject to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8a33731..64b074c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.pyc .not/ +.ropeproject/ From 8a6d653c4798b668ca195aa4d34737e303936797 Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:39:25 +0200 Subject: [PATCH 2/7] Normalize only URIRefs Check if given ref is actually a URIRef, before trying to normalize it. --- rdfcli/model.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rdfcli/model.py b/rdfcli/model.py index 602fc92..1eaff35 100644 --- a/rdfcli/model.py +++ b/rdfcli/model.py @@ -59,7 +59,12 @@ def get_reverse_properties(self, obj): return properties def norm(self, ref): - return self.graph.namespace_manager.normalizeUri(ref) if ref else None + if ref is None: + return None + elif isinstance(ref, URIRef): + return self.graph.namespace_manager.normalizeUri(ref) + else: + return unicode(ref) def to_uriref(self, string): """Expand QName to UriRef based on existing namespaces.""" From c74538c07e3b72966b8b70a6e6695ed3a0e3dda0 Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:41:35 +0200 Subject: [PATCH 3/7] Use unicode_literals Eventually this code should be migrated to Python 3, so using unicode_literals is a good start. --- test/test_controller.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_controller.py b/test/test_controller.py index 4d871a0..7656ba7 100644 --- a/test/test_controller.py +++ b/test/test_controller.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +from __future__ import unicode_literals + import unittest from rdflib import Graph from rdflib.namespace import Namespace, RDF, FOAF @@ -38,10 +40,10 @@ def test_ls(self): result = self.controller.ls(None) self.assertIn(FOAF.Person, result[RDF.type]) self.assertIn(Literal('Spiderman'), result[FOAF.name]) - self.assertIn(Literal(u'Человек-паук', lang=u'ru'), result[FOAF.name]) + self.assertIn(Literal('Человек-паук', lang='ru'), result[FOAF.name]) result = self.controller.ls('foaf:name') self.assertIn(Literal('Spiderman'), result) - self.assertIn(Literal(u'Человек-паук', lang=u'ru'), result) + self.assertIn(Literal('Человек-паук', lang='ru'), result) def test_is(self): self.controller.go(N.spiderman) From 793fa6684e05a37aefbed74d5eff5b5107f3440b Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:43:08 +0200 Subject: [PATCH 4/7] Remove unused imports and variable assignements This makes pyflakes happy. --- test/test_controller.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/test_controller.py b/test/test_controller.py index 7656ba7..0745920 100644 --- a/test/test_controller.py +++ b/test/test_controller.py @@ -3,9 +3,8 @@ from __future__ import unicode_literals import unittest -from rdflib import Graph from rdflib.namespace import Namespace, RDF, FOAF -from rdflib.term import URIRef, Literal +from rdflib.term import Literal from rdfcli.controller import Controller from rdfcli.model import Model @@ -75,16 +74,16 @@ def test_bw(self): def test_forward(self): self.controller.go(N.spiderman) self.controller.back() - result = self.controller.forward() + self.controller.forward() self.assertEqual(N.spiderman, self.controller.current) def test_back(self): self.controller.go(N.spiderman) - result = self.controller.back() + self.controller.back() self.assertEqual(None, self.controller.current) def test_this(self): self.controller.go(N.spiderman) - result = self.controller.this() + self.controller.this() self.assertEqual(N.spiderman, self.controller.current) From 0d7f957f30a61f51a47a231e913015d6b83daf8e Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:50:33 +0200 Subject: [PATCH 5/7] Fix failing tests caused by global Model.load monkey patching Here, Model.load was monkey patched globally and running all tests gives this error: ====================================================================== FAIL: test_load_local_file (test.test_model.TestModel) ---------------------------------------------------------------------- Traceback (most recent call last): t/test_model.py|25| in test_load_local_file self.assertEqual(len(self.model.graph), 213) AssertionError: 7 != 213 So instead of monkey patching Model class, I just created FakeModel with overridden `load` method. After this, all tests pass: $ nosetests test ........................ ---------------------------------------------------------------------- Ran 24 tests in 0.777s OK --- test/test_controller.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/test_controller.py b/test/test_controller.py index 0745920..3cf34da 100644 --- a/test/test_controller.py +++ b/test/test_controller.py @@ -12,18 +12,17 @@ N = Namespace('http://example.org/#') REL = Namespace('http://www.perceive.net/schemas/relationship/') + +class FakeModel(Model): + def load(self, source, format=None): + self.graph.parse('test/fixture.rdf') + + class TestController(unittest.TestCase): def setUp(self): self.controller = Controller() - - # stub Model.load to load only a local file - def load_stub(self, source, format=None): - self.graph.parse('test/fixture.rdf') - - Model.load = load_stub - model = Model() - self.controller.set_model(model) + self.controller.set_model(FakeModel()) self.controller.load('test/fixture.rdf') def test_initialization(self): From 82fe643d54a8f8ba56d1f83fce9be9971fd2af36 Mon Sep 17 00:00:00 2001 From: Mantas Date: Wed, 31 Dec 2014 10:51:20 +0200 Subject: [PATCH 6/7] select command for sparql select queries With this change it is possible to query active graph with SPARQL SELECT query, like this: > http://www.w3.org/ns/dcat> select distinct ?o where { ?s rdfs:label ?o . filter(lang(?o) = "") } +------------------------------+ | o | +------------------------------+ | Download (Deprecated) | | granularity (Deprecated) | | data quality (Deprecated) | | data dictionary (Deprecated) | | size (Deprecated) | | Web Service (Deprecated) | | size in bytes (Deprecated) | | Feed (Deprecated) | +------------------------------+ --- rdfcli/controller.py | 16 ++++++++++++++++ rdfcli/model.py | 3 ++- rdfcli/view.py | 15 +++++++++++++++ requirements.txt | 1 + test/test_controller.py | 14 ++++++++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/rdfcli/controller.py b/rdfcli/controller.py index 5bceef3..8e592b4 100644 --- a/rdfcli/controller.py +++ b/rdfcli/controller.py @@ -1,3 +1,5 @@ +import operator + from history import History class Controller: @@ -129,3 +131,17 @@ def types(self): def norm(self, ref): return self.model.norm(ref) + def select(self, query): + cols = None + rows = [] + sortkey = operator.itemgetter(1) + for row in self.model.select(query): + values = [] + if cols is None: + cols = [ + col for col, _ in sorted(row.labels.items(), key=sortkey) + ] + for col in cols: + values.append(self.norm(row[col])) + rows.append(values) + return cols, rows diff --git a/rdfcli/model.py b/rdfcli/model.py index 1eaff35..35c00e0 100644 --- a/rdfcli/model.py +++ b/rdfcli/model.py @@ -80,4 +80,5 @@ def to_uriref(self, string): else: return URIRef(string) - + def select(self, query): + return self.graph.query(query) diff --git a/rdfcli/view.py b/rdfcli/view.py index 09770e0..f707153 100644 --- a/rdfcli/view.py +++ b/rdfcli/view.py @@ -1,4 +1,6 @@ +import pyparsing from cmd import Cmd +from prettytable import PrettyTable HELP_MSG = ''' Commands: @@ -16,6 +18,7 @@ f # Go forward in history b # Go back in history hist # Print history stack. + select # SPARQL SELECT query, example: select distinct ?p where { ?s ?p ?o } order by ?p help # Print this help. exit # Exit. ''' @@ -148,6 +151,18 @@ def do_types(self, params): for type_ in types: print self.__norm(type_) + def do_select(self, params): + try: + cols, rows = self.controller.select('select %s' % params) + except pyparsing.ParseException as e: + print e + else: + table = PrettyTable(cols) + table.align = 'l' + for row in rows: + table.add_row(row) + print table + def __norm(self, ref, trim=False): res = self.controller.norm(ref) if trim and res[0] == '<' and res[-1] == '>': diff --git a/requirements.txt b/requirements.txt index 10b9c0b..053ff5e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ pyparsing==1.5.7 rdflib==4.0.1 six==1.4.1 wsgiref==0.1.2 +prettytable==0.7.2 diff --git a/test/test_controller.py b/test/test_controller.py index 3cf34da..3530f78 100644 --- a/test/test_controller.py +++ b/test/test_controller.py @@ -86,3 +86,17 @@ def test_this(self): self.controller.this() self.assertEqual(N.spiderman, self.controller.current) + def test_select(self): + self.controller.go(N.spiderman) + self.controller.model.graph.bind('ex', 'http://example.org/#') + cols, rows = self.controller.select('select ?s ?p ?o where { ?s ?p ?o . }') + self.assertEqual(cols, ['s', 'p', 'o']) + self.assertEqual(sorted(rows), [ + ['ex:green_goblin', 'foaf:name', 'Green Goblin'], + ['ex:green_goblin', 'rdf:type', 'foaf:Person'], + ['ex:green_goblin', 'rel:enemyOf', 'ex:spiderman'], + ['ex:spiderman', 'foaf:name', 'Spiderman'], + ['ex:spiderman', 'foaf:name', 'Человек-паук'], + ['ex:spiderman', 'rdf:type', 'foaf:Person'], + ['ex:spiderman', 'rel:enemyOf', 'ex:green_goblin'], + ]) From 0eac81768213b21adf607d0d3de8045c76e4105a Mon Sep 17 00:00:00 2001 From: Mantas Date: Fri, 2 Jan 2015 16:50:25 +0200 Subject: [PATCH 7/7] README.md update --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ee7bfe7..db29c64 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Commands: f # Go forward in history b # Go back in history hist # Print history stack. + select # SPARQL SELECT query, example: select distinct ?p where { ?s ?p ?o } order by ?p help # Print this help. exit # Exit.