<commit_before># -*- coding: utf-8 -*-
# Django settings for basic pinax project.

import os.path
import datetime
import posixpath
import time

from django.utils.http import http_date

import djcelery

djcelery.setup_loader()

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))

DEBUG = False
TEMPLATE_DEBUG = True

SERVE_MEDIA = DEBUG

# django-compressor is turned off by default due to deployment overhead for
# most users. See <URL> for more information
COMPRESS = False

INTERNAL_IPS = [
    "127.0.0.1",
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": "crate",
    }
}

TIME_ZONE = "UTC"
LANGUAGE_CODE = "en-us"

USE_I18N = False
USE_L10N = True
USE_TZ = True

MEDIA_ROOT = os.path.join(PROJECT_ROOT, "site_media", "media")
MEDIA_URL = "/site_media/media/"

STATIC_ROOT = os.path.join(PROJECT_ROOT, "site_media", "static")
STATIC_URL = "/site_media/static/"

ADMIN_MEDIA_PREFIX = posixpath.join(STATIC_URL, "admin/")

STATICFILES_DIRS = [
    os.path.join(PROJECT_ROOT, "static"),
]

STATICFILES_FINDERS = [
    "staticfiles.finders.FileSystemFinder",
    "staticfiles.finders.AppDirectoriesFinder",
    "staticfiles.finders.LegacyAppDirectoriesFinder",
    "compressor.finders.CompressorFinder",
]

COMPRESS_OUTPUT_DIR = "cache"

SECRET_KEY = ")ys)^6l18seiq)veen^41ox%l@6#o-2t*9-8n5$7$f+qi*x03$"

TEMPLATE_LOADERS = [
    ("django.template.loaders.cached.Loader", [
        "django.template.loaders.filesystem.Loader",
        "django.template.loaders.app_directories.Loader",
    ]),
]

MIDDLEWARE_CLASSES = [
    "django_hosts.middleware.HostsMiddleware",
    "djangosecure.middleware.SecurityMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django_openid.consumer.SessionConsumer",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",

    "pagination.middleware.PaginationMiddleware",

    "pinax.apps.account.middleware.LocaleMiddleware",
    "pinax.middleware.security.HideSensistiveFieldsMiddleware",
]

ROOT_URLCONF = "crate_project.urls"
ROOT_HOSTCONF = "crate_project.hosts"

DEFAULT_HOST = "default"

WSGI_APPLICATION = "crate_project.wsgi.application"

TEMPLATE_DIRS = [
    os.path.join(PROJECT_ROOT, "templates"),
]

JINJA_TEMPLATE_DIRS = [
    os.path.join(PROJECT_ROOT, "templates", "_jinja2"),
]

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.request",
    "django.contrib.messages.context_processors.messages",

    "staticfiles.context_processors.static",

    "pinax.core.context_processors.pinax_settings",

    "pinax.apps.account.context_processors.account",

    # "notification.context_processors.notification",
    "announcements.context_processors.site_wide_announcements",
]

INSTALLED_APPS = [
    # Admin Dashboard
    "admin_tools",
    "admin_tools.theming",
    "admin_tools.menu",
    "admin_tools.dashboard",

    # Django
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.sites",
    "django.contrib.messages",
    "django.contrib.humanize",
    "django.contrib.markup",

    "pinax.templatetags",

    # theme
    "pinax_theme_bootstrap",

    # external (Pinax)
    # "notification",  # must be first
    "staticfiles",
    "pagination",
    "compressor",
    "django_openid",
    "timezones",
    "emailconfirmation",
    "announcements",
    "idios",
    "metron",

    # Pinax
    "pinax.apps.account",
    "pinax.apps.signup_codes",

    # external (Project)
    "south",
    "djcelery",
    "django_hosts",
    "haystack",
    "storages",
    "intercom",
    "celery_haystack",
    "tastypie",
    "djangosecure",

    # project
    "about",
    "profiles",
    "packages",
    "pypi",
    "search",
    "crate",
    "evaluator",
    "favorites",
    "privatebeta",
    "helpdocs",
]

FIXTURE_DIRS = [
    os.path.join(PROJECT_ROOT, "fixtures"),
]

MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage"

ABSOLUTE_URL_OVERRIDES = {
    "auth.user": lambda o: "/profiles/profile/%s/" % o.username,
}

AUTH_PROFILE_MODULE = "profiles.Profile"
NOTIFICATION_LANGUAGE_MODULE = "account.Account"

ACCOUNT_OPEN_SIGNUP = True
ACCOUNT_USE_OPENID = True
ACCOUNT_REQUIRED_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = True
ACCOUNT_EMAIL_AUTHENTICATION = False
ACCOUNT_UNIQUE_EMAIL = EMAIL_CONFIRMATION_UNIQUE_EMAIL = True

AUTHENTICATION_BACKENDS = [
    "pinax.apps.account.auth_backends.AuthenticationBackend",
]

LOGIN_URL = "/account/login/"
LOGIN_REDIRECT_URLNAME = "what_next"
LOGOUT_REDIRECT_URLNAME = "search"

EMAIL_CONFIRMATION_DAYS = 2
EMAIL_DEBUG = DEBUG

DEBUG_TOOLBAR_CONFIG = {
    "INTERCEPT_REDIRECTS": False,
}

CELERY_SEND_TASK_ERROR_EMAILS = True
CELERY_DISABLE_RATE_LIMITS = True
CELERY_TASK_PUBLISH_RETRY = True

CELERY_IGNORE_RESULT = True

CELERY_TASK_RESULT_EXPIRES = 7 * 24 * 60 * 60  # 7 Days

CELERYD_HIJACK_ROOT_LOGGER = False

CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"

HAYSTACK_SEARCH_RESULTS_PER_PAGE = 15

AWS_QUERYSTRING_AUTH = False
AWS_S3_SECURE_URLS = False

AWS_HEADERS = {
    "Expires": lambda: http_date(time.mktime((datetime.datetime.now() + datetime.timedelta(days=365)).timetuple())),
    "Cache-Control": "max-age=31556926",
}

METRON_SETTINGS = {
    "mixpanel": {3: "a280fbfb3039709d8a5ac15834a16e5e"},
    "google": {3: "UA-28759418-1"},
    "gauges": {3: "4f1e4cd0613f5d7003000002"}
}

ADMIN_TOOLS_INDEX_DASHBOARD = "crate.dashboard.CrateIndexDashboard"
<commit_msg>fix contact email<commit_after># -*- coding: utf-8 -*-
# Django settings for basic pinax project.

import os.path
import datetime
import posixpath
import time

from django.utils.http import http_date

import djcelery

djcelery.setup_loader()

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))

DEBUG = False
TEMPLATE_DEBUG = True

SERVE_MEDIA = DEBUG

# django-compressor is turned off by default due to deployment overhead for
# most users. See <URL> for more information
COMPRESS = False

INTERNAL_IPS = [
    "127.0.0.1",
]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": "crate",
    }
}

TIME_ZONE = "UTC"
LANGUAGE_CODE = "en-us"

USE_I18N = False
USE_L10N = True
USE_TZ = True

MEDIA_ROOT = os.path.join(PROJECT_ROOT, "site_media", "media")
MEDIA_URL = "/site_media/media/"

STATIC_ROOT = os.path.join(PROJECT_ROOT, "site_media", "static")
STATIC_URL = "/site_media/static/"

ADMIN_MEDIA_PREFIX = posixpath.join(STATIC_URL, "admin/")

STATICFILES_DIRS = [
    os.path.join(PROJECT_ROOT, "static"),
]

STATICFILES_FINDERS = [
    "staticfiles.finders.FileSystemFinder",
    "staticfiles.finders.AppDirectoriesFinder",
    "staticfiles.finders.LegacyAppDirectoriesFinder",
    "compressor.finders.CompressorFinder",
]

COMPRESS_OUTPUT_DIR = "cache"

SECRET_KEY = ")ys)^6l18seiq)veen^41ox%l@6#o-2t*9-8n5$7$f+qi*x03$"

TEMPLATE_LOADERS = [
    ("django.template.loaders.cached.Loader", [
        "django.template.loaders.filesystem.Loader",
        "django.template.loaders.app_directories.Loader",
    ]),
]

MIDDLEWARE_CLASSES = [
    "django_hosts.middleware.HostsMiddleware",
    "djangosecure.middleware.SecurityMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django_openid.consumer.SessionConsumer",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",

    "pagination.middleware.PaginationMiddleware",

    "pinax.apps.account.middleware.LocaleMiddleware",
    "pinax.middleware.security.HideSensistiveFieldsMiddleware",
]

ROOT_URLCONF = "crate_project.urls"
ROOT_HOSTCONF = "crate_project.hosts"

DEFAULT_HOST = "default"

WSGI_APPLICATION = "crate_project.wsgi.application"

TEMPLATE_DIRS = [
    os.path.join(PROJECT_ROOT, "templates"),
]

JINJA_TEMPLATE_DIRS = [
    os.path.join(PROJECT_ROOT, "templates", "_jinja2"),
]

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.request",
    "django.contrib.messages.context_processors.messages",

    "staticfiles.context_processors.static",

    "pinax.core.context_processors.pinax_settings",

    "pinax.apps.account.context_processors.account",

    # "notification.context_processors.notification",
    "announcements.context_processors.site_wide_announcements",
]

INSTALLED_APPS = [
    # Admin Dashboard
    "admin_tools",
    "admin_tools.theming",
    "admin_tools.menu",
    "admin_tools.dashboard",

    # Django
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.sites",
    "django.contrib.messages",
    "django.contrib.humanize",
    "django.contrib.markup",

    "pinax.templatetags",

    # theme
    "pinax_theme_bootstrap",

    # external (Pinax)
    # "notification",  # must be first
    "staticfiles",
    "pagination",
    "compressor",
    "django_openid",
    "timezones",
    "emailconfirmation",
    "announcements",
    "idios",
    "metron",

    # Pinax
    "pinax.apps.account",
    "pinax.apps.signup_codes",

    # external (Project)
    "south",
    "djcelery",
    "django_hosts",
    "haystack",
    "storages",
    "intercom",
    "celery_haystack",
    "tastypie",
    "djangosecure",

    # project
    "about",
    "profiles",
    "packages",
    "pypi",
    "search",
    "crate",
    "evaluator",
    "favorites",
    "privatebeta",
    "helpdocs",
]

FIXTURE_DIRS = [
    os.path.join(PROJECT_ROOT, "fixtures"),
]

MESSAGE_STORAGE = "django.contrib.messages.storage.session.SessionStorage"

ABSOLUTE_URL_OVERRIDES = {
    "auth.user": lambda o: "/profiles/profile/%s/" % o.username,
}

