ProgramingLake

ナレッジ置き場

(コマンド)Docker

Dockerfile における「ENTRYPOINT」は必ず実行
Dockerfile内にこのように書かれていたら、
ENTRYPOINT ["python3.6"]
docker runコマンドで、こうすればコンテナ起動と同時に実行される
(※batchはイメージ名)
docker run -it --rm --network localnet \
-e ENVIROMENT_NAME=localhost \
batch function_xxxx.py
空き容量確保
docker system prune -f
コンテナ全停止
docker stop $(docker ps -q)
コンテナ全削除
docker container prune
volume
docker volumeを確認
docker volume ls
 

volumeの実態を確認
docker volume inspect mongo-express_mongodb-data

但し、そのpathはMac上には存在しない
"Docker for MacのDocker EngineはVM(Virtual Machine)の上で動いているので、MountpointはローカルのMacのPATHじゃなくて、VM上のPATH"

これでVMに入れる(この中にvolumeの実態が入っている)
docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh

詳しくはこちら
https://note.com/w0o0ps/n/n9bc1bcd9fa59

 依存関係のあるイメージファイルを検索
for i in $(docker images -q)
do
docker history $i | grep -q "container_id" && echo $i
done | sort -u
 
(/dev/sda1 の中がいっぱいの時は効果覿面)
activeでないvolumesを確認する
docker system df
dangling volumeのリストを確認
docker volume ls -q -f dangling=true
参照されてないvolumesを削除
docker volume rm `docker volume ls -q -f dangling=true`
不要な(none)imageを削除(対象確認)
docker images -f "dangling=true"
不要な(none)imageを削除(一括削除)
docker rmi $(docker images -f "dangling=true" -q)
docker logの出力先確認
docker inspect container_id | grep -i log
ログファイルの中身をクリア(例)
sudo truncate /var/lib/docker/containers/.../[log_file_name.log] --size 0
 その他コマンド
毎回コンテナIDを確認せずにコンテナに入る
docker exec -it $(docker ps -aq -f name=mongodb) bash
 
コンテナ名にsalesが含まれるコンテナを停止
docker stop $(docker ps -aq -f name=sales)
 
コンテナ名にsalesが含まれるコンテナを開始
docker start $(docker ps -aq -f name=sales)
 
コンテナ名にsalesが含まれるコンテナを削除
docker rm $(docker ps -aq -f name=sales)
 
Dockerfileをbuildしていると、<none>が残る
確認
docker images | grep none
 
<none>の正体とは?
同じ名前のイメージを作り直すと出来上がる。
Dockerでは異なるイメージに同じイメージ名を付けられないので、
古いほうのイメージはイメージ名が取り除かれて<none>:<none>になる。
 
<none>のイメージを一括削除
docker images | grep none | awk '{print $3}' | xargs docker rmi
 
発生しうるエラー
JavaScript heap out of memory
これをやってからもう一度docker-compose upで通った
export NODE_OPTIONS=--max_old_space_size=4096
 
イメージファイル 全削除
docker rmi $(docker images -a -aq)

(ナレッジ)Lambda

Lambda関数のライフサイクル
- ENIの作成
- コンテナの作成
- デプロイパッケージのロード
- デプロイパッケージの展開
- ランタイム起動・初期化
- 関数/メソッドの実行
- コンテナの破棄
 
(注意点)
タイムアウトはデフォルトで3秒(MAXで15分)
・Lambda関数を作成する前にロールを作っておくと良い。
 S3を操作する関数なら、LambdaベースでS3のフルアクセスをアタッチする。
・zipファイルはS3にアップロード、Lambdaにアップロード or
 ローカルからLambdaにアップロードの2通り。
