2018年10月21日日曜日

開発環境

  • macOS Mojave - Apple
  • Emacs (Text Editor)
  • Python 3.7 (プログラミング言語)

Head First Python 第2版 ―頭とからだで覚えるPythonの基本 (Paul Barry (著)、嶋田 健志 (監修)、木下 哲也 (翻訳)、オライリージャパン)の11 3/4章(スレッド入門 - 待ち時間を処理する)、エクササイズ(p. 471)を取り組んでみる。

コード(Emacs)

Python 3

from flask import Flask, render_template, request, escape, copy_current_request_context
from threading import Thread
import time

import vsearch
from DBcm import UseDatabase, ConnectionError, CredentialsError, SQLError

app = Flask(__name__)

app.config['dbconfig'] = {'host': '127.0.0.1',
                          'user': 'vsearch',
                          'password': 'vsearchpasswd',
                          'database': 'vsearchlogDB', }


@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
    @copy_current_request_context
    def log_request(req: 'flask_request', res: str) -> None:
        time.sleep(15)
        with UseDatabase(app.config['dbconfig']) as cursor:
            _SQL = '''
create table if not exists log(
id integer primary key auto_increment,
ts timestamp default current_timestamp,
phrase varchar(128) not null,
letters varchar(32) not null,
ip varchar(16) not null,
browser_string varchar(256) not null,
results varchar(64) not null)
'''
            cursor.execute(_SQL)

            _SQL = '''
insert into log
(phrase, letters, ip, browser_string, results)
values
(%s, %s, %s, %s, %s)
'''
            cursor.execute(
                _SQL,
                (req.form['phrase'], req.form['letters'], req.remote_addr,
                 req.user_agent.browser, res))

    phrase = request.form['phrase']
    letters = request.form['letters']
    title = '検索結果'
    results = str(vsearch.search4letters(phrase, letters))
    try:
        t = Thread(target=log_request, args=(request, results))
        t.start()
    except Exception as err:
        print(f'ログリクエストが失敗しました: {err}')
    return render_template('results.html',
                           the_title=title,
                           the_phrase=phrase,
                           the_letters=letters,
                           the_results=results)


@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
    return render_template(
        'entry.html', the_title='Web版のsearch4lettersにようこそ!')


@app.route('/viewlog')
def view_the_log() -> 'html':
    try:
        with UseDatabase(app.config['dbconfig']) as cursor:
            _SQL = '''
select phrase, letters, ip, browser_string, results from log
'''
            cursor.execute(_SQL)
            contents = cursor.fetchall()
        titles = ('フレーズ', '文字', 'リモートアドレス',
                  'ユーザーエージェント', '結果')
        return render_template('viewlog.html',
                               the_title='ログの閲覧',
                               the_row_titles=titles,
                               the_data=contents,)
    except ConnectionError as err:
        print(f'データベースが動作していますか?エラー: {err}')
        return 'Connection Error'
    except CredentialsError as err:
        print(f'ユーザー/パスワード問題。エラー: {err}')
    except SQLError as err:
        print(f'クエリは正しいですか?エラー: {err}')
    except Exception as err:
        print(f'何か問題が発生しました: {err}')
    return 'Error'


if __name__ == '__main__':
    app.run(debug=True)

入出力結果(Terminal, Jupyter(IPython))

$ python3 vsearch4web_before.py 
 * Serving Flask app "vsearch4web_before" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 178-619-558
127.0.0.1 - - [21/Oct/2018 14:54:35] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/Oct/2018 14:54:36] "POST /search4 HTTP/1.1" 200 -
Exception in thread Thread-4:
Traceback (most recent call last):
  File "vsearch4web_before.py", line 39, in log_request
    (req.form['phrase'], req.form['letters'], req.remote_addr,
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/werkzeug/local.py", line 306, in _get_current_object
    return self.__local()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/globals.py", line 37, in _lookup_req_object
    raise RuntimeError(_request_ctx_err_msg)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "vsearch4web_before.py", line 40, in log_request
    req.user_agent.browser, res))
  File ".../webapp/DBcm.py", line 37, in __exit__
    raise exc_type(exc_value)
RuntimeError: Working outside of request context.

This typically means that you attempted to use functionality that needed
an active HTTP request.  Consult the documentation on testing for
information about how to avoid this problem.

  C-c C-c$ python3 vsearch4web.py 
 * Serving Flask app "vsearch4web" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 178-619-558
127.0.0.1 - - [21/Oct/2018 14:55:07] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/Oct/2018 14:55:15] "POST /search4 HTTP/1.1" 200 -
  C-c C-c$

0 コメント:

コメントを投稿