AUTH_PROFILE_MODULE = "profiles.Profile"
NOTIFICATION_LANGUAGE_MODULE = "account.Account"

CONTACT_EMAIL = "support@crate.io"

ACCOUNT_OPEN_SIGNUP = True
ACCOUNT_USE_OPENID = True
ACCOUNT_REQUIRED_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = True
ACCOUNT_EMAIL_AUTHENTICATION = False
ACCOUNT_UNIQUE_EMAIL = EMAIL_CONFIRMATION_UNIQUE_EMAIL = True

AUTHENTICATION_BACKENDS = [
    "pinax.apps.account.auth_backends.AuthenticationBackend",
]

LOGIN_URL = "/account/login/"
LOGIN_REDIRECT_URLNAME = "what_next"
LOGOUT_REDIRECT_URLNAME = "search"

EMAIL_CONFIRMATION_DAYS = 2
EMAIL_DEBUG = DEBUG

DEBUG_TOOLBAR_CONFIG = {
    "INTERCEPT_REDIRECTS": False,
}

CELERY_SEND_TASK_ERROR_EMAILS = True
CELERY_DISABLE_RATE_LIMITS = True
CELERY_TASK_PUBLISH_RETRY = True

CELERY_IGNORE_RESULT = True

CELERY_TASK_RESULT_EXPIRES = 7 * 24 * 60 * 60  # 7 Days

CELERYD_HIJACK_ROOT_LOGGER = False

CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"

HAYSTACK_SEARCH_RESULTS_PER_PAGE = 15

AWS_QUERYSTRING_AUTH = False
AWS_S3_SECURE_URLS = False

AWS_HEADERS = {
    "Expires": lambda: http_date(time.mktime((datetime.datetime.now() + datetime.timedelta(days=365)).timetuple())),
    "Cache-Control": "max-age=31556926",
}

METRON_SETTINGS = {
    "mixpanel": {3: "a280fbfb3039709d8a5ac15834a16e5e"},
    "google": {3: "UA-28759418-1"},
    "gauges": {3: "4f1e4cd0613f5d7003000002"}
}

ADMIN_TOOLS_INDEX_DASHBOARD = "crate.dashboard.CrateIndexDashboard"
<|endoftext|>


<commit_before>#!/usr/bin/env python
# pylint: disable=C0111
# pylint: disable=C0103
# pylint: disable=C0330

from __future__ import print_function
import os
import sys
import argparse
import traceback
import webbrowser
import re
import json
from time import strftime, strptime
import dateparser
import pytz
import pystache
import tweepy
from ebooklib import epub

CONFIG_FILE = '.shut-up-bird.conf'
ARCHIVES_DIR = './shut-up-bird.arch'

PAR_TWEET = u'

\
    {0}
\

'

#############################################################################
# Tweepy routines

def tweep_login(consumer_key, consumer_secret, token='', secret=''):
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)

    if token and secret:
        auth.set_access_token(token, secret)
    else:
        try:
            print ("Authenticating ...please wait")
            redirect_url = auth.get_authorization_url()

            print ("Opening url - {0} ...".format(redirect_url))
            webbrowser.open(redirect_url)

            verify_code = raw_input("Verification PIN code: ")
            auth.get_access_token(verify_code)

        except tweepy.TweepError as e:
            raise Exception("Failed to get request token!", e)

    return auth

def tweep_getAPI(auth):
    api = tweepy.API(auth)

    print ("Authenticated as: {0}".format(api.me().screen_name))

    limits = api.rate_limit_status()
    statuses = limits['resources']['statuses']

    print ("Rates left:")
    print ("\tUser timeline: {0} / {1}".format(
        statuses['/statuses/user_timeline']['remaining'],
        statuses['/statuses/user_timeline']['limit']))
    print ("\tLookup: {0} / {1}".format(
        statuses['/statuses/lookup']['remaining'],
        statuses['/statuses/lookup']['limit']))

    return api

def tweep_archive(api, max_id=None, max_date=None, skip_replies=False, remove=False):
    archive = archive_open(ARCHIVES_DIR, api.me())
    delete_statuses = []

    try:
        for page in tweepy.Cursor(api.user_timeline, max_id=max_id).pages():
            for status in page:
                if status.in_reply_to_status_id and skip_replies:
                    continue

                if max_date and pytz.utc.localize(status.created_at) > pytz.utc.localize(max_date):
                    print ("Skipped tweet {0} on {1}".format(status.id_str, status.created_at))
                    continue

                archive_add(status, archive)
                #print (status)

                if remove:
                    delete_statuses.append(str(status.id_str))

        if remove:
            tweep_delete_all(delete_statuses)

    except tweepy.RateLimitError as e:
        # TODO: save current state and make it possible to continue later
        raise Exception("Twitter API rate limit reached! No tweets will be deleted.", e)
    except ValueError as e:
        raise Exception("Could not parse status create time! No tweets were deleted.", e)

    archive_close(archive)

def tweep_delete_all(status_list):
    print ("Removing {0} statuses ...".format(len(status_list)))
    # TODO this could be put in a fork

def tweep_delete(status_id):
    print ("TEST")
    # TODO delete a tweet

#############################################################################
# Archive routines

def archive_open(dest_path, user):
    if not os.path.exists(dest_path):
        os.mkdir(dest_path)

    dir_path = os.path.join(dest_path, strftime("%Y-%m-%d_%H%M"))
    if not os.path.exists(dir_path):
        os.mkdir(dir_path)

    # ePub Stuff
    book = epub.EpubBook()
    book.set_identifier('id' + str(user.id))
    book.set_title("Tweets by @" + user.screen_name)
    book.set_language(user.lang or 'en')

    book.add_author(user.name or user.screen_name)
    book.spine = ['nav']

    return {'book': book, 'dest': dir_path}

def archive_add(status, archive):
    book = archive['book']

    c = epub.EpubHtml(title='Intro', \
        file_name='chap_' + str(status.id_str) + '.xhtml', \
        lang=status.lang or 'en')

    #c.content = '
' + excerpt(status.text) + '
'
    c.content = preprocess(status.text)
    c.content += '
' + status.created_at.strftime("%A, %d %b %Y %H:%M") + '
'

    book.add_item(c)
    book.spine.append(c)

def archive_close(archive):
    epub_dest = os.path.join(archive['dest'], 'tweets.epub')
    print ("Writing ePub to {0} ...".format(epub_dest))

    # add navigation files
    archive['book'].add_item(epub.EpubNcx())
    archive['book'].add_item(epub.EpubNav())

    epub.write_epub(epub_dest, archive['book'], {})
    return epub_dest

#############################################################################
# Config routines

def config_load(config_path):
    if not os.path.exists(config_path):
        return False

    with open(config_path, 'r') as infile:
        return json.load(infile)

def config_save(config_path, consumer_key, consumer_secret, token, secret):
    data = {'ck': consumer_key, 'cs': consumer_secret, \
        't': token, 's': secret}

    with open(config_path, 'w') as outfile:
        json.dump(data, outfile, indent=2, ensure_ascii=False)

def conf_get_parser():
    parser = argparse.ArgumentParser(add_help=True,
        description="So you're stuck, eh? Here're some hints.")
    parser.add_argument('-id', '--max-id',
        help="""Archives all statuses with an ID less than
        (older than) or equal to the specified.""")
    parser.add_argument('-dt', '--max-date',
        help="""Archives all statuses with a post date less than
        (older than) or equal to the specified.""")
    parser.add_argument('-nr', '--no-reply',
        help="""Skips reply tweets.""",
        action="store_true", default=False)
    parser.add_argument('--remove',
        help="""Removes all archived tweets.
        WARNING!!! This action is irreversable!""",
        action="store_true", default=False)

    return parser

#############################################################################
# Misc routines

def get_input(message):
    return raw_input(message)

def preprocess(text):
    # thx dude! - http://stackoverflow.com/a/7254397
    text = re.sub(r'(?<!"|>)(ht|f)tps?://.*?(?=\s|$)', r'<a href="\g<0>">\g<0>', text)
    # TODO remove the @
    text = re.sub(r'@(.*?)\S*', r'<a href="https://twitter.com/\g<0>">\g<0>', text)
    return PAR_TWEET.format(text)

def excerpt(text):
    text = re.sub(r'@(.*?)\S*', '', text)
    return text[0:15] + ' ...'

#############################################################################
# Main
if __name__ == "__main__":
    try:
        home_dir = os.path.expanduser('~')
        config = config_load(os.path.join(home_dir, CONFIG_FILE))

        if config and config['t'] and config['s']:
            g_auth = tweep_login(config['ck'], config['cs'], config['t'], config['s'])
        else:
            print ("Please provide your Twitter app access keys\n")
            g_consumer_key = get_input("Consumer API Key: ")
            g_consumer_secret = get_input("Consumer API Secret: ")

            g_auth = tweep_login(g_consumer_key, g_consumer_secret)

            config_save(os.path.join(home_dir, CONFIG_FILE), g_consumer_key, \
                g_consumer_secret, g_auth.access_token, g_auth.access_token_secret)

        g_max_date = None

        g_parser = conf_get_parser()
        args = g_parser.parse_args()
        if not args.max_id and not args.max_date:
            g_parser.print_help()
            sys.exit(-1)
        elif args.max_date:
            g_max_date = dateparser.parse(args.max_date)
            print ("Max date set to: {0}".format(g_max_date))

        tweep_archive(tweep_getAPI(g_auth), max_id=args.max_id,
            max_date=g_max_date, skip_replies=args.no_reply)

    except Exception as e:
        traceback.print_exc(file=sys.stdout)
        print ("[ERROR] {0}".format(e))
<commit_msg>Fix mention and hashtag links<commit_after>#!/usr/bin/env python
# pylint: disable=C0111
# pylint: disable=C0103
# pylint: disable=C0330

from __future__ import print_function
import os
import sys
import argparse
import traceback
import webbrowser
import re
import json
from time import strftime, strptime
import dateparser
import pytz
import pystache
import tweepy
from ebooklib import epub

CONFIG_FILE = '.shut-up-bird.conf'
ARCHIVES_DIR = './shut-up-bird.arch'

PAR_TWEET = u'

\
    {0}
\

'

#############################################################################
# Tweepy routines

def tweep_login(consumer_key, consumer_secret, token='', secret=''):
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)

    if token and secret:
        auth.set_access_token(token, secret)
    else:
        try:
            print ("Authenticating ...please wait")
            redirect_url = auth.get_authorization_url()

            print ("Opening url - {0} ...".format(redirect_url))
            webbrowser.open(redirect_url)

            verify_code = raw_input("Verification PIN code: ")
            auth.get_access_token(verify_code)

        except tweepy.TweepError as e:
            raise Exception("Failed to get request token!", e)

    return auth

