【TypeScript】interfaceを作る
こんばんは、葛の葉です。
今回はTypeScriptでinterfaceオブジェクトを作ってみます。
生物に対し足の数と全長メンバー+成長というメソッド
犬というクラスとカエルというクラスを作る。
それぞれ、foot
というメンバーとlengthというメンバー,そしてgrowth
というインスタンスメソッドを持つものとします。
AnimalInterface
// animalinterface export interface AnimalInterface { foot: number; length: number; growth(): void; };
ここでは宣言だけして、内容物は何も書きません。インターフェイスとはそのようなものです。
tsc animalinterface.ts
とコンパイルをします。
インターフェイスを使ってみる。
// objects.ts import { AnimalInterface } from "./animalinterface.js" class Dog implements AnimalInterface { name:string; };
implements
がインターフェイスを使う宣言になります。今回はインターフェイスを使用していますが、その機能を無視した形を取っていますので、コンパイル時にエラーになります。
[kuzunoha@:00:31:30:~]$ tsc objects.ts objects.ts:4:7 - error TS2420: Class 'Dog' incorrectly implements interface 'AnimalInterface'. Type 'Dog' is missing the following properties from type 'AnimalInterface': foot, growth 4 class Dog implements AnimalInterface { ~~~ Found 1 error.
interface
を使用している場合、その使用したinterfaceオブジェクトで宣言されているメンバーやメソッドを必ず宣言しなきゃいけないものになります。
改めてインターフェイスを使って動物のクラスを作る。
object.ts
という名前で以下のコードを作成する。
// objects.ts import { AnimalInterface } from "./animalinterface"; // 犬クラス class Dog implements AnimalInterface { foot: number = 4; length: number = 30; tail: boolean = true; growth(): void { this.length = 90; }; }; // カエルクラス class Frog implements AnimalInterface { foot: number = 0; length: number = 3; tail: boolean = true; growth(): void { this.length = 5; this.foot = 4; this.tail = false; }; }; let inu = new Dog(); let kaeru = new Frog(); console.log(`子犬の全長:${inu.length}cm,オタマジャクシの全長:${kaeru.length}cm`) console.log(`子犬の足の数:${inu.foot}本,オタマジャクシの足の数:${kaeru.foot}本`) console.log("---そして月日は流れ、二匹は成長した---") inu.growth(); kaeru.growth(); console.log(`犬の全長:${inu.length}cm,カエルの全長:${kaeru.length}cm`) console.log(`犬の足の数:${inu.foot}本,カエルの足の数:${kaeru.foot}本`)
コンパイルして実行する。
[kuzunoha@:01:26:25:~]$ tsc objects.ts [kuzunoha@:01:28:10:~]$ node objects.js 子犬の全長:30cm,オタマジャクシの全長:3cm 子犬の足の数:4本,オタマジャクシの足の数:0本 ---そして月日は流れ、二匹は成長した--- 犬の全長:90cm,カエルの全長:5cm 犬の足の数:4本,カエルの足の数:4本
このように犬クラスとカエルクラスは共通のメンバーとメソッドを持っているけど、中身がそれぞれで異なるといった場合はインターフェイスを使用する…であってるかな?
【Linux】Bashのバックグラウンドで実行する
こんばんは、葛の葉です。
さて、今回はLinuxでバックグラウンドモードで起動する方法をお伝えします。
flaskアプリを作る
以下のコードをapp.py
として作成する。
from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "Hello World!"
&を使う
例えばflask
アプリがあるとして、flask run
で通常通り実行すると以下のようになります。
[kuzunoha@:13:44:38:~]$ flask run * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
こうなるとキーを受け付けません。
flask run &
として実行をすればバックグラウンドで起動します。
[kuzunoha@:13:40:16:~]$ flask run & [1] 11422 [kuzunoha@:13:41:06:~]$ * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) ■ <- EnterKeyを押す [kuzunoha@:13:42:21:~]$
コマンドが返ってきているようですがよくわからないのでエンターキーを押してみましょう。PSが表示されどういうことかがわかりやすくなります。
バックグラウンドで動いているのでCurlで確認できます。
[kuzunoha@:13:45:45:~]$ curl http://127.0.0.1:5000/ 127.0.0.1 - - [19/Jul/2019 13:47:28] "GET / HTTP/1.1" 200 - Hello World![kuzunoha@:13:47:28:~]$
バックグラウンドで動いていたコマンドを元に戻す
fg
と打てばコマンドが戻ってきます。
[kuzunoha@:13:47:28:~]$fg flask run
flask run
のコマンドに戻ってきたのでCtrl + c
で停止します。
^C[kuzunoha@:13:49:29:~]$
起動中のバックグラウンドコマンドを見るには
jobs
コマンドを打ちます。
[kuzunoha@:13:49:29:~]$flask run & [1] 12423 [kuzunoha@:13:50:16:~]$jobs [1]+ 実行中 flask run &
また、バックグラウンドで起動しているコマンドを削除をするにはkill
を使います。kill %n
としてjobs
で表示された[n]を指定します(nはjob番号といいます)。
[kuzunoha@:13:50:18:~]$kill %1 [1]+ Terminated flask run [kuzunoha@:13:53:30:~]$jobs [kuzunoha@:13:53:39:~]$ <- jobに表示できるものがないため何も返されない
【TypeScript】mochaとchaiでユニットテストする
こんばんは、葛の葉です。
前回からTypeScriptを使っています。
今回はTypeScriptでUnittestを行いたいと思います。
フォルダ構成
├── src │ └── fizzbuzz.ts └── test └── fizzbuzz.test.ts
FizzBuzzをつくる
srcディレクトリ内でfizzbuzz.ts
という名前のプログラムを作成します。
export class Numbers { fizz: number = 3; buzz: number = 5; fizzbuzz: number = this.fizz * this.buzz; } export class FizzBuzz { public function: string; check(params: number) { if (params % 15 == 0) { return "FizzBuzz!"; } else if (params % 3 == 0) { return "Fizz!"; } else if (params % 5 == 0) { return "Buzz!"; } else { return params.toString() }; }; }
export class
とはモジュールとして他のJSから取得出来るようにするための記述?のようですね。まだこの辺りも含めて、JSとTSがよくわかっていないというのが現状です。モウシワケナイ。
tsc fizzbuzz.ts
として、コンパイルしましょう。
fizzbuzz.js
が出来上がります。
"use strict"; exports.__esModule = true; var Numbers = /** @class */ (function () { function Numbers() { this.fizz = 3; this.buzz = 5; this.fizzbuzz = this.fizz * this.buzz; } return Numbers; }()); exports.Numbers = Numbers; var FizzBuzz = /** @class */ (function () { function FizzBuzz() { } FizzBuzz.prototype.check = function (params) { if (params % 15 == 0) { return "FizzBuzz!"; } else if (params % 3 == 0) { return "Fizz!"; } else if (params % 5 == 0) { return "Buzz!"; } else { return params.toString(); } ; }; ; return FizzBuzz; }()); exports.FizzBuzz = FizzBuzz;
テストプログラムをつくる
npmでmocha
というライブラリとchai
というライブラリを入手します。この辺りもちょっとよくわからないので、間違ったインストール方法だったら申し訳ないです。
npm install mocha chai --save-dev
npm install @types/{mocha,chai} --save-dev
testディレクトリ内でfizzbuzz.test.ts
という名前のプログラムを作ります。
import * as chai from "chai" import { FizzBuzz } from "../src/fizzbuzz" import { Numbers } from "../src/fizzbuzz" describe("FizzBuzzのテスト", () => { it("check関数のテスト", () => { let fizzbuzz = new FizzBuzz(); let nums = new Numbers(); chai.assert.equal(fizzbuzz.check(nums.fizz), "Fizz!"); chai.assert.equal(fizzbuzz.check(nums.buzz), "Buzz!"); chai.assert.equal(fizzbuzz.check(nums.fizzbuzz), "FizzBuzz!"); chai.assert.equal(fizzbuzz.check(4), "4"); }) })
describe
やit
とはmocha
というテストフレームワークの記述になります。describeがテスト内容の大項目で、itが小項目に当たるといった感じでしょうか。
chai
は多種のアサーション機能を備えたライブラリのようです。
tsc fizzbuzz.test.ts
としてコンパイルします。
fizzbuzz.test.js
が出来上がります。
"use strict"; exports.__esModule = true; var chai = require("chai"); var fizzbuzz_1 = require("../src/fizzbuzz"); var fizzbuzz_2 = require("../src/fizzbuzz"); describe("FizzBuzzのテスト", function () { it("check関数のテスト", function () { var fizzbuzz = new fizzbuzz_1.FizzBuzz(); var nums = new fizzbuzz_2.Numbers(); chai.assert.equal(fizzbuzz.check(nums.fizz), "Fizz!"); chai.assert.equal(fizzbuzz.check(nums.buzz), "Buzz!"); chai.assert.equal(fizzbuzz.check(nums.fizzbuzz), "FizzBuzz!"); chai.assert.equal(fizzbuzz.check(4), "4"); }); });
ユニットテストを実施する
test
ディレクトリがカレントディレクトリなら以下のコマンドを打ちます。
mocha fizzbuzz.test.js
以下のようにログが出力されます。
[kuzunoha@:23:44:18:~]$mocha fizzbuzz.test.js FizzBuzzのテスト ✓ check関数のテスト 1 passing (7ms)
【TypeScript】列挙型をTypeScriptで使う
こんばんは、葛の葉です。
現在、TypeScriptを勉強しています。
Enumesをちょっとだけ勉強しました。
ディレクトリ構成
├── app │ └── enum.ts └── enum.html
enum.html
/*./app/enum.tsじゃないよ*/ <script src="./app/enum.js"></script>
TypeScriptを書く
app/enum.ts
をいじる。
enum Hoge { foo, bar, hoge, piyo, fuga } let tmp = Hoge.foo console.log(tmp)
tsc app/enum.ts
としてjsにビルドします。そうするとapp/enum.js
が出来上がります。
app/enum.js
var Hoge; (function (Hoge) { Hoge[Hoge["foo"] = 0] = "foo"; Hoge[Hoge["bar"] = 1] = "bar"; Hoge[Hoge["hoge"] = 2] = "hoge"; Hoge[Hoge["piyo"] = 3] = "piyo"; Hoge[Hoge["fuga"] = 4] = "fuga"; })(Hoge || (Hoge = {})); var tmp = Hoge.foo; console.log(tmp);
Chromeで表示してみる。
console.logの出力結果を見たいのでenum.html
をChromeで開き、F12
キーを押します。
Console
タブを開くと画像のような感じに出力されていると思います。
let tmp = Hoge.foo
のfoo
としたところが、数字0
に相当するからです。
let tmp = Hoge.bar
にすると1
と表示されます。
enum.tsをもう少しいじる。
TypeScriptといえば型宣言なのかなぁと思います。
tmp
という変数に代入できる値を数字だけにしてみましょう。
enum Hoge { foo, bar, hoge, piyo, fuga } /* :numberは数値のみ代入を受け入れるということ */ let tmp: number = Hoge.foo console.log(tmp)
これでもtsc enum.ts
によってbuildは通るのです。
enum
ってただの数字ですから。
また、TypeScriptにはオブジェクト型宣言というのが使えますのでこちらを使ってみます。
enum Hoge { foo, bar, hoge, piyo, fuga } /* :HogeはHogeというオブジェクトのみ受け付けるということ */ let tmp: Hoge = Hoge.foo console.log(tmp)
これでも通ります。
オブジェクト型宣言の方が用途がわかりやすい気がしますので、私はこっちを選びたいなぁと思いました。
ちなみに
let tmp: Hoge = Hoge.foo tmp = 5
としても
let tmp: number = Hoge.foo tmp = 5
としても
いずれもビルドは通りました。
ちょっとこんがらがってきたので、勉強を続けたいと思います。
【Flask】Configについて
とても参考になったサイト
https://qiita.com/nanakenashi/items/e272ff1aafb3889230bc
https://www.subarunari.com/entry/2018/03/17/いまさらながらFlaskについてまとめる_〜Configuration〜
http://flask.pocoo.org/docs/1.0/config/
https://damyanon.net/post/flask-series-configuration/
Configを使おうというお話。
あなたは何らかのデータベースサーバーやあるいはGoogleSpreadSheetsと連携してプログラムを書いていることでしょう。
書いている内容としてはこんな感じでしょうか。
gss_url = "http://google.****.com"
さて、本番と開発をわけた開発をするとした場合、このgss_url
の値をツドツド変更しているのかもしれません。あるいは、コメントアウトして使っているのかもしれません。
# 本番 # gss_url = 'http://google.****.com' # 開発 gss_url = 'http://test.google.****.com'
ただ、どちらかといえば本番時はhttp://google.****.com
、そうでないときはhttp://test.google.****.com
と条件分岐で指定してあげたいところです。
if HONBAN == True: gss_url = 'http://google.****.com' else: gss_url = 'http://test.google.****.com'
また、Flaskなら開発環境でDEBUG
モードで開発していると思います。本番でDEBUGモードが起きるのはセキュリティ的によくないでしょう。ただ、その複数の切り替えを手動で行っていると絶対忘れが発生して事故るでしょう。
app.run(debug=True) # app.run()
開発環境、本番環境によって変えたい項目は沢山あるはずです。もう一つテスト環境というものがあると思います。
テスト環境はテスト用のデータが挿入された環境であることが望ましいかも知れませんし、あるいはデータそのものが全くない環境が望ましいものかもしれません。
テスト環境1 テスト環境2 開発環境 本番環境
それぞれの状況でアクセスするDBのアドレスやGSSのアドレスが切り替わるような仕組みがあったら便利ですね。今回は環境変数を使って切り替わりを実施できるような仕組みを考えます。
Flaskのデバッグモードとconfigについて
Flaskクラスのインスタンスにはconfig
というものがあります。configはdictionaryとなっています。
app.py
として以下を作成します。
from flask import Flask app = Flask(__name__) print(app.config)
python app.py
として起動すると以下のようになります。
[kuzunoha@:11:09:05:~/sand_box/flaskconfig]$python app.py <Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>
また、app.pyの3行目を更新してprint(app.config['DEBUG'])
として実行します。
app.py
from flask import Flask app = Flask(__name__) print(app.config['DEBUG'])
実行結果
[kuzunoha@:11:09:10:~/sand_box/flaskconfig]$python app.py False
次にapp.debug = True
を追記してprintしてみます。
from flask import Flask app = Flask(__name__) app.debug = True print(app.config['DEBUG'])
これを実行すると
[kuzunoha@:11:14:58:~/sand_box/flaskconfig]$python app.py True
それではapp.config['Debug'] = Falseと追記してからprintしてみます。
from flask import Flask app = Flask(__name__) app.debug = True app.config['DEBUG'] = False print(app.config['DEBUG'])
これを実行すると
[kuzunoha@:11:17:35:~/sand_box/flaskconfig]$python app.py False
すなわち以下の2つは同義であるということです。
app.debug = Boolean app.config['DEBUG'] = Boolean
また、app.run(debug=True)
で設定するDebugの真偽も同様です。
その他にも環境変数を使用するなどflaskをデバッグモードで実施する方法はあるようです。
参考:http://flask.pocoo.org/docs/1.0/quickstart/#debug-mode
このようにconfig[PARAMETAR]
を変更することで、Flaskアプリケーションのコンフィグを変更できます。
その他のデフォルトのパラメータは公式に載っています。
参考:http://flask.pocoo.org/docs/0.12/config/#builtin-configuration-values
オリジナルのパラメータを作る
flaskのコンフィグパラメータは好きに作ることが出来ます。app.pyを以下のように記載します。
from flask import Flask app = Flask(__name__) app.config['hogehoge'] = 'piyopiyo' print(app.config['hogehoge'])
そして実行すると
[kuzunoha@:11:19:08:~/sand_box/flaskconfig]$python app.py piyopiyo
となります。そして、これはすなわち以下のようにも使えます。
from flask import Flask app = Flask(__name__) app.config['MYSQL_ADDRESS'] = '127.0.0.1' print(app.config['MYSQL_ADDRESS'])
実行すると
[kuzunoha@:11:34:35:~/sand_box/flaskconfig]$python app.py 127.0.0.1
となります。ただ、以下のようにインスタンスとして持ち合わせることは出来ません。
from flask import Flask app = Flask(__name__) app.config['MYSQL_ADDRESS'] = '127.0.0.1' print(app.config.mysql_address) Traceback (most recent call last): File "app.py", line 4, in <module> print(app.config.mysql_address) AttributeError: 'Config' object has no attribute 'mysql_address'
さて、それではその他にもパラメータを追加してMySQLに繋げてみましょう。以下が一例になります。(ほんとにただの一例ですのでこれで実行しても何も起きないです。)
from flask import Flask app = Flask(__name__) app.config['MYSQL_ADDRESS'] = '127.0.0.1' app.config['MYSQL_USER'] = 'root' app.config['MYSQL_PASSWORD'] = 'password' app.config['MYSQL_PORT'] = 3306 app.config['MYSQL_DATABASE'] = 'hogepiyodb' import MySQLdb connection = MySQLdb.connect( host=app.config['MYSQL_ADDRESS'], user=app.config['MYSQL_USER'], passwd=app.config['MYSQL_PASSWORD'], port=app.config['MYSQL_PORT'], db=app.config['MYSQL_DATABASE']) connection.commit() connection.close()
MySQLdb
というモジュールについては以下の参考サイトを見てください。
app.config['MYSQL_ADDRESS'] = '127.0.0.1' app.config['MYSQL_USER'] = 'root' app.config['MYSQL_PASSWORD'] = 'password' app.config['MYSQL_PORT'] = 3306 app.config['MYSQL_DATABASE'] = 'hogepiyodb'
と、このようにパラメータに値を代入していくことが出来るのです。
パラメータの代入方法の選択
Configのパラメータには直接値を代入する方法以外にも方法があります。
参考:https://www.subarunari.com/entry/2018/03/17/いまさらながらFlaskについてまとめる_〜Configuration〜
以下がそれぞれ同じ設定方法になります。ここに記載してる方法以外のものもあります。
ハードコーディング(参考)
上記に書いたものと同じですね。
app.py
from flask import Flask app = Flask(__name__) app.config['DEBUG'] = True app.config['MYSQL_ADDRESS'] = '127.0.0.1' app.config['MYSQL_USER'] = 'root' app.config['MYSQL_PASSWORD'] = 'password' app.config['MYSQL_PORT'] = 3306 app.config['MYSQL_DATABASE'] = 'hogepiyodb' print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
結果は以下の感じ
[kuzunoha@:12:14:56:~/sand_box/flaskconfig]$python app.py True 127.0.0.1 root password 3306 hogepiyodb
from_pyfile
cfgファイルを読み込むタイプです。app.pyと同じディレクトリにdevelopment.cfg
というcfgファイルを作って、それを読み込むようにします。
development.cfg
DEBUG=True MYSQL_ADDRESS='127.0.0.1' MYSQL_USER='root' MYSQL_PASSWORD='password' MYSQL_PORT=3306 MYSQL_DATABASE='hogepiyodb'
app.py
from flask import Flask app = Flask(__name__) app.config.from_pyfile('development.cfg') print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
app.py
の3行目app.config.from_pyfile('development.cfg')
に注目です。
app.config.from_pyfile(CFGファイル名)となっております。
実行結果は以下の通り
[kuzunoha@:12:29:10:~/sand_box/flaskconfig]$python app.py True 127.0.0.1 root password 3306 hogepiyodb
from_object
設定のクラスが書かれたPythonファイルを読み込むようにします。
setting.py
class Development(object): DEBUG=True MYSQL_ADDRESS='127.0.0.1' MYSQL_USER='root' MYSQL_PASSWORD='password' MYSQL_PORT=3306 MYSQL_DATABASE='hogepiyodb'
app.py
from flask import Flask app = Flask(__name__) app.config.from_object('setting.Development') print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
実行結果は以下の通り
[kuzunoha@:12:37:18:~/sand_box/flaskconfig]$python app.py True 127.0.0.1 root password 3306 hogepiyodb
app.py
の3行目app.config.from_object('setting.Development')
に注目です。
app.config.from_object('Pythonファイル名.オブジェクト名')となっていることがわかると思います。
オブジェクトを取得するようになっているので、setting.pyに新しいクラスを作って読み込ませることも出来ます。クラスなので継承を使って新しいクラスを作っても良いです。
setting.py
class Development(object): DEBUG=True MYSQL_ADDRESS='127.0.0.1' MYSQL_USER='root' MYSQL_PASSWORD='password' MYSQL_PORT=3306 MYSQL_DATABASE='hogepiyodb' class Production(Development): DEBUG=False MYSQL_ADDRESS='63.31.125.212'
app.py
from flask import Flask app = Flask(__name__) app.config.from_object('setting.Production') print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
実行結果はこうなりました
[kuzunoha@:12:54:12:~/sand_box/flaskconfig]$python app.py False 63.31.125.212 root password 3306 hogepiyodb
DEBUG
とMYSQL_ADDRESS
の値が変更されていることと、それ以外は継承元のそれと同じであるというところが注目点です。
from_pyfile + from_object
ではこの2つを合体して使ってみるとどうでしょうか
password.cfg
MYSQL_PASSWORD='heavensdoor'
setting.py
class Development(object): DEBUG=True MYSQL_ADDRESS='127.0.0.1' MYSQL_USER='root' MYSQL_PASSWORD='password' MYSQL_PORT=3306 MYSQL_DATABASE='hogepiyodb' class Production(Development): DEBUG=False MYSQL_ADDRESS='63.31.125.212'
app.py
from flask import Flask app = Flask(__name__) app.config.from_object('setting.Production') app.config.from_pyfile('password.cfg') print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
実行結果は以下の通りです。
[kuzunoha@:13:10:48:~/sand_box/flaskconfig]$python app.py False 63.31.125.212 root heavensdoor 3306 hogepiyodb
最終的なMYSQL_PASSWORD
はheavensdoor
になりました。app.py
の3-4行目を見てみてください。
app.config.from_object('setting.Production') app.config.from_pyfile('password.cfg')
変数のそれと同じく、最後に宣言された値に上書きされていくからです。
環境変数を使ってそれぞれの環境にConfを変える
from_objectで読み込むクラスを変更すれば各環境ごとに使うconfigを変更できます。
# 開発なら app.config.from_object('setting.Development') # 本番なら app.config.from_object('setting.Production')
辞書型を使うともう少しスマートになります。
dict_confmode = { 'dev' : 'setting.Development', 'pro' : 'setting.Production' } # 開発なら confmode = dict_confmode['dev'] # 本番なら confmode = dict_confmode['pro'] app.config.from_object(confmode)
さらに環境変数を使います。例えばFLASK_CONFIGURATION
という環境変数名に開発ならdev
、本番ならpro
と入れておきます。
---開発環境なら---
環境変数
FLASK_CONFIGURATION=dev
app.py
の一部
import os dict_confmode = { 'dev' : 'setting.Development', 'pro' : 'setting.Production' } env_confmode = os.getenv('FLASK_CONFIGURATION') confmode = dict_confmode[env_confmode] app.config.from_object(confmode)
---本番環境なら---
環境変数
FLASK_CONFIGURATION=pro
app.py
の一部
import os dict_confmode = { 'dev' : 'setting.Development', 'pro' : 'setting.Production' } env_confmode = os.getenv('FLASK_CONFIGURATION') confmode = dict_confmode[env_confmode] app.config.from_object(confmode)
それぞれのapp.pyには全く違いはありません。この通り、PCに宣言した環境変数だけで環境を変更できるようになりました。
参考:https://wa3.i-3-i.info/word11027.html
共有することがあまりよろしくない値はfrom_pyfileへ
DBのpasswordや暗号方法、暗号キーやアクセストークンなどはcfg
ファイルへ記載するようにします。
そうしてinstance
ディレクトリを作ってそのcfg
ファイルを置いておくようにします。
アプリケーションを初期化する際にinstance_relative_config=True
という引数を当ててあげます。そうすることでinstance
というディレクトリからcfg
ファイルを読みに行くようになります。
app = Flask(__name__, instance_relative_config=True)
そうして、.gitignore
にinstance
を入れてあげます。
最終的な構成はこのようになりました。
app.py setting.py instance/ ┗ password.cfg
password.cfg
MYSQL_PASSWORD='heavensdoor'
setting.py
class Development(object): DEBUG=True MYSQL_ADDRESS='127.0.0.1' MYSQL_USER='root' MYSQL_PASSWORD='password' MYSQL_PORT=3306 MYSQL_DATABASE='hogepiyodb' class Production(Development): DEBUG = False MYSQL_ADDRESS='63.31.125.212'
app.py
import os from flask import Flask app = Flask(__name__, instance_relative_config=True) dict_confmode = { 'dev' : 'setting.Development', 'pro' : 'setting.Production' } env_confmode = os.getenv('FLASK_CONFIGURATION') confmode = dict_confmode[env_confmode] app.config.from_object(confmode) app.config.from_pyfile('password.cfg') print(app.config['DEBUG']) print(app.config['MYSQL_ADDRESS']) print(app.config['MYSQL_USER']) print(app.config['MYSQL_PASSWORD']) print(app.config['MYSQL_PORT']) print(app.config['MYSQL_DATABASE'])
実行結果
[kuzunoha@:14:38:21:~/sand_box/flaskconfig]$export FLASK_CONFIGURATION=dev [kuzunoha@:14:38:30:~/sand_box/flaskconfig]$python app.py True 127.0.0.1 root heavensdoor 3306 hogepiyodb [kuzunoha@:14:38:32:~/sand_box/flaskconfig]$export FLASK_CONFIGURATION=pro [kuzunoha@:14:38:43:~/sand_box/flaskconfig]$python app.py False 63.31.125.212 root heavensdoor 3306 hogepiyodb
参考 Windowsの環境変数設定:https://www.k-cube.co.jp/wakaba/server/environ.html
参考 Unix,Linux,Macの環境変数設定:https://qiita.com/iam1at/items/91cb8478160c9fbee134
残りはベストプラクティスを見てみてください。
細かいところは違いますが、以下のURLの内容がよくわかるようになったと思います。後はここを読んでください。
【Docker】コマンド以降をEchoするDockerfileの作成 - ENTRYPOINT
こんにちは、葛の葉です。
Dockerに出てくるENTRYPOINTについて調べていました。
今回はdocker run [IMAGE_ID] ***
の***
をエコーするDockerImageを作成したいと思います。
大変参考になったサイト
Dockerfile
FROM alpine:3.9.4 ENTRYPOINT ["echo"] CMD ["Hello World!"]
今回はecho
という名前でDockerImageにbuild
しておきます。
実行してみる。
docker run --rm -it echo
とすると
Hello World!
と返ってきます。
[kuzunoha@:18:17:53:~]$docker run -it --rm echo Hello World!
docker run --rm -it echo FOX
とすると
FOX
と返ってきます。
[kuzunoha@:18:18:39:~]$docker run -it --rm echo FOX FOX
ENTRYPOINT(echo)
がコマンドでCMD(Hello World)
がデフォルト引数といったような感じになりました。
シェルを起動したいなぁ
しかしこのままでは以下のようなコマンドではシェルを起動できません。docker run -it --rm echo /bin/sh
では/bin/sh
という値が返ってきます。
[kuzunoha@:18:22:53:~]$docker run -it --rm echo /bin/sh /bin/sh
そのため、entrypoint
を上書きしてあげる必要があります。
docker run -it --rm --entrypoint=/bin/sh echo
とすればシェルが起動します。
[kuzunoha@:18:27:45:~]$docker run -it --rm --entrypoint=/bin/sh echo / #
【DockerCompose】DockerfileのFROMに使える変数の設定
こんばんは、葛の葉です。
DockerfileでFROM
に対する変数を入れることで、色々使いまわせます。
DockerComposeのargs
を使えばこんなこともできます。
ファイル構成
. ├── Dockerfile └── docker-compose.yml
Dockerfile
ARG Ver FROM python:$Ver
docker-compose.yml
version: '3' services: test_app: build: context: ./ args: Ver: "3.7.3" command: python --version
upしてみる。
Creating network "teste_default" with the default driver Creating teste_test_app_1 ... done Attaching to teste_test_app_1 test_app_1 | Python 3.7.3 teste_test_app_1 exited with code 0
もう一つServiceを追加して実行する。
docker-compose.yml
version: '3' services: test_app: build: context: ./ args: Ver: "3.7.3" command: python --version test_app2: build: context: ./ args: Ver: "3.6.5" command: python --version
docker-compose up
としてみる。
Starting teste_test_app_1 ... done Creating teste_test_app2_1 ... done Attaching to teste_test_app_1, teste_test_app2_1 test_app_1 | Python 3.7.3 test_app2_1 | Python 3.6.5 teste_test_app_1 exited with code 0 teste_test_app2_1 exited with code 0
結論
ひとつのDockerfileを使いまわして複数のServiceを起動できる。