<commit_before>"""
Django settings for dash_test_runner project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import warnings

from django.utils.translation import ugettext_lazy as _

BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*z(s8sb^&p-6n#b!w=1-d2bho*+*0g_51bnx=-@a$wj6dnpd2w'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = DEBUG

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'django_nose',

    'guardian',

    # compress our CSS and js
    'compressor',

    # thumbnail
    'sorl.thumbnail',

    'smartmin',
    'smartmin.users',

    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

    # dash
    'dash.orgs',
    'dash.categories',
    'dash.dashblocks',
    'dash.stories',
    'dash.utils',

)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'smartmin.users.middleware.ChangePasswordMiddleware',
    'smartmin.middleware.TimezoneMiddleware',
    'dash.orgs.middleware.SetOrgMiddleware',
)

warnings.filterwarnings('error', r"DateTimeField received a naive datetime",
                        RuntimeWarning, r'django\.db\.models\.fields')

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.contrib.messages.context_processors.messages',
    'django.core.context_processors.request',
    'dash.orgs.context_processors.user_group_perms_processor',
    'dash.orgs.context_processors.set_org_processor',
)

ROOT_URLCONF = 'dash_test_runner.urls'

WSGI_APPLICATION = 'dash_test_runner.wsgi.application'

# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

SITE_ID = 1

# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/

LANGUAGE_CODE = 'en-us'

# Available languages for translation
LANGUAGES = (('en', "English"), ('fr', "French"))
DEFAULT_LANGUAGE = "en"

TIME_ZONE = 'UTC'
USER_TIME_ZONE = 'Africa/Kigali'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''

# 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 = ''

# 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 = ''

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

# 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/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',
)

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'hamlpy.template.loaders.HamlPyFilesystemLoader',
    'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    # 'django.template.loaders.eggs.Loader',
)

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',  # this is default
    'guardian.backends.ObjectPermissionBackend',
)

# create the smartmin CRUDL permissions on all objects
PERMISSIONS = {
    '*': ('create',  # can create an object
          'read',   # can read an object, viewing it's details
          'update',  # can update an object
          'delete',  # can delete an object,
          'list'),  # can view a list of the objects
    'auth.user': ('profile', 'forget', 'recover', 'expired', 'failed', 'newpassword', 'mimic'),
    'orgs.org': ('choose', 'home', 'edit', 'manage_accounts', 'create_login', 'join'),
    'stories.story': ('images',),
}

# assigns the permissions that each group should have, here creating an Administrator group with
# authority to create and change users
GROUP_PERMISSIONS = {
    "Administrators": (
        'categories.category.*',
        'categories.categoryimage.*',
        'dashblocks.dashblock.*',
        'users.user_profile',
        'orgs.org_home',
        'orgs.org_edit',
        'orgs.org_manage_accounts',
        'orgs.orgbackground.*',
        'stories.story.*',

    ),
    "Editors": (
        'categories.category.*',
        'categories.categoryimage.*',
        'dashblocks.dashblock.*',
        'dashblocks.dashblocktype.*',
        'news.newsitem.*',
        'news.video.*',
        'orgs.org_home',
        'orgs.org_profile',
        'polls.poll.*',
        'polls.pollcategory.*',
        'polls.pollimage.*',
        'polls.featuredresponse.*',
        'stories.story.*',
        'stories.storyimage.*',
        'users.user_profile',
    ),
    "Viewers": [],
}

ANONYMOUS_USER_ID = -1
LOGIN_URL = '/users/login/'
LOGIN_REDIRECT_URL = "/manage/org/choose/"
LOGOUT_REDIRECT_URL = "/"

# ----------------------------------------------------------------------------
# Django-Nose config
# ----------------------------------------------------------------------------

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

# ----------------------------------------------------------------------------
# Async tasks with django-celery
# ----------------------------------------------------------------------------

CELERY_RESULT_BACKEND = None

BROKER_BACKEND = 'redis'
BROKER_HOST = 'localhost'
BROKER_PORT = 6379
BROKER_VHOST = '4'

# RapidPRO
API_ENDPOINT = 'http://localhost:8001'
HOSTNAME = 'ureport.io'
SITE_CHOOSER_TEMPLATE = 'orgs/org_chooser.html'
SITE_CHOOSER_URL_NAME = 'orgs.org_chooser'

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.cache.RedisCache',
        'LOCATION': '127.0.0.1:6379:1',
        'OPTIONS': {
            'CLIENT_CLASS': 'redis_cache.client.DefaultClient',
        }
    }
}

ORG_CONFIG_FIELDS = [
    dict(name='shortcode',
         field=dict(help_text=_("The shortcode that users will use to contact U-report locally"),
                    required=True)),
    dict(name='join_text',
         field=dict(help_text=_("The short text used to direct visitors to join U-report"),
                    required=False)),
    dict(name='join_fg_color',
         field=dict(help_text=_("The color used to draw the text on the join bar"),
                    required=False),
         superuser_only=True),
    dict(name='join_bg_color',
         field=dict(help_text=_("The color used to draw the background on the join bar"),
                    required=False),
         superuser_only=True),
    dict(name='primary_color',
         field=dict(help_text=_("The primary color for styling for this organization"),
                    required=False),
         superuser_only=True),
    dict(name='secondary_color',
         field=dict(help_text=_("The secondary color for styling for this organization"),
                    required=False),
         superuser_only=True),
    dict(name='bg_color',
         field=dict(help_text=_("The background color for the site"),
                    required=False),
         superuser_only=True),
    dict(name='colors',
         field=dict(help_text=_("Up to 6 colors for styling charts, use comma between colors"),
                    required=False),
         superuser_only=True),
    dict(name='google_tracking_id',
         field=dict(help_text=_("The Google Analytics Tracking ID for this organization"),
                    required=False)),
    dict(name='youtube_channel_url',
         field=dict(help_text=_("The URL to the Youtube channel for this organization"),
                    required=False)),
    dict(name='facebook_page_url',
         field=dict(help_text=_("The URL to the Facebook page for this organization"),
                    required=False)),
    dict(name='twitter_handle',
         field=dict(help_text=_("The Twitter handle for this organization"),
                    required=False)),
    dict(name='twitter_user_widget',
         field=dict(help_text=_("The Twitter widget used for following new users"),
                    required=False)),
    dict(name='twitter_search_widget',
         field=dict(help_text=_("The Twitter widget used for searching"),
                    required=False)),
    dict(name='reporter_group',
         field=dict(help_text=_("The name of txbhe Contact Group that contains "
                                "registered reporters")),
         superuser_only=True),
    dict(name='born_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the birth date of reporters")),
         superuser_only=True),
    dict(name='gender_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the gender of reporters")),
         superuser_only=True),
    dict(name='occupation_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the occupation of reporters")),
         superuser_only=True),
    dict(name='registration_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the registration date of reporters")),
         superuser_only=True),
    dict(name='state_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the State of reporters")),
         superuser_only=True),
    dict(name='district_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the District of reporters")),
         superuser_only=True),
    dict(name='male_label',
         field=dict(help_text=_("The label assigned to U-reporters that are Male.")),
         superuser_only=True),
    dict(name='female_label',
         field=dict(help_text=_("The label assigned to U-reporters that are Female.")),
         superuser_only=True),
    dict(name='has_jobs',
         field=dict(help_text=_("If there are jobs to be shown on the public site"),
                    required=False)),
    # dict(name='featured_state',
    #      field=dict(help_text=_("Choose the featured State of reporters "
    #                             "shown on the home page"))),
]

# ----------------------------------------------------------------------------
# Directory Configuration
# ----------------------------------------------------------------------------

PROJECT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)))
RESOURCES_DIR = os.path.join(PROJECT_DIR, '../resources')
TESTFILES_DIR = os.path.join(PROJECT_DIR, '../testfiles')
MEDIA_ROOT = os.path.join(PROJECT_DIR, '../media')
MEDIA_URL = "/media/"
<commit_msg>Disable logging while running tests<commit_after>"""
Django settings for dash_test_runner project.