デプロイパッケージサイズは直接アップロードであれば50MBが上限。
・圧縮時はzipコマンドのオプションに圧縮度が高い「-9」「-r9」を指定するのが望ましい。
・Lambda関数実行時に渡されたJSONはdictに変換される。
・Lambdaのレスポンスの文字エンコーディングを変える方法は無い
・Lambda異常終了時でも、異常終了させずに正常終了させるか。(SQSが無駄にリトライしないように)
API Gateway + Lambdaという組み合わせだと、API Gatewayの制限が最大で30秒なので、29秒でタイムアウトする。
 (29秒以内にLambda関数から値を返却する必要あり)
 上記タイムアウトに引っ掛かり、処理の分割・並列化が難しい場合はAmazon EC2で実装するなどの対応が考えられる。
・Lambdaのテンポラリディレクトリの上限は512MB
 これが枯渇するとエラーが発生する。関数の中でファイルの解凍などをやりたい場合は要注意。
 前回の処理で保存したファイルが残った状態のまま次の処理で再利用されるケースがあるので、
 「Lambdaは毎回使い切り」ではないということを認識すべき。
・メモリを指定できる。128MB〜。1msあたりに課金。
・lambdaファンクションを作成する際は、裏でRoleの作成、Policyの作成、Policyのアタッチが動くのでこの辺りの権限がないとエラーになる。
 ・lambdaの実行用ロールにアタッチされているポリシーの中でSQSメッセージのレシーブ許可をしないと、SQSでキューが作成出来ない。
 
Dynamoとの組み合わせでLambdaの冪等性を担保
 
Lambdaファンクションの関数一覧
関数名でソート
aws lambda list-functions --query "sort_by(Functions,&FunctionName).[FunctionName,Handler,Timeout,Runtime,MemorySize,Role]" --output table --profile any
(--output tableオプションによりテーブル形式に整形して表示)
aws lambda list-functions --query "sort_by(Functions,&FunctionName).{FunctionName:FunctionName,Handler:Handler,Timeout:Timeout,Runtime:Runtime,Memory:MemorySize,Role:Role}" --output table --profile any
(""ではなく"{}"で囲むとカラム名が指定できる)
 
空のlambda
(lambda_function.py)
import json
 
def lambda_handler(event, context):
print("event: " + json.dumps(event))
return 0
 
lambdaの起動元
Amazon EventBridge
ルールにて、ターゲットに「Lambda関数」を指定すればよい。
起動スケジュールはcron式で。
 
・SQS
(lambda関数に紐づいたSQSにJsonメッセージを送る)
下記コマンドで指定したlambdaファンクションのキック元が分かる
aws lambda list-event-source-mappings --function-name {メソッド名} --profile it
(lambdaファンクションのキック元がSQSの場合、SQSのARNが表示される。)
 
・StepFunction
など
 
ローカルでlambda実行
aws lambda invoke
aws lambda invoke --function-name fc-0001 --payload file://fc_0001_request_1.json fc_0001_response_1.json --profile any
(リクエストデータはUTF-8で保存すること。引数のjsonファイル2つ目はレスポンスファイル)
lambda関数のレスポンスに日本語文字が含まれていた場合、文字化けすることがある。
aws sqs send-message
$ aws sqs send-message \
--message-body file://request_message.json
 
エラーログ+スタックトレース出す場合
(pythonコード)
except Exception as err:
logger.error(strMessage, [err]))
import traceback
traceback.print_exc()
 
その他
Lambda関数の意図しない同時実行を回避するには
対策としては、DynamoDBにトリガーとなったイベントを保存。
そして、重複起動が発生した場合はDynamoDBに保存されているイベントを確認して後続処理を動かさない。
CloudWatchLogをLambdaに送る
実現方法
CloudWatch Logs サブスクリプションのフィルターを作成すると、ログデータを AWS Lambda 関数に送信出来る。
 
CloudWatch > Log groups > サブスクリプションのフィルター(タブ)
(ここで、destination ARN(destination=行先)でlambdaファンクションのARNを指定する)
 
CloudWatchのログで特定の文字列が出たらLambdaを起動させる
CloudWatch Logs のサブスクリプションフィルタを使って特定文字列を検知したログをEメール通知する
 

Git

ブランチ名指定でclone

git clone -b develop https://github.com/xxxxxxxxxxxxxxxxxxxxxxxxxx.git

