<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"""
===============================
    Shimehari.app
    ~~~~~~~~~~~~~
    Flask などなど参考に。
    ルーティングが多少複雑になっても
    対応できるような作りにしたいなぁ
===============================
"""

import os
import sys
from  threading import Lock, RLock
from functools import update_wrapper
from datetime import timedelta

from werkzeug.exceptions import NotFound, HTTPException, InternalServerError, MethodNotAllowed, BadRequest
from werkzeug.datastructures import ImmutableDict
from werkzeug.routing import RequestRedirect, Rule

from .helpers import _Kouzi, findPackage, getHandlerAction, getModulesFromPyFile, getEnviron, \
                    lockedCachedProperty, getTemplater
from .contexts import RequestContext, AppContext
from .routing import Router
from core.config import RESTFUL_ACTIONS
from .wrappers import Request, Response
from shimehari.configuration import Config, ConfigManager
from shimehari.session import SessionStore
from shimehari.shared import _requestContextStack, _appContextStack, _SharedRequestClass, request
from shimehari.template import _defaultTemplateCtxProcessor
from shimehari.core.exceptions import ShimehariException, ShimehariSetupError
from shimehari.core.signals import appContextTearingDown, requestContextTearingDown


_loggerLock = Lock()


def setupMethod(f):
    def wrapperFunc(self, *args, **kwargs):
        if self.debug and self._gotFirstRequest:
            raise AssertionError('Setup seems to have already completed ...')
        return f(self, *args, **kwargs)
    return update_wrapper(wrapperFunc, f)