For more information on this file, see
https://docs.djangoproject.com/en/dev/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/dev/ref/settings/
"""

import logging
import os
import warnings

from django.utils.translation import ugettext_lazy as _

# Disable logging during test runs.
logging.disable(logging.CRITICAL)

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(__file__))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/dev/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*z(s8sb^&p-6n#b!w=1-d2bho*+*0g_51bnx=-@a$wj6dnpd2w'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

TEMPLATE_DEBUG = DEBUG

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'django_nose',

    'guardian',

    # compress our CSS and js
    'compressor',

    # thumbnail
    'sorl.thumbnail',

    'smartmin',
    'smartmin.users',

    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

    # dash
    'dash.orgs',
    'dash.categories',
    'dash.dashblocks',
    'dash.stories',
    'dash.utils',

)

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'smartmin.users.middleware.ChangePasswordMiddleware',
    'smartmin.middleware.TimezoneMiddleware',
    'dash.orgs.middleware.SetOrgMiddleware',
)

warnings.filterwarnings('error', r"DateTimeField received a naive datetime",
                        RuntimeWarning, r'django\.db\.models\.fields')

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.contrib.messages.context_processors.messages',
    'django.core.context_processors.request',
    'dash.orgs.context_processors.user_group_perms_processor',
    'dash.orgs.context_processors.set_org_processor',
)

ROOT_URLCONF = 'dash_test_runner.urls'

WSGI_APPLICATION = 'dash_test_runner.wsgi.application'

# Database
# https://docs.djangoproject.com/en/dev/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

SITE_ID = 1

# Internationalization
# https://docs.djangoproject.com/en/dev/topics/i18n/

LANGUAGE_CODE = 'en-us'

# Available languages for translation
LANGUAGES = (('en', "English"), ('fr', "French"))
DEFAULT_LANGUAGE = "en"

TIME_ZONE = 'UTC'
USER_TIME_ZONE = 'Africa/Kigali'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''

# 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 = ''

# 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 = ''

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

# 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/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',
)

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'hamlpy.template.loaders.HamlPyFilesystemLoader',
    'hamlpy.template.loaders.HamlPyAppDirectoriesLoader',
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
    # 'django.template.loaders.eggs.Loader',
)

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',  # this is default
    'guardian.backends.ObjectPermissionBackend',
)

# create the smartmin CRUDL permissions on all objects
PERMISSIONS = {
    '*': ('create',  # can create an object
          'read',   # can read an object, viewing it's details
          'update',  # can update an object
          'delete',  # can delete an object,
          'list'),  # can view a list of the objects
    'auth.user': ('profile', 'forget', 'recover', 'expired', 'failed', 'newpassword', 'mimic'),
    'orgs.org': ('choose', 'home', 'edit', 'manage_accounts', 'create_login', 'join'),
    'stories.story': ('images',),
}

# assigns the permissions that each group should have, here creating an Administrator group with
# authority to create and change users
GROUP_PERMISSIONS = {
    "Administrators": (
        'categories.category.*',
        'categories.categoryimage.*',
        'dashblocks.dashblock.*',
        'users.user_profile',
        'orgs.org_home',
        'orgs.org_edit',
        'orgs.org_manage_accounts',
        'orgs.orgbackground.*',
        'stories.story.*',

    ),
    "Editors": (
        'categories.category.*',
        'categories.categoryimage.*',
        'dashblocks.dashblock.*',
        'dashblocks.dashblocktype.*',
        'news.newsitem.*',
        'news.video.*',
        'orgs.org_home',
        'orgs.org_profile',
        'polls.poll.*',
        'polls.pollcategory.*',
        'polls.pollimage.*',
        'polls.featuredresponse.*',
        'stories.story.*',
        'stories.storyimage.*',
        'users.user_profile',
    ),
    "Viewers": [],
}

ANONYMOUS_USER_ID = -1
LOGIN_URL = '/users/login/'
LOGIN_REDIRECT_URL = "/manage/org/choose/"
LOGOUT_REDIRECT_URL = "/"

# ----------------------------------------------------------------------------
# Django-Nose config
# ----------------------------------------------------------------------------

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

# ----------------------------------------------------------------------------
# Async tasks with django-celery
# ----------------------------------------------------------------------------

CELERY_RESULT_BACKEND = None

BROKER_BACKEND = 'redis'
BROKER_HOST = 'localhost'
BROKER_PORT = 6379
BROKER_VHOST = '4'

# RapidPRO
API_ENDPOINT = 'http://localhost:8001'
HOSTNAME = 'ureport.io'
SITE_CHOOSER_TEMPLATE = 'orgs/org_chooser.html'
SITE_CHOOSER_URL_NAME = 'orgs.org_chooser'

CACHES = {
    'default': {
        'BACKEND': 'redis_cache.cache.RedisCache',
        'LOCATION': '127.0.0.1:6379:1',
        'OPTIONS': {
            'CLIENT_CLASS': 'redis_cache.client.DefaultClient',
        }
    }
}

ORG_CONFIG_FIELDS = [
    dict(name='shortcode',
         field=dict(help_text=_("The shortcode that users will use to contact U-report locally"),
                    required=True)),
    dict(name='join_text',
         field=dict(help_text=_("The short text used to direct visitors to join U-report"),
                    required=False)),
    dict(name='join_fg_color',
         field=dict(help_text=_("The color used to draw the text on the join bar"),
                    required=False),
         superuser_only=True),
    dict(name='join_bg_color',
         field=dict(help_text=_("The color used to draw the background on the join bar"),
                    required=False),
         superuser_only=True),
    dict(name='primary_color',
         field=dict(help_text=_("The primary color for styling for this organization"),
                    required=False),
         superuser_only=True),
    dict(name='secondary_color',
         field=dict(help_text=_("The secondary color for styling for this organization"),
                    required=False),
         superuser_only=True),
    dict(name='bg_color',
         field=dict(help_text=_("The background color for the site"),
                    required=False),
         superuser_only=True),
    dict(name='colors',
         field=dict(help_text=_("Up to 6 colors for styling charts, use comma between colors"),
                    required=False),
         superuser_only=True),
    dict(name='google_tracking_id',
         field=dict(help_text=_("The Google Analytics Tracking ID for this organization"),
                    required=False)),
    dict(name='youtube_channel_url',
         field=dict(help_text=_("The URL to the Youtube channel for this organization"),
                    required=False)),
    dict(name='facebook_page_url',
         field=dict(help_text=_("The URL to the Facebook page for this organization"),
                    required=False)),
    dict(name='twitter_handle',
         field=dict(help_text=_("The Twitter handle for this organization"),
                    required=False)),
    dict(name='twitter_user_widget',
         field=dict(help_text=_("The Twitter widget used for following new users"),
                    required=False)),
    dict(name='twitter_search_widget',
         field=dict(help_text=_("The Twitter widget used for searching"),
                    required=False)),
    dict(name='reporter_group',
         field=dict(help_text=_("The name of txbhe Contact Group that contains "
                                "registered reporters")),
         superuser_only=True),
    dict(name='born_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the birth date of reporters")),
         superuser_only=True),
    dict(name='gender_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the gender of reporters")),
         superuser_only=True),
    dict(name='occupation_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the occupation of reporters")),
         superuser_only=True),
    dict(name='registration_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the registration date of reporters")),
         superuser_only=True),
    dict(name='state_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the State of reporters")),
         superuser_only=True),
    dict(name='district_label',
         field=dict(help_text=_("The label of the Contact Field that contains "
                                "the District of reporters")),
         superuser_only=True),
    dict(name='male_label',
         field=dict(help_text=_("The label assigned to U-reporters that are Male.")),
         superuser_only=True),
    dict(name='female_label',
         field=dict(help_text=_("The label assigned to U-reporters that are Female.")),
         superuser_only=True),
    dict(name='has_jobs',
         field=dict(help_text=_("If there are jobs to be shown on the public site"),
                    required=False)),
    # dict(name='featured_state',
    #      field=dict(help_text=_("Choose the featured State of reporters "
    #                             "shown on the home page"))),
]

# ----------------------------------------------------------------------------
# Directory Configuration
# ----------------------------------------------------------------------------

PROJECT_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)))
RESOURCES_DIR = os.path.join(PROJECT_DIR, '../resources')
TESTFILES_DIR = os.path.join(PROJECT_DIR, '../testfiles')
MEDIA_ROOT = os.path.join(PROJECT_DIR, '../media')
MEDIA_URL = "/media/"
<|endoftext|>


<commit_before># -*- coding: UTF-8
from globaleaks.db.migrations.update import MigrationBase
from globaleaks.models.config import NodeFactory, NotificationFactory
from globaleaks.models.l10n import EnabledLanguage
from globaleaks.settings import GLSettings
from globaleaks.models import *

class Context_v_34(ModelWithID):
    __storm_table__ = 'context'
    show_small_receiver_cards = Bool(default=False)
    show_context = Bool(default=True)
    show_recipients_details = Bool(default=False)
    allow_recipients_selection = Bool(default=False)
    maximum_selectable_receivers = Int(default=0)
    select_all_receivers = Bool(default=True)
    enable_comments = Bool(default=True)
    enable_messages = Bool(default=False)
    enable_two_way_comments = Bool(default=True)
    enable_two_way_messages = Bool(default=True)
    enable_attachments = Bool(default=True)
    tip_timetolive = Int(default=15)
    name = JSON(validator=shortlocal_v)
    description = JSON(validator=longlocal_v)
    recipients_clarification = JSON()
    status_page_message = JSON()
    show_receivers_in_alphabetical_order = Bool(default=False)
    presentation_order = Int(default=0)
    questionnaire_id = Unicode()
    img_id = Unicode()

    localized_keys = ['name', 'description', 'recipients_clarification', 'status_page_message']

class MigrationScript(MigrationBase):

    # Trim a Config validator to fall within the range of the range_v object
    # This ensures that future update to the config dictionary will not fail
    # because an old value was set outside of the acceptable range.
    def trim_value_to_range(self, factory, name):
        cfg_v = factory.get_val(name)
        cfg_d = factory.group_desc[name]
        if cfg_v > cfg_d.validator.stop:
            nf.set_val(name, cfg_d.validator.stop)
        if cfg_v < cfg_d.validator.start:
            GLSettings.print_msg('[Warning!] Found field with negative value %s reseting to default' % s)
            nf.set_val(name, cfg_d.default)

    def prologue(self):
       nf = NodeFactory(self.store_old)
       self.trim_value_to_range(nf, 'wbtip_timetolive')
       self.trim_value_to_range(nf, 'submission_maximum_ttl')
       self.store_old.commit()

       # TODO include fix for PGP KEYS

    def migrate_Context(self):
        old_objs = self.store_old.find(self.model_from['Context'])
        for old_obj in old_objs:
            new_obj = self.model_to['Context']()
            for _, v in new_obj._storm_columns.iteritems():
                if v.name == 'tip_timetolive':
                    # NOTE hardcoded policy. . . .
                    tip_ttl = 5*365
                    if old_obj.tip_timetolive > tip_ttl:
                        GLSettings.print_msg('[WARNING] This update changes the servers submission retention policy')
                        # If data retention was larger than 5 years the intended goal was
                        # probably to keep the submission around forever.
                        new_obj.tip_timetolive = -1
                    elif old_obj.tip_timetolive < -1:
                        GLSettings.print_msg('[WARNING] Found tip_ttl with negative value %s reseting to default')
                        new_obj.tip_timetolive = Context.tip_timetolive.default
                    else:
                        new_obj.tip_timetolive = old_obj.tip_timetolive
                    continue

class MigrationScript(MigrationBase):
    def migrate_User(self):
        default_language = NodeFactory(self.store_old).get_val('default_language')
        enabled_languages = EnabledLanguage.list(self.store_old)

        old_objs = self.store_old.find(self.model_from['User'])
        for old_obj in old_objs:
            new_obj = self.model_to['User']()
            for _, v in new_obj._storm_columns.iteritems():
                if v.name == 'language' and getattr(old_obj, v.name) not in enabled_languages:
                    # fix users that have configured a language that has never been there
                    #setattr(new_obj, v.name, default_language)
                    continue

                setattr(new_obj, v.name, getattr(old_obj, v.name))

            self.store_new.add(new_obj)
<commit_msg>Decomment line in migration script 35<commit_after># -*- coding: UTF-8
from globaleaks.db.migrations.update import MigrationBase
from globaleaks.models.config import NodeFactory, NotificationFactory
from globaleaks.models.l10n import EnabledLanguage
from globaleaks.settings import GLSettings
from globaleaks.models import *

class Context_v_34(ModelWithID):
    __storm_table__ = 'context'
    show_small_receiver_cards = Bool(default=False)
    show_context = Bool(default=True)
    show_recipients_details = Bool(default=False)
    allow_recipients_selection = Bool(default=False)
    maximum_selectable_receivers = Int(default=0)
    select_all_receivers = Bool(default=True)
    enable_comments = Bool(default=True)
    enable_messages = Bool(default=False)
    enable_two_way_comments = Bool(default=True)
    enable_two_way_messages = Bool(default=True)
    enable_attachments = Bool(default=True)
    tip_timetolive = Int(default=15)
    name = JSON(validator=shortlocal_v)
    description = JSON(validator=longlocal_v)
    recipients_clarification = JSON()
    status_page_message = JSON()
    show_receivers_in_alphabetical_order = Bool(default=False)
    presentation_order = Int(default=0)
    questionnaire_id = Unicode()
    img_id = Unicode()

    localized_keys = ['name', 'description', 'recipients_clarification', 'status_page_message']

class MigrationScript(MigrationBase):

    # Trim a Config validator to fall within the range of the range_v object
    # This ensures that future update to the config dictionary will not fail
    # because an old value was set outside of the acceptable range.
    def trim_value_to_range(self, factory, name):
        cfg_v = factory.get_val(name)
        cfg_d = factory.group_desc[name]
        if cfg_v > cfg_d.validator.stop:
            nf.set_val(name, cfg_d.validator.stop)
        if cfg_v < cfg_d.validator.start:
            GLSettings.print_msg('[Warning!] Found field with negative value %s reseting to default' % s)
            nf.set_val(name, cfg_d.default)

    def prologue(self):
       nf = NodeFactory(self.store_old)
       self.trim_value_to_range(nf, 'wbtip_timetolive')
       self.trim_value_to_range(nf, 'submission_maximum_ttl')
       self.store_old.commit()

       # TODO include fix for PGP KEYS

    def migrate_Context(self):
        old_objs = self.store_old.find(self.model_from['Context'])
        for old_obj in old_objs:
            new_obj = self.model_to['Context']()
            for _, v in new_obj._storm_columns.iteritems():
                if v.name == 'tip_timetolive':
                    # NOTE hardcoded policy. . . .
                    tip_ttl = 5*365
                    if old_obj.tip_timetolive > tip_ttl:
                        GLSettings.print_msg('[WARNING] This update changes the servers submission retention policy')
                        # If data retention was larger than 5 years the intended goal was
                        # probably to keep the submission around forever.
                        new_obj.tip_timetolive = -1
                    elif old_obj.tip_timetolive < -1:
                        GLSettings.print_msg('[WARNING] Found tip_ttl with negative value %s reseting to default')
                        new_obj.tip_timetolive = Context.tip_timetolive.default
                    else:
                        new_obj.tip_timetolive = old_obj.tip_timetolive
                    continue

class MigrationScript(MigrationBase):
    def migrate_User(self):
        default_language = NodeFactory(self.store_old).get_val('default_language')
        enabled_languages = EnabledLanguage.list(self.store_old)

        old_objs = self.store_old.find(self.model_from['User'])
        for old_obj in old_objs:
            new_obj = self.model_to['User']()
            for _, v in new_obj._storm_columns.iteritems():
                if v.name == 'language' and getattr(old_obj, v.name) not in enabled_languages:
                    # fix users that have configured a language that has never been there
                    setattr(new_obj, v.name, default_language)
                    continue

                setattr(new_obj, v.name, getattr(old_obj, v.name))

            self.store_new.add(new_obj)
<|endoftext|>


<commit_before>
#
# spyne - Copyright (C) Spyne contributors.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
#

"""The ``spyne.server.twisted`` module contains a server transport compatible
with the Twisted event loop. It uses the TwistedWebResource object as transport.