GitHubパスワード認証廃止 GitHubは過去1年間使用されていない個人アクセストークンを自動的に削除 使用例

$ git clone https://github.com/username/repository.git
Cloning into 'repository'...
Username for 'https://github.com': username
Password for 'https://username@github.com': ここで取得した個人アクセストークンを入力する

※個人アクセストークンは HTTPS Git 操作だけにしか使用できない。

直前のコミットメッセージを変更したい時 "amend"=「修正する、改める」という意味。直前のコミットを修正する。 但し、pushする前のコミットを修正したい時だけ。

間違えたコミット

git commit -m "誤字を含むコミット"

訂正

git commit --amend -m "修正されたコミット"

過去のコミット直前時点に巻き戻す 「まだ作業をしようと思っていたのに間違えてコミットしてしまった」 「2つのファイルをまとめてコミットするべきだったのに、間違えて1つしかコミットしていなかった」 (コミットする直前のステージング状態に戻れる)

git reset --soft HEAD^
HEAD^

(=1つ前のコミット。2つ前は^^。) コミットIDを指定して戻ることもできる

取り消し
git merge

「マージしたらコンフリクトした。やっぱりやめよう。」 マージしたらコンフリクトした、コンフリクトするとは思わなかった、いったんやめよう、などといういう時。 (コンフリクトの編集をしていないときに限る)

git merge --abort

「マージしたらコンフリクトした。コンフリクトを解消しようといろいろ編集した。でもやっぱりやめよう。」 コンフリクト解消のためにコードをいろいろ編集したけどやっぱりマージやめよう、という時。 (編集した内容もマージもすべて取り消される)

git reset --hard HEAD
pull

https://dev.classmethod.jp/articles/how-to-checkout-remote-branch/
例えば、git pull origin master と打った 変な風になった... (本当ならgit pullだけで良かった...)

git reflog
git reset --hard HEAD@{1}

git revertは指定したコミットの内容を打ち消して、新しいコミットを作成する。(ポインタを前に進める) git resetは指定したコミットを削除する。(ポインタを過去に戻す)  

その他

ファイルのリネーム

git mv
例:git mv search.html Search.html

これをやらないと、git で差分として認識されない。

コミットID確認

git log |grep '^commit' |head -1|awk '{print $2}'

現在のブランチを確認

git branch --contains

ローカルブランチ一覧

git branch

ローカルでマージ
マージしたいブランチに移動

git checkout stg
git pull origin stg

マージさせたいブランチに移動

git checkout master
git pull origin master
git merge --no-ff stg ←3ウェイマージ(意図的にfast-forwardを行わないコミットをすることが出来る)
git push origin master

PRに含まれているファイル名取得(devツールのconsoleで取得)

[...document.querySelectorAll('.file-info a')].map(x => x.title)

(イディオム)Python

python仮想環境作成(venv)

https://qiita.com/sychocola1/items/93c4e043e4c8dbc60cad


新しい環境の作成
$ cd [project dir]
$ python3 -m venv [newenvname]

 

Activate
(Mac)
$ source [newenvname]/bin/activate

(Windows)
$ .\[newenvname]\Scripts\activate

 

Deactivate
([newenvname])$ deactivate

 
可変長引数
引数の数が決まっていない引数。汎用的なメソッドを作成したい場合に登場する。
*args (*1個。タプルで受け取る。)
**kwargs (*2個。辞書で受け取る。)
 
String型をlistに
input = "[1,2,3]"を
input = [1,2,3]に変えたい
 
import ast
def string_to_list(string):
return ast.literal_eval(string)
 
冒頭のuやr
r"文字列" ... raw文字列 / raw string literal
u"文字列" ... unicode文字列 / unicode string literal
 
プログラムの中に突然現れる数字
悪い例 : return $price * 0.08;
良い例:return $price * TAX_RATE;
 
PEP8
・ファイル名
ファイル名は英小文字の短い名前
読みやすさのためにアンダースコアで単語を区切ってもよい
(例)s3_read.py
 