class Shimehari(_Kouzi):
    u"""Shimehari Object は WSGI アプリケーションとして必要な機能を実装しており、
    アプリケーションの中心となるオブジェクトです。

    メインモジュール、または __init__.py ファイルの中で以下のように書くことで
    Shimehari インスタンスを生成することができます。

    .. code-block:: python

        from shimehari import Shimehari
        app = Shimehari(__name__)

    ただし、Shimehari では通常コマンドラインでアプリケーションを生成することを推奨しているので
    あなたが直接インスタンス生成のコードを書くことはそうそうないと思われます。

    :param importName: アプリケーションのパッケージ名
    :param staticURL: サイト内共通、静的ファイルの URL
    :param staticFolder: 静的ファイルが格納されているディレクトリ
    :param appFolder: アプリケーション全体が格納されているディレクトリ
    :param controllerFolder: コントローラーが格納されているディレクトリ
    :param viewFolder: ビューが格納されているディレクトリ
    :param assetsFolder: アセットファイルが格納されているディレクトリ
    :param instancePath: アプリケーションのための代替インスタンスパス

    """

    currentEnv = getEnviron()
    debug = None
    testing = None

    requestClass = Request
    responseClass = Response

    testClientCls = None

    teardownAppContextFuncs = []

    defaultConfig = {
        'DEBUG': False,
        'TEST': False,
        'APP_DIRECTORY': 'app',
        'CONTROLLER_DIRECTORY': 'controllers',
        'VIEW_DIRECTORY': 'views',
        #for daiginjou
        'MODEL_DIRECTORY': 'models',
        'PREFERRED_URL_SCHEME': 'http',
        'AUTO_SETUP': True,
        'TEMPLATE_ENGINE': 'jinja2',
        'TRAP_HTTP_EXCEPTIONS': False,
        'SERVER_NAME': None,
        'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
        'SECRET_KEY': '_secret_shimehari'
    }

    templateOptions = {}

    sessionStore = SessionStore()

    sharedRequestClass = _SharedRequestClass

    def __init__(self, importName,
                 staticURL=None, staticFolder='static',
                 appFolder='app', controllerFolder='controllers',
                 viewFolder='views', assetsFolder='assets',
                 instancePath=None, isRelativeConfig=False, templateOptions={}):

        _Kouzi.__init__(self, importName, appFolder=appFolder,
                        controllerFolder=controllerFolder, viewFolder=viewFolder)

        if instancePath is None:
            self._instancePath = self.getInstancePath()

        self._logger = None
        self.loggerName = self.importName

        self.config = self.getConfig()

        self.controllers = {}
        self.urlValuePreprocesors = {}
        self.beforeRequestFuncs = {}
        self.beforeFirstRequestFuncs = []
        self.urlDefaultFuncs = {}
        self.afterRequestFuncs = {}
        self._errorHandlers = {}
        self.errorHandlerSpec = {None: self._errorHandlers}
        self.buildErrorHandlers = None
        self.teardownRequestContextFuncs = {}

        self.templateContextProcessors = {
            None: [_defaultTemplateCtxProcessor]
        }

        #CSRF
        from shimehari.crypt import CSRF
        self.csrf = CSRF(self)

        self._router = Router()

        self._gotFirstRequest = False

        self._beforeRequestLock = Lock()

        self.debug = self.config['DEBUG']
        self.test = self.config['TEST']
        self.sessionKey = self.config['SECRET_KEY']
        self.useXSendFile = self.config['USE_X_SENDFILE']

        self.templateOptions = templateOptions

        if self.config['AUTO_SETUP']:
            self.setup()

    @property
    def gotFirstRequest(self):
        return self._gotFirstRequest

    @property
    def propagateExceptions(self):
        return self.testing or self.debug

    @property
    def preserveContextOnException(self):
        rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION']
        if rv is not None:
            return rv
        return self.debug

    @property
    def logger(self):
        if self._logger and self._logger.name == self.loggerName:
            return self._logger
        with _loggerLock:<commit_msg>[issue](#17)酒が飲めるぞ!<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"""
===============================
    Shimehari.app
    ~~~~~~~~~~~~~
    Flask などなど参考に。
    ルーティングが多少複雑になっても
    対応できるような作りにしたいなぁ
===============================
"""

import os
import sys
from  threading import Lock, RLock
from functools import update_wrapper
from datetime import timedelta

from werkzeug.exceptions import NotFound, HTTPException, InternalServerError, MethodNotAllowed, BadRequest
from werkzeug.datastructures import ImmutableDict
from werkzeug.routing import RequestRedirect, Rule

from .helpers import _Kouzi, findPackage, getHandlerAction, getModulesFromPyFile, getEnviron, \
                    lockedCachedProperty, getTemplater
from .contexts import RequestContext, AppContext
from .routing import Router
from core.config import RESTFUL_ACTIONS
from .wrappers import Request, Response
from shimehari.configuration import Config, ConfigManager
from shimehari.session import SessionStore
from shimehari.shared import _requestContextStack, _appContextStack, _SharedRequestClass, request
from shimehari.template import _defaultTemplateCtxProcessor
from shimehari.core.exceptions import ShimehariException, ShimehariSetupError
from shimehari.core.signals import appContextTearingDown, requestContextTearingDown


_loggerLock = Lock()


def setupMethod(f):
    def wrapperFunc(self, *args, **kwargs):
        if self.debug and self._gotFirstRequest:
            raise AssertionError('Setup seems to have already completed ...')
        return f(self, *args, **kwargs)
    return update_wrapper(wrapperFunc, f)


class Shimehari(_Kouzi):
    u"""Shimehari Object は WSGI アプリケーションとして必要な機能を実装しており、
    アプリケーションの中心となるオブジェクトです。

    メインモジュール、または __init__.py ファイルの中で以下のように書くことで
    Shimehari インスタンスを生成することができます。

    .. code-block:: python

        from shimehari import Shimehari
        app = Shimehari(__name__)

    ただし、Shimehari では通常コマンドラインでアプリケーションを生成することを推奨しているので
    あなたが直接インスタンス生成のコードを書くことはそうそうないと思われます。

    :param importName: アプリケーションのパッケージ名
    :param staticURL: サイト内共通、静的ファイルの URL
    :param staticFolder: 静的ファイルが格納されているディレクトリ
    :param appFolder: アプリケーション全体が格納されているディレクトリ
    :param controllerFolder: コントローラーが格納されているディレクトリ
    :param viewFolder: ビューが格納されているディレクトリ
    :param assetsFolder: アセットファイルが格納されているディレクトリ
    :param instancePath: アプリケーションのための代替インスタンスパス

    """

    currentEnv = getEnviron()
    debug = None
    testing = None

    requestClass = Request
    responseClass = Response

    testClientCls = None

    teardownAppContextFuncs = []

    defaultConfig = {
        'DEBUG': False,
        'TEST': False,
        'APP_DIRECTORY': 'app',
        'CONTROLLER_DIRECTORY': 'controllers',
        'VIEW_DIRECTORY': 'views',
        #for daiginjou
        'MODEL_DIRECTORY': 'models',
        'PREFERRED_URL_SCHEME': 'http',
        'AUTO_SETUP': True,
        'TEMPLATE_ENGINE': 'jinja2',
        'TRAP_HTTP_EXCEPTIONS': False,
        'SERVER_NAME': None,
        'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
        'SECRET_KEY': '_secret_shimehari'
    }

    templateOptions = {}

    sessionStore = SessionStore()

    sharedRequestClass = _SharedRequestClass

    def __init__(self, importName,
                 staticURL=None, staticFolder='static',
                 appFolder='app', controllerFolder='controllers',
                 viewFolder='views', assetsFolder='assets',
                 instancePath=None, isRelativeConfig=False, templateOptions={}):

        _Kouzi.__init__(self, importName, appFolder=appFolder,
                        controllerFolder=controllerFolder, viewFolder=viewFolder)

        if instancePath is None:
            self._instancePath = self.getInstancePath()

        self._logger = None
        self.loggerName = self.importName

        self.config = self.getConfig()

        self.controllers = {}
        self.urlValuePreprocesors = {}
        self.beforeRequestFuncs = {}
        self.beforeFirstRequestFuncs = []
        self.urlDefaultFuncs = {}
        self.afterRequestFuncs = {}
        self._errorHandlers = {}
        self.errorHandlerSpec = {None: self._errorHandlers}
        self.buildErrorHandlers = None
        self.teardownRequestContextFuncs = {}

        self.templateContextProcessors = {
            None: [_defaultTemplateCtxProcessor]
        }

        #CSRF
        from shimehari.crypt import CSRF
        self.csrf = CSRF(self)

        self._router = Router()

        self._gotFirstRequest = False

        self._beforeRequestLock = Lock()

        self.debug = self.config['DEBUG']
        self.test = self.config['TEST']
        self.sessionKey = self.config['SECRET_KEY']
        self.useXSendFile = self.config['USE_X_SENDFILE']

        self.templateOptions = templateOptions

        if self.config['AUTO_SETUP']:
            self.setup()

    @lockedCachedProperty
    def name(self):
        if self.importName == '__main__':
            fn = getattr(sys.modules['__main__'], '__file__', None)
            if fn is None:
                return '__main__'
            return os.path.splittext(os.path.basename(fn))[0]
        return self.importName

    @property
    def gotFirstRequest(self):
        return self._gotFirstRequest

    @property
    def propagateExceptions(self):
        return self.testing or self.debug

    @property
    def preserveContextOnException(self):
        rv = self.config['PRESERVE_CONTEXT_ON_EXCEPTION']
        if rv is not None:
            return rv
        return self.debug

    @property
    def logger(self):
        if self._logger and self._logger.name == self.loggerName:
            return self._logger
        with _loggerLock:
{'fraction_non_alphanumeric': 0.0943584170968034, 'fraction_numerical': 0.0009961061305804582, 'mean_word_length': 3.0469036277024553, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2683944', 'n_tokens_mistral': 3741, 'n_tokens_neox': 3568, 'n_words': 685}