Also see the twisted examples in the examples directory of the source
distribution.

If you want to have a hard-coded URL in the wsdl document, this is how to do
it: ::

    resource = TwistedWebResource(...)
    resource.http_transport.doc.wsdl11.build_interface_document("http://example.com")

This is not strictly necessary -- if you don't do this, Spyne will get the
URL from the first request, build the wsdl on-the-fly and cache it as a
string in memory for later requests. However, if you want to make sure
you only have this url on the WSDL, this is how to do it. Note that if
your client takes the information in wsdl seriously, all requests will go
to the designated url above which can make testing a bit difficult. Use
in moderation.

This module is EXPERIMENTAL. Your mileage may vary. Patches are welcome.
"""

from __future__ import absolute_import

import logging
logger = logging.getLogger(__name__)

from inspect import isgenerator

from spyne.error import InternalError
from twisted.python.log import err
from twisted.internet.interfaces import IPullProducer
from twisted.internet.defer import Deferred
from twisted.internet.protocol import Factory
from twisted.web.iweb import UNKNOWN_LENGTH
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.python import log

# FIXME: Switch to:
#    from twisted.web.websockets import WebSocketsProtocol
#    from twisted.web.websockets import WebSocketsResource
#    from twisted.web.websockets import CONTROLS

from spyne.util._twisted_ws import WebSocketsProtocol
from spyne.util._twisted_ws import WebSocketsResource
from spyne.util._twisted_ws import CONTROLS

from zope.interface import implements

from spyne import MethodContext
from spyne import TransportContext
from spyne.auxproc import process_contexts
from spyne.const.ansi_color import LIGHT_GREEN
from spyne.const.ansi_color import END_COLOR
from spyne.const.http import HTTP_404
from spyne.model import PushBase
from spyne.model.complex import ComplexModel
from spyne.model.fault import Fault
from spyne.server import ServerBase
from spyne.server.http import HttpBase
from spyne.server.http import HttpMethodContext

def _reconstruct_url(request):
    server_name = request.getRequestHostname()
    server_port = request.getHost().port
    if (bool(request.isSecure()), server_port) not in [(True, 443), (False, 80)]:
        server_name = '%s:%d' % (server_name, server_port)

    if request.isSecure():
        url_scheme = 'https'
    else:
        url_scheme = 'http'

    return ''.join([url_scheme, "://", server_name, request.uri])

class _Producer(object):
    implements(IPullProducer)

    deferred = None

    def __init__(self, body, consumer):
        """:param body: an iterable of strings"""

        # check to see if we can determine the length
        try:
            len(body) # iterator?
            self.length = sum([len(fragment) for fragment in body])
            self.body = iter(body)

        except TypeError:
            self.length = UNKNOWN_LENGTH
            self.body = body

        self.deferred = Deferred()

        self.consumer = consumer

    def resumeProducing(self):
        try:
            chunk = self.body.next()

        except StopIteration, e:
            self.consumer.unregisterProducer()
            if self.deferred is not None:
                self.deferred.callback(self.consumer)
                self.deferred = None
            return

        self.consumer.write(chunk)

    def pauseProducing(self):
        pass

    def stopProducing(self):
        if self.deferred is not None:
            self.deferred.errback(
                               Exception("Consumer asked us to stop producing"))
        self.deferred = None

class TwistedHttpTransport(HttpBase):
    @staticmethod
    def decompose_incoming_envelope(prot, ctx, message):
        """This function is only called by the HttpRpc protocol to have the
        twisted web's Request object is parsed into ``ctx.in_body_doc`` and
        ``ctx.in_header_doc``.
        """

        request = ctx.in_document

        ctx.method_request_string = '{%s}%s' % (prot.app.interface.get_tns(),
                                                    request.path.split('/')[-1])

        logger.debug("%sMethod name: %r%s" % (LIGHT_GREEN,
                                          ctx.method_request_string, END_COLOR))

        ctx.in_header_doc = dict(request.requestHeaders.getAllRawHeaders())
        ctx.in_body_doc = request.args

class TwistedWebResource(Resource):
    """A server transport that exposes the application as a twisted web
    Resource.
    """

    isLeaf = True

    def __init__(self, app, chunked=False, max_content_length=2 * 1024 * 1024,
                                           block_length=8 * 1024):
        Resource.__init__(self)

        self.http_transport = TwistedHttpTransport(app, chunked,
                                            max_content_length, block_length)
        self._wsdl = None

    def render_GET(self, request):
        if request.uri.endswith('.wsdl') or request.uri.endswith('?wsdl'):
            return self.__handle_wsdl_request(request)

        else:
            return self.handle_rpc(request)

    def render_POST(self, request):
        return self.handle_rpc(request)

    def handle_rpc_error(self, p_ctx, others, error, request):
        resp_code = p_ctx.transport.resp_code
        # If user code set its own response code, don't touch it.
        if resp_code is None:
            resp_code = p_ctx.out_protocol.fault_to_http_response_code(error)

        request.setResponseCode(int(resp_code[:3]))

        # In case user code set its own out_* attributes before failing.
        p_ctx.out_document = None
        p_ctx.out_string = None

        p_ctx.out_object = error
        self.http_transport.get_out_string(p_ctx)

        retval = ''.join(p_ctx.out_string)

        p_ctx.close()

        process_contexts(self.http_transport, others, p_ctx, error=error)

        return retval

    def handle_rpc(self, request):
        initial_ctx = HttpMethodContext(self.http_transport, request,
                                 self.http_transport.app.out_protocol.mime_type)
        initial_ctx.in_string = [request.content.getvalue()]

        contexts = self.http_transport.generate_contexts(initial_ctx)
        p_ctx, others = contexts[0], contexts[1:]

        if p_ctx.in_error:
            return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request)

        else:
            self.http_transport.get_in_object(p_ctx)

            if p_ctx.in_error:
                return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request)

            else:
                self.http_transport.get_out_object(p_ctx)
                if p_ctx.out_error:
                    return self.handle_rpc_error(p_ctx, others, p_ctx.out_error,
                                                                        request)

        def _cb_request_finished(request):
            request.finish()
            p_ctx.close()

        def _eb_request_finished(request):
            err(request)
            p_ctx.close()
            request.finish()

        def _cb_deferred(retval, request, cb=True):
            if cb and len(p_ctx.descriptor.out_message._type_info) <= 1:
                p_ctx.out_object = [retval]
            else:
                p_ctx.out_object = retval

            self.http_transport.get_out_string(p_ctx)

            process_contexts(self.http_transport, others, p_ctx)

            producer = _Producer(p_ctx.out_string, request)
            producer.deferred.addCallbacks(_cb_request_finished,
                                                           _eb_request_finished)
            request.registerProducer(producer, False)

        def _eb_deferred(retval, request):
            p_ctx.out_error = retval.value
            if not issubclass(retval.type, Fault):
                retval.printTraceback()
                p_ctx.out_error = InternalError(retval.value)

            ret = self.handle_rpc_error(p_ctx, others, p_ctx.out_error, request)
            request.write(ret)
            request.finish()

        ret = p_ctx.out_object[0]
        if isinstance(ret, Deferred):
            ret.addCallback(_cb_deferred, request)
            ret.addErrback(_eb_deferred, request)

        elif isinstance(ret, PushBase):
            gen = self.http_transport.get_out_string(p_ctx)

            assert isgenerator(gen), "It looks like this protocol is not " \
                                     "async-compliant yet."

            def _cb_push():
                process_contexts(self.http_transport, others, p_ctx)

                producer = _Producer(p_ctx.out_string, request)
                producer.deferred.addCallbacks(_cb_request_finished,
                                                           _eb_request_finished)
                request.registerProducer(producer, False)

            ret.init(p_ctx, request, gen, _cb_push, None)

        else:
            _cb_deferred(p_ctx.out_object, request, cb=False)

        return NOT_DONE_YET

    def __handle_wsdl_request(self, request):
        ctx = HttpMethodContext(self.http_transport, request,
                                                      "text/xml; charset=utf-8")
        url = _reconstruct_url(request)

        if self.http_transport.doc.wsdl11 is None:
            return HTTP_404

        if self._wsdl is None:
            self._wsdl = self.http_transport.doc.wsdl11.get_interface_document()

        ctx.transport.wsdl = self._wsdl

        try:
            if self._wsdl is None:
                self.http_transport.doc.wsdl11.build_interface_document(url)
                ctx.transport.wsdl = self._wsdl = \
                         self.http_transport.doc.wsdl11.get_interface_document()

            assert ctx.transport.wsdl is not None

            self.http_transport.event_manager.fire_event('wsdl', ctx)

            return ctx.transport.wsdl

        except Exception, e:
            ctx.transport.wsdl_error = e
            self.http_transport.event_manager.fire_event('wsdl_exception', ctx)
            raise

        finally:
            ctx.close()
<commit_msg>Implemented TwistedHttpMethodContext and TwistedHttpTransportContext to enable properly setting Content-Type HTTP header as necessary.<commit_after>
#
# spyne - Copyright (C) Spyne contributors.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
#

"""The ``spyne.server.twisted`` module contains a server transport compatible
with the Twisted event loop. It uses the TwistedWebResource object as transport.