・クラス名
最初大文字 + 大文字区切り
(例)MyFavoriteClass
 
・メソッド名
全小文字 + アンダースコア区切り
 
boto3の認証情報
優先順位順が高い順
>>> import boto3
>>> client = boto3.client('iam', aws_access_key_id='YOURACCESSKEY', aws_secret_access_key='YOURSECRETKEY')
>>> client.list_users()
 
>>> import boto3
>>> session = boto3.session.Session(aws_access_key_id='YOURACCESSKEY', aws_secret_access_key='YOURSECRETKEY')
>>> client = session.client('iam')
>>> client.list_users()
 
プロファイル指定
>>> import boto3
>>> session = boto3.session.Session(profile_name='YOURPROFILENAME')
>>> client = session.client('iam')
>>> client.list_users()
 
$ export AWS_ACCESS_KEY_ID=YOURACCESSKEY
$ export AWS_SECRET_ACCESS_KEY=YOURSECRETKEY
$ python3
Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import boto3
>>> client = boto3.client('iam')
>>> client.list_users()
 
ここまでの認証情報がない場合、認証情報ファイル(~/.aws/credentials)内に default プロファイルとして構成されている認証情報が使われる。
(aws configure コマンドで設定)
 
ここまでの認証情報がない場合、AWS設定ファイル(~/.aws/config)内に default プロファイルとして構成されている認証情報が使われる。
 
 
現在の日付取得
datetime.datetime.strftime(current_datetime(), '%Y%m%d%H%M%S')
 
抽象(基底)クラス
別名:abstract base class: ABC
抽象基底クラスを実装するための標準ライブラリとして、abcモジュールが提供されている。abstract=抽象。
抽象クラスでは、メソッドのインターフェースのみ規定し、その実装はサブクラス(子クラス)に任せる。
 
特徴
・抽象クラスをインスタンス化しようとするとエラー。インスタンス化は子クラスでやる必要あり。
例:u = Users()
・専ら他のクラスに継承されることによって使用される。
 
(実装例)
from abc import ABCMeta
from abc import abstractmethod
 
#抽象クラスvehicleの定義(抽象基底クラス、親クラス、とも。継承元としてのみ存在するクラス。)
class vehicle(metaclass = ABCMeta):
#@abstractmethodデコレーターを使用(中身は空)
@abstractmethod
def start(self):
pass
@abstractmethod
def stop(self):
pass
 
#vehicleを継承したクラスcarの定義
class car(vehicle):
def start(self):
print("car start.")
def stop(self):
print("car stop")
 
#vehicleを継承したクラスmotorcycleの定義
class motorcycle(vehicle):
def start(self):
print("moto start.")
def stop(self):
print("moto stop")
 
#テスト部
if __name__ == "__main__":
mycar = car()
mycar.start()
mycar.stop()
 
JSON出力
辞書をjson出力
import json
dict = {"name": "太郎", "age": 23, "gender": "男"}
enc = json.dumps(dict, indent=2, ensure_ascii=False)
(ensure_ascii=False 指定しないと、日本語が文字化けする。)
 
基底クラス
継承元となるクラス。スーパークラス、親クラスとも呼ばれる。
 
テストメソッド
setUpメソッドは、各テストメソッドが呼び出される前に実行。
逆に、tearDownメソッドでは、各テストメソッドの終了後に実行されるメソッド。
 
オブジェクトのメモリ使用量を確認(単位:バイト)
import sys
print(sys.getsizeof("aaaaa"))
 
辞書を使用していて、存在しないキーにアクセスしようとすると、エラー
回避方法:defaultdictを使用する
from collections import defaultdict
 
my_dictonary = defaultdict(str)
my_dictonary['name'] = "Name"
my_dictonary['surname'] = "Surname"
 
print(my_dictonary["age"])
 
環境変数設定/取得
os.environ['AAAAAAAAAAA'] = 'aaa'
os.environ.get('AAAAAAAAAAA')
 
