11"""
22The class used to manage the connection to SPARQL endpoint: send queries and
3- format results for notebook display. Also process all the defined magics
3+ format results for notebook display.
44"""
55
66from __future__ import print_function
4949 SPARQLWrapper .XML : set (_SPARQL_XML )
5050}
5151
52- # ----------------------------------------------------------------------
53-
54- # The list of implemented magics with their help, as a pair [param,help-text]
55- magics = {
56- '%lsmagics' : ['' , 'list all magics' ],
57- '%endpoint' : ['<url>' , 'set SPARQL endpoint. **REQUIRED**' ],
58- '%auth' : ['(basic|digest|none) <username> <passwd>' , 'send HTTP authentication' ],
59- '%qparam' : ['<name> [<value>]' , 'add (or delete) a persistent custom parameter to all queries' ],
60- '%http_header' : ['<name> [<value>]' , 'add (or delete) an arbitrary HTTP header to all queries' ],
61- '%prefix' : ['<name> [<uri>]' , 'set (or delete) a persistent URI prefix for all queries' ],
62- '%header' : ['<string> | OFF' , 'add a persistent SPARQL header line before all queries, or delete all defined headers' ],
63- '%graph' : ['<uri>' , 'set default graph for the queries' ],
64- '%format' : ['JSON | N3 | XML | default | any | none' , 'set requested result format' ],
65- '%display' : ['raw | table [withtypes] | diagram [svg|png] [withliterals]' ,
66- 'set display format' ],
67- '%lang' : ['<lang> [...] | default | all' ,
68- 'language(s) preferred for labels' ],
69- '%show' : ['<n> | all' ,
70- 'maximum number of shown results' ],
71- '%outfile' : ['<filename> | off' , 'save raw output to a file (use "%d" in name to add cell number, "off" to cancel saving)' ],
72- '%log' : ['critical | error | warning | info | debug' ,
73- 'set logging level' ],
74- '%method' : ['get | post' , 'set HTTP method' ],
75- }
76-
77- # The full list of all magics
78- magic_help = ('Available magics:\n ' +
79- ' ' .join (sorted (magics .keys ())) +
80- '\n \n ' +
81- '\n ' .join (('{0} {1} : {2}' .format (k , * v )
82- for k , v in sorted (magics .items (), key = itemgetter (0 )))))
83-
84-
8552# ----------------------------------------------------------------------
8653
8754def cleanhtml (raw_html , ctype ):
@@ -375,11 +342,16 @@ def render_graph(result, cfg, **kwargs):
375342
376343class CfgStruct :
377344 """
378- A simple class containing a bunch of fields
345+ A simple class containing a bunch of fields. Equivalent to Python3
346+ SimpleNamespace
379347 """
380348 def __init__ (self , ** entries ):
381349 self .__dict__ .update (entries )
382350
351+ def __repr__ (self ):
352+ return '<' + ' ' .join ('{}={!r}' .format (* kv )
353+ for kv in self .__dict__ .items ()) + '>'
354+
383355
384356# ----------------------------------------------------------------------
385357
@@ -394,198 +366,19 @@ def __init__(self, logger=None):
394366 self .log .info ("START" )
395367 self .cfg = CfgStruct (hdr = [], pfx = {}, lmt = 20 , fmt = None , out = None , aut = None ,
396368 grh = None , dis = 'table' , typ = False , lan = [], par = {},
397- mth = 'GET' , hhr = KeyCaseInsensitiveDict ())
398-
399- def magic (self , line ):
400- """
401- Read and process magics
402- @param line (str): the full line containing a magic
403- @return (list): a tuple (output-message,css-class), where
404- the output message can be a single string or a list (containing
405- a Python format string and its arguments)
406- """
407- # The %lsmagic has no parameters
408- if line .startswith ('%lsmagic' ):
409- return magic_help , 'magic-help'
410-
411- # Split line into command & parameters
412- try :
413- cmd , param = line .split (None , 1 )
414- except ValueError :
415- raise KrnlException ("invalid magic: {}" , line )
416- cmd = cmd [1 :].lower ()
417-
418- # Process each magic
419- if cmd == 'endpoint' :
420-
421- self .srv = SPARQLWrapper .SPARQLWrapper (param )
422- return ['Endpoint set to: {}' , param ], 'magic'
423-
424- elif cmd == 'auth' :
425-
426- auth_data = param .split (None , 2 )
427- if auth_data [0 ].lower () == 'none' :
428- self .cfg .aut = None
429- return ['HTTP authentication: None' ], 'magic'
430- if auth_data and len (auth_data ) != 3 :
431- raise KrnlException ("invalid %auth magic" )
432- self .cfg .aut = auth_data
433- return ['HTTP authentication: {}' , auth_data ], 'magic'
434-
435- elif cmd == 'qparam' :
436-
437- v = param .split (None , 1 )
438- if len (v ) == 0 :
439- raise KrnlException ("missing %qparam name" )
440- elif len (v ) == 1 :
441- self .cfg .par .pop (v [0 ], None )
442- return ['Param deleted: {}' , v [0 ]], 'magic'
443- else :
444- self .cfg .par [v [0 ]] = v [1 ]
445- return ['Param set: {} = {}' ] + v , 'magic'
446-
447- elif cmd == 'http_header' :
448-
449- v = param .split (None , 1 )
450- if len (v ) == 0 :
451- raise KrnlException ("missing %http_header name" )
452- elif len (v ) == 1 :
453- try :
454- del self .cfg .hhr [v [0 ]]
455- return ['HTTP header deleted: {}' , v [0 ]], 'magic'
456- except KeyError :
457- return ['Not-existing HTTP header: {}' , v [0 ]], 'magic'
458- else :
459- self .cfg .hhr [v [0 ]] = v [1 ]
460- return ['HTTP header set: {} = {}' ] + v , 'magic'
461-
462- elif cmd == 'prefix' :
463-
464- v = param .split (None , 1 )
465- if len (v ) == 0 :
466- raise KrnlException ("missing %prefix value" )
467- elif len (v ) == 1 :
468- self .cfg .pfx .pop (v [0 ], None )
469- return ['Prefix deleted: {}' , v [0 ]], 'magic'
470- else :
471- self .cfg .pfx [v [0 ]] = v [1 ]
472- return ['Prefix set: {} = {}' ] + v , 'magic'
473-
474- elif cmd == 'show' :
475-
476- if param == 'all' :
477- self .cfg .lmt = None
478- else :
479- try :
480- self .cfg .lmt = int (param )
481- except ValueError as e :
482- raise KrnlException ("invalid result limit: {}" , e )
483- sz = self .cfg .lmt if self .cfg .lmt is not None else 'unlimited'
484- return ['Result maximum size: {}' , sz ], 'magic'
485-
486- elif cmd == 'format' :
487-
488- fmt_list = {'JSON' : SPARQLWrapper .JSON ,
489- 'N3' : SPARQLWrapper .N3 ,
490- 'XML' : SPARQLWrapper .XML ,
491- 'RDF' : SPARQLWrapper .RDF ,
492- 'NONE' : None ,
493- 'DEFAULT' : True ,
494- 'ANY' : False }
495- try :
496- fmt = param .upper ()
497- self .cfg .fmt = fmt_list [fmt ]
498- except KeyError :
499- raise KrnlException ('unsupported format: {}\n Supported formats are: {!s}' , param , list (fmt_list .keys ()))
500- return ['Request format: {}' , fmt ], 'magic'
501-
502- elif cmd == 'lang' :
503-
504- self .cfg .lan = DEFAULT_TEXT_LANG if param == 'default' else [] if param == 'all' else param .split ()
505- return ['Label preferred languages: {}' , self .cfg .lan ], 'magic'
506-
507- elif cmd in 'graph' :
508-
509- self .cfg .grh = param if param else None
510- return ['Default graph: {}' , param if param else 'None' ], 'magic'
511-
512- elif cmd == 'display' :
513-
514- v = param .lower ().split (None , 2 )
515- if len (v ) == 0 or v [0 ] not in ('table' , 'raw' , 'graph' , 'diagram' ):
516- raise KrnlException ('invalid %display command: {}' , param )
517-
518- msg_extra = ''
519- if v [0 ] not in ('diagram' , 'graph' ):
520- self .cfg .dis = v [0 ]
521- self .cfg .typ = len (v ) > 1 and v [1 ].startswith ('withtype' )
522- if self .cfg .typ and self .cfg .dis == 'table' :
523- msg_extra = '\n Show Types: on'
524- elif len (v ) == 1 : # graph format, defaults
525- self .cfg .dis = ['svg' ]
526- else : # graph format, with options
527- if v [1 ] not in ('png' , 'svg' ):
528- raise KrnlException ('invalid graph format: {}' , param )
529- if len (v ) > 2 :
530- if not v [2 ].startswith ('withlit' ):
531- raise KrnlException ('invalid graph option: {}' , param )
532- msg_extra = '\n Show literals: on'
533- self .cfg .dis = v [1 :3 ]
534-
535- display = self .cfg .dis [0 ] if is_collection (self .cfg .dis ) else self .cfg .dis
536- return ['Display: {}{}' , display , msg_extra ], 'magic'
537-
538- elif cmd == 'outfile' :
539-
540- if param in ('NONE' , 'OFF' ):
541- self .cfg .out = None
542- return ['no output file' ], 'magic'
543- else :
544- self .cfg .out = param
545- return ['Output file: {}' , os .path .abspath (param )], 'magic'
546-
547- elif cmd == 'log' :
548-
549- if not param :
550- raise KrnlException ('missing log level' )
551- try :
552- lev = param .upper ()
553- parent_logger = logging .getLogger (__name__ .rsplit ('.' , 1 )[0 ])
554- parent_logger .setLevel (lev )
555- return ("Logging set to {}" , lev ), 'magic'
556- except ValueError :
557- raise KrnlException ('unknown log level: {}' , param )
558-
559- elif cmd == 'header' :
560-
561- if param .upper () == 'OFF' :
562- num = len (self .cfg .hdr )
563- self .cfg .hdr = []
564- return ['All headers deleted ({})' , num ], 'magic'
565- else :
566- if param in self .cfg .hdr :
567- return ['Header skipped (repeated)' ], 'magic'
568- self .cfg .hdr .append (param )
569- return ['Header added: {}' , param ], 'magic'
570-
571- elif cmd == 'method' :
572-
573- method = param .upper ()
574- if method not in ('GET' , 'POST' ):
575- raise KrnlException ('invalid HTTP method: {}' , param )
576- self .cfg .mth = method
577- return ['HTTP method: {}' , method ], 'magic'
578-
579- else :
580- raise KrnlException ("magic not found: {}" , cmd )
369+ mth = 'GET' , hhr = KeyCaseInsensitiveDict (), ept = None )
581370
582371
583372 def query (self , query , num = 0 , silent = False ):
584373 """
585374 Launch an SPARQL query, process & convert results and return them
586375 """
587- if self .srv is None :
376+ self .log .debug ("CONFIG: %s" , self .cfg )
377+ # Create server object, if needed
378+ if self .cfg .ept is None :
588379 raise KrnlException ('no endpoint defined' )
380+ elif self .srv is None or self .srv .endpoint != self .cfg .ept :
381+ self .srv = SPARQLWrapper .SPARQLWrapper (self .cfg .ept )
589382
590383 # Add to the query all predefined SPARQL prefixes
591384 if self .cfg .pfx :
0 commit comments