Clean Architecture, Clean Life

仕事・個人での技術的なことつぶやきます

【Python】kivyとtkinterの簡易比較

はじめに

個人開発でWindowsGUIアプリを作ってるのですが、その際にGUIライブラリであるkivyとtkinterをそれぞれ使ってみたのでお互いのメリデメをメモ程度に書いておこうと思います

一般的な内容は他のサイトに結構上がっているので、少し細かいところや使用感のところメインで書きたいと思います

UI配置に癖があるのは、全GUIライブラリ共通なので割愛しています

kivy

メリット

デメリット

  • kv言語を新たに覚える必要があり、結構癖がある
  • 日本語の情報が少ない(そもそも情報自体が少ない)
  • 最近更新されていない
  • exe化できなかった(頑張ればできるかもしれない)
  • 日本語でテキスト入力させたい時に使いづらい

そもそも日本語入力自体がろくにできませんでした 解決策を開発していただいた方もいますが、候補が表示されなかったりとやっぱりまだ癖があると言った所感です

vucavucalife.com

私としてはここがすごく高いハードルで、結局後述のtkinterに乗り換えました

tkinter

メリット

  • UIがシンプル
  • 動作が軽い
  • サンプルが多い(日本語もある)
  • 外部ライブラリ不要

デメリット

  • スクロールする画面を作るときに癖がある

最後のデメリットさえなければほぼ完璧でした

なので、スクロール画面を使わないことで対策としました

まとめ

現状PythonGUIとしては事例の数や情報量、日本語の対応というところから見てもtkinterが第一候補かなと言ったところです

kivyもかっこいいので使ってみたい気持ちはあるのですが、いかんせん癖が強いですね(^_^;)

他にもPyQtなどいろいろなGUIライブラリがあるので、使ったことのある方は是非感想聞かせて下さい

今回も最後まで見ていただきありがとうございました

Pythonの開発環境を一新した

はじめに

最近個人開発でよくPythonを使ってるのですが、仕事でも使うようになり、そろそろ開発環境を真面目に構築しようと思い、色々調べたのでご紹介しようと思います

構成

今回は以下のパッケージを使用しました

  • パッケージ管理+仮装環境
    • rye
  • Linter
    • ruff
  • 静的型チェック
    • mypy

rye

ちなみに業務の方ではryeではなく、poetry+venv(pyenv)の構成で使っています

一応公式には実験的プロジェクトでプロダクトでの利用は不向きと判断したからです

Rye は、Rust の Rustup と Cargo からインスピレーションを得て、Python に新しいタイプのパッケージング エクスペリエンスを構築する実験的な取り組みです。まだ製品化の準備ができていませんが、フィードバックや提案をいただければ幸いです。

  1. まずはryeをダウンロードします

公式サイトの通りに進めます

rye-up.com

私はWindowsを使っているので、そこに記載の通りにダウンロード→インストールして進めました

  1. プロジェクトに入って初期化する

私は既存のプロジェクトに対してpipからの移行だったので、トップディレクトに入って下記コマンドを実行しました

rye init -r requirements.txt

新規でプロジェクト作成する場合は

rye init

でよさそうです

パッケージを追加するときは

rye add パッケージ名

で追加します

Pythonのバージョンを変更する際は下記のコマンドを実行します 例はPython3.10に変更しています

rye pin 3.10

そうすると、.python-versionのファイルが書き変わってると思います

3.10.13
  1. project.scripts→tool.rye.scriptsに書き換える

正直違いがわかってないのですが、npmみたいに直接実行したいコマンドをベタ書きするなら後者に書き換える必要があるようです(init.pyじゃないとだめ??)

前者はデフォルトで「"test_project:hello"」のように少し変わった書き方をしていますが、よくわからないです(^_^;)

書き換え後は以下のような感じです

[tool.rye.scripts]
main = "python main.py"
home = "python home/home.py"
  1. パッケージインストール

下記コマンドで設定値を反映させます

rye sync

rye addでパッケージ追加した場合やPythonバージョンを書き換えた際は都度上記コマンドで反映させます

  1. 仮想環境に入る

syncすると.venvフォルダができると思います 仮想環境へ入るやり方は二つあります

  • ..venv\Scripts\activate + deactivate
  • rye shell + exit

どちらも入った後は

