import sys from future.standard_library import install_aliases install_aliases() from urllib import request, parse from rdflib import Graph, term, Namespace, BNode from lxml import etree import IPython js = "IPython.CodeCell.options_default.highlight_modes['magic_turtle'] = {'reg':[/^%%ttl/]};" IPython.core.display.display_javascript(js, raw=True) from IPython.core.magic import (register_line_magic, register_cell_magic, register_line_cell_magic) from IPython.display import HTML, display, Image, Markdown DEFINITIONS = {} def solution(exercise='default'): if exercise not in DEFINITIONS: raise Exception('Solution for {} not found. Have you defined it?'.format(exercise)) return DEFINITIONS[exercise] @register_cell_magic def ttl(line, cell): ''' TTL magic command for ipython. It can be used in a cell like this: ``` %%ttl ... Your TTL definition ... ``` The definition will be loaded into a DEFINITION variable, using RDFlib. This definition can then be used for evaluation. ''' g = Graph() msg = '''Error on line {line} Reason: {reason} If you don\'t know what this error means, try an online validator: http://ttl.summerofcode.be/ ''' global DEFINITIONS key = line or 'default' DEFINITIONS[key] = None try: DEFINITIONS[key] = g.parse(data=cell, format="n3") except SyntaxError as ex: print(msg.format(line=ex.lines, reason=ex._why), file=sys.stderr) raise Exception('Bad Turtle syntax') from None except Exception as ex: print(msg.format(line='?', reason=ex), file=sys.stderr) raise Exception('Bad Turtle syntax') from None return Markdown('The Turtle syntax is correct.') def extract_data(url): g = Graph() try: g.parse(url, format='rdfa') except Exception: print('Could not get rdfa data', file=sys.stderr) try: g.parse(url, format='microdata') except Exception: print('Could not get microdata', file=sys.stderr) def sanitize_triple(t): """Function to remove bad URIs from the graph that would otherwise make the serialization fail.""" def sanitize_triple_item(item): if isinstance(item, term.URIRef) and ' ' in item: return term.URIRef(parse.quote(str(item))) return item return (sanitize_triple_item(t[0]), sanitize_triple_item(t[1]), sanitize_triple_item(t[2])) with request.urlopen(url) as response: # Get all json-ld objects embedded in the html file html = response.read().decode('utf-8', errors='ignore') parser = etree.XMLParser(recover=True) root = etree.fromstring(html.encode(), parser=parser) if root is not None and len(root): for jsonld in root.findall(".//script[@type='application/ld+json']"): g.parse(data=jsonld.text, publicID=BNode(), format='json-ld') fixedgraph = Graph() fixedgraph += [sanitize_triple(s) for s in g] return fixedgraph def turtle(g): return Markdown(''' Results: ```turtle {} ``` '''.format(g.serialize(format='turtle').decode('utf-8', errors='ignore'))) def print_data(url): g = extract_data(url) return turtle(g) def check(testname): import tests test = getattr(tests, 'test_{}'.format(testname), None) if test is None: raise Exception('There are no tests for {}'.format(testname)) definition = solution(testname) if definition is None: raise Exception('The definition for {} is empty or invalid.'.format(testname)) return test(definition)