def tweep_getAPI(auth):
    api = tweepy.API(auth)

    print ("Authenticated as: {0}".format(api.me().screen_name))

    limits = api.rate_limit_status()
    statuses = limits['resources']['statuses']

    print ("Rates left:")
    print ("\tUser timeline: {0} / {1}".format(
        statuses['/statuses/user_timeline']['remaining'],
        statuses['/statuses/user_timeline']['limit']))
    print ("\tLookup: {0} / {1}".format(
        statuses['/statuses/lookup']['remaining'],
        statuses['/statuses/lookup']['limit']))

    return api

def tweep_archive(api, max_id=None, max_date=None, skip_replies=False, remove=False):
    archive = archive_open(ARCHIVES_DIR, api.me())
    delete_statuses = []

    try:
        for page in tweepy.Cursor(api.user_timeline, max_id=max_id).pages():
            for status in page:
                if status.in_reply_to_status_id and skip_replies:
                    continue

                if max_date and pytz.utc.localize(status.created_at) > pytz.utc.localize(max_date):
                    print ("Skipped tweet {0} on {1}".format(status.id_str, status.created_at))
                    continue

                print (preprocess(status.text))

                #archive_add(status, archive)
                #print (status)

                if remove:
                    delete_statuses.append(str(status.id_str))

        if remove:
            tweep_delete_all(delete_statuses)

    except tweepy.RateLimitError as e:
        # TODO: save current state and make it possible to continue later
        raise Exception("Twitter API rate limit reached! No tweets will be deleted.", e)
    except ValueError as e:
        raise Exception("Could not parse status create time! No tweets were deleted.", e)

    archive_close(archive)

def tweep_delete_all(status_list):
    print ("Removing {0} statuses ...".format(len(status_list)))
    # TODO this could be put in a fork

def tweep_delete(status_id):
    print ("TEST")
    # TODO delete a tweet

#############################################################################
# Archive routines

def archive_open(dest_path, user):
    if not os.path.exists(dest_path):
        os.mkdir(dest_path)

    dir_path = os.path.join(dest_path, strftime("%Y-%m-%d_%H%M"))
    if not os.path.exists(dir_path):
        os.mkdir(dir_path)

    # ePub Stuff
    book = epub.EpubBook()
    book.set_identifier('id' + str(user.id))
    book.set_title("Tweets by @" + user.screen_name)
    book.set_language(user.lang or 'en')

    book.add_author(user.name or user.screen_name)
    book.spine = ['nav']

    return {'book': book, 'dest': dir_path}

def archive_add(status, archive):
    book = archive['book']

    c = epub.EpubHtml(title='Intro', \
        file_name='chap_' + str(status.id_str) + '.xhtml', \
        lang=status.lang or 'en')

    #c.content = '
' + excerpt(status.text) + '
'
    c.content = preprocess(status.text)
    c.content += '
' + status.created_at.strftime("%A, %d %b %Y %H:%M") + '
'

    book.add_item(c)
    book.spine.append(c)

def archive_close(archive):
    epub_dest = os.path.join(archive['dest'], 'tweets.epub')
    print ("Writing ePub to {0} ...".format(epub_dest))

    # add navigation files
    archive['book'].add_item(epub.EpubNcx())
    archive['book'].add_item(epub.EpubNav())

    epub.write_epub(epub_dest, archive['book'], {})
    return epub_dest

#############################################################################
# Config routines

def config_load(config_path):
    if not os.path.exists(config_path):
        return False

    with open(config_path, 'r') as infile:
        return json.load(infile)

def config_save(config_path, consumer_key, consumer_secret, token, secret):
    data = {'ck': consumer_key, 'cs': consumer_secret, \
        't': token, 's': secret}

    with open(config_path, 'w') as outfile:
        json.dump(data, outfile, indent=2, ensure_ascii=False)

def conf_get_parser():
    parser = argparse.ArgumentParser(add_help=True,
        description="So you're stuck, eh? Here're some hints.")
    parser.add_argument('-id', '--max-id',
        help="""Archives all statuses with an ID less than
        (older than) or equal to the specified.""")
    parser.add_argument('-dt', '--max-date',
        help="""Archives all statuses with a post date less than
        (older than) or equal to the specified.""")
    parser.add_argument('-nr', '--no-reply',
        help="""Skips reply tweets.""",
        action="store_true", default=False)
    parser.add_argument('--remove',
        help="""Removes all archived tweets.
        WARNING!!! This action is irreversable!""",
        action="store_true", default=False)

    return parser

#############################################################################
# Misc routines

def get_input(message):
    return raw_input(message)

def preprocess(text):
    # thx dude! - http://stackoverflow.com/a/7254397
    text = re.sub(r'(?<!"|>)(ht|f)tps?://.*?(?=\s|$)',
        r'<a href="\g<0>">\g<0>', text)
    text = re.sub(r'(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9]+)',
        r'@\1', text)
    text = re.sub(r'(?:^|\s)[#]{1}(\w+)',
        r'#\1', text)
    return PAR_TWEET.format(text)

def excerpt(text):
    text = re.sub(r'@(.*?)\S*', '', text)
    return text[0:15] + ' ...'

#############################################################################
# Main
if __name__ == "__main__":
    try:
        home_dir = os.path.expanduser('~')
        config = config_load(os.path.join(home_dir, CONFIG_FILE))

        if config and config['t'] and config['s']:
            g_auth = tweep_login(config['ck'], config['cs'], config['t'], config['s'])
        else:
            print ("Please provide your Twitter app access keys\n")
            g_consumer_key = get_input("Consumer API Key: ")
            g_consumer_secret = get_input("Consumer API Secret: ")

            g_auth = tweep_login(g_consumer_key, g_consumer_secret)

            config_save(os.path.join(home_dir, CONFIG_FILE), g_consumer_key, \
                g_consumer_secret, g_auth.access_token, g_auth.access_token_secret)

        g_max_date = None

        g_parser = conf_get_parser()
        args = g_parser.parse_args()
        if not args.max_id and not args.max_date:
            g_parser.print_help()
            sys.exit(-1)
        elif args.max_date:
            g_max_date = dateparser.parse(args.max_date)
            print ("Max date set to: {0}".format(g_max_date))

        tweep_archive(tweep_getAPI(g_auth), max_id=args.max_id,
            max_date=g_max_date, skip_replies=args.no_reply)

    except Exception as e:
        traceback.print_exc(file=sys.stdout)
        print ("[ERROR] {0}".format(e))
<|endoftext|>


<commit_before>import bohrium
import numpy

class test_bh_opcodes:
    def init(self):
        for op in bohrium._info.op.values():
            if op["name"] not in ["identity", "sign"]:
                for type_sig in op["type_sig"]:
                    yield (op, type_sig)

    def test_ufunc(self, arg):
        (op, type_sig) = arg

        cmd = "R = bh.random.RandomState(42); "

        for i, dtype in enumerate(type_sig[1:]):
            cmd += "a%d = R.random(10, dtype=np.%s, bohrium=BH); " % (i, dtype)

        if op["name"] == "arccosh":
            cmd += "a%d += 1;" % i

        cmd += "res = M.%s(" % (op["name"])

        for i in range(op["nop"]-1):
            cmd += "a%d, " % i

        cmd = cmd[:-2] + ");"
        return cmd