rye run コマンド名

で先ほど設定したコマンドを実行することが可能です 個人的には後者は仮想環境に入ってるのか入ってないのかがわからないので、従来通り前者の方がいいかもしれないですが、全社の方がコマンド打ちやすいのでなんとも言えないところですね。好みでいいと思います

ryeの感想としては、使っただけでは実験的プロジェクト感を感じなかったので、普通に使いたい気持ちです npmに慣れている私としては非常に使い勝手が良かったです

mypy&ruff

  1. パッケージ追加

下記コマンドを実行するだけです

rye add --dev mypy ruff

syncも忘れずに

  1. VSCodeの設定ファイル更新

こちらも設定します

.vscode/extentions.json

{
    "recommendations": [
        "charliermarsh.ruff",
        "ms-python.mypy-type-checker"
    ]
}

.vscode/settings.json

{
    "python.defaultInterpreterPath": "${workspaceFolder}/.venv/Scripts/",
    "[python]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.codeActionsOnSave": {
            "source.fixAll": "explicit",
            "source.organizeImports": "explicit"
        }
  }
}
  1. pyproject.toml追記

それぞれの設定値やルールを指定します 内容に関しては割愛するので、個人でカスタマイズしてみて下さい

[tool.mypy]
ignore_missing_imports = true

[tool.ruff]
target-version = "py310"

select = ["E", "F", "W", "I", "B"]
fixable = ["ALL"]

ignore = ["E402", "E501"]

補足:pre-commit

個人開発では使っていないですが、業務では以下の形でpre-commitを使っています

まずはadd

rye add --dev pre-commit

設定ファイル追加

.pre-commit-contig.yaml

repos:
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.2.0
    hooks:
      - id: mypy

  - repo: https://github.com/charliermarsh/ruff-pre-commit
    rev: "v0.1.8"
    hooks:
      - id: ruff
        id: ruff-format
        args: [--fix, --exit-non-zero-on-fix]

まとめ

まだ細かい設定はあると思いますが、後は開発しながらカスタマイズしていけばいいと思います

みなさんおすすめの設定や環境があれば教えていただけると幸いです

今回も最後まで見ていただきありがとうございました

【Python】OURAリングAPIでpandasの2.0.x系へ対応していない件に関して

経緯

私は2年前からOURAリングというウェアラブルバイスを利用しています

以下、ChatGPTによる説明文です

Ouraリングは、睡眠、活動、心拍数、体温などの生体データを測定するためのウェアラブルバイスです。このリングは、指に装着することで日常の活動や健康状態をモニタリングすることができます。

Ouraリングは、内蔵されたセンサーを使用してさまざまな生体データを収集します。睡眠中には、睡眠の質や時間を評価し、深い睡眠と浅い睡眠の割合を追跡します。活動中には、歩数や消費カロリーなどのデータを計測します。心拍数を測定することで、心臓の健康状態やストレスレベルを把握することができます。また、体温の変化を記録することで、身体のリズムや体調の変動を把握することも可能です。

Ouraリングは、これらのデータをスマートフォンのアプリに同期させることで、より詳細な解析やレポートを提供します。個々のユーザーに合わせた目標設定やアドバイスも提供される場合があります。

Ouraリングは、個人の健康とフィットネスの管理に役立つツールとして人気があります。睡眠の質や活動量、ストレスレベルなどのデータを追跡することで、生活習慣の改善や健康状態の把握に貢献することが期待されています。

このOURAリングというリングのデータは専用サイトから閲覧できるのに加え、APIが公開されているので、それ経由で取得することも可能です

github.com

私はここから取得したデータをNotionのテーブルにコピーするというスクリプトをGitHubActions上で動かしていたのですが、最近エラーが頻発するようになり、原因を探っていました

原因

エラーの原因はおそらく、OURAのAPIがpandasの2.0.x系へ対応していないために起こったと考えられます

エラー自体はActions上でのみ起こっており、私のローカル環境上では起こっていませんでした

ですので、なにかライブラリのバージョン違いかなと疑っていたところ、pandasのメジャーバージョンが異なっていることに気づき、エラー内容と一致することから更に深ぼって調査していました

ドキュメントを調べてみると、ここで使われているto_datetimeの仕様が2.0.0から変わっているとの記載がありました

pandas.pydata.org