Also see the twisted examples in the examples directory of the source
distribution.

If you want to have a hard-coded URL in the wsdl document, this is how to do
it: ::

    resource = TwistedWebResource(...)
    resource.http_transport.doc.wsdl11.build_interface_document("http://example.com")

This is not strictly necessary -- if you don't do this, Spyne will get the
URL from the first request, build the wsdl on-the-fly and cache it as a
string in memory for later requests. However, if you want to make sure
you only have this url on the WSDL, this is how to do it. Note that if
your client takes the information in wsdl seriously, all requests will go
to the designated url above which can make testing a bit difficult. Use
in moderation.

This module is EXPERIMENTAL. Your mileage may vary. Patches are welcome.
"""

from __future__ import absolute_import

import logging
logger = logging.getLogger(__name__)

from inspect import isgenerator

from spyne.error import InternalError
from twisted.python.log import err
from twisted.internet.interfaces import IPullProducer
from twisted.internet.defer import Deferred
from twisted.internet.protocol import Factory
from twisted.web.iweb import UNKNOWN_LENGTH
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.python import log

# FIXME: Switch to:
#    from twisted.web.websockets import WebSocketsProtocol
#    from twisted.web.websockets import WebSocketsResource
#    from twisted.web.websockets import CONTROLS

from spyne.util._twisted_ws import WebSocketsProtocol
from spyne.util._twisted_ws import WebSocketsResource
from spyne.util._twisted_ws import CONTROLS

from zope.interface import implements

from spyne import MethodContext
from spyne import TransportContext
from spyne.auxproc import process_contexts
from spyne.const.ansi_color import LIGHT_GREEN
from spyne.const.ansi_color import END_COLOR
from spyne.const.http import HTTP_404
from spyne.model import PushBase
from spyne.model.complex import ComplexModel
from spyne.model.fault import Fault
from spyne.server import ServerBase
from spyne.server.http import HttpBase
from spyne.server.http import HttpMethodContext
from spyne.server.http import HttpTransportContext

def _reconstruct_url(request):
    server_name = request.getRequestHostname()
    server_port = request.getHost().port
    if (bool(request.isSecure()), server_port) not in [(True, 443), (False, 80)]:
        server_name = '%s:%d' % (server_name, server_port)

    if request.isSecure():
        url_scheme = 'https'
    else:
        url_scheme = 'http'

    return ''.join([url_scheme, "://", server_name, request.uri])

class _Producer(object):
    implements(IPullProducer)

    deferred = None

    def __init__(self, body, consumer):
        """:param body: an iterable of strings"""

        # check to see if we can determine the length
        try:
            len(body) # iterator?
            self.length = sum([len(fragment) for fragment in body])
            self.body = iter(body)

        except TypeError:
            self.length = UNKNOWN_LENGTH
            self.body = body

        self.deferred = Deferred()

        self.consumer = consumer

    def resumeProducing(self):
        try:
            chunk = self.body.next()

        except StopIteration, e:
            self.consumer.unregisterProducer()
            if self.deferred is not None:
                self.deferred.callback(self.consumer)
                self.deferred = None
            return

        self.consumer.write(chunk)

    def pauseProducing(self):
        pass

    def stopProducing(self):
        if self.deferred is not None:
            self.deferred.errback(
                               Exception("Consumer asked us to stop producing"))
        self.deferred = None

class TwistedHttpTransportContext(HttpTransportContext):

    def set_mime_type(self, what):
        super(TwistedHttpTransportContext, self).set_mime_type(what)
        self.req.setHeader('Content-Type', what)

class TwistedHttpMethodContext(HttpMethodContext):

    default_transport_context = TwistedHttpTransportContext

class TwistedHttpTransport(HttpBase):
    @staticmethod
    def decompose_incoming_envelope(prot, ctx, message):
        """This function is only called by the HttpRpc protocol to have the
        twisted web's Request object is parsed into ``ctx.in_body_doc`` and
        ``ctx.in_header_doc``.
        """

        request = ctx.in_document

        ctx.method_request_string = '{%s}%s' % (prot.app.interface.get_tns(),
                                                    request.path.split('/')[-1])

        logger.debug("%sMethod name: %r%s" % (LIGHT_GREEN,
                                          ctx.method_request_string, END_COLOR))

        ctx.in_header_doc = dict(request.requestHeaders.getAllRawHeaders())
        ctx.in_body_doc = request.args

class TwistedWebResource(Resource):
    """A server transport that exposes the application as a twisted web
    Resource.
    """

    isLeaf = True

    def __init__(self, app, chunked=False, max_content_length=2 * 1024 * 1024,
                                           block_length=8 * 1024):
        Resource.__init__(self)

        self.http_transport = TwistedHttpTransport(app, chunked,
                                            max_content_length, block_length)
        self._wsdl = None

    def render_GET(self, request):
        if request.uri.endswith('.wsdl') or request.uri.endswith('?wsdl'):
            return self.__handle_wsdl_request(request)

        else:
            return self.handle_rpc(request)

    def render_POST(self, request):
        return self.handle_rpc(request)

    def handle_rpc_error(self, p_ctx, others, error, request):
        resp_code = p_ctx.transport.resp_code
        # If user code set its own response code, don't touch it.
        if resp_code is None:
            resp_code = p_ctx.out_protocol.fault_to_http_response_code(error)

        request.setResponseCode(int(resp_code[:3]))

        # In case user code set its own out_* attributes before failing.
        p_ctx.out_document = None
        p_ctx.out_string = None

        p_ctx.out_object = error
        self.http_transport.get_out_string(p_ctx)

        retval = ''.join(p_ctx.out_string)

        p_ctx.close()

        process_contexts(self.http_transport, others, p_ctx, error=error)

        return retval

    def handle_rpc(self, request):
        initial_ctx = TwistedHttpMethodContext(self.http_transport, request,
                                 self.http_transport.app.out_protocol.mime_type)
        initial_ctx.in_string = [request.content.getvalue()]

        contexts = self.http_transport.generate_contexts(initial_ctx)
        p_ctx, others = contexts[0], contexts[1:]

        if p_ctx.in_error:
            return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request)

        else:
            self.http_transport.get_in_object(p_ctx)

            if p_ctx.in_error:
                return self.handle_rpc_error(p_ctx, others, p_ctx.in_error, request)

            else:
                self.http_transport.get_out_object(p_ctx)
                if p_ctx.out_error:
                    return self.handle_rpc_error(p_ctx, others, p_ctx.out_error,
                                                                        request)

        def _cb_request_finished(request):
            request.finish()
            p_ctx.close()

        def _eb_request_finished(request):
            err(request)
            p_ctx.close()
            request.finish()

        def _cb_deferred(retval, request, cb=True):
            if cb and len(p_ctx.descriptor.out_message._type_info) <= 1:
                p_ctx.out_object = [retval]
            else:
                p_ctx.out_object = retval

            self.http_transport.get_out_string(p_ctx)

            process_contexts(self.http_transport, others, p_ctx)

            producer = _Producer(p_ctx.out_string, request)
            producer.deferred.addCallbacks(_cb_request_finished,
                                                           _eb_request_finished)
            request.registerProducer(producer, False)

        def _eb_deferred(retval, request):
            p_ctx.out_error = retval.value
            if not issubclass(retval.type, Fault):
                retval.printTraceback()
                p_ctx.out_error = InternalError(retval.value)

            ret = self.handle_rpc_error(p_ctx, others, p_ctx.out_error, request)
            request.write(ret)
            request.finish()

        ret = p_ctx.out_object[0]
        if isinstance(ret, Deferred):
            ret.addCallback(_cb_deferred, request)
            ret.addErrback(_eb_deferred, request)

        elif isinstance(ret, PushBase):
            gen = self.http_transport.get_out_string(p_ctx)

            assert isgenerator(gen), "It looks like this protocol is not " \
                                     "async-compliant yet."

            def _cb_push():
                process_contexts(self.http_transport, others, p_ctx)

                producer = _Producer(p_ctx.out_string, request)
                producer.deferred.addCallbacks(_cb_request_finished,
                                                           _eb_request_finished)
                request.registerProducer(producer, False)

            ret.init(p_ctx, request, gen, _cb_push, None)

        else:
            _cb_deferred(p_ctx.out_object, request, cb=False)

        return NOT_DONE_YET

    def __handle_wsdl_request(self, request):
        ctx = TwistedHttpMethodContext(self.http_transport, request,
                                                      "text/xml; charset=utf-8")
        url = _reconstruct_url(request)

        if self.http_transport.doc.wsdl11 is None:
            return HTTP_404

        if self._wsdl is None:
            self._wsdl = self.http_transport.doc.wsdl11.get_interface_document()

        ctx.transport.wsdl = self._wsdl

        try:
            if self._wsdl is None:
                self.http_transport.doc.wsdl11.build_interface_document(url)
                ctx.transport.wsdl = self._wsdl = \
                         self.http_transport.doc.wsdl11.get_interface_document()

            assert ctx.transport.wsdl is not None

            self.http_transport.event_manager.fire_event('wsdl', ctx)

            return ctx.transport.wsdl

        except Exception, e:
            ctx.transport.wsdl_error = e
            self.http_transport.event_manager.fire_event('wsdl_exception', ctx)
            raise

        finally:
            ctx.close()
<|endoftext|>


<commit_before>"""
Define base controller for your API.
"""
import json
from werkzeug.exceptions import BadRequest
from werkzeug.wrappers import Request
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from abc import ABCMeta
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.exceptions import NotFound

class WSGIWrapper(object):
    """
    Base Wsgi application loader. WSGIWrapper is an abstract
    class. Herited by :class:`.ApiController` it make the class
    callable and implement the request/response process
    """

    __metaclass__ = ABCMeta

    def __call__(self, environ, start_response):
        """
        return the wsgi wrapper
        """
        return self.wsgi_app(environ, start_response)

    def wsgi_app(self, environ, start_response):
        """
        instanciate a Request object, dispatch to the needed method,
        return a response
        """
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ, start_response)

    def dispatch_request(self, request):
        """
        Using the :class:`werkzeug.routing.Map` constructed by
        :meth:`.load_urls` call the view method with the request
        object and return the response object.
        """
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, values = adapter.match()
            return getattr(self, endpoint)(request, **values)
        except HTTPException, e:
            return e

class WSGIDispatcher(DispatcherMiddleware):
    """
    WSGIDispatcher take a list of :class:`.Controller` and mount them
    on their ressource mount point.
    basic syntax is:

    .. code-block:: python

       app = WSGIDispatcher([FirstApp, SecondApp])
    """

    def __init__(self, apps):
        endpoints = {}
        for elem in apps:
            endpoints["/{0}".format(elem.ressource["ressource_name"])] = elem()
        app = NotFound()
        mounts = endpoints
        super(WSGIDispatcher, self).__init__(app, mounts=mounts)

class ApiController(WSGIWrapper):
    """
    Inherit from :class:`.WSGIWrapper`
    implement the base API method. Should be inherited to create your own API
    """

    __metaclass__ = ABCMeta

    views = None

    def __init__(self, *args, **kwargs):
        super(ApiController, self).__init__(*args, **kwargs)

    def render_list(self, objs):
        for obj in objs:
            obj['ressource_uri'] = "/{0}/{1}/".format(
                self.ressource['ressource_name'],
                obj['id'])
        return objs

    def index(self, request):
        """
        The root url of your ressources. Should present a list of
        ressources if method is GET.
        Should create a ressource if method is POST
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        if self.auth is set call
        :meth:`.authentication.Authentication.check_auth`

        :return: :meth:`.get_list` if request.method is GET,
                 :meth:`.create` if request.method is POST
        """
        if hasattr(self, "authorization"):
            self.authorization.check_auth(request)

        if request.method == "GET":
            return self.get_list(request)

        if request.method == "POST":
            return self.create(request)

    def paginate(self, request):
        """
        A pagination example. Feel free to implement your own

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """

        if hasattr(self, "pagination"):
            offset, count, request_kwargs = self.pagination.paginate(request)
        else:
            offset, count = None
        filters = request_kwargs
        return self.view['response_class'](
            self.render_list(
                self.datastore.get_list(offset=offset,
                                        count=count,
                                        **filters)
                ),
            status=200)

    def get_list(self, request):
        """
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        return self.paginate(request)

    def unique_uri(self, request, identifier):
        """
        Retreive a unique object with his URI.
        Act on it accordingly to the Http verb used.

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        if hasattr(self, "authorization"):
            self.authorization.check_auth(request)

        if request.method == "GET":
            return self.get(request, identifier)
        if request.method == "PUT":
            return self.update(request, identifier)
        if request.method == "DELETE":
            return self.delete(request, identifier)

    def get(self, request, identifier):
        """
        Return an object or 404

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        obj = self.datastore.get(identifier=identifier)

        return self.view['response_class'](
            obj,
            status=200)

    def create(self, request):
        """
        Create a new object in the datastore

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        try:
            data = json.loads(request.data)
        except:
            raise BadRequest()
        response = self.datastore.create(data)
        return self.view['response_class'](
            headers={"location": str(response)}, status=201)

    def update(self, request, identifier):
        """
        Update an object in the datastore

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`

        """
        obj = self.datastore.get(identifier=identifier)
        obj = self.datastore.update(obj, json.loads(request.data))
        return self.view['response_class'](
            obj,
            status=200)

    def delete(self, request, identifier):
        """
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        self.datastore.delete(identifier=identifier)
        return self.view['response_class'](status=200)

class Controller(ApiController):
    """
    The main views of the application
    """

    __metaclass__ = ABCMeta

    def __init__(self, *args, **kwargs):
        self.urls = [
            ('/', 'index', self.controller['list_verbs']),
            ('/<int:identifier>/',
             'unique_uri',
             self.controller['unique_verbs']),
            ]
        self.url_map = self.load_urls()
        self.datastore = self.ressource['datastore'](
            self.ressource['ressource'],
            self.ressource['model'],
            **self.ressource.get('options', {})
            )
        if self.controller.get("options", None):
            self.make_options(self.controller["options"])

        super(Controller, self).__init__(*args, **kwargs)

    def load_urls(self):
        """
        :param urls: A list of tuple in the form (url(string),
                     view(string), permitted Http verbs(list))
        :type urls: list

        return a :class:`werkzeug.routing.Map`

        this method is automaticaly called by __init__ to build the
        :class:`.Controller` urls mapping
        """
        return Map(
            [
                Rule(pattern[0], endpoint=pattern[1], methods=pattern[2])
                for pattern in self.urls
                ]
            )

    def make_options(self, options):
        if options.get("pagination", None):
            self.pagination = options["pagination"]
        if options.get("authentication", None):
            self.authentication = options["authentication"]
        if options.get("authorization", None):
            if not hasattr(self, "authentication"):
                raise ValueError(
                    "Authorization option need an Authentication backend")
            self.authorization = options["authorization"](self.authentication)
<commit_msg>code quality improvement<commit_after>"""
Define base controller for your API.
"""
import json
from werkzeug.exceptions import BadRequest
from werkzeug.wrappers import Request
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from abc import ABCMeta
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.exceptions import NotFound

class WSGIWrapper(object):
    """
    Base Wsgi application loader. WSGIWrapper is an abstract
    class. Herited by :class:`.ApiController` it make the class
    callable and implement the request/response process
    """

    __metaclass__ = ABCMeta
    url_map = None

    def __call__(self, environ, start_response):
        """
        return the wsgi wrapper
        """
        return self.wsgi_app(environ, start_response)

    def wsgi_app(self, environ, start_response):
        """
        instanciate a Request object, dispatch to the needed method,
        return a response
        """
        request = Request(environ)
        response = self.dispatch_request(request)
        return response(environ, start_response)

    def dispatch_request(self, request):
        """
        Using the :class:`werkzeug.routing.Map` constructed by
        :meth:`.load_urls` call the view method with the request
        object and return the response object.
        """
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, values = adapter.match()
            return getattr(self, endpoint)(request, **values)
        except HTTPException, e:
            return e

class WSGIDispatcher(DispatcherMiddleware):
    """
    WSGIDispatcher take a list of :class:`.Controller` and mount them
    on their ressource mount point.
    basic syntax is:

    .. code-block:: python

       app = WSGIDispatcher([FirstApp, SecondApp])
    """

    def __init__(self, apps):
        endpoints = {}
        for elem in apps:
            endpoints["/{0}".format(elem.ressource["ressource_name"])] = elem()
        app = NotFound()
        mounts = endpoints
        super(WSGIDispatcher, self).__init__(app, mounts=mounts)

class ApiController(WSGIWrapper):
    """
    Inherit from :class:`.WSGIWrapper`
    implement the base API method. Should be inherited to create your own API
    """

    __metaclass__ = ABCMeta

    view = None
    ressource = None
    authorization = None
    pagination = None
    datastore = None

    def __init__(self, *args, **kwargs):
        super(ApiController, self).__init__(*args, **kwargs)

    def render_list(self, objs):
        for obj in objs:
            obj['ressource_uri'] = "/{0}/{1}/".format(
                self.ressource['ressource_name'],
                obj['id'])
        return objs

    def index(self, request):
        """
        The root url of your ressources. Should present a list of
        ressources if method is GET.
        Should create a ressource if method is POST
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        if self.auth is set call
        :meth:`.authentication.Authentication.check_auth`

        :return: :meth:`.get_list` if request.method is GET,
                 :meth:`.create` if request.method is POST
        """
        if self.authorization:
            self.authorization.check_auth(request)

        if request.method == "GET":
            return self.get_list(request)

        if request.method == "POST":
            return self.create(request)

    def paginate(self, request):
        """
        A pagination example. Feel free to implement your own

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """

        if self.pagination:
            offset, count, request_kwargs = self.pagination.paginate(request)
        else:
            offset, count = None
        filters = request_kwargs
        return self.view['response_class'](
            self.render_list(
                self.datastore.get_list(offset=offset,
                                        count=count,
                                        **filters)
                ),
            status=200)

    def get_list(self, request):
        """
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        return self.paginate(request)

    def unique_uri(self, request, identifier):
        """
        Retreive a unique object with his URI.
        Act on it accordingly to the Http verb used.

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        if self.authorization:
            self.authorization.check_auth(request)

        if request.method == "GET":
            return self.get(request, identifier)
        if request.method == "PUT":
            return self.update(request, identifier)
        if request.method == "DELETE":
            return self.delete(request, identifier)

    def get(self, request, identifier):
        """
        Return an object or 404

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        obj = self.datastore.get(identifier=identifier)

        return self.view['response_class'](
            obj,
            status=200)

    def create(self, request):
        """
        Create a new object in the datastore

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        try:
            data = json.loads(request.data)
        except:
            raise BadRequest()
        response = self.datastore.create(data)
        return self.view['response_class'](
            headers={"location": str(response)}, status=201)

    def update(self, request, identifier):
        """
        Update an object in the datastore

        :param request:
        :type request: :class:`werkzeug.wrappers.Request`

        """
        obj = self.datastore.get(identifier=identifier)
        obj = self.datastore.update(obj, json.loads(request.data))
        return self.view['response_class'](
            obj,
            status=200)

    def delete(self, request, identifier):
        """
        :param request:
        :type request: :class:`werkzeug.wrappers.Request`
        """
        self.datastore.delete(identifier=identifier)
        return self.view['response_class'](status=200)

class Controller(ApiController):
    """
    The main views of the application
    """

    __metaclass__ = ABCMeta

    def __init__(self, *args, **kwargs):
        self.urls = [
            ('/', 'index', self.controller['list_verbs']),
            ('/<int:identifier>/',
             'unique_uri',
             self.controller['unique_verbs']),
            ]
        self.url_map = self.load_urls()
        self.datastore = self.ressource['datastore'](
            self.ressource['ressource'],
            self.ressource['model'],
            **self.ressource.get('options', {})
            )
        if self.controller.get("options", None):
            self.make_options(self.controller["options"])

        super(Controller, self).__init__(*args, **kwargs)

    def load_urls(self):
        """
        :param urls: A list of tuple in the form (url(string),
                     view(string), permitted Http verbs(list))
        :type urls: list

        return a :class:`werkzeug.routing.Map`

        this method is automaticaly called by __init__ to build the
        :class:`.Controller` urls mapping
        """
        return Map(
            [
                Rule(pattern[0], endpoint=pattern[1], methods=pattern[2])
                for pattern in self.urls
                ]
            )

    def make_options(self, options):
        if options.get("pagination", None):
            self.pagination = options["pagination"]
        if options.get("authentication", None):
            self.authentication = options["authentication"]
        if options.get("authorization", None):
            if not hasattr(self, "authentication"):
                raise ValueError(
                    "Authorization option need an Authentication backend")
            self.authorization = options["authorization"](self.authentication)
<|endoftext|>


<commit_before>from __future__ import unicode_literals
from six import StringIO, text_type
from uuid import UUID

from ordereddict import OrderedDict
from openpyxl import Workbook

from rest_framework.renderers import BaseRenderer

# six versions 1.3.0 and previous don't have PY2
try:
    from six import PY2
except ImportError:
    import sys
    PY2 = sys.version_info[0] == 2

class ExcelRenderer(BaseRenderer):

    """
    Renderer which serializes to Excel
    """

    media_type = 'application/ms-excel'
    format = 'xlsx'
    level_sep = '.'

    def render(self, data, media_type=None, renderer_context=None):
        """
        Renders serialized *data* into Excel. For a dictionary:
        """
        if data is None:
            return ''

        stream = StringIO()

        wb = Workbook()
        ws = wb.active

        table = self.tablize(data)

        for row_idx, row in enumerate(table, 1):
            for col_idx, elem in enumerate(row, 1):
                if isinstance(elem, text_type) and PY2:
                    ws.cell(column=col_idx, row=row_idx, value=elem.encode('utf-8'))
                elif isinstance(elem, UUID):
                    ws.cell(column=col_idx, row=row_idx, value=unicode(elem))
                else:
                    ws.cell(column=col_idx, row=row_idx, value=elem)

        wb.save(stream)

        return stream.getvalue()

    def tablize(self, data):
        """
        Convert a list of data into a table.
        """
        if data:

            # First, flatten the data (i.e., convert it to a list of
            # dictionaries that are each exactly one level deep).  The key for
            # each item designates the name of the column that the item will
            # fall into.
            data = self.flatten_data(data)

            # Get the set of all unique headers, and sort them.
            headers = []
            if data[0]:
                headers = data[0].keys()

            # Create a row for each dictionary, filling in columns for which the
            # item has no data with None values.
            rows = []
            for item in data:
                row = []
                for key in headers:
                    row.append(item.get(key, None))
                rows.append(row)

            # Return your "table", with the headers as the first row.
            return [headers] + rows

        else:

            return []

    def flatten_data(self, data):
        """
        Convert the given data collection to a list of dictionaries that are
        each exactly one level deep. The key for each value in the dictionaries
        designates the name of the column that the value will fall into.
        """
        flat_data = []
        for item in data:
            flat_item = self.flatten_item(item)
            flat_data.append(flat_item)

        return flat_data

    def flatten_item(self, item):
        if isinstance(item, list):
            flat_item = self.flatten_list(item)
        elif isinstance(item, dict):
            flat_item = self.flatten_dict(item)
        else:
            flat_item = {'': item}

        return flat_item

    def nest_flat_item(self, flat_item, prefix):
        """
        Given a "flat item" (a dictionary exactly one level deep), nest all of
        the column headers in a namespace designated by prefix.  For example:
         header... | with prefix... | becomes...
        -----------|----------------|----------------
         'lat'     | 'location'     | 'location.lat'
         ''        | '0'            | '0'
         'votes.1' | 'user'         | 'user.votes.1'
        """
        nested_item = {}
        for header, val in flat_item.items():
            nested_header = self.level_sep.join([prefix, header]) if header else prefix
            nested_item[nested_header] = val
        return nested_item

    def flatten_list(self, l):
        flat_list = {}
        for index, item in enumerate(l):
            index = text_type(index)
            flat_item = self.flatten_item(item)
            nested_item = self.nest_flat_item(flat_item, index)
            flat_list.update(nested_item)
        return flat_list

    def flatten_dict(self, d):
        flat_dict = OrderedDict()
        for key, item in d.iteritems():
            key = str(key)
            flat_item = self.flatten_item(item)
            nested_item = self.nest_flat_item(flat_item, key)
            flat_dict.update(nested_item)
        return flat_dict
<commit_msg>Update renderers.py<commit_after>from __future__ import unicode_literals
from six import StringIO, text_type
from uuid import UUID

from collections import OrderedDict
from openpyxl import Workbook

from rest_framework.renderers import BaseRenderer

# six versions 1.3.0 and previous don't have PY2
try:
    from six import PY2
except ImportError:
    import sys
    PY2 = sys.version_info[0] == 2

class ExcelRenderer(BaseRenderer):

    """
    Renderer which serializes to Excel
    """

    media_type = 'application/ms-excel'
    format = 'xlsx'
    level_sep = '.'

    def render(self, data, media_type=None, renderer_context=None):
        """
        Renders serialized *data* into Excel. For a dictionary:
        """
        if data is None:
            return ''

        stream = StringIO()

        wb = Workbook()
        ws = wb.active

        table = self.tablize(data)

        for row_idx, row in enumerate(table, 1):
            for col_idx, elem in enumerate(row, 1):
                if isinstance(elem, text_type) and PY2:
                    ws.cell(column=col_idx, row=row_idx, value=elem.encode('utf-8'))
                elif isinstance(elem, UUID):
                    ws.cell(column=col_idx, row=row_idx, value=unicode(elem))
                else:
                    ws.cell(column=col_idx, row=row_idx, value=elem)

        wb.save(stream)

        return stream.getvalue()

    def tablize(self, data):
        """
        Convert a list of data into a table.
        """
        if data:

            # First, flatten the data (i.e., convert it to a list of
            # dictionaries that are each exactly one level deep).  The key for
            # each item designates the name of the column that the item will
            # fall into.
            data = self.flatten_data(data)

            # Get the set of all unique headers, and sort them.
            headers = []
            if data[0]:
                headers = data[0].keys()

            # Create a row for each dictionary, filling in columns for which the
            # item has no data with None values.
            rows = []
            for item in data:
                row = []
                for key in headers:
                    row.append(item.get(key, None))
                rows.append(row)

            # Return your "table", with the headers as the first row.
            return [headers] + rows

        else:

            return []

    def flatten_data(self, data):
        """
        Convert the given data collection to a list of dictionaries that are
        each exactly one level deep. The key for each value in the dictionaries
        designates the name of the column that the value will fall into.
        """
        flat_data = []
        for item in data:
            flat_item = self.flatten_item(item)
            flat_data.append(flat_item)

        return flat_data

    def flatten_item(self, item):
        if isinstance(item, list):
            flat_item = self.flatten_list(item)
        elif isinstance(item, dict):
            flat_item = self.flatten_dict(item)
        else:
            flat_item = {'': item}

        return flat_item

    def nest_flat_item(self, flat_item, prefix):
        """
        Given a "flat item" (a dictionary exactly one level deep), nest all of
        the column headers in a namespace designated by prefix.  For example:
         header... | with prefix... | becomes...
        -----------|----------------|----------------
         'lat'     | 'location'     | 'location.lat'
         ''        | '0'            | '0'
         'votes.1' | 'user'         | 'user.votes.1'
        """
        nested_item = {}
        for header, val in flat_item.items():
            nested_header = self.level_sep.join([prefix, header]) if header else prefix
            nested_item[nested_header] = val
        return nested_item

    def flatten_list(self, l):
        flat_list = {}
        for index, item in enumerate(l):
            index = text_type(index)
            flat_item = self.flatten_item(item)
            nested_item = self.nest_flat_item(flat_item, index)
            flat_list.update(nested_item)
        return flat_list

    def flatten_dict(self, d):
        flat_dict = OrderedDict()
        for key, item in d.iteritems():
            key = str(key)
            flat_item = self.flatten_item(item)
            nested_item = self.nest_flat_item(flat_item, key)
            flat_dict.update(nested_item)
        return flat_dict
<|endoftext|>


<commit_before>from rpython.rtyper.lltypesystem import rffi, lltype
from sqpyte.interpreter import Sqlite3DB
from sqpyte import function
from sqpyte.capi import CConfig
from sqpyte import capi
import os, sys

testdb = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test.db")

def test_create_function():
    class MyContext(function.Context):
        def __init__(self, pfunc):
            self.pfunc = pfunc
            self.currlength = 0

        def step(self, args):
            arg, = args
            self.currlength += arg.get_n()

        def finalize(self, memout):
            memout.sqlite3_result_int64(self.currlength)

    db = Sqlite3DB(testdb)
    db.create_aggregate("sumlength", 1, MyContext)
    query = db.execute('select sumlength(name), sum(length(name)) from contacts;')
    rc = query.mainloop()
    assert rc == CConfig.SQLITE_ROW
    assert query.python_sqlite3_column_int64(0) == query.python_sqlite3_column_int64(1)
<commit_msg>some smoke tests for aggregation functions<commit_after>import pytest
from rpython.rtyper.lltypesystem import rffi, lltype
from sqpyte.interpreter import Sqlite3DB
from sqpyte import function
from sqpyte.capi import CConfig
from sqpyte import capi
import os, sys

testdb = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test.db")

def test_create_function():
    class MyContext(function.Context):
        def __init__(self, pfunc):
            self.pfunc = pfunc
            self.currlength = 0

        def step(self, args):
            arg, = args
            self.currlength += arg.get_n()

        def finalize(self, memout):
            memout.sqlite3_result_int64(self.currlength)

    db = Sqlite3DB(testdb)
    db.create_aggregate("sumlength", 1, MyContext)
    query = db.execute('select sumlength(name), sum(length(name)) from contacts;')
    rc = query.mainloop()
    assert rc == CConfig.SQLITE_ROW
    assert query.python_sqlite3_column_int64(0) == query.python_sqlite3_column_int64(1)

def test_sum():
    db = Sqlite3DB(testdb)
    query = db.execute('select sum(age) from contacts;')
    rc = query.mainloop()
    assert rc == CConfig.SQLITE_ROW
    res = query.python_sqlite3_column_int64(0)
    assert res == 4832

def test_avg():
    db = Sqlite3DB(testdb)
    query = db.execute('select avg(age) from contacts where age > 18;')
    rc = query.mainloop()
    assert rc == CConfig.SQLITE_ROW
    res = query.python_sqlite3_column_double(0)
    assert round(res, 2) == 58.91
<|endoftext|>