ディレクトリ操作(Windows用? Linuxは「HOMEDIR」ではなく、おそらく「PATH」)
# このファイルの一つ上のディレクトリをホームディレクトリってことにする
os.chdir(f'{os.path.dirname(__file__)}/../')
HOMEDIR = os.getcwd()
os.environ['HOMEDIR'] = HOMEDIR
 
# テスト実行用にカレントディレクトリをsrc配下に移動する
os.chdir(f'{HOMEDIR}/src')
 
# テスト実行用にsys,pathを通す
sys.path.append(f"{HOMEDIR}/src") # nopep8 # テスト実行時にsrc側にパスを通す
sys.path.append(f"{HOMEDIR}/tests") # nopep8 # テスト実行時にtests側にパスを通す
 
S3操作
from boto3_type_annotations.s3 import Client as s3Client
from botocore.config import Config
import boto3
 
session = boto3.session.Session(profile_name='localstack')
s3client: s3Client = session.client('s3', endpoint_url=localstack_url, config=Config(signature_version='s3v4'))
 
 
def count_s3_keys(bucket: str, prefix: str):
"""
キーが指定したプレフィクスであるオブジェクトの件数を取得する
"""
keys =
res = s3client.list_objects_v2(
Prefix=prefix
)
if res and res.get('Contents'):
keys = [content.get("Key") for content in res.get("Contents")]
 
return len(keys)
 
 
def get_s3_keys(bucket: str, prefix: str):
"""
キーが指定したプレフィクスであるオブジェクトを取得する
"""
keys = []
res = s3client.list_objects_v2(
Prefix=prefix
)
if res and res.get('Contents'):
keys = [content.get("Key") for content in res.get("Contents")]
 
return keys
 
辞書のループ
test = {'apple': 'red', 'remon': 'yellow'}
 
for key,value in test.items():
print('key:', key, 'value:', value, ',', end=' ')
 
データクラス(3.7〜)
データ保持用のクラス
 
(通常)
class Hoge:
def __init__(self, x=0, y=0, name=""):
self.x = x
self.y = y
self.name = name
 
(データクラス使用)
@dataclass
class Hoge2:
x: int = 0
y: int = 0
name: str = ""
 
使い方は一緒
hoge2 = Hoge2()
 
メリット
クラス定義を短くかける
 
データの集合とその読み書き手段のみからなるシンプルなオブジェクトで、
そのデータを利用して行われる具体的な処理(ビジネスロジックなど)は含まない。
 
zip
複数のイテラブルオブジェクト(リストやタプルなど)の要素をまとめる関数
 
names = ['Alice', 'Bob', 'Charlie']
ages = [24, 50, 18]
 
for name, age in zip(names, ages):
print(name, age)
# Alice 24
# Bob 50
# Charlie 18
 
map
仕様
配列のすべての要素にアクセスし、関数を適応させる。
 