DeepLの翻訳では、

これまで、to_datetime()は、各要素の書式を個別に推測していました。しかし、ユーザーが一貫した書式を期待しているにもかかわらず、関数が要素間で書式を切り替えてしまうような場合には、定期的に問題が発生することがありました。バージョン2.0.0から、解析には一貫したフォーマットが使われるようになりました。

とのことでした

実際にOURA側で持っているデータ自体はエラー内容にあるようにISO8601形式でした(エラーが起こった際のデータでは「2023-04-02T05:40:59+09:00」)

しかし、to_datetimeに渡している引数では「%Y-%m-%d %H:%M:%S」を指定しているので、本来ならばエラーになるところを、pandas1.5.3の仕様上、データの値から推測してよしなに変換してくれていたようです

その型予測が良からぬバグを生んでいたようで、2.0.0から指定したフォーマットどおりでないとエラーが出るように変更されたのですが、逆にその仕様の恩恵を受けていたOURAのAPIでバグが発生してしまっている、という現状のようです

実際to_datetimeのformat引数でISO8601を指定すれば問題なく動作することが確認できました

解決策

こちらでできることとしてはpandasのバージョンを1.5.3に戻すのが一番安いでしょう

というよりOURAのAPIが2.0.xに対応するまではそれ以外に方法はないように思います

現状1.5.3でも問題なく動くので、ライブラリがアップデートされるまではそちらで様子見しようと思います

このAPIを使っている方がどれだけいるかはわからないですが、同じ問題で困っている方の助けになれば幸いです

とおもったら、すでにIssueで困っている方を見かけたので、コメントしておきました^^

github.com

今回も最後まで読んでいただいてありがとうございました

ゴルフ記録アプリ「ゴルログ」の使い方

このページについて

Android/iOS用アプリ「ゴルログ」の使い方を記載するページです

アプリ概要

打ちっぱなし、ラウンド、レッスンなどで取り組んだことや感じたことを日記感覚で記録するアプリです 特にラウンドではスコアカードで記録できない打った後の感覚やもっとこう打つべきだった、といった反省をホールごとに記録することができます

使い方

  • 基本的には「練習」「ラウンド」「レッスン」共に使い方は同じです。差異のあるところのみ追記します
    • ラウンドのみ「ホール」の記録ができます(別途記載)

一覧画面

  • 今までの記録をカード形式で閲覧することができます
  • 各記録を押すと編集画面に飛びます
  • 「登録順」「日付順」でソートすることが可能(デフォルトは「登録順」)で、それぞれ「降順」「昇順」で表示できます(デフォルトは降順)
  • 「お気に入り」を押すとお気に入りのみを表示することができます
  • 右上のアイコンを押すと新規登録画面に飛びます
  • 真ん中のボタンを押すと画像や動画を含んだデータをエクスポートすることができます
    • データは任意の場所にzip形式で保存されます
  • 左上のアイコンを押すと設定画面に飛びます
  • 長押しで複数選択モードになり、一括削除することが可能です
    • 再度長押しもしくは戻るボタンで複数選択モードが解除されます

編集画面(新規登録画面)

  • 「日付」「時刻」は現在の値が自動入力されますが、値をタップすることで編集可能です
  • 「場所」は後述の設定画面から行きつけの場所を登録でき、自動入力することも可能です。フォームの横のボタンで行きつけの場所から選択できます
  • 右上のゴミ箱アイコンで「削除」、フロッピーアイコンで「保存」、星アイコンで「お気に入り登録」ができます
  • 右下の2つのアイコンではそれぞれ「写真(左のアイコン)」「動画(右のアイコン)」を登録する画面に飛びます
  • ラウンドのみ「ホール」の記録ができます
    • 左のボタンを押すと説明が出てきます
    • 右のボタンを押すと全ホールの記録を削除できます

ホール記録画面

  • ティーショット」「ロングショット」「ミドルショット」「アプローチ」「パター」の評価と「総括」を記録できます(すべて任意)
  • 「ロングショット」はPar5、「ミドルショット」はPar4,5のみです
  • Par数は一番右のボタンから変更可能です
  • 矢印で編集するホールを移動できます
  • 一番右のボタンで編集中ホールを削除できます
  • 他と同様に、ホールごとの写真と動画を残すことも可能です