class test_bh_operators:
    def init(self):
        for op in ['+', '-', '*', '/', '//', '%', '==']:
            for dtype in ['float64', 'int64']:
                yield (op, dtype)

    def test_arrays(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a2 = R.random(10, dtype=np.%s, bohrium=BH) + 1; " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

    def test_scalar_rhs(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a2 = np.%s(42); " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

class test_bh_operators_lhs:
    def init(self):
        if numpy.__version__ >= "1.13":
            for op in ['+', '-', '*', '/', '//', '%', '==']:
                for dtype in ['float64', 'int64']:
                    yield (op, dtype)
        else:
            print("The version of NumPy is too old (<= 1.13), ignoring test")

    def test_scalar_lhs(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = np.%s(42); " % dtype
        cmd += "a2 = R.random(10, dtype=np.%s, bohrium=BH) + 1; " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

class test_extra_binary_ops:
    def init(self):
        for op in ["true_divide", "floor_divide"]:
            for dtype in ["float64", "int64", "uint64"]:
                yield (op, dtype)

    def test_ufunc(self, arg):
        (op, dtype) = arg

        cmd =  "R = bh.random.RandomState(42); "
        cmd += "a0 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "res = M.%s(a0, a1)" % op
        return cmd

class test_power:
    def init(self):
        for op in ["power"]:
            for dtype in ["float32", "float64"]:
                yield (op, dtype)

    def test_ufunc(self, arg):
        (op, dtype) = arg

        cmd =  "R = bh.random.RandomState(42); "
        cmd += "a0 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "res = M.%s(a0, 1.42)" % op
        return cmd
<commit_msg>test: the primitive tests now ignores non-elementwise ops<commit_after>import bohrium
import numpy

class test_bh_opcodes:
    def init(self):
        for op in bohrium._info.op.values():
            if op["name"] not in ["identity", "sign"] and op['elementwise']:
                for type_sig in op["type_sig"]:
                    yield (op, type_sig)

    def test_ufunc(self, arg):
        (op, type_sig) = arg

        cmd = "R = bh.random.RandomState(42); "

        for i, dtype in enumerate(type_sig[1:]):
            cmd += "a%d = R.random(10, dtype=np.%s, bohrium=BH); " % (i, dtype)

        if op["name"] == "arccosh":
            cmd += "a%d += 1;" % i

        cmd += "res = M.%s(" % (op["name"])

        for i in range(op["nop"]-1):
            cmd += "a%d, " % i

        cmd = cmd[:-2] + ");"
        return cmd

class test_bh_operators:
    def init(self):
        for op in ['+', '-', '*', '/', '//', '%', '==']:
            for dtype in ['float64', 'int64']:
                yield (op, dtype)

    def test_arrays(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a2 = R.random(10, dtype=np.%s, bohrium=BH) + 1; " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

    def test_scalar_rhs(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a2 = np.%s(42); " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

class test_bh_operators_lhs:
    def init(self):
        if numpy.__version__ >= "1.13":
            for op in ['+', '-', '*', '/', '//', '%', '==']:
                for dtype in ['float64', 'int64']:
                    yield (op, dtype)
        else:
            print("The version of NumPy is too old (<= 1.13), ignoring test")

    def test_scalar_lhs(self, arg):
        (op, dtype) = arg
        cmd = "R = bh.random.RandomState(42); "
        cmd += "a1 = np.%s(42); " % dtype
        cmd += "a2 = R.random(10, dtype=np.%s, bohrium=BH) + 1; " % dtype
        cmd += "res = a1 %s a2" % op
        return cmd

class test_extra_binary_ops:
    def init(self):
        for op in ["true_divide", "floor_divide"]:
            for dtype in ["float64", "int64", "uint64"]:
                yield (op, dtype)

    def test_ufunc(self, arg):
        (op, dtype) = arg

        cmd =  "R = bh.random.RandomState(42); "
        cmd += "a0 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "a1 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "res = M.%s(a0, a1)" % op
        return cmd

class test_power:
    def init(self):
        for op in ["power"]:
            for dtype in ["float32", "float64"]:
                yield (op, dtype)

    def test_ufunc(self, arg):
        (op, dtype) = arg

        cmd =  "R = bh.random.RandomState(42); "
        cmd += "a0 = R.random(10, dtype=np.%s, bohrium=BH); " % dtype
        cmd += "res = M.%s(a0, 1.42)" % op
        return cmd
<|endoftext|>


<commit_before>from flask import Flask

from config import config

from . import extensions, modules

def create_app(config_name):
    config_obj = config[config_name]()
    app = Flask(__name__, static_url_path='/static')

    # Initializes configuration values.
    app.config.from_object(config_obj)

    # Configure SSL if the current platform supports it.
    if not app.debug and not app.testing and not app.config.get('SSL_DISABLE'):
        from flask.ext.sslify import SSLify
        SSLify(app)

    # Initializes Flask extensions.
    extensions.init_app(app)

    # Initializes modules.
    modules.init_app(app)

    return app
<commit_msg>Fixed flask-sslify initialization<commit_after>from flask import Flask

from config import config

from . import extensions, modules

def create_app(config_name):
    config_obj = config[config_name]()
    app = Flask(__name__, static_url_path='/static')

    # Initializes configuration values.
    app.config.from_object(config_obj)

    # Configure SSL if the current platform supports it.
    if not app.debug and not app.testing and not app.config.get('SSL_DISABLE'):
        from flask_sslify import SSLify
        SSLify(app)

    # Initializes Flask extensions.
    extensions.init_app(app)

    # Initializes modules.
    modules.init_app(app)

    return app
<|endoftext|>


<commit_before># Copyright (c) 2018, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import re

from django.apps import apps as django_apps
from django.core.exceptions import ImproperlyConfigured
from django.db import IntegrityError
from django.utils import six
from django.utils.translation import ugettext_lazy as _
import jwt
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from . import settings
from .compat import User

def get_accept_list(request):
    http_accept = request.META.get('HTTP_ACCEPT', '*/*')
    return [item.strip() for item in http_accept.split(',')]

def get_account_model():
    """
    Returns the ``Account`` model that is active in this project.
    """
    try:
        return django_apps.get_model(settings.ACCOUNT_MODEL)
    except ValueError:
        raise ImproperlyConfigured(
            "ACCOUNT_MODEL must be of the form 'app_label.model_name'")
    except LookupError:
        raise ImproperlyConfigured("ACCOUNT_MODEL refers to model '%s'"\
" that has not been installed" % settings.ACCOUNT_MODEL)

def has_invalid_password(user):
    return user.password.startswith('!')

def printable_name(user):
    full_name = user.get_full_name()
    if full_name:
        return full_name
    return user.username

def update_db_row(instance, form):
    """
    Updates the record in the underlying database, or adds a validation
    error in the form. When an error is added, the form is returned otherwise
    this function returns `None`.
    """
    try:
        try:
            instance.save()
        except IntegrityError as err:
            handle_uniq_error(err)
    except ValidationError as err:
        fill_form_errors(form, err)
    return None

def fill_form_errors(form, err):
    """
    Fill a Django form from DRF ValidationError exceptions.
    """
    for detail in err.detail:
        if isinstance(detail, dict):
            for field, msg in six.iteritems(detail):
                form.add_error(field, msg)

def handle_uniq_error(err):
    """
    Will raise a ``ValidationError`` with the appropriate error message.
    """
    err_msg = str(err).splitlines().pop()
    # PostgreSQL unique constraint.
    look = re.match(
        r'DETAIL:\s+Key \(([a-z_]+)\)=\(.*\) already exists\.', err_msg)
    if look:
        raise ValidationError({look.group(1):
            _("This %(field)s is already taken.") % {
                'field': look.group(1)}})
    # SQLite unique constraint.
    look = re.match(
        r'UNIQUE constraint failed: [a-z_]+\.([a-z_]+)', err_msg)
    if look:
        raise ValidationError({look.group(1):
            _("This %(field)s is already taken.") % {
                'field': look.group(1)}})
    raise err

def verify_token(token):
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            True, # verify
            options={'verify_exp': True},
            algorithms=[settings.JWT_ALGORITHM])
    except jwt.ExpiredSignature:
        raise serializers.ValidationError(
            _("Signature has expired."))
    except jwt.DecodeError:
        raise serializers.ValidationError(
            _("Error decoding signature."))
    username = payload.get('username', None)
    if not username:
        raise serializers.ValidationError(
            _("Missing username in payload"))
    # Make sure user exists
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        raise serializers.ValidationError(_("User does not exist."))
    return user
<commit_msg>fixes silenced errors<commit_after># Copyright (c) 2018, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import re

from django.apps import apps as django_apps
from django.core.exceptions import ImproperlyConfigured
from django.db import IntegrityError
from django.utils import six
from django.utils.translation import ugettext_lazy as _
import jwt
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from . import settings
from .compat import User

def get_accept_list(request):
    http_accept = request.META.get('HTTP_ACCEPT', '*/*')
    return [item.strip() for item in http_accept.split(',')]

def get_account_model():
    """
    Returns the ``Account`` model that is active in this project.
    """
    try:
        return django_apps.get_model(settings.ACCOUNT_MODEL)
    except ValueError:
        raise ImproperlyConfigured(
            "ACCOUNT_MODEL must be of the form 'app_label.model_name'")
    except LookupError:
        raise ImproperlyConfigured("ACCOUNT_MODEL refers to model '%s'"\
" that has not been installed" % settings.ACCOUNT_MODEL)

def has_invalid_password(user):
    return user.password.startswith('!')

def printable_name(user):
    full_name = user.get_full_name()
    if full_name:
        return full_name
    return user.username

def update_db_row(instance, form):
    """
    Updates the record in the underlying database, or adds a validation
    error in the form. When an error is added, the form is returned otherwise
    this function returns `None`.
    """
    try:
        try:
            instance.save()
        except IntegrityError as err:
            handle_uniq_error(err)
    except ValidationError as err:
        fill_form_errors(form, err)
        return form
    return None

def fill_form_errors(form, err):
    """
    Fill a Django form from DRF ValidationError exceptions.
    """
    if isinstance(err.detail, dict):
        for field, msg in six.iteritems(err.detail):
            form.add_error(field, msg)

def handle_uniq_error(err):
    """
    Will raise a ``ValidationError`` with the appropriate error message.
    """
    err_msg = str(err).splitlines().pop()
    # PostgreSQL unique constraint.
    look = re.match(
        r'DETAIL:\s+Key \(([a-z_]+)\)=\(.*\) already exists\.', err_msg)
    if look:
        raise ValidationError({look.group(1):
            _("This %(field)s is already taken.") % {
                'field': look.group(1)}})
    # SQLite unique constraint.
    look = re.match(
        r'UNIQUE constraint failed: [a-z_]+\.([a-z_]+)', err_msg)
    if look:
        raise ValidationError({look.group(1):
            _("This %(field)s is already taken.") % {
                'field': look.group(1)}})
    raise err

def verify_token(token):
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            True, # verify
            options={'verify_exp': True},
            algorithms=[settings.JWT_ALGORITHM])
    except jwt.ExpiredSignature:
        raise serializers.ValidationError(
            _("Signature has expired."))
    except jwt.DecodeError:
        raise serializers.ValidationError(
            _("Error decoding signature."))
    username = payload.get('username', None)
    if not username:
        raise serializers.ValidationError(
            _("Missing username in payload"))
    # Make sure user exists
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        raise serializers.ValidationError(_("User does not exist."))
    return user
<|endoftext|>


<commit_before># Copyright (c) 2018, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import logging, re

from django.apps import apps as django_apps
from django.core.exceptions import ImproperlyConfigured, NON_FIELD_ERRORS
from django.core.files.storage import default_storage
from django.db import IntegrityError
from django.utils import six
from django.utils.translation import ugettext_lazy as _
import jwt
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings

from . import settings
from .compat import User, import_string

LOGGER = logging.getLogger(__name__)

def get_accept_list(request):
    http_accept = request.META.get('HTTP_ACCEPT', '*/*')
    return [item.strip() for item in http_accept.split(',')]

def get_account_model():
    """
    Returns the ``Account`` model that is active in this project.
    """
    try:
        return django_apps.get_model(settings.ACCOUNT_MODEL)
    except ValueError:
        raise ImproperlyConfigured(
            "ACCOUNT_MODEL must be of the form 'app_label.model_name'")
    except LookupError:
        raise ImproperlyConfigured("ACCOUNT_MODEL refers to model '%s'"\
" that has not been installed" % settings.ACCOUNT_MODEL)

def has_invalid_password(user):
    return user.password.startswith('!')

def printable_name(user):
    full_name = user.get_full_name()
    if full_name:
        return full_name
    return user.username

def update_db_row(instance, form):
    """
    Updates the record in the underlying database, or adds a validation
    error in the form. When an error is added, the form is returned otherwise
    this function returns `None`.
    """
    try:
        try:
            instance.save()
        except IntegrityError as err:
            handle_uniq_error(err)
    except ValidationError as err:
        fill_form_errors(form, err)
        return form
    return None

def fill_form_errors(form, err):
    """
    Fill a Django form from DRF ValidationError exceptions.
    """
    if isinstance(err.detail, dict):
        for field, msg in six.iteritems(err.detail):
            if field in form.fields:
                form.add_error(field, msg)
            elif field == api_settings.NON_FIELD_ERRORS_KEY:
                form.add_error(NON_FIELD_ERRORS, msg)
            else:
                form.add_error(NON_FIELD_ERRORS,
                    _("No field '%(field)s': %(msg)s" % {
                    'field': field, 'msg': msg}))

def handle_uniq_error(err, renames=None):
    """
    Will raise a ``ValidationError`` with the appropriate error message.
    """
    field_name = None
    err_msg = str(err).splitlines().pop()
    # PostgreSQL unique constraint.
    look = re.match(
        r'DETAIL:\s+Key \(([a-z_]+)\)=\(.*\) already exists\.', err_msg)
    if look:
        field_name = look.group(1)
    else:
        look = re.match(
          r'DETAIL:\s+Key \(lower\(([a-z_]+)::text\)\)=\(.*\) already exists\.',
            err_msg)
        if look:
            field_name = look.group(1)
        else:
            # SQLite unique constraint.
            look = re.match(
                r'UNIQUE constraint failed: [a-z_]+\.([a-z_]+)', err_msg)
            if look:
                field_name = look.group(1)
    if field_name:
        if renames and field_name in renames:
            field_name = renames[field_name]
        raise ValidationError({field_name:
            _("This %(field)s is already taken.") % {'field': field_name}})
    raise err

def verify_token(token):
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            True, # verify
            options={'verify_exp': True},
            algorithms=[settings.JWT_ALGORITHM])
    except jwt.ExpiredSignature:
        raise serializers.ValidationError(
            _("Signature has expired."))
    except jwt.DecodeError:
        raise serializers.ValidationError(
            _("Error decoding signature."))
    username = payload.get('username', None)
    if not username:
        raise serializers.ValidationError(
            _("Missing username in payload"))
    # Make sure user exists
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        raise serializers.ValidationError(_("User does not exist."))
    return user

def get_disabled_authentication():
    if isinstance(organization, six.string_types):
        return import_string(settings.DISABLED_AUTHENTICATION)()
    return bool(settings.DISABLED_AUTHENTICATION)

def get_disabled_registration():
    if isinstance(organization, six.string_types):
        return import_string(settings.DISABLED_REGISTRATION)()
    return bool(settings.DISABLED_REGISTRATION)

def get_picture_storage():
    if settings.PICTURE_STORAGE_CALLABLE:
        try:
            return import_string(settings.PICTURE_STORAGE_CALLABLE)()
        except ImportError:
            pass
    return default_storage
<commit_msg>issue #22 quickfix<commit_after># Copyright (c) 2018, DjaoDjin inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import logging, re

from django.apps import apps as django_apps
from django.core.exceptions import ImproperlyConfigured, NON_FIELD_ERRORS
from django.core.files.storage import default_storage
from django.db import IntegrityError
from django.utils import six
from django.utils.translation import ugettext_lazy as _
import jwt
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.settings import api_settings

from . import settings
from .compat import User, import_string

LOGGER = logging.getLogger(__name__)

def get_accept_list(request):
    http_accept = request.META.get('HTTP_ACCEPT', '*/*')
    return [item.strip() for item in http_accept.split(',')]

def get_account_model():
    """
    Returns the ``Account`` model that is active in this project.
    """
    try:
        return django_apps.get_model(settings.ACCOUNT_MODEL)
    except ValueError:
        raise ImproperlyConfigured(
            "ACCOUNT_MODEL must be of the form 'app_label.model_name'")
    except LookupError:
        raise ImproperlyConfigured("ACCOUNT_MODEL refers to model '%s'"\
" that has not been installed" % settings.ACCOUNT_MODEL)

def has_invalid_password(user):
    return user.password.startswith('!')

def printable_name(user):
    full_name = user.get_full_name()
    if full_name:
        return full_name
    return user.username

def update_db_row(instance, form):
    """
    Updates the record in the underlying database, or adds a validation
    error in the form. When an error is added, the form is returned otherwise
    this function returns `None`.
    """
    try:
        try:
            instance.save()
        except IntegrityError as err:
            handle_uniq_error(err)
    except ValidationError as err:
        fill_form_errors(form, err)
        return form
    return None

def fill_form_errors(form, err):
    """
    Fill a Django form from DRF ValidationError exceptions.
    """
    if isinstance(err.detail, dict):
        for field, msg in six.iteritems(err.detail):
            if field in form.fields:
                form.add_error(field, msg)
            elif field == api_settings.NON_FIELD_ERRORS_KEY:
                form.add_error(NON_FIELD_ERRORS, msg)
            else:
                form.add_error(NON_FIELD_ERRORS,
                    _("No field '%(field)s': %(msg)s" % {
                    'field': field, 'msg': msg}))

def handle_uniq_error(err, renames=None):
    """
    Will raise a ``ValidationError`` with the appropriate error message.
    """
    field_name = None
    err_msg = str(err).splitlines().pop()
    # PostgreSQL unique constraint.
    look = re.match(
        r'DETAIL:\s+Key \(([a-z_]+)\)=\(.*\) already exists\.', err_msg)
    if look:
        field_name = look.group(1)
    else:
        look = re.match(
          r'DETAIL:\s+Key \(lower\(([a-z_]+)::text\)\)=\(.*\) already exists\.',
            err_msg)
        if look:
            field_name = look.group(1)
        else:
            # SQLite unique constraint.
            look = re.match(
                r'UNIQUE constraint failed: [a-z_]+\.([a-z_]+)', err_msg)
            if look:
                field_name = look.group(1)
    if field_name:
        if renames and field_name in renames:
            field_name = renames[field_name]
        raise ValidationError({field_name:
            _("This %(field)s is already taken.") % {'field': field_name}})
    raise err

def verify_token(token):
    try:
        payload = jwt.decode(
            token,
            settings.JWT_SECRET_KEY,
            True, # verify
            options={'verify_exp': True},
            algorithms=[settings.JWT_ALGORITHM])
    except jwt.ExpiredSignature:
        raise serializers.ValidationError(
            _("Signature has expired."))
    except jwt.DecodeError:
        raise serializers.ValidationError(
            _("Error decoding signature."))
    username = payload.get('username', None)
    if not username:
        raise serializers.ValidationError(
            _("Missing username in payload"))
    # Make sure user exists
    try:
        user = User.objects.get(username=username)
    except User.DoesNotExist:
        raise serializers.ValidationError(_("User does not exist."))
    return user

def get_disabled_authentication():
    if isinstance(settings.DISABLED_REGISTRATION, six.string_types):
        return import_string(settings.DISABLED_AUTHENTICATION)()
    return bool(settings.DISABLED_AUTHENTICATION)

def get_disabled_registration():
    if isinstance(settings.DISABLED_REGISTRATION, six.string_types):
        return import_string(settings.DISABLED_REGISTRATION)()
    return bool(settings.DISABLED_REGISTRATION)

def get_picture_storage():
    if settings.PICTURE_STORAGE_CALLABLE:
        try:
            return import_string(settings.PICTURE_STORAGE_CALLABLE)()
        except ImportError:
            pass
    return default_storage
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

__LIBRARY_VERSION__ = '1.5.0'
__SII_VERSION__ = '1.0'
<commit_msg>Bump to v1.5.1<commit_after># -*- coding: utf-8 -*-

__LIBRARY_VERSION__ = '1.5.1'
__SII_VERSION__ = '1.0'
<|endoftext|>


<commit_before>"""
Diagnostics and admin tasks
"""
from __future__ import with_statement
import contextlib
import time
from fabric.api import *
from util import venv
from targetenvs import _needs_targetenv

def can_i_deploy():
    """Tests password less sudo for automatic deploys."""
    sudo("echo 'it seems that I can run sudo as '", shell=False)
    sudo("whoami", shell=False)

def list_dist():
    _needs_targetenv()
    run("ls -latr %(dist_dir)s/"%env)

def clean_dist():
    _needs_targetenv()
    run("rm -rf %(dist_dir)s/*"%env)

def tail():
    _needs_targetenv()
    sudo("ls -t %(tomcat)s/logs/catalina*.* | head -1 | xargs tail -f"%env)

def tail2():
    _needs_targetenv()
    run("tail -f %(tomcat)s/logs/localhost.%(datestamp)s.log"%env)

def restart_all():
    _needs_targetenv()
    sudo("/etc/init.d/apache2 stop")
    restart_tomcat()
    sudo("/etc/init.d/apache2 start")

@contextlib.contextmanager
def _managed_tomcat_restart(wait=5, headless=False):
    _needs_targetenv()
    result = sudo("%(tomcat_stop)s" % env, term=not headless)
    if result.failed:
        raise OSError(result)
    yield
    print "... restarting in",
    for i in range(wait, 0, -1):
        print "%d..." % i,
        time.sleep(1)
    print
    sudo("%(tomcat_start)s" % env, term=not headless)

def restart_tomcat():
    with _managed_tomcat_restart(): pass

def restart_apache():
    _needs_targetenv()
    #sudo("/etc/init.d/apache2 stop")
    #sudo("/etc/init.d/apache2 start")
    sudo("/etc/init.d/apache2 restart")

def war_props(warname="ROOT"):
    _needs_targetenv()
    run("unzip -p %(tomcat_webapps)s/%(warname)s.war"
            " WEB-INF/classes/*.properties"%venv())

<commit_msg>Fixed syntax error in previous commit.<commit_after>"""
Diagnostics and admin tasks
"""
from __future__ import with_statement
import contextlib
import time
from fabric.api import *
from util import venv
from targetenvs import _needs_targetenv

def can_i_deploy():
    """Tests password less sudo for automatic deploys."""
    sudo("echo 'it seems that I can run sudo as '", shell=False)
    sudo("whoami", shell=False)

def list_dist():
    _needs_targetenv()
    run("ls -latr %(dist_dir)s/"%env)

def clean_dist():
    _needs_targetenv()
    run("rm -rf %(dist_dir)s/*"%env)

def tail():
    _needs_targetenv()
    sudo("ls -t %(tomcat)s/logs/catalina*.* | head -1 | xargs tail -f"%env)

def tail2():
    _needs_targetenv()
    run("tail -f %(tomcat)s/logs/localhost.%(datestamp)s.log"%env)

def restart_all():
    _needs_targetenv()
    sudo("/etc/init.d/apache2 stop")
    restart_tomcat()
    sudo("/etc/init.d/apache2 start")

@contextlib.contextmanager
def _managed_tomcat_restart(wait=5, headless=False):
    _needs_targetenv()
    result = sudo("%(tomcat_stop)s" % env, shell=not headless)
    if result.failed:
        raise OSError(result)
    yield
    print "... restarting in",
    for i in range(wait, 0, -1):
        print "%d..." % i,
        time.sleep(1)
    print
    sudo("%(tomcat_start)s" % env, shell=not headless)

def restart_tomcat():
    with _managed_tomcat_restart(): pass

def restart_apache():
    _needs_targetenv()
    #sudo("/etc/init.d/apache2 stop")
    #sudo("/etc/init.d/apache2 start")
    sudo("/etc/init.d/apache2 restart")

def war_props(warname="ROOT"):
    _needs_targetenv()
    run("unzip -p %(tomcat_webapps)s/%(warname)s.war"
            " WEB-INF/classes/*.properties"%venv())

<|endoftext|>


<commit_before>#!/usr/bin/env python
import ecto
import ecto_test
import sys, time

print "Hardware concurrency is", ecto.hardware_concurrency()

def makeplasm():
    plasm = ecto.Plasm()

    ping = ecto_test.Ping("Ping")
    sleep0 = ecto_test.Sleep("Sleep_0", seconds=0.1)
    sleep1 = ecto_test.Sleep("Sleep_1", seconds=0.1)

    plasm.connect(ping[:] >> sleep0[:],
                  sleep0[:] >> sleep1[:])

    return plasm

def sthreaded():
    p = makeplasm()

    s = ecto.schedulers.Singlethreaded(p)

    assert not s.running()

    stime = time.time()

    s.execute(niter=3)

    assert not s.running()
    etime = time.time()
    print "elapsed:", etime-stime
    assert 0.62 > etime - stime >= 0.6
    stime = time.time()
    s.execute_async(niter=3)
    assert s.running()
    nloops = 0
    while s.running():
        time.sleep(0.01)
        nloops = nloops + 1

    assert not s.running()
    print "nloops=", nloops
    assert nloops >= 59
    etime = time.time()
    print "elapsed:", etime-stime
    assert 0.62 > etime - stime >= 0.6

    stime = time.time()
    assert not s.running()
    s.execute_async(niter=3)
    assert s.running()
    s.wait()
    assert not s.running()
    etime = time.time()
    print "elapsed=", etime-stime
    assert 0.62 > etime - stime >= 0.6

kwargs = dict(niter=10)

def tpool():
    def bang(fn):
        p = makeplasm()
        s = ecto.schedulers.Threadpool(p)
        assert not s.running()
        stime = time.time()
        fn(s)
        etime = time.time()
        elapsed = etime-stime
        return elapsed

    def justrun(s):
        print "just run it"
        s.execute(**kwargs)

    runtime = bang(justrun)

    def asyncit(s):
        print "async and wait on running() == false"
        s.execute_async(**kwargs)
        while s.running():
            pass

    asynctime = bang(asyncit)

    def waitit(s):
        print "async and wait()"
        s.execute_async(**kwargs)
        s.wait()

    waittime = bang(waitit)

    print runtime, asynctime, waittime

    median = (runtime + asynctime + waittime) / 3.0
    low = median*0.75
    high = median*1.2

    print "lowest acceptable:", low, "highest acceptable:", high
    print "runtime:", runtime, "asynctime", asynctime, "waittime", waittime
    assert high > runtime > low
    assert high > asynctime > low
    assert high > waittime > low

def tpool_interrupt():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.execute_async()
    time.sleep(0.1)
    s.interrupt()
    s.wait()
    etime = time.time()
    time.sleep(0.1)
    print "elapsed:", etime-stime
    assert etime-stime > 0.1
    assert 0.4 > etime-stime

def tpool_throw_on_double_execute():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.execute_async()
    try:
        s.execute()
    except Exception, e:
        assert e.message == "threadpool scheduler already running"
        print "as expected:", e.message

def tpool_wait_on_nothing():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.wait()
    etime = time.time()
    print etime-stime
    assert 0.01 > etime-stime

if ecto.hardware_concurrency() > 1:
    tpool()
    tpool_wait_on_nothing()
    tpool_throw_on_double_execute()
    tpool_interrupt()
else:
    print "threadpool async execution tests disabled due to lack of hardware concurrency"

sthreaded()

print "okay."
<commit_msg>tweaks for tests running on very, very slow buildbot vms<commit_after>#!/usr/bin/env python
import ecto
import ecto_test
import sys, time

print "Hardware concurrency is", ecto.hardware_concurrency()

def makeplasm():
    plasm = ecto.Plasm()

    ping = ecto_test.Ping("Ping")
    sleep0 = ecto_test.Sleep("Sleep_0", seconds=0.1)
    sleep1 = ecto_test.Sleep("Sleep_1", seconds=0.1)

    plasm.connect(ping[:] >> sleep0[:],
                  sleep0[:] >> sleep1[:])

    return plasm

def sthreaded():
    p = makeplasm()

    s = ecto.schedulers.Singlethreaded(p)

    assert not s.running()

    stime = time.time()

    s.execute(niter=3)

    assert not s.running()
    etime = time.time()
    print "elapsed:", etime-stime
    assert 0.63 > etime - stime >= 0.6
    stime = time.time()
    s.execute_async(niter=3)
    assert s.running()
    nloops = 0
    while s.running():
        time.sleep(0.01)
        nloops = nloops + 1

    assert not s.running()
    print "nloops=", nloops
    assert nloops >= 59
    etime = time.time()
    print "elapsed:", etime-stime
    assert 0.63 > etime - stime >= 0.6

    stime = time.time()
    assert not s.running()
    s.execute_async(niter=3)
    assert s.running()
    s.wait()
    assert not s.running()
    etime = time.time()
    print "elapsed=", etime-stime
    assert 0.63 > etime - stime >= 0.6

kwargs = dict(niter=10)

def tpool():
    def bang(fn):
        p = makeplasm()
        s = ecto.schedulers.Threadpool(p)
        assert not s.running()
        stime = time.time()
        fn(s)
        etime = time.time()
        elapsed = etime-stime
        return elapsed

    def justrun(s):
        print "just run it"
        s.execute(**kwargs)

    runtime = bang(justrun)

    def asyncit(s):
        print "async and wait on running() == false"
        s.execute_async(**kwargs)
        while s.running():
            pass

    asynctime = bang(asyncit)

    def waitit(s):
        print "async and wait()"
        s.execute_async(**kwargs)
        s.wait()

    waittime = bang(waitit)

    print runtime, asynctime, waittime

    median = (runtime + asynctime + waittime) / 3.0
    low = median*0.75
    high = median*1.2

    print "lowest acceptable:", low, "highest acceptable:", high
    print "runtime:", runtime, "asynctime", asynctime, "waittime", waittime
    assert high > runtime > low
    assert high > asynctime > low
    assert high > waittime > low

def tpool_interrupt():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.execute_async()
    time.sleep(0.1)
    s.interrupt()
    s.wait()
    etime = time.time()
    time.sleep(0.1)
    print "elapsed:", etime-stime
    assert etime-stime > 0.1
    assert 0.4 > etime-stime

def tpool_throw_on_double_execute():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.execute_async()
    try:
        s.execute()
    except Exception, e:
        assert e.message == "threadpool scheduler already running"
        print "as expected:", e.message

def tpool_wait_on_nothing():
    p = makeplasm()
    s = ecto.schedulers.Threadpool(p)

    stime = time.time()
    s.wait()
    etime = time.time()
    print etime-stime
    assert 0.01 > etime-stime

if ecto.hardware_concurrency() > 1:
    tpool()
    tpool_wait_on_nothing()
    tpool_throw_on_double_execute()
    tpool_interrupt()
else:
    print "threadpool async execution tests disabled due to lack of hardware concurrency"

sthreaded()

print "okay."
<|endoftext|>


<commit_before># coding=utf-8
import re
from unidecode import unidecode

from sii import __SII_VERSION__
from sii.models import invoices_record

SIGN = {'B': -1, 'A': -1, 'N': 1, 'R': 1}

def get_iva_values(invoice, in_invoice, is_export=False, is_import=False):
    vals = {
        'sujeta_a_iva': False,
        'detalle_iva': [],
        'no_sujeta_a_iva': False,
        'iva_exento': False,
        'iva_no_exento': False,
        'detalle_iva_exento': {'BaseImponible': 0},
        'importe_no_sujeto': 0
    }

    invoice_total = invoice.amount_total

    for inv_tax in invoice.tax_line:
        if 'iva' in inv_tax.name.lower():
            vals['sujeta_a_iva'] = True

            invoice_total -= (abs(inv_tax.tax_amount) + abs(inv_tax.base))

            is_iva_exento = (
                inv_tax.tax_id.amount == 0 and inv_tax.tax_id.type == 'percent'
            )
            if not is_export and not is_import and is_iva_exento:
                vals['iva_exento'] = True
                vals['detalle_iva_exento']['BaseImponible'] += inv_tax.base
            else:
                sign = SIGN[invoice.rectificative_type]
                iva = {
                    'BaseImponible': sign * abs(inv_tax.base),
                    'TipoImpositivo': inv_tax.tax_id.amount * 100
                }
                if in_invoice:
                    iva['CuotaSoportada'] = sign * abs(inv_tax.tax_amount)
                else:
                    iva['CuotaRepercutida'] = sign * abs(inv_tax.tax_amount)
                vals['iva_no_exento'] = True
                vals['detalle_iva'].append(iva)

    invoice_total = round(invoice_total, 2)
    if invoice_total > 0:
        vals['no_sujeta_a_iva'] = True
        vals['importe_no_sujeto'] = invoice_total

    return vals

def get_contraparte(partner, in_invoice):
    vat_type = partner.sii_get_vat_type()
    contraparte = {'NombreRazon': unidecode(partner.name)}

    partner_country = partner.country or partner.country_id

    if vat_type == '02':
        if not partner.aeat_registered and not in_invoice:
            contraparte['IDOtro'] = {
                'CodigoPais': partner_country.code,
                'IDType': '07',
                'ID': partner.vat
            }
        else:
            contraparte['NIF'] = partner.vat
    else:
        contraparte['IDOtro'] = {
            'CodigoPais': partner_country.code,
            'IDType': vat_type,
            'ID': partner.vat
        }

    return contraparte

def get_factura_emitida_tipo_desglose(invoice):

    if invoice.sii_out_clave_regimen_especial == '02':  # Exportación
        iva_values = get_iva_values(invoice, in_invoice=False, is_export=True)

        if iva_values['sujeta_a_iva']:
            entrega = {
                'Sujeta': {
                    'NoExenta': {
                        'TipoNoExenta': 'S1',
                        'DesgloseIVA': {
                            'DetalleIVA': iva_values['detalle_iva']
                        }
                    }
                }
            }
        else:
            entrega = {
                'Sujeta': {
                    'Exenta': iva_values['detalle_iva_exento']
                }
            }
            # Exenta por el artículo 21
            entrega['Sujeta']['Exenta']['CausaExencion'] = 'E2'

        tipo_desglose = {
            'DesgloseTipoOperacion': {
                'Entrega': entrega
            }
        }
    else:
        iva_values = get_iva_values(invoice, in_invoice=False)
        desglose = {}

        if iva_values['sujeta_a_iva']:
            desglose['Sujeta'] = {}
            if iva_values['iva_exento']:
                desglose['Sujeta']['Exenta'] = iva_values['detalle_iva_exento']
            if iva_values['iva_no_exento']:
                desglose['Sujeta']['NoExenta'] = {
                    'TipoNoExenta': 'S1',
                    'DesgloseIVA': {
                        'DetalleIVA': iva_values['detalle_iva']
                    }
                }
        if iva_values['no_sujeta_a_iva']:
            importe_no_sujeto = iva_values['importe_no_sujeto']

            fp = invoice.fiscal_position
            if fp and 'islas canarias' in unidecode(fp.name.lower()):
                desglose['NoSujeta'] = {
                    'ImporteTAIReglasLocalizacion': importe_no_sujeto
                }
            else:
                desglose['NoSujeta'] = {
                    'ImportePorArticulos7_14_Otros': importe_no_sujeto
                }

        partner_vat = invoice.partner_id.vat
        partner_vat_starts_with_n = (
            partner_vat and partner_vat.upper().startswith('N')
        )
        has_id_otro = invoice.partner_id.sii_get_vat_type() != '02'
        if has_id_otro or partner_vat_starts_with_n:
            tipo_desglose = {
                'DesgloseTipoOperacion': {
                    'PrestacionServicios': desglose
                }
            }
        else:
            tipo_desglose = {
                'DesgloseFactura': desglose
            }

    return tipo_desglose

def get_factura_emitida(invoice):

    factura_expedida = {
        'TipoFactura': 'R4' if invoice.rectificative_type == 'R' else 'F1',
        'ClaveRegimenEspecialOTrascendencia':
            invoice.sii_out_clave_regimen_especial,
        'ImporteTotal': SIGN[invoice.rectificative_type] * invoice.amount_total,
        'DescripcionOperacion':
            invoice.journal_id.sii_description or invoice.journal_id.name,
        'Contraparte': get_contraparte(invoice.partner_id, in_invoice=False),
        'TipoDesglose': get_factura_emitida_tipo_desglose(invoice)
    }

    # Si la factura es una operación de arrendamiento
    # de local de negocio (alquiler)
    if invoice.sii_out_clave_regimen_especial in ['12', '13']:
        detalle_inmueble = {}

        codigo_comunidad_autonoma = \
            invoice.address_contact_id.state_id.comunitat_autonoma.codi

        # '01', '02', ..., '19': Comunidades autónomas de España
        if codigo_comunidad_autonoma in [str(s).zfill(2) for s in range(1, 20)]:
            ref_catastral = invoice.address_contact_id.ref_catastral
            if ref_catastral:
                detalle_inmueble['ReferenciaCatastral'] = ref_catastral

                # '15': Comunidad Foral de Navarra
                # '16': País Vasco
                if codigo_comunidad_autonoma not in ['15', '16']:
                    situacion_inmueble = '1'
                else:
                    situacion_inmueble = '2'
            else:
                situacion_inmueble = '3'
        else:
            situacion_inmueble = '4'

        detalle_inmueble['SituacionInmueble'] = situacion_inmueble

        factura_expedida['DatosInmueble'] = {
            'DetalleInmueble': detalle_inmueble
        }

    return factura_expedida

def get_factura_recibida(invoice):
    cuota_deducible = 0

    # Factura correspondiente a una importación (informada sin asociar a un DUA
    if invoice.sii_in_clave_regimen_especial == '13':
        iva_values = get_iva_values(invoice, in_invoice=True, is_import=True)
    else:
        iva_values = get_iva_values(invoice, in_invoice=True)

    if iva_values['sujeta_a_iva'] and iva_values['iva_no_exento']:
        desglose_factura = {  # TODO to change
            # 'InversionSujetoPasivo': {
            #     'DetalleIVA': iva_values['detalle_iva']
            # },
            'DesgloseIVA': {
                'DetalleIVA': iva_values['detalle_iva']
            }
        }

        for detalle_iva in iva_values['detalle_iva']:
            cuota_deducible += detalle_iva['CuotaSoportada']
    else:
        desglose_factura = {
            'DesgloseIVA': {
                'DetalleIVA': [{
                    'BaseImponible': invoice.amount_untaxed
                }]
            }
        }

    factura_recibida = {
        'TipoFactura': 'R4' if invoice.rectificative_type == 'R' else 'F1',
        'ClaveRegimenEspecialOTrascendencia':
            invoice.sii_in_clave_regimen_especial,
        'ImporteTotal': SIGN[invoice.rectificative_type] * invoice.amount_total,
        'DescripcionOperacion':
            invoice.journal_id.sii_description or invoice.journal_id.name,
        'Contraparte': get_contraparte(invoice.partner_id, in_invoice=True),
        'DesgloseFactura': desglose_factura,
        'CuotaDeducible': cuota_deducible,
        'FechaRegContable': invoice.date_invoice
    }

    return factura_recibida

def get_header(invoice):
    cabecera = {
        'IDVersionSii': __SII_VERSION__,
        'Titular': {
            'NombreRazon': invoice.company_id.partner_id.name,
            'NIF': invoice.company_id.partner_id.vat
        },
        'TipoComunicacion': 'A0' if not invoice.sii_registered else 'A1'
    }

    return cabecera

def get_factura_rectificativa_fields():
    rectificativa_fields = {
        'TipoRectificativa': 'S',  # Por sustitución
        'ImporteRectificacion': {
            'BaseRectificada': 0,
            'CuotaRectificada': 0
        }
    }

    return rectificativa_fields

def get_factura_emitida_dict(invoice, rectificativa=False):
    obj = {
        'SuministroLRFacturasEmitidas': {
            'Cabecera': get_header(invoice),
            'RegistroLRFacturasEmitidas': {
                'PeriodoImpositivo': {
                    'Ejercicio': invoice.period_id.name[3:7],
                    'Periodo': invoice.period_id.name[0:2]
                },
                'IDFactura': {
                    'IDEmisorFactura': {
                        'NIF': invoice.company_id.partner_id.vat
                    },
                    'NumSerieFacturaEmisor': invoice.number,
                    'FechaExpedicionFacturaEmisor': invoice.date_invoice
                },
                'FacturaExpedida': get_factura_emitida(invoice)
            }
        }
    }

    if rectificativa:
        vals = get_factura_rectificativa_fields()

        (
            obj['SuministroLRFacturasEmitidas']['RegistroLRFacturasEmitidas']
            ['FacturaExpedida']
        ).update(vals)

    return obj

def get_factura_recibida_dict(invoice, rectificativa=False):
    obj = {
        'SuministroLRFacturasRecibidas': {
            'Cabecera': get_header(invoice),
            'RegistroLRFacturasRecibidas': {
                'PeriodoImpositivo': {
                    'Ejercicio': invoice.period_id.name[3:7],
                    'Periodo': invoice.period_id.name[0:2]
                },
                'IDFactura': {
                    'IDEmisorFactura': {
                        'NIF': invoice.partner_id.vat
                    },
                    'NumSerieFacturaEmisor': invoice.origin,
                    'FechaExpedicionFacturaEmisor': invoice.origin_date_invoice
                },
                'FacturaRecibida': get_factura_recibida(invoice)
            }
        }
    }

    if rectificativa:
        vals = get_factura_rectificativa_fields()

        (
            obj['SuministroLRFacturasRecibidas']['RegistroLRFacturasRecibidas']
            ['FacturaRecibida']
        ).update(vals)

    return obj

def refactor_nifs(invoice):
    for partner in (invoice.partner_id, invoice.company_id.partner_id):
        if partner.vat:
            partner.vat = re.sub('^ES', '', partner.vat.upper())

class SII(object):
    def __init__(self, invoice):
        self.invoice = invoice
        refactor_nifs(self.invoice)
        rectificativa = invoice.rectificative_type == 'R'
        if invoice.type.startswith('in'):
            self.invoice_model = invoices_record.SuministroFacturasRecibidas()
            self.invoice_dict = get_factura_recibida_dict(
                self.invoice, rectificativa=rectificativa
            )
        elif invoice.type.startswith('out'):
            self.invoice_model = invoices_record.SuministroFacturasEmitidas()
            self.invoice_dict = get_factura_emitida_dict(
                self.invoice, rectificativa=rectificativa
            )
        else:
            raise AttributeError(
                'Valor desconocido en el tipo de factura: {}'.format(
                    invoice.type
                )
            )

    def get_validation_errors_list(self, errors):
        error_messages = []

        for key, values in errors.items():
            if isinstance(values, dict):
                error_messages += self.get_validation_errors_list(values)
            else:
                error_messages += ['{}: {}'.format(key, val) for val in values]

        return error_messages

    def validate_invoice(self):

        res = {}

        errors = self.invoice_model.validate(self.invoice_dict)

        res['successful'] = False if errors else True
        if errors:
            errors_list = self.get_validation_errors_list(errors)
            res['errors'] = errors_list

        return res

    def generate_object(self):

        validation_values = self.validate_invoice()
        if not validation_values['successful']:
            raise Exception(
                'Errors were found while trying to validate the data:',
                validation_values['errors']
            )

        res = self.invoice_model.dump(self.invoice_dict)
        if res.errors:
            raise Exception(
                'Errors were found while trying to generate the dump:',
                res.errors
            )

        return res.data
<commit_msg>Fix checking for partner country<commit_after># coding=utf-8
import re
from unidecode import unidecode

from sii import __SII_VERSION__
from sii.models import invoices_record

SIGN = {'B': -1, 'A': -1, 'N': 1, 'R': 1}

def get_iva_values(invoice, in_invoice, is_export=False, is_import=False):
    vals = {
        'sujeta_a_iva': False,
        'detalle_iva': [],
        'no_sujeta_a_iva': False,
        'iva_exento': False,
        'iva_no_exento': False,
        'detalle_iva_exento': {'BaseImponible': 0},
        'importe_no_sujeto': 0
    }

    invoice_total = invoice.amount_total

    for inv_tax in invoice.tax_line:
        if 'iva' in inv_tax.name.lower():
            vals['sujeta_a_iva'] = True

            invoice_total -= (abs(inv_tax.tax_amount) + abs(inv_tax.base))

            is_iva_exento = (
                inv_tax.tax_id.amount == 0 and inv_tax.tax_id.type == 'percent'
            )
            if not is_export and not is_import and is_iva_exento:
                vals['iva_exento'] = True
                vals['detalle_iva_exento']['BaseImponible'] += inv_tax.base
            else:
                sign = SIGN[invoice.rectificative_type]
                iva = {
                    'BaseImponible': sign * abs(inv_tax.base),
                    'TipoImpositivo': inv_tax.tax_id.amount * 100
                }
                if in_invoice:
                    iva['CuotaSoportada'] = sign * abs(inv_tax.tax_amount)
                else:
                    iva['CuotaRepercutida'] = sign * abs(inv_tax.tax_amount)
                vals['iva_no_exento'] = True
                vals['detalle_iva'].append(iva)

    invoice_total = round(invoice_total, 2)
    if invoice_total > 0:
        vals['no_sujeta_a_iva'] = True
        vals['importe_no_sujeto'] = invoice_total

    return vals

def get_contraparte(partner, in_invoice):
    vat_type = partner.sii_get_vat_type()
    contraparte = {'NombreRazon': unidecode(partner.name)}

    partner_country = partner.country_id or partner.country

    if vat_type == '02':
        if not partner.aeat_registered and not in_invoice:
            contraparte['IDOtro'] = {
                'CodigoPais': partner_country.code,
                'IDType': '07',
                'ID': partner.vat
            }
        else:
            contraparte['NIF'] = partner.vat
    else:
        contraparte['IDOtro'] = {
            'CodigoPais': partner_country.code,
            'IDType': vat_type,
            'ID': partner.vat
        }

    return contraparte

def get_factura_emitida_tipo_desglose(invoice):

    if invoice.sii_out_clave_regimen_especial == '02':  # Exportación
        iva_values = get_iva_values(invoice, in_invoice=False, is_export=True)

        if iva_values['sujeta_a_iva']:
            entrega = {
                'Sujeta': {
                    'NoExenta': {
                        'TipoNoExenta': 'S1',
                        'DesgloseIVA': {
                            'DetalleIVA': iva_values['detalle_iva']
                        }
                    }
                }
            }
        else:
            entrega = {
                'Sujeta': {
                    'Exenta': iva_values['detalle_iva_exento']
                }
            }
            # Exenta por el artículo 21
            entrega['Sujeta']['Exenta']['CausaExencion'] = 'E2'

        tipo_desglose = {
            'DesgloseTipoOperacion': {
                'Entrega': entrega
            }
        }
    else:
        iva_values = get_iva_values(invoice, in_invoice=False)
        desglose = {}

        if iva_values['sujeta_a_iva']:
            desglose['Sujeta'] = {}
            if iva_values['iva_exento']:
                desglose['Sujeta']['Exenta'] = iva_values['detalle_iva_exento']
            if iva_values['iva_no_exento']:
                desglose['Sujeta']['NoExenta'] = {
                    'TipoNoExenta': 'S1',
                    'DesgloseIVA': {
                        'DetalleIVA': iva_values['detalle_iva']
                    }
                }
        if iva_values['no_sujeta_a_iva']:
            importe_no_sujeto = iva_values['importe_no_sujeto']

            fp = invoice.fiscal_position
            if fp and 'islas canarias' in unidecode(fp.name.lower()):
                desglose['NoSujeta'] = {
                    'ImporteTAIReglasLocalizacion': importe_no_sujeto
                }
            else:
                desglose['NoSujeta'] = {
                    'ImportePorArticulos7_14_Otros': importe_no_sujeto
                }

        partner_vat = invoice.partner_id.vat
        partner_vat_starts_with_n = (
            partner_vat and partner_vat.upper().startswith('N')
        )
        has_id_otro = invoice.partner_id.sii_get_vat_type() != '02'
        if has_id_otro or partner_vat_starts_with_n:
            tipo_desglose = {
                'DesgloseTipoOperacion': {
                    'PrestacionServicios': desglose
                }
            }
        else:
            tipo_desglose = {
                'DesgloseFactura': desglose
            }

    return tipo_desglose

def get_factura_emitida(invoice):

    factura_expedida = {
        'TipoFactura': 'R4' if invoice.rectificative_type == 'R' else 'F1',
        'ClaveRegimenEspecialOTrascendencia':
            invoice.sii_out_clave_regimen_especial,
        'ImporteTotal': SIGN[invoice.rectificative_type] * invoice.amount_total,
        'DescripcionOperacion':
            invoice.journal_id.sii_description or invoice.journal_id.name,
        'Contraparte': get_contraparte(invoice.partner_id, in_invoice=False),
        'TipoDesglose': get_factura_emitida_tipo_desglose(invoice)
    }

    # Si la factura es una operación de arrendamiento
    # de local de negocio (alquiler)
    if invoice.sii_out_clave_regimen_especial in ['12', '13']:
        detalle_inmueble = {}

        codigo_comunidad_autonoma = \
            invoice.address_contact_id.state_id.comunitat_autonoma.codi

        # '01', '02', ..., '19': Comunidades autónomas de España
        if codigo_comunidad_autonoma in [str(s).zfill(2) for s in range(1, 20)]:
            ref_catastral = invoice.address_contact_id.ref_catastral
            if ref_catastral:
                detalle_inmueble['ReferenciaCatastral'] = ref_catastral

                # '15': Comunidad Foral de Navarra
                # '16': País Vasco
                if codigo_comunidad_autonoma not in ['15', '16']:
                    situacion_inmueble = '1'
                else:
                    situacion_inmueble = '2'
            else:
                situacion_inmueble = '3'
        else:
            situacion_inmueble = '4'

        detalle_inmueble['SituacionInmueble'] = situacion_inmueble

        factura_expedida['DatosInmueble'] = {
            'DetalleInmueble': detalle_inmueble
        }

    return factura_expedida

def get_factura_recibida(invoice):
    cuota_deducible = 0

    # Factura correspondiente a una importación (informada sin asociar a un DUA
    if invoice.sii_in_clave_regimen_especial == '13':
        iva_values = get_iva_values(invoice, in_invoice=True, is_import=True)
    else:
        iva_values = get_iva_values(invoice, in_invoice=True)

    if iva_values['sujeta_a_iva'] and iva_values['iva_no_exento']:
        desglose_factura = {  # TODO to change
            # 'InversionSujetoPasivo': {
            #     'DetalleIVA': iva_values['detalle_iva']
            # },
            'DesgloseIVA': {
                'DetalleIVA': iva_values['detalle_iva']
            }
        }

        for detalle_iva in iva_values['detalle_iva']:
            cuota_deducible += detalle_iva['CuotaSoportada']
    else:
        desglose_factura = {
            'DesgloseIVA': {
                'DetalleIVA': [{
                    'BaseImponible': invoice.amount_untaxed
                }]
            }
        }

    factura_recibida = {
        'TipoFactura': 'R4' if invoice.rectificative_type == 'R' else 'F1',
        'ClaveRegimenEspecialOTrascendencia':
            invoice.sii_in_clave_regimen_especial,
        'ImporteTotal': SIGN[invoice.rectificative_type] * invoice.amount_total,
        'DescripcionOperacion':
            invoice.journal_id.sii_description or invoice.journal_id.name,
        'Contraparte': get_contraparte(invoice.partner_id, in_invoice=True),
        'DesgloseFactura': desglose_factura,
        'CuotaDeducible': cuota_deducible,
        'FechaRegContable': invoice.date_invoice
    }

    return factura_recibida

def get_header(invoice):
    cabecera = {
        'IDVersionSii': __SII_VERSION__,
        'Titular': {
            'NombreRazon': invoice.company_id.partner_id.name,
            'NIF': invoice.company_id.partner_id.vat
        },
        'TipoComunicacion': 'A0' if not invoice.sii_registered else 'A1'
    }

    return cabecera

def get_factura_rectificativa_fields():
    rectificativa_fields = {
        'TipoRectificativa': 'S',  # Por sustitución
        'ImporteRectificacion': {
            'BaseRectificada': 0,
            'CuotaRectificada': 0
        }
    }

    return rectificativa_fields

def get_factura_emitida_dict(invoice, rectificativa=False):
    obj = {
        'SuministroLRFacturasEmitidas': {
            'Cabecera': get_header(invoice),
            'RegistroLRFacturasEmitidas': {
                'PeriodoImpositivo': {
                    'Ejercicio': invoice.period_id.name[3:7],
                    'Periodo': invoice.period_id.name[0:2]
                },
                'IDFactura': {
                    'IDEmisorFactura': {
                        'NIF': invoice.company_id.partner_id.vat
                    },
                    'NumSerieFacturaEmisor': invoice.number,
                    'FechaExpedicionFacturaEmisor': invoice.date_invoice
                },
                'FacturaExpedida': get_factura_emitida(invoice)
            }
        }
    }

    if rectificativa:
        vals = get_factura_rectificativa_fields()

        (
            obj['SuministroLRFacturasEmitidas']['RegistroLRFacturasEmitidas']
            ['FacturaExpedida']
        ).update(vals)

    return obj

def get_factura_recibida_dict(invoice, rectificativa=False):
    obj = {
        'SuministroLRFacturasRecibidas': {
            'Cabecera': get_header(invoice),
            'RegistroLRFacturasRecibidas': {
                'PeriodoImpositivo': {
                    'Ejercicio': invoice.period_id.name[3:7],
                    'Periodo': invoice.period_id.name[0:2]
                },
                'IDFactura': {
                    'IDEmisorFactura': {
                        'NIF': invoice.partner_id.vat
                    },
                    'NumSerieFacturaEmisor': invoice.origin,
                    'FechaExpedicionFacturaEmisor': invoice.origin_date_invoice
                },
                'FacturaRecibida': get_factura_recibida(invoice)
            }
        }
    }

    if rectificativa:
        vals = get_factura_rectificativa_fields()

        (
            obj['SuministroLRFacturasRecibidas']['RegistroLRFacturasRecibidas']
            ['FacturaRecibida']
        ).update(vals)

    return obj

def refactor_nifs(invoice):
    for partner in (invoice.partner_id, invoice.company_id.partner_id):
        if partner.vat:
            partner.vat = re.sub('^ES', '', partner.vat.upper())

class SII(object):
    def __init__(self, invoice):
        self.invoice = invoice
        refactor_nifs(self.invoice)
        rectificativa = invoice.rectificative_type == 'R'
        if invoice.type.startswith('in'):
            self.invoice_model = invoices_record.SuministroFacturasRecibidas()
            self.invoice_dict = get_factura_recibida_dict(
                self.invoice, rectificativa=rectificativa
            )
        elif invoice.type.startswith('out'):
            self.invoice_model = invoices_record.SuministroFacturasEmitidas()
            self.invoice_dict = get_factura_emitida_dict(
                self.invoice, rectificativa=rectificativa
            )
        else:
            raise AttributeError(
                'Valor desconocido en el tipo de factura: {}'.format(
                    invoice.type
                )
            )

    def get_validation_errors_list(self, errors):
        error_messages = []

        for key, values in errors.items():
            if isinstance(values, dict):
                error_messages += self.get_validation_errors_list(values)
            else:
                error_messages += ['{}: {}'.format(key, val) for val in values]

        return error_messages

    def validate_invoice(self):

        res = {}

        errors = self.invoice_model.validate(self.invoice_dict)

        res['successful'] = False if errors else True
        if errors:
            errors_list = self.get_validation_errors_list(errors)
            res['errors'] = errors_list

        return res

    def generate_object(self):

        validation_values = self.validate_invoice()
        if not validation_values['successful']:
            raise Exception(
                'Errors were found while trying to validate the data:',
                validation_values['errors']
            )

        res = self.invoice_model.dump(self.invoice_dict)
        if res.errors:
            raise Exception(
                'Errors were found while trying to generate the dump:',
                res.errors
            )

        return res.data
<|endoftext|>