goo blog サービス終了のお知らせ 

dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

django のエラーハンドリング

2025-03-30 13:25:15 | python
django のエラーハンドリング」を Qiita に投稿しました。

python で2つの PDF のテキストの差分を検出

2025-03-22 12:54:42 | python
python で2つの PDF のテキストの差分を検出」を Qiita に投稿しました。

python で辞書から指定の項目のみの辞書を作成

2024-10-17 22:43:20 | python

python で辞書から指定の項目のみの辞書を作成する方法のメモ。

> a = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}
> print(a)
{'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4}

> b = {k: a[k] for k in ['a', 'b', 'c']}
> print(b)
{'a': 0, 'b': 1, 'c': 2}

python でクラス名、メンバ変数を参照

2024-10-06 14:44:09 | python

python でインスタンスのクラス名、メンバ変数を参照する方法のメモ。

インスタンスのクラス名は __class__.__name__ で参照でき、メンバ変数は __dict__ で参照できます。

class Class1:
    def __init__(self, num, str):
        self.num = num
        self.str = str


i1 = Class1('abc', 123)
i2 = Class1('def', 456)

# クラス名
print(i1.__class__.__name__)
print(i2.__class__.__name__)

# メンバ変数の値
print(i1.__dict__)
print(i2.__dict__)
■実行結果
Class1
Class1
{'num': 'abc', 'str': 123}
{'num': 'def', 'str': 456}

python で出力ストリームを flush する方法

2024-10-01 23:39:31 | python

python で出力ストリームを flush する方法のメモ

print() で flush=True を指定

print('Hello World!', flush=True)

sys.stdout.flush() を実行

print('Hello World!')
sys.stdout.flush()

base64 エンコードされた画像を Cloud Storage にアップロード

2024-09-30 23:00:03 | python

base64 エンコードされた画像を Cloud Storage にアップロードする方法のメモ。

プログラム

アップロード時に content_type を指定しないと、テキストデータとして扱われます。
# usage: uplaod_base64_image_to_gcs.py {bucket} {dir} < {json}

import sys
import base64
import json
from google.cloud import storage

def upload_to_gcs(bucket, dir, obj):
    img_bytes = base64.b64decode(obj['image_base64'])
    blob = bucket.blob(f"{dir}/{obj['file_name']}")
    blob.upload_from_string(img_bytes, content_type='image/jpeg')

def main():
    gcs_bucket = sys.argv[1]
    gcs_dir = sys.argv[2]

    client = storage.Client()
    bucket = client.bucket(gcs_bucket)

    for line in sys.stdin:
        obj = json.loads(line)
        upload_to_gcs(bucket, gcs_dir, obj)

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

データ

$ cat data.jsonl
{"id":"01","file_name":"01.jpg","image_base64":"/9j/4AAQSkZJ..."}
{"id":"02","file_name":"02.jpg","image_base64":"/9j/4AAQSkZJ..."}

プログラム実行・実行結果確認

$ cat data.jsonl | python upload_base64_image_to_gcs.py gcs-bucket-001 images

$ gsutil ls -L gs://gcs-bucket-001/images/*.jpg
gs://gcs-bucket-001/images/01.jpg:
    ...
    Storage class:          STANDARD
    Content-Length:         28300
    Content-Type:           image/jpeg
    ...
gs://gcs-bucket-001/images/02.jpg:
    ...
    Storage class:          STANDARD
    Content-Length:         21648
    Content-Type:           image/jpeg
    ...

python で画像を base64 エンコード

2024-09-29 12:21:34 | python

python で画像を base64 エンコードする方法のメモ。

プログラム


import sys
import io
import base64
import json


def read_image_file(image_file):
    with open(image_file, 'rb') as inst:
        image = inst.read()
        return image

    return None


def main():
    for i in range(1, len(sys.argv)):
        image_file = sys.argv[i]
        image = read_image_file(image_file)
        image_bytes = io.BytesIO(image).read()
        image_base64 = base64.b64encode(image_bytes).decode('utf-8')
        obj = {
            'id': i,
            'image_base64': image_base64,
        }
        print(json.dumps(obj, ensure_ascii=False))

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

実行結果

$ python image_base64.py img1.jpg img2.jpg

{"id": 1, "file_name": "img1.jpg", "image_base64": "/9j/4AA..."}
{"id": 2, "file_name": "img2.jpg", "image_base64": "/9j/4AA..."}

python でアップロードされた画像を取得する方法のメモ

2024-09-22 20:57:11 | python

ドラッグ&ドロップでアップロードする画像を指定し、画像をサーバに送信します。

サーバは python の flask を使って作成します。

※テンプレートファイルが html と解釈されてしまっています。

ファイル構成

.
├── image_controller.py
├── image_processor.py
├── image_server.py
└── template
    ├── index.html
    └── upload.html

サーバ本体: image_server.py

from flask import Flask, render_template
from image_controller import ImageController

gconfig = {
    'port': 5001,
    'template': {
        'folder': 'template',
    },
    'index': {
        'url': '/intra/test/upload_image/',
        'template': 'index.html',
    },
    'upload': {
        'url': '/intra/test/upload_image/upload',
        'template': 'upload.html',
    }
}

app = Flask(__name__, template_folder=gconfig['template']['folder'])

@app.route(gconfig['index']['url'], methods=["e;GET"e;])
def view_index():
    html = render_template(gconfig['index']['template'])
    return html

@app.route(gconfig['upload']['url'], methods=["e;POST"e;])
def view_upload():
    ctrl = ImageController(gconfig)
    resp_obj = ctrl.upload()
    html = render_template(
        gconfig['upload']['template'],
        title=resp_obj['title'],
        image_type=resp_obj['image_type'],
        image_base64=resp_obj['image_base64']
    )
    return html

def main():
    app.run(port=gconfig['port'], host='0.0.0.0')
    return 1

if __name__ == '__main__':
    res = main()
    exit(res)

コントローラ: image_controller.py

from flask import request
from image_processor import ImageProcessor

class ImageController:
    def __init__(self, config):
        self.config = config
        self.processor = ImageProcessor(config)

    def upload(self):
        params = {}
        params['title'] = request.form.get('title', '')
        params['image'] = request.files.get('image').stream.read()
        #print(params['image'])
        resp_obj = self.processor.upload(params)
        return resp_obj

処理: image_processor.py

import io
import base64
import imghdr

class ImageProcessor:
    def __init__(self, config):
        self.config = config

    def upload(self, params):
        image_base64 = base64.b64encode(params['image']).decode('utf-8')
        image_type = imghdr.what(io.BytesIO(params['image']))

        obj = {
            'title': params['title'],
            'image_type': f'image/{image_type}',
            'image_base64': image_base64,
        }

        return obj

画像アップロード画面テンプレート: index.html

<!DOCTYPE html>
<html lang="e;ja"e;>
<head>


<title>drag & drop image</title>
</head>
<body>
<form method="e;POST"e; action="e;upload"e; enctype="e;multipart/form-data"e;>
<input id="e;id_input"e; type="e;file"e; name="e;image"e; accept="e;image/*"e; hidden>
<input id="e;id_title"e; type="e;text"e; name="e;title"e; size="e;40"e;>


e;
<button id="e;id_remove"e; type="e;button"e;>削除</button> <button id="e;id_submit"e; type="e;submit"e;>送信</button> </form> <script> const uploadObj = document.getElementById("e;id_upload"e;); const previewObj = document.getElementById("e;id_preview"e;); const noImageObj = document.getElementById("e;id_no_image"e;); const imageInputObj = document.getElementById("e;id_input"e;); const removeObj = document.getElementById("e;id_remove"e;); const submitObj = document.getElementById("e;id_submit"e;); // クリック時にはファイル選択 uploadObj.addEventListener("e;click"e;, () => imageInput.click()); // プレビュー表示 imageInputObj.addEventListener("e;change"e;, (e) => { const file = e.target.files[0]; if (!file) return; previewObj.removeAttribute("e;hidden"e;); previewObj.src = URL.createObjectURL(file); }, false); // uploadObj.addEventListener("e;dragover"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#cccccc"e;; }); // uploadObj.addEventListener("e;dragleave"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#ffffff"e;; }); // ドロップ uploadObj.addEventListener("e;drop"e;, (e) => { e.stopPropagation(); e.preventDefault(); uploadObj.style.background = "e;#ffffff"e;; const files = e.dataTransfer.files; if (files.length > 1) return; imageInputObj.files = files; previewObj.removeAttribute("e;hidden"e;); previewObj.src = URL.createObjectURL(imageInputObj.files[0]); }); // 削除 removeObj.addEventListener("e;click"e;, (e) => { previewObj.setAttribute("e;hidden"e;, true); previewObj.src = "e;"e;; }); </script> </body> </html>

サーバレスポンステンプレート: upload.html

<html>
<head>
</head>
<body>

画像アップロード

{{ title }}
</body> </html>

python で imghdr による画像形式の判定

2024-09-22 20:19:12 | python

python で imghdr による画像形式の判定する方法のメモ。


ここでは画像ファイル名で画像を指定した場合と、画像データを指定した場合の判定方法を検証します。

import sys
import io
import imghdr


def read_image_file(image_file):
    image = None
    with open(image_file, 'rb') as inst:
        image = inst.read()

    return image


def main():
    image_file = sys.argv[1]

    # 画像ファイルで判定
    res = imghdr.what(image_file)
    print(f'image file: {res}')

    # 画像バイトデータで判定
    image = read_image_file(image_file)
    res = imghdr.what(io.BytesIO(image))
    print(f'image data: {res}')

    return 0


if __name__ == '__main__':
    res = main()
    exit(res)

jpg ファイル、png ファイルの画像判定結果では、それぞれ正しく判定しています。

$ python test_imghdr.py jpg1.jpg
image file: jpeg
image data: jpeg

$ python test_imghdr.py png1.png
image file: png
image data: png

jpg ファイルの拡張子を png に変更しても、正しく判定することができます。

$ python test_imghdr1.py jpg1.png

image file: jpeg
image data: jpeg

python で例外のメッセージを stderr に出力

2024-09-18 23:33:53 | python

python で例外のメッセージを strerr に出力する方法のメモ。

print({例外}, file=sys.stderr) で例外を stderr に出力することができます。

import sys
import json;

try:
    a = '[0, 1, 2'
    obj = json.loads(a)
except Exception as e:
    print(e, file=sys.stderr)

実行結果

Expecting ',' delimiter: line 1 column 9 (char 8)

str() で例外オブジェクトを文字列化してから出力することもできます。

import sys
import json;

try:
    a = '[0, 1, 2'
    obj = json.loads(a)
except Exception as e:
    sys.stderr.write(str(e) + '\n')

出力結果

Expecting ',' delimiter: line 1 column 9 (char 8)

python で json5

2024-09-03 23:24:47 | python

python の json5 ライブラリの利用方法のメモ。

json5 では以下のような json としてはエラーになる文字列でもエラーになりません。

インストール

pip install json5

json5 での parse

> import json5
> a = '{"a": 123, "b": 456, }'
> json5.loads(a)
{'a': 123, 'b': 456}
> b = '[1, 2, ]'
> json5.load2(b)
[1, 2]

json5 での文字列化

> a = '{"a-b": 1, "a_b": 2}'
> obj = json5.loads(a)
> json5.dumps(obj)
'{"a-b": 1, a_b: 2}'

pyenv による python のインストール

2024-08-31 14:20:40 | python

pyenv による python のインストールメモ。

pyenv のインストール

準備

sudo yum install git

pyenv のインストール

curl https://pyenv.run | bash

python のインストール

準備

sudo yum install gcc
sudo yum install g++
sudo yum install gcc-c++
sudo yum install zlib-devel
sudo yum install openssl-devel
sudo yum install bzip2-devel
sudo yum install xz-devel
sudo yum install ncurses-devel
sudo yum install libffi-devel
sudo yum install sqlite-devel
sudo yum install readline-devel

インストール可能な python のバージョンを確認

pyenv install --list

python のインストール

pyenv install 3.12.5
Downloading Python-3.12.5.tar.xz...
-> https://www.python.org/ftp/python/3.12.5/Python-3.12.5.tar.xz
Installing Python-3.12.5...
Installed Python-3.12.5 to /home/{...}/.pyenv/versions/3.12.5

利用可能な python のバージョンを表示

pyenv versions
* system (set by /home/{...}/.pyenv/version)
  3.12.5

python のバージョンを選択

pyenv global 3.12.5
pyenv versions
  system
* 3.12.5 (set by /home/{...}/.pyenv/version)

python で文字列の先頭を指定バイト以内で切り出し

2024-08-31 13:03:35 | python

python で文字列の先頭を指定バイト以内で切り出す方法のメモ。

単純に指定バイト数で文字列の先頭を取得すると、日本語のマルチバイト文字が途中で切れてしまうため、文字が途中で切れないように確認しながら先頭文字列を取得します。。

import io

def get_head_by_bytes(str, max_bytes, encoding='utf-8'):
    buf = io.BytesIO()
    buf_len = 0
    str_len = len(str)

    for c in str:
        b = c.encode(encoding)
        b_len = len(b)

        if buf_len + b_len <= max_bytes:
            buf.write(b)
            buf_len += b_len
        else:
            break

    bytes = buf.getvalue()
    buf.close()
    out_str = bytes.decode(encoding)

    return out_str

def main():
    strs = [
        "ビール!麦酒!",
	"ビール!beer!麦酒!",
    ]

    for str in strs:
        head = get_head_by_bytes(str, 15)
        num_bytes = len(head.encode('utf-8'))
        print(f'''org:  {str}''')
        print(f'''head: {head}({num_bytes})''')

    return 0

if __name__ == '__main__':
    res = main()
    exit(res)

実行結果

org:  ビール!麦酒!
head: ビール!麦(13)
org:  ビール!beer!
head: ビール!beer!(15)

python で画像をリサイズ

2024-02-24 13:36:44 | python
python で画像をリサイズする方法のメモ。
import sys
from PIL import Image

def main():
    in_file = sys.argv[1]
    out_file = sys.argv[2]
    rate = float(sys.argv[3])

    img = Image.open(in_file)
    out_width = int(img.width * rate)
    out_height = int(img.height * rate)

    out_img = img.resize((out_width, out_height))
    out_img.save(out_file)

    return 0

exit(main())


python で excel ファイルを生成

2024-01-25 00:18:35 | python
python で excel ファイルを作成する方法のメモ。
import xlsxwriter

class ExcelConverter:
    def __init__(self, fname):
        self.workbook = xlsxwriter.Workbook(fname)
        self.worksheet = self.workbook.add_worksheet()
	
        # 赤・ボールド
        self.strong = self.workbook.add_format({'color': 'red', 'bold': True})

        # 上・左詰め・折り返し
        self.cell_format = self.workbook.add_format()
        self.cell_format.set_text_wrap()
        self.cell_format.set_align('left')
        self.cell_format.set_align('top')

        self.data_idx = 0
        self.row = 0

    # ヘッダ行を出力する
    def output_header(self):
        self.row += 1

        cell = f'A{self.row}'
        self.worksheet.write(cell, '行番号')

        cell = f'B{self.row}'
        self.worksheet.write(cell, 'データ')

    # データを出力する
    def output_data(self, obj):
        self.data_idx += 1
        self.row += 1

        # 行番号
        cell = f'A{self.row}'
        self.worksheet.set_column(f'{cell}:{cell}', 7, self.cell_format)
        self.worksheet.write(cell, self.data_idx)

        # データ
        cell = f'B{self.row}'
        self.worksheet.set_column(f'{cell}:{cell}', 15, self.cell_format)
        self.worksheet.write(cell, obj['product-id'])

    def close(self):
        self.workbook.close()

def main():
    out_fname = sys.argv[1]

    conv = ExcelConverter(out_fname)
    conv.output_header()

    for line in sys.stdin:
        try:
            obj = json.loads(line)
            conv.output_data(obj)
        except Exception as e:
            try:
                sys.stderr.write(json.dumps(obj, ensure_ascii=False) + '\n')
                sys.stderr.write(e)
                sys.stderr.write('\n')
            except:
                pass

    conv.close()