├── .gitignore ├── COPYING.txt ├── ChangeLog.txt ├── README.md ├── apps └── demo │ ├── __init__.py │ ├── config.n3 │ ├── log.py │ ├── manage.py │ ├── settings.py │ └── urls.py ├── doc └── images │ ├── djubby.png │ └── djubby.vsd └── lib ├── MANIFEST.in ├── djubby ├── __init__.py ├── configuration.py ├── dispatcher.py ├── http.py ├── ns.py ├── rdf.py ├── resource.py └── uri.py ├── ez_setup.py ├── setup.py └── tpl └── resource.tpl /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | 167 | -------------------------------------------------------------------------------- /ChangeLog.txt: -------------------------------------------------------------------------------- 1 | djubby's changelog: 2 | ------------------ 3 | 4 | 0.1.8 (28/04/2010): 5 | * Fixed problem distributing templates on the tarball (issue #1) 6 | 7 | 0.1.7 (27/04/2010): 8 | * Fixed issue with empty values for conf:webResourcePrefix 9 | * Refactorized URI module 10 | * Added support to conf:fixUnescapedCharacters 11 | 12 | 0.1.6 (21/04/2010): 13 | * Fixed issue getting documents' URL with the new URIs scheme 14 | 15 | 0.1.5 (20/04/2010): 16 | * Added N3 support 17 | 18 | 0.1.4 (16/04/2010): 19 | * Improved HTML renderization 20 | 21 | 0.1.3 (15/04/2010): 22 | * Added CURIEs support 23 | * Implemented default language 24 | * Improved properties presentation style 25 | 26 | 0.1.2 (15/04/2010): 27 | * Allowing to serve resources from different web base URI 28 | * Added support to ASK queries over Virtuoso endpoints 29 | 30 | 0.1.1 (13/04/2010): 31 | * Added some cosmetic details to the HTML renderization 32 | 33 | 0.1.0 (13/04/2010): 34 | * First public release with the core features 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project is currently **not maintained**, so please use it under your own risk. 2 | 3 | # Djubby, a Linked Data frontend for SPARQL endpoints 4 | 5 | Djubby is a Linked Data frontend for SPARQL endpoints for the Django Web framework. 6 | It's quite inspired by Richard Cyganiak's [Pubby](http://wifo5-03.informatik.uni-mannheim.de/pubby/), 7 | and with the exception of the HTML style, all the code has beed written from scratch 8 | due the many differences between languages (Java vs. Python) and the frameworks (JavaEE vs. Django). 9 | 10 | ![djubby](https://raw.githubusercontent.com/wikier/djubby/master/doc/images/djubby.png) 11 | 12 | More information at: https://github.com/wikier/djubby 13 | 14 | ## Features 15 | 16 | * Provides a Linked Data interface to local or remote SPARQL protocol servers. 17 | * Provides dereferenceable URIs by rewriting URIs found in the SPARQL-exposed dataset into the djubby server's namespace. 18 | * Provides a simple HTML interface showing the data available about each resource. 19 | * Takes care of handling 303 redirects and content negotiation. 20 | * Compatible with the Django Web framework. 21 | 22 | ### Planned 23 | 24 | * Include a metadata extension to add metadata to the provided data. 25 | 26 | ### Limitations 27 | 28 | * Only works for SPARQL endpoint that can answer ASK and DESCRIBE queries. 29 | * Multiple dataset support may not work as expected, so it is recommended to simply set up a separate djubby instance for each dataset. 30 | 31 | ## Dependencies 32 | 33 | * RDFLib >= 2.4.0 34 | * SPARQLWrapper >= 1.3.2 35 | * Django >= 1.1.0 36 | * mimeparse >= 0.1.2 37 | 38 | ## Usage 39 | 40 | ### Installation 41 | 42 | cd lib/ 43 | sudo python setup.py install 44 | 45 | ## Authors 46 | 47 | * [Sergio Fernández](http://www.wikier.org) 48 | 49 | ## License 50 | 51 | GNU Library or Lesser General Public License (LGPL) v3, http://www.gnu.org/licenses/lgpl.html 52 | -------------------------------------------------------------------------------- /apps/demo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wikier/djubby/f001565c095d9dd84617b50dbf19ee500105bf62/apps/demo/__init__.py -------------------------------------------------------------------------------- /apps/demo/config.n3: -------------------------------------------------------------------------------- 1 | # djubby Example Configuration 2 | # 3 | # This configuration connects to the DBpedia SPARQL endpoint and 4 | # re-publishes on your local machine, with dereferenceable 5 | # localhost URIs. 6 | # 7 | # This assumes you already have a servlet container running 8 | # on your machine at http://localhost:8080/ . 9 | # 10 | # Install djubby library and make sure the django's settings.py 11 | # points to this configuration file. 12 | # 13 | # Start your application, and then browse to http://127.0.0.1:8000/ 14 | 15 | # Prefix declarations to be used in RDF output 16 | @prefix conf: . 17 | @prefix meta: . 18 | @prefix rdf: . 19 | @prefix rdfs: . 20 | @prefix xsd: . 21 | @prefix owl: . 22 | @prefix dc: . 23 | @prefix dcterms: . 24 | @prefix foaf: . 25 | @prefix skos: . 26 | @prefix geo: . 27 | @prefix dbpedia: . 28 | @prefix o: . 29 | @prefix p: . 30 | @prefix yago: . 31 | @prefix units: . 32 | @prefix geonames: . 33 | @prefix prv: . 34 | @prefix prvTypes: . 35 | 36 | # Server configuration section 37 | <> a conf:Configuration; 38 | # Project name for display in page titles 39 | conf:projectName "djubby demo with dbpedia"; 40 | # Homepage with description of the project for the link in the page header 41 | conf:projectHomepage ; 42 | # The Pubby root, where the webapp is running inside the servlet container. 43 | conf:webBase ; 44 | # URL of an RDF file whose prefix mapping is to be used by the 45 | # server; defaults to <>, which is *this* file. 46 | conf:usePrefixesFrom <>; 47 | # If labels and descriptions are available in multiple languages, 48 | # prefer this one. 49 | conf:defaultLanguage "en"; 50 | # When the homepage of the server is accessed, this resource will 51 | # be shown. 52 | conf:indexResource ; 53 | 54 | # Dataset configuration section #1 (for DBpedia resources) 55 | # 56 | # URIs in the SPARQL endpoint: http://dbpedia.org/resource/* 57 | # URIs on the Web: http://localhost:8080/resource/* 58 | conf:dataset [ 59 | # SPARQL endpoint URL of the dataset 60 | conf:sparqlEndpoint ; 61 | # Default graph name to query (not necessary for most endpoints) 62 | conf:sparqlDefaultGraph ; 63 | # Common URI prefix of all resource URIs in the SPARQL dataset 64 | conf:datasetBase ; 65 | # Will be appended to the conf:webBase to form the public 66 | # resource URIs; if not present, defaults to "" 67 | conf:webResourcePrefix "resource/"; 68 | # Fixes an issue with the server running behind an Apache proxy; 69 | # can be ignored otherwise 70 | conf:fixUnescapedCharacters "(),'!$&*+;=@"; 71 | 72 | # include metadata 73 | conf:metadataTemplate "metadata.n3"; 74 | 75 | # configure your metadata here 76 | # Use properties with the meta: prefix where the property name 77 | # corresponds to the placeholder URIs in metadata.n3 that begin 78 | # with about:metadata:metadata: 79 | # Examples for such properties are: 80 | # meta:pubbyUser ; 81 | # meta:pubbyOperator ; 82 | # meta:endpointUser ; 83 | # meta:endpointOperator ; 84 | ]; 85 | 86 | . 87 | 88 | -------------------------------------------------------------------------------- /apps/demo/log.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # python logging trick for django, based on http://stackoverflow.com/questions/342434/python-logging-in-django 4 | 5 | import sys 6 | import logging 7 | 8 | logInitDone = False 9 | if not logInitDone: 10 | logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s: %(message)s", stream=sys.stdout) 11 | logInitDone = True 12 | 13 | -------------------------------------------------------------------------------- /apps/demo/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from django.core.management import execute_manager 3 | try: 4 | import settings # Assumed to be in the same directory. 5 | except ImportError: 6 | import sys 7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) 8 | sys.exit(1) 9 | 10 | if __name__ == "__main__": 11 | execute_manager(settings) 12 | 13 | -------------------------------------------------------------------------------- /apps/demo/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for demo project. 2 | 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | ADMINS = ( 7 | # ('Your Name', 'your_email@domain.com'), 8 | ) 9 | 10 | MANAGERS = ADMINS 11 | 12 | DATABASE_ENGINE = '' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. 13 | DATABASE_NAME = '' # Or path to database file if using sqlite3. 14 | DATABASE_USER = '' # Not used with sqlite3. 15 | DATABASE_PASSWORD = '' # Not used with sqlite3. 16 | DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. 17 | DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. 18 | 19 | # Local time zone for this installation. Choices can be found here: 20 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 21 | # although not all choices may be available on all operating systems. 22 | # If running in a Windows environment this must be set to the same as your 23 | # system time zone. 24 | TIME_ZONE = 'America/Chicago' 25 | 26 | # Language code for this installation. All choices can be found here: 27 | # http://www.i18nguy.com/unicode/language-identifiers.html 28 | LANGUAGE_CODE = 'en-us' 29 | 30 | SITE_ID = 1 31 | 32 | # If you set this to False, Django will make some optimizations so as not 33 | # to load the internationalization machinery. 34 | USE_I18N = True 35 | 36 | # Absolute path to the directory that holds media. 37 | # Example: "/home/media/media.lawrence.com/" 38 | MEDIA_ROOT = '' 39 | 40 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 41 | # trailing slash if there is a path component (optional in other cases). 42 | # Examples: "http://media.lawrence.com", "http://example.com/media/" 43 | MEDIA_URL = '' 44 | 45 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a 46 | # trailing slash. 47 | # Examples: "http://foo.com/media/", "/media/". 48 | ADMIN_MEDIA_PREFIX = '/media/' 49 | 50 | # Make this unique, and don't share it with anybody. 51 | SECRET_KEY = '4k(p2jgcm6-q1i7oky55ko6ftq$xrk@ec#v(&+3oe6)=km)2m9' 52 | 53 | # List of callables that know how to import templates from various sources. 54 | TEMPLATE_LOADERS = ( 55 | 'django.template.loaders.filesystem.load_template_source', 56 | 'django.template.loaders.app_directories.load_template_source', 57 | # 'django.template.loaders.eggs.load_template_source', 58 | ) 59 | 60 | MIDDLEWARE_CLASSES = ( 61 | 'django.middleware.common.CommonMiddleware', 62 | 'django.contrib.sessions.middleware.SessionMiddleware', 63 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 64 | ) 65 | 66 | ROOT_URLCONF = 'demo.urls' 67 | 68 | TEMPLATE_DIRS = ( 69 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 70 | # Always use forward slashes, even on Windows. 71 | # Don't forget to use absolute paths, not relative paths. 72 | ) 73 | 74 | INSTALLED_APPS = ( 75 | 'django.contrib.auth', 76 | 'django.contrib.contenttypes', 77 | 'django.contrib.sessions', 78 | 'django.contrib.sites', 79 | ) 80 | 81 | import log 82 | 83 | DJUBBY_CONF = "config.n3" 84 | from djubby import Configuration 85 | conf = Configuration(DJUBBY_CONF) 86 | 87 | -------------------------------------------------------------------------------- /apps/demo/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls.defaults import * 2 | 3 | urlpatterns = patterns('', 4 | 5 | (r'^(.*)', 'djubby.dispatcher'), 6 | 7 | ) 8 | 9 | -------------------------------------------------------------------------------- /doc/images/djubby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wikier/djubby/f001565c095d9dd84617b50dbf19ee500105bf62/doc/images/djubby.png -------------------------------------------------------------------------------- /doc/images/djubby.vsd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wikier/djubby/f001565c095d9dd84617b50dbf19ee500105bf62/doc/images/djubby.vsd -------------------------------------------------------------------------------- /lib/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include tpl/*.tpl 2 | 3 | -------------------------------------------------------------------------------- /lib/djubby/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | __version__ = "0.1.9-dev" 22 | __authors__ = "Sergio Fernández" 23 | __license__ = "GNU Library or Lesser General Public License (LGPL) v3" 24 | __contact__ = "sergio@wikier.org" 25 | __date__ = "2014-09-01" 26 | __agent__ = "djubby %s (http://github.com/wikier/djubby)" % __version__ 27 | 28 | # Some common stuff for network: 29 | import socket 30 | import urllib2 31 | socket.setdefaulttimeout(10) 32 | 33 | # Making imports easier for users: 34 | from dispatcher import dispatcher 35 | from configuration import Configuration 36 | 37 | -------------------------------------------------------------------------------- /lib/djubby/configuration.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | import os 22 | import logging 23 | from django.conf import settings 24 | from rdflib.Graph import ConjunctiveGraph 25 | import rdf 26 | import ns 27 | 28 | class Configuration: 29 | """Configuration using the Borg design pattern""" 30 | 31 | __shared_state = { "data" : None, "path" : None, "graph" : None, "endpoint" : None} 32 | 33 | def __init__(self, path=None): 34 | self.__dict__ = self.__shared_state 35 | if (self.data == None): 36 | if (path == None): 37 | raise ValueError("djubby's configuration MUST be initialized a first time, read http://code.google.com/p/djubby/wiki/GettingStarted") 38 | else: 39 | self.path = os.path.abspath(path) 40 | logging.debug("Reading djubby's configuration from %s..." % self.path) 41 | if (not os.path.exists(self.path)): 42 | raise ValueError("Not found a proper file at '%s' with a configuration for djubby. Please, provide a right path" % self.path) 43 | 44 | data = ConjunctiveGraph() 45 | data.bind("conf", ns.config) 46 | try: 47 | data.load(path, format='n3') 48 | except Exception, e: 49 | raise ValueError("Not found a proper N3 file at '%s' with a configuration for djubby. Please, provide a valid N3 file" % self.path) 50 | 51 | self.data = data 52 | try: 53 | self.graph = self.get_value("sparqlDefaultGraph") 54 | self.endpoint = self.get_value("sparqlEndpoint") 55 | except Exception, e: 56 | raise ValueError("Not found the graph not the endpoint that it's supposed djubby have to query. Please, provide a right donfiguration") 57 | 58 | logging.info("Using <%s> as default graph to query the endpoint <%s>" % (self.graph, self.endpoint)) 59 | self.__class__.__dict__['_Configuration__shared_state']["data"] = data #FIXME 60 | 61 | def get_values(self, prop): 62 | return rdf.get_values(self.data, predicate=ns.config[prop]) 63 | 64 | def get_value(self, prop): 65 | return rdf.get_value(self.data, predicate=ns.config[prop]) 66 | 67 | -------------------------------------------------------------------------------- /lib/djubby/dispatcher.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | import logging 22 | from django.http import HttpResponse, HttpResponseRedirect, Http404 23 | from configuration import Configuration 24 | from resource import Resource 25 | from http import Http303, get_preferred_prefix, get_preferred_output, get_mimetype, url_handler 26 | from urllib2 import URLError 27 | 28 | def dispatcher(request, ref=None): 29 | logging.debug("Dispatching request on '%s'..." % ref) 30 | conf = Configuration() 31 | if (ref == None or len(ref) == 0): 32 | index = conf.get_value("indexResource") 33 | index = index.replace(conf.get_value("datasetBase"), conf.get_value("webBase")) 34 | logging.debug("Redirecting to the index resource...") 35 | return HttpResponseRedirect(index) 36 | else: 37 | try: 38 | uri, prefix = url_handler(ref) 39 | resource = Resource(uri) 40 | except ValueError, ve: 41 | logging.error("Error processing request for '%s': %s" % (ref, str(ve))) 42 | raise Http404(ve) 43 | except URLError, ue: 44 | logging.error("Error retrieving data for '%s': %s" % (ref, str(ue))) 45 | raise Http404(ue) 46 | 47 | if (prefix == None): 48 | prefix = get_preferred_prefix(request) 49 | get_url = getattr(resource, "get_%s_url" % prefix) 50 | url = get_url() 51 | logging.debug("Redirecting to the %s representation of %s: %s" % (prefix, uri, url)) 52 | return Http303(url) 53 | else: 54 | output = get_preferred_output(request, prefix) 55 | func = getattr(resource, "get_%s_%s" % (prefix, output)) 56 | mimetype = get_mimetype(prefix, output) 57 | logging.debug("Returning the %s representation of %s serialized as %s" % (prefix, uri, output)) 58 | return HttpResponse(func(), mimetype=mimetype) 59 | 60 | -------------------------------------------------------------------------------- /lib/djubby/http.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | from configuration import Configuration 22 | import mimeparse 23 | from sets import Set 24 | from django.http import HttpResponseRedirect 25 | from django.utils.datastructures import MultiValueDictKeyError 26 | 27 | formats = { 28 | "data" : { "default":"application/rdf+xml", "xml":"application/rdf+xml", "n3":"text/n3" }, 29 | "page" : { "default":"text/html", "html":"text/html", "xhtml":"application/xhtml+xml" } 30 | 31 | } 32 | 33 | def get_supported_prefixes(): 34 | return formats.keys() 35 | 36 | def get_supported_formats(): 37 | fs = Set() 38 | for f in formats.itervalues(): 39 | for m in f.itervalues(): 40 | fs.add(m) 41 | return list(fs) 42 | 43 | def get_supported_outputs(): 44 | outputs = Set() 45 | for f in formats.itervalues(): 46 | for o in f.iterkeys(): 47 | if (not o == "default"): 48 | outputs.add(o) 49 | return list(outputs) 50 | 51 | def get_mimetype(prefix, output): 52 | if (not prefix in formats): 53 | prefix = "data" 54 | if (not output in formats[prefix]): 55 | output = "default" 56 | return formats[prefix][output] 57 | 58 | def get_prefix(mimetype): 59 | for prefix, f in formats.items(): 60 | mimes = f.values() 61 | if mimetype in mimes: 62 | return prefix 63 | return "data" 64 | 65 | def get_preferred_format(request): 66 | try: 67 | accept = request.META["HTTP_ACCEPT"] 68 | except KeyError: 69 | accept = formats["data"]["xml"] 70 | return mimeparse.best_match(get_supported_formats(), accept) 71 | 72 | def get_preferred_prefix(request): 73 | return get_prefix(get_preferred_format(request)) 74 | 75 | def get_preferred_output(request, prefix): 76 | if (prefix == "page"): 77 | return "html" 78 | else: 79 | try: 80 | output = request.GET["output"] 81 | if (output in get_supported_outputs()): 82 | return output 83 | else: 84 | return "xml" 85 | except MultiValueDictKeyError: 86 | format = get_preferred_format(request) 87 | for output, mimetype in formats["data"].items(): 88 | if (output != "default"): 89 | if (mimetype == format): 90 | return output 91 | return "xml" 92 | 93 | def get_document_url(uri, prefix, conf=None): 94 | if (conf == None): 95 | conf = Configuration() 96 | webResourcePrefix = conf.get_value("webResourcePrefix") 97 | datasetBase = conf.get_value("datasetBase") 98 | webBase = conf.get_value("webBase") 99 | if (len(webResourcePrefix) == 0): 100 | return "%s%s/%s" % (webBase, prefix, uri[len(datasetBase):]) 101 | else: 102 | return uri.replace(datasetBase, webBase).replace(webResourcePrefix, "%s/" % prefix) 103 | 104 | def url_handler(ref): 105 | uri = None 106 | prefix = None 107 | conf = Configuration() 108 | datasetBase = conf.get_value("datasetBase") 109 | webBase = conf.get_value("webBase") 110 | webResourcePrefix = conf.get_value("webResourcePrefix") 111 | 112 | if (len(webResourcePrefix) == 0): 113 | splitted = ref.split("/") 114 | prefix = splitted[0] 115 | if (prefix in get_supported_prefixes()): 116 | uri = "%s%s" % (datasetBase, ref[len(prefix)+1:]) 117 | return uri, prefix 118 | else: 119 | prefix = None 120 | uri = datasetBase + ref 121 | return uri, prefix 122 | else: 123 | if (ref.startswith(webResourcePrefix)): 124 | prefix = None 125 | uri = datasetBase + ref 126 | return uri, prefix 127 | else: 128 | splitted = ref.split("/") 129 | prefix = splitted[0] 130 | if (prefix in get_supported_prefixes()): 131 | uri = datasetBase + ref.replace(prefix+"/", conf.get_value("webResourcePrefix")) 132 | return uri, prefix 133 | else: 134 | raise ValueError("Unsupportet type '%s'" % splitted[0]) 135 | 136 | class Http303(HttpResponseRedirect): 137 | status_code = 303 138 | 139 | -------------------------------------------------------------------------------- /lib/djubby/ns.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | from rdflib import Namespace 22 | 23 | rdf = Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#") 24 | rdfs = Namespace("http://www.w3.org/2000/01/rdf-schema#") 25 | xsd = Namespace("http://www.w3.org/2001/XMLSchema#") 26 | owl = Namespace("http://www.w3.org/2002/07/owl#") 27 | config = Namespace("http://richard.cyganiak.de/2007/pubby/config.rdf#") 28 | dc = Namespace("http://purl.org/dc/elements/1.1/") 29 | dct = Namespace("http://purl.org/dc/terms/") 30 | skos = Namespace("http://www.w3.org/2004/02/skos/core#") 31 | foaf = Namespace("http://xmlns.com/foaf/0.1/") 32 | 33 | -------------------------------------------------------------------------------- /lib/djubby/rdf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | from rdflib import URIRef 22 | 23 | #FIXME: duplicate function because circular import 24 | def str2uri(uri): 25 | if (type(uri)==str or type(uri)==unicode): 26 | return URIRef(uri) 27 | else: 28 | return uri 29 | 30 | def get_values(graph, subject=None, predicate=None): 31 | return graph.objects(subject=str2uri(subject), predicate=predicate) 32 | 33 | def get_value(graph, subject=None, predicate=None, lang=None): 34 | if (lang == None): 35 | try: 36 | return str(get_values(graph, subject, predicate).next()) 37 | except StopIteration: 38 | return "" 39 | else: 40 | values = get_values(graph, subject, predicate) 41 | for value in values: 42 | if (value.language == lang): 43 | return value 44 | return "" 45 | 46 | def get_predicates(graph, subject=None): 47 | return graph.predicate_objects(str2uri(subject)) 48 | 49 | -------------------------------------------------------------------------------- /lib/djubby/resource.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | import os 22 | import logging 23 | from configuration import Configuration 24 | from SPARQLWrapper import SPARQLWrapper, JSON 25 | from django.template import Template, Context 26 | import rdf 27 | import ns 28 | from uri import URI, uri2curie, uri2str, quote 29 | from rdflib import URIRef 30 | from rdflib import Literal 31 | from http import get_document_url 32 | 33 | class Resource: 34 | 35 | queries = { 36 | "ask" : "ASK { GRAPH <%s> { <%s> ?p ?o } }", 37 | "describe" : "DESCRIBE <%s> FROM <%s>" 38 | } 39 | 40 | def __init__(self, uri): 41 | logging.debug("Trying to build resource with URI <%s>..." % uri) 42 | self.uri = uri2str(uri) 43 | self.conf = Configuration() 44 | self.graph = self.conf.graph 45 | self.endpoint = self.conf.endpoint 46 | if (self.__ask__()): 47 | logging.info("Successfully found the resource with URI <%s> on this dataset" % self.uri) 48 | else: 49 | #FIXME: patch to support incosistencies on the URIs 50 | cleanuri = self.uri 51 | self.uri = quote(self.uri) 52 | logging.debug("Not found on the first try, trying the encoded URI <%s>..." % self.uri) 53 | if (self.__ask__()): 54 | logging.info("Successfully found the resource with URI <%s> on this dataset" % self.uri) 55 | else: 56 | raise ValueError("Resource with URI <%s> not found on this dataset" % self.uri) 57 | 58 | def get_triples(self): 59 | sparql = SPARQLWrapper(self.endpoint) 60 | sparql.setQuery(self.queries["describe"] % (self.uri, self.graph)) 61 | g = sparql.query().convert() 62 | logging.debug("Returning %d triples describing resource <%s>" % (len(g), self.uri)) 63 | #FIXME: enrich with metadata 64 | for prefix, namespace in self.conf.data.namespaces(): 65 | g.bind(prefix, namespace) 66 | return g 67 | 68 | def get_uri(self): 69 | return uri 70 | 71 | def get_data_url(self): 72 | return get_document_url(self.uri, "data") 73 | 74 | def get_page_url(self): 75 | return get_document_url(self.uri, "page") 76 | 77 | def get_data(self): 78 | return get_data_xml() 79 | 80 | def get_data_xml(self): 81 | g = self.get_triples() 82 | return g.serialize(format="pretty-xml") 83 | 84 | def get_data_n3(self): 85 | g = self.get_triples() 86 | return g.serialize(format="n3") 87 | 88 | def get_page(self): 89 | return get_page_html() 90 | 91 | def get_page_html(self): 92 | g = self.get_triples() 93 | tpl = Template(self.__read_template__()) 94 | 95 | data = {} 96 | data["uri"] = URI(self.uri) 97 | lang = self.conf.get_value("defaultLanguage") 98 | data["lang"] = lang 99 | label = rdf.get_value(g, self.uri, ns.rdfs["label"], lang) 100 | if (len(label)>0): 101 | data["label"] = label 102 | else: 103 | data["label"] = self.uri 104 | datasetBase = self.conf.get_value("datasetBase") 105 | webBase = self.conf.get_value("webBase") 106 | data["data"] = self.get_data_url() 107 | data["project"] = self.conf.get_value("projectName") 108 | data["homelink"] = self.conf.get_value("projectHomepage") 109 | data["endpoint"] = self.conf.get_value("sparqlEndpoint") 110 | depiction = rdf.get_value(g, self.uri, ns.foaf["depiction"]) 111 | if (len(depiction)>0): 112 | data["depiction"] = depiction 113 | 114 | data["rows"] = self.__get_rows__(g) 115 | 116 | ctx = Context(data) 117 | return tpl.render(ctx) 118 | 119 | def __ask__(self): 120 | sparql = SPARQLWrapper(self.endpoint) 121 | query = self.queries["ask"] % (self.graph, self.uri) 122 | sparql.setQuery(query) 123 | sparql.setReturnFormat(JSON) 124 | results = sparql.query().convert() 125 | if (results.has_key("boolean")): 126 | # expected answer according SPARQL Protocol 127 | if (results["boolean"]): 128 | return True 129 | elif (results.has_key("results") and results["results"].has_key("bindings") and len(results["results"]["bindings"])>0): 130 | # I don't know why, but virtuoso sometimes uses __ask_retval 131 | # http://docs.openlinksw.com/virtuoso/rdfsparql.html 132 | if (bool(results["results"]["bindings"][0]["__ask_retval"]["value"])): 133 | return True 134 | else: 135 | return False 136 | return False 137 | 138 | def __get_rows__(self, g): 139 | rows = {} 140 | for p, o in rdf.get_predicates(g, self.uri): 141 | prop = URI(p) 142 | if (not rows.has_key(prop)): 143 | rows[prop] = [] 144 | if (type(o) == URIRef): 145 | rows[prop].append(URI(o)) 146 | elif (type(o) == Literal): 147 | item = {} 148 | item["literal"] = unicode(o) 149 | if (o.language): 150 | item["language"] = o.language 151 | if (o.datatype): 152 | item["datatype"] = uri2curie(o.datatype, self.conf.data.namespaces()) 153 | rows[prop].append(item) 154 | else: 155 | rows[prop].append(o) 156 | return rows 157 | 158 | def __read_template__(self, name="resource"): 159 | path = "%s/../tpl/%s.tpl" % (os.path.dirname(__file__), name) 160 | logging.debug("Reading template '%s' from %s" % (name, path)) 161 | f = open(path, "r") 162 | content = f.read() 163 | f.close() 164 | return content 165 | 166 | -------------------------------------------------------------------------------- /lib/djubby/uri.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | from configuration import Configuration 22 | from rdflib import URIRef 23 | import urllib 24 | 25 | class URI: 26 | 27 | def __init__(self, uri): 28 | conf = Configuration() 29 | if (type(uri)==URIRef): 30 | self.uri = unicode(uri) 31 | else: 32 | self.uri = uri 33 | self.label = uri2curie(self.uri, conf.data.namespaces()) 34 | self.url = uri2url(self.uri) 35 | 36 | def __str__(self): 37 | return self.uri 38 | 39 | def __cmp__(self, o): 40 | return cmp(self.uri, o.uri) 41 | 42 | def __eq__(self, o): 43 | return self.uri.__eq__(o.uri) 44 | 45 | def __hash__(self): 46 | return self.uri.__hash__() 47 | 48 | def str2uri(uri): 49 | if (type(uri)==str or type(uri)==unicode): 50 | return URIRef(uri) 51 | else: 52 | return uri 53 | 54 | def uri2str(uri): 55 | if (type(uri)==URIRef(uri)): 56 | uri = unicode(uri) 57 | return urllib.unquote(uri) 58 | 59 | def quote(uri): 60 | uri = uri2str(uri) 61 | #return urllib.quote(uri) 62 | conf = Configuration() 63 | fixUnescapedCharacters = conf.get_value("fixUnescapedCharacters") 64 | for c in fixUnescapedCharacters: 65 | uri = uri.replace(c, urllib.quote(c)) 66 | return uri 67 | 68 | def uri2curie(uri, namespaces): 69 | url, fragment = splitUri(uri) 70 | for prefix, ns in namespaces: #improve the performace of this operation 71 | if (unicode(ns) == url): 72 | return "%s:%s" % (prefix, fragment) 73 | return uri 74 | 75 | def splitUri(uri): 76 | if ("#" in uri): 77 | splitted = uri.split("#") 78 | return ("%s#"%splitted[0], splitted[1]) 79 | else: 80 | splitted = uri.split("/") 81 | return ("/".join(splitted[:-1])+"/", splitted[-1]) 82 | 83 | def uri2url(uri): 84 | conf = Configuration() 85 | datasetBase = conf.get_value("datasetBase") 86 | webBase = conf.get_value("webBase") 87 | return uri.replace(datasetBase, webBase) 88 | 89 | -------------------------------------------------------------------------------- /lib/ez_setup.py: -------------------------------------------------------------------------------- 1 | #!python 2 | """Bootstrap setuptools installation 3 | 4 | If you want to use setuptools in your package's setup.py, just include this 5 | file in the same directory with it, and add this to the top of your setup.py:: 6 | 7 | from ez_setup import use_setuptools 8 | use_setuptools() 9 | 10 | If you want to require a specific version of setuptools, set a download 11 | mirror, or use an alternate download directory, you can do so by supplying 12 | the appropriate options to ``use_setuptools()``. 13 | 14 | This file can also be run as a script to install or upgrade setuptools. 15 | """ 16 | import sys 17 | DEFAULT_VERSION = "0.6c11" 18 | DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] 19 | 20 | md5_data = { 21 | 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 22 | 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 23 | 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 24 | 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 25 | 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 26 | 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 27 | 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 28 | 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 29 | 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 30 | 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 31 | 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', 32 | 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', 33 | 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', 34 | 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', 35 | 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', 36 | 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', 37 | 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', 38 | 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', 39 | 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 40 | 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 41 | 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 42 | 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 43 | 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 44 | 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 45 | 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 46 | 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 47 | 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 48 | 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 49 | 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 50 | 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 51 | 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 52 | 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 53 | 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 54 | 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 55 | 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 56 | 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 57 | 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 58 | 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 59 | 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', 60 | 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', 61 | 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', 62 | 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', 63 | } 64 | 65 | import sys, os 66 | try: from hashlib import md5 67 | except ImportError: from md5 import md5 68 | 69 | def _validate_md5(egg_name, data): 70 | if egg_name in md5_data: 71 | digest = md5(data).hexdigest() 72 | if digest != md5_data[egg_name]: 73 | print >>sys.stderr, ( 74 | "md5 validation of %s failed! (Possible download problem?)" 75 | % egg_name 76 | ) 77 | sys.exit(2) 78 | return data 79 | 80 | def use_setuptools( 81 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 82 | download_delay=15 83 | ): 84 | """Automatically find/download setuptools and make it available on sys.path 85 | 86 | `version` should be a valid setuptools version number that is available 87 | as an egg for download under the `download_base` URL (which should end with 88 | a '/'). `to_dir` is the directory where setuptools will be downloaded, if 89 | it is not already available. If `download_delay` is specified, it should 90 | be the number of seconds that will be paused before initiating a download, 91 | should one be required. If an older version of setuptools is installed, 92 | this routine will print a message to ``sys.stderr`` and raise SystemExit in 93 | an attempt to abort the calling script. 94 | """ 95 | was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules 96 | def do_download(): 97 | egg = download_setuptools(version, download_base, to_dir, download_delay) 98 | sys.path.insert(0, egg) 99 | import setuptools; setuptools.bootstrap_install_from = egg 100 | try: 101 | import pkg_resources 102 | except ImportError: 103 | return do_download() 104 | try: 105 | pkg_resources.require("setuptools>="+version); return 106 | except pkg_resources.VersionConflict, e: 107 | if was_imported: 108 | print >>sys.stderr, ( 109 | "The required version of setuptools (>=%s) is not available, and\n" 110 | "can't be installed while this script is running. Please install\n" 111 | " a more recent version first, using 'easy_install -U setuptools'." 112 | "\n\n(Currently using %r)" 113 | ) % (version, e.args[0]) 114 | sys.exit(2) 115 | else: 116 | del pkg_resources, sys.modules['pkg_resources'] # reload ok 117 | return do_download() 118 | except pkg_resources.DistributionNotFound: 119 | return do_download() 120 | 121 | def download_setuptools( 122 | version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, 123 | delay = 15 124 | ): 125 | """Download setuptools from a specified location and return its filename 126 | 127 | `version` should be a valid setuptools version number that is available 128 | as an egg for download under the `download_base` URL (which should end 129 | with a '/'). `to_dir` is the directory where the egg will be downloaded. 130 | `delay` is the number of seconds to pause before an actual download attempt. 131 | """ 132 | import urllib2, shutil 133 | egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) 134 | url = download_base + egg_name 135 | saveto = os.path.join(to_dir, egg_name) 136 | src = dst = None 137 | if not os.path.exists(saveto): # Avoid repeated downloads 138 | try: 139 | from distutils import log 140 | if delay: 141 | log.warn(""" 142 | --------------------------------------------------------------------------- 143 | This script requires setuptools version %s to run (even to display 144 | help). I will attempt to download it for you (from 145 | %s), but 146 | you may need to enable firewall access for this script first. 147 | I will start the download in %d seconds. 148 | 149 | (Note: if this machine does not have network access, please obtain the file 150 | 151 | %s 152 | 153 | and place it in this directory before rerunning this script.) 154 | ---------------------------------------------------------------------------""", 155 | version, download_base, delay, url 156 | ); from time import sleep; sleep(delay) 157 | log.warn("Downloading %s", url) 158 | src = urllib2.urlopen(url) 159 | # Read/write all in one block, so we don't create a corrupt file 160 | # if the download is interrupted. 161 | data = _validate_md5(egg_name, src.read()) 162 | dst = open(saveto,"wb"); dst.write(data) 163 | finally: 164 | if src: src.close() 165 | if dst: dst.close() 166 | return os.path.realpath(saveto) 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | def main(argv, version=DEFAULT_VERSION): 204 | """Install or upgrade setuptools and EasyInstall""" 205 | try: 206 | import setuptools 207 | except ImportError: 208 | egg = None 209 | try: 210 | egg = download_setuptools(version, delay=0) 211 | sys.path.insert(0,egg) 212 | from setuptools.command.easy_install import main 213 | return main(list(argv)+[egg]) # we're done here 214 | finally: 215 | if egg and os.path.exists(egg): 216 | os.unlink(egg) 217 | else: 218 | if setuptools.__version__ == '0.0.1': 219 | print >>sys.stderr, ( 220 | "You have an obsolete version of setuptools installed. Please\n" 221 | "remove it from your system entirely before rerunning this script." 222 | ) 223 | sys.exit(2) 224 | 225 | req = "setuptools>="+version 226 | import pkg_resources 227 | try: 228 | pkg_resources.require(req) 229 | except pkg_resources.VersionConflict: 230 | try: 231 | from setuptools.command.easy_install import main 232 | except ImportError: 233 | from easy_install import main 234 | main(list(argv)+[download_setuptools(delay=0)]) 235 | sys.exit(0) # try to force an exit 236 | else: 237 | if argv: 238 | from setuptools.command.easy_install import main 239 | main(argv) 240 | else: 241 | print "Setuptools version",version,"or greater has been installed." 242 | print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' 243 | 244 | def update_md5(filenames): 245 | """Update our built-in md5 registry""" 246 | 247 | import re 248 | 249 | for name in filenames: 250 | base = os.path.basename(name) 251 | f = open(name,'rb') 252 | md5_data[base] = md5(f.read()).hexdigest() 253 | f.close() 254 | 255 | data = [" %r: %r,\n" % it for it in md5_data.items()] 256 | data.sort() 257 | repl = "".join(data) 258 | 259 | import inspect 260 | srcfile = inspect.getsourcefile(sys.modules[__name__]) 261 | f = open(srcfile, 'rb'); src = f.read(); f.close() 262 | 263 | match = re.search("\nmd5_data = {\n([^}]+)}", src) 264 | if not match: 265 | print >>sys.stderr, "Internal error!" 266 | sys.exit(2) 267 | 268 | src = src[:match.start(1)] + repl + src[match.end(1):] 269 | f = open(srcfile,'w') 270 | f.write(src) 271 | f.close() 272 | 273 | 274 | if __name__=='__main__': 275 | if len(sys.argv)>2 and sys.argv[1]=='--md5update': 276 | update_md5(sys.argv[2:]) 277 | else: 278 | main(sys.argv[1:]) 279 | 280 | 281 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /lib/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This file is part of djubby , 4 | # a Linked Data frontend for SPARQL endpoints for the Django Web framework 5 | # 6 | # Copyright (C) 2010 Sergio Fernández 7 | # 8 | # Djubby is free software: you can redistribute it and/or modify it 9 | # under the terms of the GNU Lesser General Public License as published 10 | # by the Free Software Foundation, either version 3 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Djubby is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public License 19 | # along with Djubby. If not, see . 20 | 21 | 22 | from ez_setup import use_setuptools 23 | use_setuptools() 24 | from setuptools import setup, find_packages 25 | 26 | setup( 27 | name = "djubby", 28 | version = "0.1.9-dev", 29 | description = "A Linked Data frontend for SPARQL endpoints for Django", 30 | license = "GNU Library or Lesser General Public License (LGPL) v3", 31 | author = "Sergio Fernández", 32 | author_email = "sergio@wikier.org", 33 | url = "https://github.com/wikier/djubby", 34 | download_url = "https://github.com/wikier/djubby/releases", 35 | platforms = ["any"], 36 | packages = ["djubby"], 37 | requires = ["rdflib", "SPARQLWrapper", "django", "mimeparse"], 38 | install_requires = ["rdflib >= 4.1.0", "SPARQLWrapper >= 1.6.4", "django >= 1.1.0", "mimeparse >= 0.1.2"], 39 | classifiers = [ 40 | "Development Status :: 4 - Beta ", 41 | "Intended Audience :: Developers", 42 | "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", 43 | "Operating System :: OS Independent", 44 | "Programming Language :: Python :: 2.6", 45 | ], 46 | keywords = "python django rdf sparql linkeddata", 47 | scripts = ["ez_setup.py"], 48 | data_files = [ ("tpl", ["tpl/resource.tpl"]) ] 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /lib/tpl/resource.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{label}} | {{project}} 6 | 7 | 8 | 64 | 65 | 66 | 67 | 68 | 77 | 78 | {% if depiction %} 79 |
Depiction of {{label}}
80 | {% endif %} 81 | 82 | 83 | 84 | 85 | 86 | 87 | {% for prop, values in rows.items %} 88 | 89 | 92 | 118 | 119 | {% endfor %} 120 |
PropertyValue/s
90 | {{prop.label}} 91 | 93 |
    94 | {% for value in values%} 95 |
  • 96 | {% if value.uri %} 97 | {{value.label}} 98 | {% else %} 99 | {% if value.literal %} 100 | 101 | {% if value.language %} 102 | {{value.literal}} ({{value.language}}) 103 | {% else %} 104 | {{value.literal}} 105 | {% endif %} 106 | {% if value.datatype %} 107 | ({{value.datatype}}) 108 | {% endif %} 109 | 110 | {% else %} 111 | {{value}} 112 | {% endif %} 113 | {% endif %} 114 |
  • 115 | {% endfor %} 116 |
117 |
121 | 122 | 130 | 131 | 132 | 133 | 134 | 135 | --------------------------------------------------------------------------------