# HG changeset patch # User ymh # Date 1521154331 -3600 # Node ID 385e3a12ee27fb1bc666ea508b9ccac93b78b42a # Parent dc349ee445686f77a5c3b9769a560d3da42fd6bb Containerization and various corrections to make it work diff -r dc349ee44568 -r 385e3a12ee27 .hgignore --- a/.hgignore Tue Mar 13 16:52:47 2018 +0100 +++ b/.hgignore Thu Mar 15 23:52:11 2018 +0100 @@ -24,4 +24,4 @@ ^src/hdalab.egg-info ^src/dist ^src/MANIFEST.in$ -^build/hdalab/dist +^dev/hdalab/dist diff -r dc349ee44568 -r 385e3a12ee27 dev/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/README.md Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,131 @@ +# HDALab Docker images + +- restore database +- + + +## Comment construire les container HDALab + +Toutes les commandes suivantes sont à effectuer dans le répertoire contenant le fichier `docker-compose.yml`. + +``` +$ ./prepare_docker_build.sh +$ docker-compose -p hdalab build +$ docker-compose -p hdalab up -d +$ docker-compose -p hdalab exec hdalab django-admin collectstatic --noinput +$ docker-compose -p hdalab exec hdalab django-admin migrate --noinput +$ docker-compose -p hdalab exec hdalab supervisorctl restart all +``` + +Le site est consultable à l'adresse suivante : [http://127.0.0.1:8080](http://127.0.0.1:8080) +Le système est fonctionnel mais avec une bases de donnée vide. + +### Création d'un "superuser" +Cette commande permet la creation d'un utilisateur administeur de l'application. + +``` +$ docker-compose -p hdalab exec hdalab django-admin createsuperuser +``` + +### Import des données issues de l'export HDA + +Cette commande importe les données RDF exportées à partir de l'application HDA. +Attention cette commande peut être longue. + +``` +$ docker-compose -p hdalab exec hdalab /usr/local/sbin/import_hda_rdf.sh /etc/hdalab/data /var/lib/hdalab http://data.culture.fr/entrepot/HDA/export.tgz +``` + +### Import d'un dump de l'application + +#### Import d'un dump de la base de donnée + +Le fichier de dump de base de données doit être décompressé. + +``` +$ docker-compose -p hdalab stop hdalab +$ docker exec -i hdalab_pg_1 psql -U iri postgres < +$ docker-compose -p hdalab start hdalab +$ docker-compose -p hdalab exec hdalab django-admin migrate --noinput +$ echo "from django.contrib.sites.models import Site; site=Site.objects.all()[0]; site.domain='127.0.0.1:8080'; site.name='HDALab'; site.save()" | docker exec -i hdalab_hdalab_1 django-admin shell +$ docker-compose -p hdalab exec hdalab django-admin changepassword admin +$ docker-compose -p hdalab exec hdalab django-admin rebuild_index --noinput +``` + +#### Import des miniatures renkan + +Ces commandes supposent que le service `hdalab` est actif. +L'archive comprenant l'export des miniatures doit être décompressé. +Cette archive contient le répertoire `media` à la racine + +``` +$ docker cp ./media/. hdalab_hdalab_1:/var/lib/hdalab/static/media + +``` + + +# Commandes utiles + +## liste des services +Les services suivants sont définis dans le fichier `docker-compose.yml`: + - pg : La base de donnée postgresql + - es : ElasticSearch + - mail : Mailhog, fourni un serveur smtp de test + - front : Le serveur web (nginx) + - hdalab : application hdalab comprenant l'application web elle-même et les services associés (envoi de mail et calcul des preevisualisations Renkan) + +## Démarrage des services + +Les services se contrôlent avec la commande `docker-compose`. +La ligne de commande typique est la suivante: + +``` +$ docker-compose [-f ] -p hdalab [COMMAND] [ARGS...] +``` + +Il faut bien noter l'utilisation systématique de l'option `-p hdalab` qui spécifie le nom du projet. +Si la commande est lancée dans le même répertoire que celui du fichier `docker-compose.yml` l'option `-f` peut être ignorée. + + +## Construction des images des conteneurs +``` +$ docker-compose [-f ] -p hdalab build [SERVICE...] +``` + +## création et lancement des services +``` +$ docker-compose [-f ] -p hdalab up -d [SERVICE...] +``` +A noter l'option `-d` qui mettent les services en tache de fond. + +## lancement des services +``` +$ docker-compose [-f ] -p hdalab run SERVICE [COMMAND] [ARGS...] +``` +Cette commande lance un service. + +## Execution d'une commande sur un service lancé +``` +$ docker-compose [-f ] -p hdalab exec SERVICE COMMAND [ARGS...] +``` + +## arrêt des services +``` +$ docker-compose [-f ] -p hdalab stop [SERVICE...] +``` + + +## consulter la sortie des containers +``` +$ docker-compose [-f ] -p hdalab logs [-f] [SERVICE...] +``` + +## effacement et recréation de la base de donnée vide + +Attention, toutes les données de la base seront définitivement supprimées. + +``` +$ docker-compose [-f ] -p hdalab stop hdalab +$ echo "drop database hdalab;\ncreate database hdalab owner iri encoding 'utf-8';" | docker exec -i hdalab_pg_1 psql -U iri postgres +``` + diff -r dc349ee44568 -r 385e3a12ee27 dev/docker-compose.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/docker-compose.yml Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,68 @@ +version: '3' + +services: + # postgres + pg: + image: postgres:alpine + environment: + POSTGRES_USER: iri + POSTGRES_PASSWORD: iri + POSTGRES_DB: hdalab + ports: + - '5432:5432' + volumes: + - pg-data:/var/lib/postgresql/data + # nginx (webserver) + front: + build: + context: ./front + ports: + - '8080:80' + depends_on: + - "hdalab" + volumes: + - static-content:/var/lib/hdalab/static + - front-data:/usr/share/nginx/html + - front-logs:/var/log/nginx + # Elasticsearch + es: + image: docker.elastic.co/elasticsearch/elasticsearch:5.6.8 + environment: + - "discovery.type=single-node" + - "cluster.name=docker-cluster" + - "xpack.security.enabled=false" + - "ES_JAVA_OPTS=-Xms256m -Xmx256m" + volumes: + - es-data:/usr/share/elasticsearch/data + # mailhog + mail: + image: mailhog/mailhog + ports: + - "8025:8025" + # rabbitmq + rabbitmq: + hostname: hdalab-rabbitmq + image: rabbitmq:alpine + environment: + RABBITMQ_DEFAULT_VHOST: hdalab + + # hdalab + hdalab: + build: ./hdalab + volumes: + - static-content:/var/lib/hdalab/static + - hdalab-logs:/var/log/hdalab + depends_on: + - "pg" + - "es" + - "mail" + - "rabbitmq" + +volumes: + static-content: + hdalab-logs: + pg-data: + front-data: + front-logs: + es-data: + diff -r dc349ee44568 -r 385e3a12ee27 dev/front/Dockerfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/front/Dockerfile Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,3 @@ +FROM nginx:alpine + +COPY hdalab.conf /etc/nginx/conf.d/default.conf diff -r dc349ee44568 -r 385e3a12ee27 dev/front/hdalab.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/front/hdalab.conf Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,25 @@ +resolver 127.0.0.11; + +# configuration of the server +server { + # the port your site will be served on + listen 80; + # the domain name it will serve for + server_name hdalab.test; # substitute your machine's IP address or FQDN + charset utf-8; + + # max upload size + client_max_body_size 75M; # adjust to taste + + location /static { + alias /var/lib/hdalab/static; + } + + set $upstream hdalab:8001; + + # Finally, send all non-media requests to the Django server. + location / { + uwsgi_pass $upstream; + include uwsgi_params; # the uwsgi_params file you installed + } +} diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/Dockerfile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/Dockerfile Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,79 @@ +FROM python:2.7-alpine + +ENV PHANTOMJS_ARCHIVE="phantomjs.tar.gz" +ENV REDLAND_ARCHIVE="redland-bindings-1.0.17.1" + +RUN echo '@edge http://nl.alpinelinux.org/alpine/edge/main'>> /etc/apk/repositories \ + && apk update \ + && apk add --upgrade apk-tools@edge \ + && apk add --no-cache --virtual build-deps gcc python-dev musl-dev linux-headers postgresql-dev \ + && apk add --no-cache supervisor curl bash \ + && apk add --no-cache --virtual build-deps libxml2-dev \ + && apk add --no-cache --virtual build-deps libxslt-dev \ + && apk add --no-cache unixodbc raptor2 rasqal redland \ + && apk add --no-cache --virtual build-deps sqlite-dev libtool make automake autoconf swig raptor2-dev rasqal-dev redland-dev \ + && apk add --no-cache jpeg zlib freetype lcms2 openjpeg tiff tk tcl harfbuzz fribidi \ + && apk add --no-cache --virtual build-deps jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev harfbuzz-dev fribidi-dev \ + && mkdir -p /usr/include/libxml \ + && ln -s /usr/include/libxml2/libxml/xmlexports.h /usr/include/libxml/xmlexports.h \ + && ln -s /usr/include/libxml2/libxml/xmlversion.h /usr/include/libxml/xmlversion.h \ + && addgroup -S www && adduser -S -G www www \ + && mkdir /etc/supervisord.d \ + && mkdir -p /tmp/build-tmp \ + && mkdir -p /var/lib/hdalab \ + && mkdir -p /var/log/hdalab \ + && mkdir -p /etc/hdalab \ + && mkdir -p /etc/uwsgi \ + && chown -R www:www /var/log/hdalab \ + && chown -R www:www /var/lib/hdalab \ + && mkdir /usr/local/sbin + +COPY entrypoint.sh /usr/local/sbin/entrypoint.sh +COPY dist/renkanmanager.tar.gz /tmp/build-tmp +COPY dist/hdalab.tar.gz /tmp/build-tmp +COPY dist/base_requirements.txt /tmp/build-tmp +COPY srvr_requirements.txt /tmp/build-tmp +COPY settings.py /etc/hdalab/hdalab_settings.py +COPY supervisord.conf /etc/supervisord.conf +COPY supervisor.d/hdalab.ini /etc/supervisor.d/ +COPY supervisor.d/celeryd-hdalab.ini /etc/supervisor.d/ +COPY supervisor.d/celerybeat-hdalab.ini /etc/supervisor.d/ +COPY uwsgi/hdalab.yml /etc/uwsgi/hdalab.yml +COPY dist/data /etc/hdalab/data +COPY import_hda_rdf.sh /usr/local/sbin/import_hda_rdf.sh +COPY renkan_default_icon.png /etc/hdalab/ + +RUN pip install --no-cache-dir -r /tmp/build-tmp/base_requirements.txt \ + && pip install --no-cache-dir -r /tmp/build-tmp/srvr_requirements.txt \ + && pip install /tmp/build-tmp/renkanmanager.tar.gz \ + && pip install /tmp/build-tmp/hdalab.tar.gz \ + && curl -Lk -o /tmp/build-tmp/$REDLAND_ARCHIVE.tar.gz http://download.librdf.org/source/$REDLAND_ARCHIVE.tar.gz \ + && tar -xf /tmp/build-tmp/$REDLAND_ARCHIVE.tar.gz -C /tmp/build-tmp/ + +WORKDIR /tmp/build-tmp/${REDLAND_ARCHIVE} + +RUN ./autogen.sh \ + && cd python \ + && make \ + && make install + +WORKDIR / + +RUN rm -fr /tmp/build-tmp \ + && chmod +x /usr/local/sbin/import_hda_rdf.sh /usr/local/sbin/entrypoint.sh \ + && curl -Lk -o $PHANTOMJS_ARCHIVE https://github.com/fgrehm/docker-phantomjs2/releases/download/v2.0.0-20150722/dockerized-phantomjs.tar.gz \ + && tar -xf $PHANTOMJS_ARCHIVE -C /tmp/ \ + && cp -R /tmp/etc/fonts /etc/ \ + && cp -R /tmp/lib/* /lib/ \ + && cp -R /tmp/lib64 / \ + && cp -R /tmp/usr/lib/* /usr/lib/ \ + && cp -R /tmp/usr/lib/x86_64-linux-gnu /usr/ \ + && cp -R /tmp/usr/share/* /usr/share/ \ + && cp /tmp/usr/local/bin/phantomjs /usr/bin/ \ + && rm -fr $PHANTOMJS_ARCHIVE /tmp/* \ + && apk del build-deps + +ENV PYTHONPATH="/etc/hdalab" +ENV DJANGO_SETTINGS_MODULE=hdalab_settings + +CMD ["/bin/sh", "/usr/local/sbin/entrypoint.sh"] diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/renkan_default_icon.png Binary file dev/hdalab/renkan_default_icon.png has changed diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/settings.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/settings.py Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,323 @@ +# -*- coding: utf-8 -*- +# Django settings for hdalab project. +import logging + +DEBUG = True + +ADMINS = ( + ('Hdalab admin', 'admin@hdalab.test'), +) + +MANAGERS = ADMINS + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. + 'NAME': 'hdalab', # Or path to database file if using sqlite3. + 'USER': 'iri', # Not used with sqlite3. + 'PASSWORD': 'iri', # Not used with sqlite3. + 'HOST': 'pg', # Set to empty string for localhost. Not used with sqlite3. + 'PORT': '', # Set to empty string for default. Not used with sqlite3. + } +} + +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + } +} + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +# On Unix systems, a value of None will cause Django to use the same +# timezone as the operating system. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'Europe/Paris' + +# Language code for this installation. All choices can be found here: +# http://www.i18nguy.com/unicode/language-identifiers.html +LANGUAGE_CODE = 'fr-fr' + +ugettext = lambda s:s + +LANGUAGES = ( + ('fr', ugettext('French')), + ('en', ugettext('English')), + ('it', ugettext('Italian')), + ('de', ugettext('German')), + ('es', ugettext('Spanish')), + ('ja', ugettext('Japanese')), + #('zh-tw', ugettext('Chinese')), +) + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# If you set this to False, Django will not format dates, numbers and +# calendars according to the current locale +USE_L10N = True + +BASE_DIR = "/var/lib/hdalab/" +BASE_URL = '/' +WEB_URL = 'http://127.0.0.1:8080' +FRONT_WEB_URL = 'http://front:80' +SCRIPT_PREFIX = BASE_URL + 'hdalab' + + +# Absolute filesystem path to the directory that will hold user-uploaded files. +# Example: "/home/media/media.lawrence.com/media/" +MEDIA_ROOT = '/var/lib/hdalab/static/media/' + +# URL that handles the media served from MEDIA_ROOT. Make sure to use a +# trailing slash. +# Examples: "http://media.lawrence.com/media/", "http://example.com/media/" +MEDIA_URL = "/static/media/" + +# Absolute path to the directory static files should be collected to. +# Don't put anything in this directory yourself; store your static files +# in apps' "static/" subdirectories and in STATICFILES_DIRS. +# Example: "/home/media/media.lawrence.com/static/" +STATIC_ROOT = '/var/lib/hdalab/static/site/' + +# URL prefix for static files. +# Example: "http://media.lawrence.com/static/" +STATIC_URL = '/static/site/' + +# URL prefix for admin static files -- CSS, JavaScript and images. +# Make sure to use a trailing slash. +# Examples: "http://foo.com/static/admin/", "/static/admin/". +ADMIN_MEDIA_PREFIX = '/static/site/admin/' + +# Additional locations of static files +STATICFILES_DIRS = ( + # Put strings here, like "/home/html/static" or "C:/www/django/static". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. +) + +# List of finder classes that know how to find static files in +# various locations. +STATICFILES_FINDERS = ( + 'django.contrib.staticfiles.finders.FileSystemFinder', + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', +# 'django.contrib.staticfiles.finders.DefaultStorageFinder', +) + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'yp-0o!v#a9vswim0*0=jdp1$=*f6cn_o$^u)y53si8u3gs9+r(' + +# Hosts/domain names that are valid for this site; required if DEBUG is False +# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts +ALLOWED_HOSTS = ['hdalab.test', '127.0.0.1'] + +GOOGLE_ANALYTICS_CODE = 'UA-12345678-9' + +HAYSTACK_CONNECTIONS = { + 'default': { + 'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine', + 'URL': 'es:9200', + 'INDEX_NAME': 'hdalab', + }, +} + +LOG_FILE = '/var/log/hdalab/hdalab.log' +LOG_LEVEL = logging.DEBUG + +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'formatters' : { + 'simple' : { + 'format': "%(asctime)s - %(levelname)s : %(message)s", + }, + 'semi-verbose': { + 'format': '%(levelname)s %(asctime)s %(module)s %(message)s' + }, + }, + 'handlers': { + 'mail_admins': { + 'level': 'ERROR', + 'class': 'django.utils.log.AdminEmailHandler' + }, + 'stream_to_console': { + 'level': LOG_LEVEL, + 'class': 'logging.StreamHandler' + }, + 'file': { + 'level': LOG_LEVEL, + 'class': 'logging.FileHandler', + 'filename': LOG_FILE, + 'formatter': 'semi-verbose', + }, + } , + 'loggers': { + 'hdabo': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + 'hdalab': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + 'rdflib': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + # 'django.db.backends':{ + # 'handlers': ['file'], + # 'level': LOG_LEVEL, + # 'propagate': True, + # }, + 'django.request': { + 'handlers': ['file'], + 'level': LOG_LEVEL, + 'propagate': True, + }, + } +} + +#template settings +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + ], + 'OPTIONS': { + 'context_processors': [ + 'django.contrib.auth.context_processors.auth', + 'django.template.context_processors.debug', + 'django.template.context_processors.i18n', + 'django.template.context_processors.media', + 'django.template.context_processors.static', + 'django.template.context_processors.tz', + 'django.contrib.messages.context_processors.messages', + 'hdalab.context_processors.version', + ], + 'loaders': [ + ('django.template.loaders.cached.Loader', ( + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + )), + ], + 'debug': DEBUG, + }, + }, +] + + +MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware' +) + + +ROOT_URLCONF = 'hdalab.urls' + + +INSTALLED_APPS = ( + 'hdalab', + 'hdabo', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'django.contrib.admin', + 'django_extensions', + 'djcelery_email', + 'registration', + 'honeypot', + 'envelope', + 'haystack', + 'easy_thumbnails', + 'renkanmanager', +) + + +SOUTH_MIGRATION_MODULES = { + 'easy_thumbnails': 'easy_thumbnails.south_migrations', +} +DEFAULT_RENKAN_ICON = "thumbnails/renkan/renkan_default_icon.png" + +WIKIPEDIA_VERSION_PERMALINK_TEMPLATE = "http://fr.wikipedia.org/w/index.php?oldid=%s" +DBPEDIA_URI_TEMPLATE = "http://fr.dbpedia.org/%s/%s" + +SEARCH_STAR_CHARACTER = "*" +PAGINATION_DEFAULT_NB_BY_PAGE = 50 +RENKANS_PER_PAGE = 8 + +TEST_RUNNER = 'django.test.runner.DiscoverRunner' + +# User class after migration to django > 1.6.5 +AUTH_USER_MODEL = 'hdabo.User' + +ACCOUNT_ACTIVATION_DAYS = 7 + +LOCALE_PATHS = () + +RENKAN_PREVIEW_DIM = (500,500) +RENKAN_PREVIEW_WAIT = 5000 + +CELERY_TASK_SERIALIZER = 'json' +CELERY_ACCEPT_CONTENT = ['json', 'msgpack', 'yaml'] + +EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' +EMAIL_HOST="mail" +EMAIL_PORT=1025 + +SE_ETAGS = False + +DEFAULT_FROM_EMAIL = "do-not-reply@hdalab.test" + +ENVELOPE_EMAIL_RECIPIENTS= ['histoiredesarts@hdalab.test'] + +RENKAN_PREVIEW_PHANTOMJS_PATH = '/usr/bin/phantomjs' + +BROKER_URL = 'amqp://guest:guest@rabbitmq:5672/hdalab' + +RENKAN_TUTORIAL_VIDEO_URLS = [ + {'format': 'video/mp4', 'url': 'http://media.iri.centrepompidou.fr/video/hdalab/hdalab_renkan_presentation_720p.mp4' }, + {'format': 'video/webm', 'url': 'http://media.iri.centrepompidou.fr/video/hdalab/hdalab_renkan_presentation_720p.webm' }, + {'format': 'video/ogg', 'url': 'http://media.iri.centrepompidou.fr/video/hdalab/hdalab_renkan_presentation_720p.ogv' } +] + +WIKIPEDIA_API_URL = "https://fr.wikipedia.org/w/api.php" + + +HONEYPOT_FIELD_NAME='phone' +ENVELOPE_SUBJECT_INTRO='[hdalab contact]' + +X_FRAME_OPTIONS='DENY' +SESSION_COOKIE_SECURE=False +SECURE_CONTENT_TYPE_NOSNIFF=True +SECURE_BROWSER_XSS_FILTER=True +CSRF_COOKIE_SECURE=False + +#SILENCED_SYSTEM_CHECKS = ['fields.W342'] # to silence a problem in registration module +REGISTRATION_FORM = 'hdabo.forms.HdaboRegistrationForm' +REGISTRATION_EMAIL_HTML = False + +OLDER_WINDOWS = [ + u'Windows', u'Windows Mobile', u'Windows XP', + u'Windows ME', u'Windows 2000', u'Windows NT 4.0', + u'Windows CE', u'Windows 95', u'Windows 98', + u'Windows 3.1', u'Windows NT' +] + +LOGIN_REDIRECT_URL = "/" +LOGIN_URL = "/hdalab/hdabo/accounts/login" diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/srvr_requirements.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/srvr_requirements.txt Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,3 @@ +#pylibmc +uWSGI +pytz diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/supervisor.d/celerybeat-hdalab.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/supervisor.d/celerybeat-hdalab.ini Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,18 @@ +[program:celerybeat-hdalab] +; Set full path to celery program if using virtualenv +command=/usr/local/bin/celery beat -A hdalab --schedule /var/lib/hdalab/celery/beat.db --loglevel=INFO + +; remove the -A myapp argument if you are not using an app instance + +directory=/var/lib/hdalab +user=www +numprocs=1 +stdout_logfile=/var/log/hdalab/celery/hdalab-beat.log +stderr_logfile=/var/log/hdalab/celery/hdalab-beat.log +autostart=true +autorestart=true +startsecs=10 + +; if rabbitmq is supervised, set its priority higher +; so it starts first +priority=999 diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/supervisor.d/celeryd-hdalab.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/supervisor.d/celeryd-hdalab.ini Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,25 @@ +[program:celeryd-hdalab] +; Set full path to celery program if using virtualenv +command=/usr/local/bin/celery worker -A hdalab --loglevel=INFO + +directory=/var/lib/hdalab +user=www +numprocs=1 +stdout_logfile=/var/log/hdalab/celery/hdalab-worker.log +stderr_logfile=/var/log/hdalab/celery/hdalab-worker.log +autostart=true +autorestart=true +startsecs=10 + +; Need to wait for currently executing tasks to finish at shutdown. +; Increase this if you have very long running tasks. +stopwaitsecs = 600 + +; When resorting to send SIGKILL to the program to terminate it +; send SIGKILL to its whole process group instead, +; taking care of its children as well. +killasgroup=true + +; if rabbitmq is supervised, set its priority higher +; so it starts first +priority=998 diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/supervisor.d/hdalab.ini --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/supervisor.d/hdalab.ini Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,10 @@ +[program:hdalab] +command=/usr/local/bin/uwsgi --yaml /etc/uwsgi/hdalab.yml +user=www +directory=/var/lib/hdalab/ +autostart=true +autorestart=true +redirect_stderr=true +stopsignal=QUIT +startretries=10 + diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/supervisord.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/supervisord.conf Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,22 @@ +; Minimum supervisor config file. +[unix_http_server] +file=/run/supervisord.sock ; (the path to the socket file) +username = dummy ; avoid CRIT message in log. +password = dummy ; avoid CRIT message in log. + +[supervisord] +logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log) +logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) +logfile_backups=10 ; (num of main logfile rotation backups;default 10) +loglevel=info ; (log level;default info; others: debug,warn,trace) + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///run/supervisord.sock ; use a unix:// URL for a unix socket +username = dummy ; avoid CRIT message in log. +password = dummy ; avoid CRIT message in log. + +[include] +files = /etc/supervisor.d/*.ini diff -r dc349ee44568 -r 385e3a12ee27 dev/hdalab/uwsgi/hdalab.yml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dev/hdalab/uwsgi/hdalab.yml Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,9 @@ +uwsgi: + master: 1 + socket: 0.0.0.0:8001 + processes: 2 + logto: /var/log/hdalab/uwsgi/hdalab.log + chdir: /var/lib/hdalab + module: hdalab.wsgi + pythonpath: /etc/hdalab + env: DJANGO_SETTINGS_MODULE=hdalab_settings diff -r dc349ee44568 -r 385e3a12ee27 src/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/README Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,23 @@ +# HDALAB + +HDALAB project + +## Installation + +TODO: Write Installation + +## Usage + +TODO: Write Usage + +## History + +TODO: Write history + +## Credits + +TODO: Write credits + +## License + +TODO: Write license diff -r dc349ee44568 -r 385e3a12ee27 src/hdalab/management/commands/import_hdabo_db.py --- a/src/hdalab/management/commands/import_hdabo_db.py Tue Mar 13 16:52:47 2018 +0100 +++ b/src/hdalab/management/commands/import_hdabo_db.py Thu Mar 15 23:52:11 2018 +0100 @@ -22,20 +22,20 @@ ) - def handle(self, *args, **options): - + def handle(self, *args, **options): + if len(args) == 0: data_path = os.path.abspath(os.path.join(os.path.abspath(__file__),'../../../../../data')) else: data_path = args[0] - + print("=========== MIGRATE ===========") call_command('migrate') if options.get('categories', False): print("=========== QUERY WIKIPEDIA CATEGORY ===========") call_command('query_wikipedia_category', interactive=False, force=True, all=True) - print("=========== QUERY DBPEDIA ===========") + print("=========== QUERY DBPEDIA ===========") call_command('query_dbpedia', interactive=False, force=True, all=True) print("=========== FILL TAG YEAR ===========") call_command('fill_tag_years') @@ -51,5 +51,4 @@ call_command('import_hda_insee_csv', os.path.join(data_path,'HDA_Insee.csv')) print("=========== QUERY CATEGORY INCLUSION ===========") call_command('query_category_inclusion', all=True, force=True, interactive=False) - - \ No newline at end of file + diff -r dc349ee44568 -r 385e3a12ee27 src/hdalab/migrations/0003_default_site.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hdalab/migrations/0003_default_site.py Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import re + +from django.conf import settings +from django.db import models, migrations + +def set_site_name(apps, schema_editor): + Sites = apps.get_model('sites', 'site') + site = Sites.objects.filter(id=1).first() + if site == None: + site = Sites() + + m = re.match(r"^https?\:\/\/(.+)", settings.WEB_URL) + if m: + site.name = "HDALab" + site.domain = m.group(1) + site.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('sites', '0001_initial'), + ('hdalab', '0002_alter_tagyears_tag_one2one'), + ] + + operations = [ + migrations.RunPython(set_site_name), + ] diff -r dc349ee44568 -r 385e3a12ee27 src/hdalab/services.py --- a/src/hdalab/services.py Tue Mar 13 16:52:47 2018 +0100 +++ b/src/hdalab/services.py Thu Mar 15 23:52:11 2018 +0100 @@ -23,13 +23,13 @@ @transaction.atomic def change_renkan_state(hda_renkan, state, message=None, author=None): - + if state != hda_renkan.state: - + HdalabRenkanStateTransition.objects.create(renkan=hda_renkan, from_state=hda_renkan.state, to_state=state, message=message, author=author) hda_renkan.state = state hda_renkan.save() - + def renkan_capture_preview(hdalab_renkan): #get last state date or last modification date @@ -45,33 +45,33 @@ rel_export_path_dir = "thumbnails/renkan/%04d/%02d/%02d" % (folder_date.year, folder_date.month, folder_date.day) export_path_dir = os.path.join(settings.MEDIA_ROOT,rel_export_path_dir) export_filename = "%s.png" % hdalab_renkan.renkan.rk_id - + export_path = os.path.join(export_path_dir, export_filename) rel_export_path = os.path.join(rel_export_path_dir, export_filename) - + if not os.path.exists(export_path_dir): try: os.makedirs(export_path_dir) except OSError, e: if e.errno != 17: - raise + raise # time.sleep might help here pass - + preview_dim = getattr(settings, 'RENKAN_PREVIEW_DIM', (500,500)) preview_wait = getattr(settings, 'RENKAN_PREVIEW_WAIT', 5000) preview_args = [ getattr(settings,'RENKAN_PREVIEW_PHANTOMJS_PATH','phantomjs'), os.path.join(os.path.dirname(os.path.abspath(__file__)),'scripts/capture-phantomjs.js'), - "%s%shdalab%s?rk_id=%s" % (settings.WEB_URL, settings.BASE_URL, reverse('renkan_full'),hdalab_renkan.renkan.rk_id), + "%s%s%s?rk_id=%s" % (getattr(settings, 'FRONT_WEB_URL', settings.WEB_URL), settings.BASE_URL, reverse('renkan_full'),hdalab_renkan.renkan.rk_id), export_path, "--width=%d" % preview_dim[0], "--height=%d" % preview_dim[1], "--wait=%d" % preview_wait ] check_call(preview_args) - + hdalab_renkan.renkan.image = rel_export_path hdalab_renkan.renkan.save() diff -r dc349ee44568 -r 385e3a12ee27 src/hdalab/settings.py --- a/src/hdalab/settings.py Tue Mar 13 16:52:47 2018 +0100 +++ b/src/hdalab/settings.py Thu Mar 15 23:52:11 2018 +0100 @@ -225,3 +225,6 @@ LOGIN_REDIRECT_URL = BASE_URL if 'LOGIN_URL' not in locals(): LOGIN_URL = BASE_URL + "hdalab/hdabo/accounts/login" + +if 'FRONT_WEB_URL' not in locals(): + FRONT_WEB_URL = WEB_URL #defined for preview calculation when internal url may be different than external url diff -r dc349ee44568 -r 385e3a12ee27 src/setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/setup.py Thu Mar 15 23:52:11 2018 +0100 @@ -0,0 +1,143 @@ +import os +try: + from setuptools import setup +except ImportError: + from distutils.core import setup +from distutils.command.install_data import install_data +from distutils.command.install import INSTALL_SCHEMES +import sys + + +class osx_install_data(install_data): + """ + On MacOS, the platform-specific lib dir is /System/Library/Framework/Python/.../ + which is wrong. Python 2.5 supplied with MacOS 10.5 has an Apple-specific fix + for this in distutils.command.install_data#306. It fixes install_lib but not + install_data, which is why we roll our own install_data class. + """ + + def finalize_options(self): + """ + By the time finalize_options is called, install.install_lib is set to the + fixed directory, so we set the installdir to install_lib. The + install_data class uses ('install_data', 'install_dir') instead. + """ + self.set_undefined_options('install', ('install_lib', 'install_dir')) + install_data.finalize_options(self) + +def fullsplit(path, result=None): + """ + Split a pathname into components (the opposite of os.path.join) in a + platform-neutral way. + """ + if result is None: + result = [] + head, tail = os.path.split(path) + if head == '': + return [tail] + result + if head == path: + return result + return fullsplit(head, [tail] + result) + + +def launch_setup(setup_script_name, setup_script_args): + """ + Start setup + """ + if sys.platform == "darwin": + cmdclasses = {'install_data': osx_install_data} + else: + cmdclasses = {'install_data': install_data} + + + root_dir = os.path.dirname(__file__) + if root_dir != '': + os.chdir(root_dir) + source_dirs = ['hdabo', 'hdalab'] + + version_variables = {} + try: + with open(os.path.join(source_dirs[0], "__init__.py")) as f: + code = compile(f.read(), "__init__.py", 'exec') + exec(code, version_variables) + except: + pass + + version = version_variables['__version__'] + + packages, data_files = [], [] + + for source_dir in source_dirs: + for dirpath, dirnames, filenames in os.walk(source_dir): + # Ignore dirnames that start with '.' + for i, dirname in enumerate(dirnames): + if dirname.startswith('.') or dirname.startswith('__pycache__'): del dirnames[i] + if '__init__.py' in filenames: + packages.append('.'.join(fullsplit(dirpath))) + elif filenames: + data_files.append([dirpath, [os.path.join(dirpath, f) for f in filenames]]) + + + # Tell distutils to put the data_files in platform-specific installation + # locations. See here for an explanation: + # http://groups.google.com/group/comp.lang.python/browse_thread/thread/35ec7b2fed36eaec/2105ee4d9e8042cb + for scheme in INSTALL_SCHEMES.values(): + scheme['data'] = scheme['purelib'] + + # Small hack for working with bdist_wininst. + # See http://mail.python.org/pipermail/distutils-sig/2004-August/004134.html + if len(sys.argv) > 1 and sys.argv[1] == 'bdist_wininst': + for file_info in data_files: + file_info[0] = '\\PURELIB\\%s' % file_info[0] + + #write MANIFEST.in + + with open("MANIFEST.in", "w") as m: + m.write("exclude hdabo/config.py\n") + m.write("exclude hdalab/config.py\n") + m.write("include LICENSE\n") + m.write("include README\n") + m.write("include MANIFEST.in\n") + for entry in data_files: + file_list = entry[1] + for filename in file_list: + m.write("include %s\n" % (filename)) + + long_description = '' + with open('README', 'r') as f: + long_description = f.read() + + setup( + script_name=setup_script_name, + script_args=setup_script_args, + name='hdalab', + version=version, + author='IRI', + author_email='contact@iri.centrepompidou.fr', + packages=packages, + data_files=data_files, + cmdclass=cmdclasses, + scripts=[], + url='http://www.iri.centrepompidou.fr/dev/hg/hdabo', + license='CECILL-C', + description='projet Irinotes', + long_description=long_description, + classifiers=[ + 'Development Status :: 4 - Beta', + 'Environment :: Web Environment', + 'Framework :: Django', + 'Intended Audience :: Developers', + 'License :: Ceccil-B', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Topic :: Utilities' + ], + ) + + +if __name__ == "__main__": + + script_name = os.path.basename(sys.argv[0]) + script_args = sys.argv[1:] + + launch_setup(script_name, script_args) diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/lib/lib_create_env.py --- a/virtualenv/res/lib/lib_create_env.py Tue Mar 13 16:52:47 2018 +0100 +++ b/virtualenv/res/lib/lib_create_env.py Thu Mar 15 23:52:11 2018 +0100 @@ -49,11 +49,11 @@ 'REDLAND_BINDINGS': { 'setup': 'redland_bindings', 'url':'redland-bindings-1.0.17.1.tar.gz', 'local':"redland-bindings-1.0.17.1.tar.gz", 'install': {'method': 'install_redland_bindings', 'option_str': None, 'dict_extra_env': None}}, 'UNIDECODE': { 'setup': 'unidecode', 'url':'https://pypi.python.org/packages/source/U/Unidecode/Unidecode-0.04.17.tar.gz', 'local':"Unidecode-0.04.17.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, 'PYTZ': { 'setup': 'pytz', 'url':'https://pypi.python.org/packages/source/p/pytz/pytz-2015.4.tar.bz2', 'local':"pytz-2015.4.tar.bz2", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, - 'KOMBU': { 'setup': 'kombu', 'url':'https://github.com/celery/kombu/archive/v3.0.26.tar.gz', 'local':"kombu-3.0.26.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, - 'AMQP': { 'setup': 'amqp', 'url':'https://github.com/celery/py-amqp/archive/v1.4.6.tar.gz', 'local':"py-amqp-1.4.6.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, + 'KOMBU': { 'setup': 'kombu', 'url':'https://github.com/celery/kombu/archive/v4.1.0.tar.gz', 'local':"kombu-4.1.0.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, + 'AMQP': { 'setup': 'amqp', 'url':'https://github.com/celery/py-amqp/archive/v2.2.2.tar.gz', 'local':"amqp-2.2.2.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, 'ANYJSON': { 'setup': 'anyjson', 'url':'https://bitbucket.org/runeh/anyjson/get/0.3.3.tar.gz', 'local':"anyjson-0.3.3.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, - 'BILLIARD': { 'setup': 'billiard', 'url':'https://github.com/celery/billiard/archive/v3.3.0.20.tar.gz', 'local':"billiard-3.3.0.20.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, - 'CELERY': { 'setup': 'celery', 'url':'https://github.com/celery/celery/archive/v3.1.18.tar.gz', 'local':"celery-3.1.18.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, + 'BILLIARD': { 'setup': 'billiard', 'url':'https://github.com/celery/billiard/archive/v3.5.0.3.tar.gz', 'local':"billiard-3.5.0.3.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, + 'CELERY': { 'setup': 'celery', 'url':'https://github.com/celery/celery/archive/v4.1.0.tar.gz', 'local':"celery-4.1.0.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, 'APPCONF': { 'setup': 'django-appconf', 'url':'https://github.com/jezdez/django-appconf/archive/v1.0.1.tar.gz', 'local':"django-appconf-1.0.1.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, 'CELERY-EMAIL': { 'setup': 'django-celery-email', 'url':'https://github.com/pmclanahan/django-celery-email/archive/1.1.0.tar.gz', 'local':"django-celery-email-1.1.0.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, 'DJANGO-ENVELOPE': { 'setup': 'django-envelope', 'url':'https://github.com/zsiciarz/django-envelope/archive/1.0.0.tar.gz', 'local':'django-envelope-1.0.0.tar.gz', 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, @@ -84,7 +84,7 @@ URLS.update({ 'PSYCOPG2': {'setup': 'psycopg2','url': 'http://initd.org/psycopg/tarballs/PSYCOPG-2-6/psycopg2-2.6.tar.gz', 'local':"psycopg2-2.6.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, - 'PILLOW': {'setup': 'pillow', 'url': 'https://github.com/python-pillow/Pillow/archive/2.7.0.tar.gz', 'local':"Pillow-2.7.0.tar.gz", 'install': {'method': 'easy_install', 'option_str': None, 'dict_extra_env': None}}, + 'PILLOW': {'setup': 'pillow', 'url': 'https://github.com/python-pillow/Pillow/archive/5.0.0.tar.gz', 'local':"Pillow-5.0.0.tar.gz", 'install': {'method': 'easy_install', 'option_str': None, 'dict_extra_env': None}}, 'LXML': {'setup': 'lxml', 'url':"lxml-3.4.2.tar.gz", 'local':"lxml-3.4.2.tar.gz", 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': lxml_options}}, 'PYYAML' : { 'setup': 'PyYAML', 'url': 'http://pyyaml.org/download/pyyaml/PyYAML-3.11.tar.gz', 'local': 'PyYAML-3.11.tar.gz', 'install': {'method': 'pip', 'option_str': None, 'dict_extra_env': None}}, }) diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/Pillow-2.7.0.tar.gz Binary file virtualenv/res/src/Pillow-2.7.0.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/Pillow-5.0.0.tar.gz Binary file virtualenv/res/src/Pillow-5.0.0.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/amqp-1.4.6.tar.gz Binary file virtualenv/res/src/amqp-1.4.6.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/amqp-2.2.2.tar.gz Binary file virtualenv/res/src/amqp-2.2.2.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/billiard-3.3.0.20.tar.gz Binary file virtualenv/res/src/billiard-3.3.0.20.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/billiard-3.5.0.3.tar.gz Binary file virtualenv/res/src/billiard-3.5.0.3.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/celery-3.1.18.tar.gz Binary file virtualenv/res/src/celery-3.1.18.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/celery-4.1.0.tar.gz Binary file virtualenv/res/src/celery-4.1.0.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/kombu-3.0.26.tar.gz Binary file virtualenv/res/src/kombu-3.0.26.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/res/src/kombu-4.1.0.tar.gz Binary file virtualenv/res/src/kombu-4.1.0.tar.gz has changed diff -r dc349ee44568 -r 385e3a12ee27 virtualenv/web/res/base_requirements.txt --- a/virtualenv/web/res/base_requirements.txt Tue Mar 13 16:52:47 2018 +0100 +++ b/virtualenv/web/res/base_requirements.txt Thu Mar 15 23:52:11 2018 +0100 @@ -1,42 +1,42 @@ -Django==1.8.2 -Pillow==2.7.0 -PyYAML==3.11 -SPARQLWrapper==1.6.4 -SQLAlchemy==0.9.9 -Unidecode==0.04.17 -Whoosh==2.6.0 -amqp==1.4.6 +amqp==2.2.2 anyjson==0.3.3 -billiard==3.3.0.20 -celery==3.1.18 +billiard==3.5.0.3 +celery==4.1.0 cssselect==0.9.1 cssutils==1.0 +Django==1.8.2 django-appconf==1.0.1 django-celery-email==1.1.0 django-envelope==1.0 django-extensions==1.5.1 django-haystack==2.4.0 django-honeypot==0.4.0 -django-registration==1.2 +django-registration-redux==1.2 easy-thumbnails==2.2 elasticsearch==1.4.0 html5lib==0.999 httplib2==0.9 isodate==0.5.1 -jedi==0.8.1-final0 -kombu==3.0.26 +jedi===0.8.1-final0 +kombu==4.1.0 lxml==3.4.2 +Pillow==5.0.0 premailer==2.8.3 psycopg2==2.6 pycrypto==2.6.1 pyparsing==2.0.3 pytz -rdflib==4.2.0-dev +PyYAML==3.11 +rdflib==4.2.2 requests==2.6.0 simplejson==3.6.5 six==1.9.0 +SPARQLWrapper==1.6.4 +SQLAlchemy==0.9.9 ua-parser==0.3.6 +Unidecode==0.4.17 urllib3==1.10.2 user-agents==0.3.0 +wheel==0.24.0 +Whoosh==2.6.0 wikitools==1.2 -wsgiref==0.1.2