写真(動画)登録画面

  • 右上のアイコンを押すと、ライブラリから写真・動画を登録できます
  • 左側のカメラアイコンを押すとカメラが起動し、写真・動画を撮ることができます
  • 写真・動画を長押しすると削除することができます

設定画面

  • 自分のベスト・平均スコアや、悩みなどをメモしておくことができます
  • 行きつけの場所を登録することで、記録の場所の内容をここから選択することが可能になります
  • 自動入力をONにしておくと、記録新規作成時に、一番上に登録している行きつけの場所が自動入力されます

【Flutter】CodemagicなどでAppStoreにCDするときの注意点

経緯

今作っているFlutterアプリをアップデートする際、毎回GooglePlayとAppStoreに手動でアップロードするの面倒だったので、Codemagicという無料で使えるCICDツールがあったのでそちらで自動化しました

codemagic.io

こちらの導入に関しては色々な方が記事上げられているのでそちらを参考にしてください

私は以下のサイトを参考にさせていただきました

こちらはZennで書かれている本なんですが、Flutterの基本的な内容がほぼ網羅されており、無料で読むことができるのでCICD以外でもかなりおすすめです

zenn.dev

問題点

アプリバージョンアップの際、GooglePlayの方は問題なかったのですが、AppStoreの方で以下のエラーが発生しました

The bundle version, 3, must be a higher than the previously uploaded version

最初はpubspec.yamlのバージョン番号+ビルド番号の変更漏れかと思って確認したのですが、きちんとversionの表記は「1.1.1+5」になっていました

解決策

iOSではyamlに加えて、project.pbxprojの変更が必要だったようです

手動で行う際に、XCodeからアーカイブ作ってビルドファイルをアップロードしてたと思いますが、あの時に行っていた作業が抜けていたようです

パスは(アプリ名)/ios/Runner.xcworkspaceにあります

変更箇所はCURRENT_PROJECT_VERSIONMARKETING_VERSIONです

それぞれ3カ所(Profile、Debug、Release)ありますので忘れないように変更しておきましょう

ここを変更した後でCDを実行すると問題なくAppStoreにビルドファイルがアップロードされました

同じところでつまづいている方もいらっしゃると思うので、ぜひ参考にしてください

【Flutter】RiverPodでautodispose+readを使う際の注意点

経緯

RiverPodのStateProviderを使う際、stateの監視が不要で、Notifier内で定義している関数を使いたかったので、watchではなく下記のようにreadを使用しました

(コードはダミーです)

Widget build(BuildContext context, WidgetRef ref) {
  return ElevatedButton(
    onTap: () => ref.read(counterProvider.notifier).update(state),
    Navigator.of(context).push(
           MaterialPageRoute(
             builder: (context) =>
                const NextPage(),
           ),
    )
  );
}

しかし、これを実行しても関数が実行されずに画面遷移してしまいました

原因

対象のProvider(ここでいうcounterProvider)でautoDisposeを設定されていたのが原因でした

readで関数を呼び出しているので関数内でstateを更新しても、watchしていないためすぐにstateが破棄されてしまい、stateが更新されていないように見えたということでした

解決策

①readではなくwatch使う

onTap: () => ref.watch(counterProvider.notifier).update(state),

watchにしてもWidgetが頻繁に再描画されたりすることはなく、特に困ることはないので、これが一番安い解決策です

②autoDispose修飾子を外す

【before】

final counterProvider = StateNotifierProvider.autoDispose<int>((ref) => 0);

【after】

final counterProvider = StateNotifierProvider<int>((ref) => 0);

ただ、わざわざref.refresh()追記するくらいならwatchでいいと思います

autoDispose使う際は気を付けたいですね

ゴルフ記録アプリ「ゴルログ」プライバシーポリシー

このページについて

Android/iOS用アプリ「ゴルログ」のプライバシーポリシーを記載するページです

プライバシーポリシー

個人情報の取得

本アプリが個人情報を取得するものはありません。

個人情報の利用

本アプリが個人情報を利用することはありません。

個人情報の提供

本アプリが個人情報を第三者へ提供することはありません。

ユーザが入力したデータやその記録

ユーザが入力した情報は、端末内に保存され、ユーザの同意なしに外部に送信されることはありません。

外部ツールの利用

本アプリでは、外部ツールを利用していません。