使い方
list(map(関数, 配列)
 
i = '1 2 3'
print(list(map(int, i.split(' '))))
# [1, 2, 3]
print([int(x) for x in i.split(' ')])
# [1, 2, 3]
 
getattr
#   <用途>
#  様々な処理のリクエスト(クラス内で定義されていないもの)をすべていったんひとつのオブジェクトに集めて、
# そのオブジェクトから実際の処理を他の処理に委託する際に使用。こういった仕組みはdelegationデリゲーションという。
 
class MyCls(object):
def __init__(self):
self.x="x_value"
 
def __getattr__(self,name):
print("__getattribute__:name=",name,"は定義されてないよ")
return "undefine_value"
 
my_inst=MyCls()
# 定義されている
print(my_inst.x)
# 定義されていない
print(my_inst.y)
 
デコレータ
# 既存関数の中身を書き換えずに装飾する為の仕組み
# 呼び出される既存関数もデコレートされる前提で作成されている必要がある?
# ここで言う既存関数とはwrapperのこと
 
def decodeco(func):
def wrapper(*args,**kwargs):
print('======start=======')
func(*args,**kwargs)
print('======end=======')
return wrapper
 
# 次の行の関数(test())をデコレートしますよ
@decodeco
def test():
print('Hello Decporator')
 
test()
 
2進数作成
#15桁くらいが限界
FLG_CNT = 3
 
# 2のFLG_CNT乗
i = (2**FLG_CNT)
#10進数
print(i)
 
#10進数->2進数
i2 =int(format(i, 'b'))
 
lst = [format(l, 'b').zfill(FLG_CNT) for l in range(1,i)]
lst
 
指定箇所だけ置換
a='1234567890ABCDEFGHIJKLMN'
 
i = 5
 
print(a[0:i],'@',a[i:len(a)].lower())
 
pendulum
import pendulum
_date = pendulum.datetime(2020,7,3,13)
 
ISODate
import pendulum
import datetime
 
def convert_to_ISODate(dt:str) -> datetime:
 
dt_p = pendulum.parse(dt)
dt_ymd = dt_p.strftime('%Y-%m-%d')
dt_hm = dt_p.strftime('%H:%M:%S')
iso_date = datetime.datetime.strptime(f"{dt_ymd}T{dt_hm}Z", "%Y-%m-%dT%H:%M:%SZ") - datetime.timedelta(hours=9)
 
return iso_date
 
os.chdir(f'{os.path.dirname(__file__)}/../')
 
辞書一括置換
dct = [{'title':'報道1','onair_time_begin':'2020-06-25 19:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'1,2,3'},
{'title':'報道2','onair_time_begin':'2020-06-25 20:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'4,5,6'},
{'title':'報道3','onair_time_begin':'2020-06-25 21:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'7,8,9'},
{'title':'報道4','onair_time_begin':'2020-06-25 22:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'10,11,12'},
{'title':'報道5','onair_time_begin':'2020-06-25 23:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'13,14,15'},
{'title':'報道6','onair_time_begin':'2020-06-26 00:00:00+00','onair_time_end':'2020-06-25 19:30:00+00','plan_id':'16,17,18'}
]
 
a = [(d['title'].replace('報道','AAA')) for d in dct]
print(a)
 
時間丸め
import numpy as np
import pendulum
 
start_time = '2020-01-02 02:25:00'
 
# 分単位丸めロジック
# 数字の部分は丸めたい分数を指定
dt = pendulum.parse(start_time)
print(dt.weekday())
dt = dt.subtract(minutes=(dt.minute - int(np.floor(dt.minute / 10) * 10))).strftime('%H%M')
print(dt)
 
# 数字の部分は丸めたい分数を指定
dt_end = pendulum.parse(start_time)
dt_end = dt_end.add(minutes=(30 - (dt_end.minute - int(np.floor(dt_end.minute / 30) * 30))))
print(dt_end)
 
GET
【呼び出され側】
import requests
from pprint import pformat
 
def fetch_json(method: str, url: str, **kwgs) -> Dict[str, Any]:
""""""
return fetch(method, url, **kwgs).json()
 
 
def fetch(method: str, url: str, **kwgs) -> requests.models.Response:
""""""
logger.info(f'Request: [{method.upper()}] {url}\n{pformat(kwgs)}')
m = getattr(requests, method.lower())
r = m(url, **kwgs)
logger.info(f'Response: {r.status_code} {r.reason}')
if r.status_code != requests.codes.ok:
try:
logger.info(f'ErrorDetail:\n{pformat(r.json())}')
except Exception:
pass
raise HttpStatusERROR(f'{r} {r.reason}: {url}')
return r
-------------------------------------
【呼び出し側】
import fetch_json
 
get_data = fetch_json('GET', url)
 
POST
import requests
import json
 
url = 'xxxxxxxxxxxxxxxxxx'
headers = {'Content-Type': 'application/json; charset=utf-8'}
data = [{"xxxx":"11111"},{"yyyy":"22222"}]
 
r = requests.post(url, headers=headers, data=json.dumps(data))
 
#codes.createdやcodes.okなど
if r.status_code != requests.codes.created:
raise Exception(f'APIError: {r} {r.reason}')
 
パラメータストア取得
import boto3
# boto3の認証情報の渡し方メモ
 
def ssm_parameter(name: str, region_name: str) -> Dict[str, str] or str:
"""
パラメータストア 想定値(SecureString)
JSON文字列を想定。変換に失敗した場合はそのまま返却
 
```
{"aws_access_key_id": "XXXXXX",
"aws_secret_access_key": "XXXXX",
"region_name": "ap-northeast-1"}
```
"""
ssm = boto3.client('ssm', region_name=region_name)
r = ssm.get_parameter(Name=name, WithDecryption=True)
v = r['Parameter']['Value']
try:
v = json.loads(v)
except json.decoder.JSONDecodeError:
pass
return v
 
実行時引数受け取り
######################################################################
# Pythonコマンド 引数受け取り
######################################################################
import argparse
 
# ==========================================================
# 実行コマンド例
# python etc/command_para.py --path=s3:xxxxx --fname=sample.txt
# python etc/command_para.py --path s3:xxxxx --fname sample.txt
# ==========================================================
 
# ==========================================================
# コマンド引数の解析
# ==========================================================
parser = argparse.ArgumentParser()
parser.add_argument('--path', help='参照ディレクトリ', required=True)
parser.add_argument('--fname', help='ファイル名', required=True)
# これでもOK(ハイフンあり)
# parser.add_argument('--path', help='参照ディレクトリ', required=True)
# parser.add_argument('--fname', help='ファイル名', required=True)
 
parsed, extra = parser.parse_known_args()
 
_path = parsed.path
_fname = parsed.fname
 
print("パス:",_path)
print("ファイル名:",_fname)
 
HTTPヘッダ取得
import requests
 
try:
res = requests.get(url, stream=True, headers={})
print('au',res.headers['Content-Length'])
except Exception as e:
pass
 
try:
res = requests.get(url, stream=True, headers={})
print('sb',res.headers['Content-Length'])
except Exception as e:
pass
 
try:
res = requests.get(url, stream=True, headers={})
print('docomo',res.headers['Content-Length'])
except Exception as e:
pass
 
同じディレクトリにあるSQLファイルのパスを取得
from os import path
sql_path = f"{path.dirname*1}/test-sql/test_正常系_setup.sql"
 
 
path = "1111/22222/3333/5555.txt"
ファイル名だけにする
filename = re.sub(".*/", '',path) か
filename = re.sub("^.*/", '',path)
print(filename)
>5555.txt
 
 
pytest
python -m pytest tests
 
時間操作
JST_TIMEZONE = timezone(timedelta(hours=+9))
current_dt = current_datetime()
comp_dt = os.environ['COMP_DATETIME']
deadline_dt = datetime.datetime.strptime(comp_dt, '%Y-%m-%d %H:%M:%S')
deadline_dt = deadline_dt.replace(year=current_dt.year, month=current_dt.month, day=current_dt.day,
hour=4, minute=30, second=0, microsecond=0)
 
ディレクトリ構成(参考)
project
└src
    └app
        └batch
        └user
        └job
        └・・・
└tests
     └test_function1
        └テスト用.py
     └common.py(中身はdefだけ)
 
FastAPI

Python製の非同期前提なWeb APIをいい感じに作るためのFramework。flaskに近い。関連用語「RESTful API
REST=セッション等の状態管理はせず、やり取りされる情報はそれ自体で完結。

Applicationとしてのエントリーポイントはapp.py
$ python app.py

(例)
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}

 
実行時引数を文字列にして返却
(ex. arg1=a,arg2=b,arg3=c)
#vars:辞書属性を返却
arg_dict = vars(args)
items = list(map(lambda x: f'{x[0]}={(x[1] or "")}', list(arg_dict.items())))
return ','.join(items)
 
CSV出力(ヘッダ)
import csv
writer = csv.writer(csv_file, delimiter=',', quoting=csv.QUOTE_ALL, lineterminator='\r\n')
writer.writerow(['HEADER1', 'HEADER2', 'HEADER3', 'HEADER4'])
 
json読み込み
yobi_id_json = json.load(open('resources/yobi_id.json', 'r'))
 
traceback
標準ライブラリ。エラー時の詳細情報が出力される。以下の2通りの書き方がある。
・traceback.print_exc()
・traceback.print_exception()
  
改行/空白の除去
import re
query = re.sub(r"(\n)", " ", query)
query = re.sub(r"( +)", " ", query)
 
終了処理
メソッドの最後で
# 正常終了
sys.exit(0)
# 異常終了
sys.exit(9)
 
8桁の数字であること
re.match(r'^\d{8}$', self.day)
半角英数字6桁(ではないこと)
re.match(r"^[0-9a-zA-Z]{1,6}$", text) is None
半角数字0埋め4桁(ではないこと)
re.match(r"^[0-9]{4}$", text) is None
0か1(ではないこと)
re.match(r"^[01]$", args.kbn) is None
 
その他
実行ファイルのパス
__file__
 
使用例
os.path.basename(__file__)
os.path.dirname(__file__)
 
ファイル名を取得: os.path.basename()
フォルダ名を取得: base_path = os.path.dirname()
ファイル名とフォルダ名のペアを取得: os.path.split() 

*1:__file__

現場入場時

修飾キー(Mac)

Git

インストール(Mac)
homebrewを入れたらgitのインストールは完了
https://brew.sh/index_ja

インストール(Windows)
https://gitforwindows.org/
(説明)
https://qiita.com/andna0410/items/c9b8e232d4aa9ac77584

 config

$ git config --global user.name 'xxxxxxxxxxxx'
$ git config --global user.email 'xxxxxxxxxxxx.com'

改行コードの置換禁止

$ git config --global core.autocrlf false

設定確認

$ git config --global --list

 

Python2→3に切り替え

https://nontitle.xyz/archives/135
※「source .bash_profile」は「source ~/.bash_profile」に読み替える

.bash_profille

# Setting PATH for Python 3.7
# The original version is saved in .bash_profile.pysave
PATH="/Library/Frameworks/Python.framework/Versions/3.7/bin:${PATH}"
export PATH

# Setting PATH for Python 3.7
# The original version is saved in .bash_profile.pysave
# PATH="/Library/Frameworks/Python.framework/Versions/3.7/bin:${PATH}"
# export PATH
export PATH="$HOME/.pyenv/shims:$PATH"

pip(Mac)

sudo easy_install pip

 

profile作成

aws configure --profile switchmoto

その後でスイッチロール用のプロファイルを追加

echo "
[profile switchsaki]
region = ap-northeast-1
role_arn = arn:aws:iam::xxxxxxxxxxxx:role/{ロール名}
source_profile = switchmoto
" >> ~/.aws/config

鍵作成

cd ~/.ssh
ssh-keygen -t rsa -f fuji_keypairs
秘密鍵(fuji_keypairs_rsa)と公開鍵(fuji_keypairs_rsa.pub)が作成される

公開鍵出力
cat ~/.ssh/fuji_keypairs_rsa.pub > /Users/username/Documents/authorized_keys.txt

cd ~/.ssh/config

これらを設定すると「ssh host1」とかでssh接続できる。
Host host1
  HostName git-codecommit.ap-northeast-1.amazonaws.com
  User xxxxxxxxxxxxxxxxxxx
  IdentityFile ~/.ssh/id_rsa
  TCPKeepAlive yes
  IdentitiesOnly yes
Host github.com
  HostName github.com
  IdentityFile ~/.ssh/rsa_github
  User git

VSCode

https://code.visualstudio.com/

拡張機能
・Docker
・Git Graph
・Japanese Language Pack...
Python
・Remote - Containers
VSCodeでコミット間の差分を確認
・Git History

Pythonのリンター ・flake8 ・mypy

必須ではないがあると便利な拡張機能
vscode-icons
・Bracket Pair
・Whitespace+
・zenkaku
・Rainbow CSV

curl

sudo apt install curl

CotEditor

coteditor.com