GitHub のリポジトリの所有権を、Organizationに移管する手順

こんばんは、ウチイダです。

先日、GitHub上でソースコードの管理をしていたプロジェクトを、組織(Organization)上で管理することになりました。

はじめて自分で対応したので、メモに残しておこうと思います。

(事前準備)Organizationを作成する

GitHubのOrganizationがない場合、作成するのも簡単です。

無料プランで用意できるので、多人数で開発をする予定があれば、あらかじめOrganizationを要しておくとよいかもしれません。

まずは以下のURLからOrganizationの画面を開き、「New Organization」ボタンをクリックします。

https://github.com/settings/organizations

「New Organization」ボタンをクリック

プラン選択画面が表示されるので、作成するOrganizationで利用するプランを選びます。とりあえず作成するだけであれば、Freeでよいと思います。ウチイダも今回Freeを選択しました。

プランを選択。とりあえずFreeを選ぶ

Organizationの情報を入力する画面が表示されるので、組織名などを入力していきます。

ビジネス用途(A business or institusion)を選択した場合、Organizationが所属する組織を入力する必要があります。

個人名でも大丈夫だと思いますが、法人名とか屋号を入力しておくのがベターのようです。

ウチイダは実際にはリポジトリを管理する団体の名称(クライアント名)を入力しました。

すべて入力できたら、画面したの「Next」ボタンをクリックします。

Organizationの情報を入力する

以上でOrganizationの作成は完了です。

Organizationに招待したいユーザーを追加して、「Complete Setup」ボタンをクリックします。

招待するユーザーがいなければ、「Skip this step」で先に進めることも可能です。

Organizationに追加するユーザーに招待を送って、作成手順は完了

1. 移管するリポジトリの設定画面を開く

まずはリポジトリの設定画面を開きます。

リポジトリの設定画面を開く

2. 移管設定から、移管先組織を選択する

設定画面のメニュー「General」の下の方に、「Danger Zone」のエリアがあります。

この中に「Transfer ownership」の設定項目があります。「Transfer」ボタンをクリックすると、リポジトリの移管設定画面が開きます。

Transfer ボタンをクリックして、移管設定の画面を開く

3. 移管先組織を設定する

移管設定画面で、リポジトリを移管するOrganizationの名称を入力します。

確認のためにリポジトリ名を入力した後、「I understand, transfer this repository.」ボタンをクリックします。

移管先のOrganizationを指定して、ボタンをクリック

4. 移管が完了するのを待つ

ボタンクリック後、トップページに戻ります。

画面上部に「Moving repozitory ***/*** . This may take a few minutes.」というメッセージが表示されます。

しばらく待ってからリポジトリ一覧を再表示すると、移管したリポジトリが消えているのが確認できます。

トップページに戻り、メッセージが表示されれば操作は完了

5. リポジトリにアクセスできるか確認

リポジトリの移管によって、GitHub上のリポジトリ名称が変更されています。

念のため、表示ができるかを確認しておくとよいです。

ウチイダは念のため以下2点を確認しました。

  • 移管前の名称でURLを開いて、移管後の画面が表示できるか
  • 移管前にクローンしてあったローカルのリポジトリの設定のまま、fetch操作ができるか

リダイレクトの設定がされているのか、どちらも正しく動作しました。

もしかしたら、リポジトリのURLとかリモートリポジトリの参照先とか、いろいろな押さないといけないかなと心配していましたが、杞憂でした。

細かいところまで行き届いています。

このほかに、例えばGitHub Actionsを使う場合の検証などはしていないので、もしかしたらエラーが出る場面もあるかもしれません。

移管が終わったら、一連のワークフローが問題なく動作するか、確認しておくとよいと思います。

まとめ

Organizationも無料で作成できるうえ、移管設定もとても簡単に対応できました。

思っていたよりもすぐに済んでよかったです。

以上です。あなたのお役に立てればうれしいです。

GitHubのRSA鍵が変更された!鍵交換の対応手順

こんにちは、ウチイダです。

GitHubのリモートリポジトリへpush しようとしたところ、以下のようにエラーが表示されました。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s.
Please contact your system administrator.
Add correct host key in ~/.ssh/known_hosts to get rid of this message.
Offending RSA key in ~/.ssh/known_hosts:1
  remove with:
  ssh-keygen -f "~/.ssh/known_hosts" -R "github.com"
RSA host key for github.com has changed and you have requested strict checking.

ローカルに保持している接続先情報と違うサーバーにつながったよ、とのこと。

中間者攻撃かもしれないと書かれており、ちょっとドキッとしますよね。。。

調べてみたところ、公式からアナウンスが出ていました。

GitHubサーバーの秘密鍵を、公開リポジトリに置いてしまったのとこと…

短時間ってどのくらいなんでしょうね…?

このセキュリティインシデントに対する措置として鍵を取り換えたということのようです。

新しい内容で接続できるように変更しておきます。

やることは特に難しくなく、古い情報を破棄して新しい情報に差し替えるだけです。

# 古い鍵情報の破棄
$ ssh-keygen -R github.com
/home/y-uchiida/.ssh/known_hosts updated.
Original contents retained as /home/y-uchiida/.ssh/known_hosts.old

# 新しい鍵情報を追加
$ ssh -T github.com
The authenticity of host 'github.com (20.27.177.113)' can't be established.
ECDSA key fingerprint is SHA256:p2QAMXNIC1TJYWeIOttrVc98/R1BUFWu3/LiyKgUfQM. # 表示される鍵情報が正しいものか確認
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes # yes を入力
Warning: Permanently added 'github.com' (ECDSA) to the list of known hosts.
Hi y-uchiida! You've successfully authenticated, but GitHub does not provide shell access.

アナウンスだと、known_hosts に接続先情報を手動追加、もしくはコマンドで追加するように記載されていましたが、少し違う方法を取りました。

ssh -T github.com で接続テストをすると、known_hosts に接続先の情報がなければ確認を出してくれます。

ここでyes を入力すれば、接続先情報がknown_hosts に登録されます。

以下のページで、GitHubの公開鍵が一覧化されています。

https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints

接続確認時に表示された公開鍵が、いずれかに一致していれば問題ありません。

以上です。あなたのお役に立てれば幸いです。

Python, Djangoをきちんと使いたい_05: Flake8 でコーディングルール違反を自動チェック

皆さまこんにちは、ウチイダです。

時間を見つけてはDjango で中規模以上のアプリケーションを開発するための環境構築について調べています。

前回の記事はこちら。

ウチイダの作業環境は以下です。

  • Windows 11 21H2
  • WSL2 Ubuntu20.04
  • GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

以降の内容は、この環境にPython/Djangoの開発環境を導入していく手順メモとなります。

PEP 8 遵守はFlake8 におまかせ

さて、前回も述べたとおりですが、コーディングルールを決めたり、目視・手動でルールを順守するのはとても大変です。プログラムを書くときは、ロジックの実装のことだけ考えていたいものです。

PythonにはPEP 8というデファクトスタンダードなスタイルガイドがありますので、これにきっちり合わせていきたいです。

書いたプログラムがPEP 8 のルールに沿っていない場合に教えてくれるのが、Flake8 です。

厳密には、コードチェックのためのいくつかのパッケージを含んでいますが、今回はPEP 8のチェックのために利用します。

パッケージのインストール

過去の記事に続いて、poetry でインストールしていきます。

(python-flake8-sample-py3.11) $ poetry add --dev flake8
Creating virtualenv flake8-sample in /home/y-uchiida/python/flake8_sample/.venv
The --dev option is deprecated, use the `--group dev` notation instead.
Using version ^6.0.0 for flake8

Updating dependencies
Resolving dependencies... (0.2s)

Writing lock file

Package operations: 4 installs, 0 updates, 0 removals

  • Installing mccabe (0.7.0)
  • Installing pycodestyle (2.10.0)
  • Installing pyflakes (3.0.1)
  • Installing flake8 (6.0.0)

CLI から実行する

それではFlake8 を使ってみます。

flake8 <チェック対象のファイルパス> で実行できます。

PEP 8に沿ってない内容のスクリプトを書いて、、、

if 1 is 1:  # リテラルの比較に is は使わない
  print('always true')  # インデントはスペース4つにする

Flake8 で検査します。

(python-flake8-sample-py3.11) $ flake8 flake8_test.py
flake8_test.py:1:4: F632 use ==/!= to compare constant literals (str, bytes, int, float, tuple)
flake8_test.py:2:3: E111 indentation is not a multiple of 4

しっかりエラーを出してくれました!

Flake8 はチェックツールなので、自動での修正はしてくれません。列挙された内容を見て、それぞれ必要な修正をしていきましょう。

VSCode のFlake8 拡張

とはいえ、CLIでコマンドを実行して、それを確認しながら修正するのは大変です。

コードを記述している段階で、エディタ上にエラーが出てくる方が簡単です。

というわけで、VSCodeに拡張機能を導入していきます。

Microsoft が提供している拡張機能があるので、これを利用します。

Flake8 の拡張機能を導入

拡張機能の説明文によると、この拡張機能を導入するだけで、Flake8でのコードチェックが使えるようになるみたいです。

プロジェクトで選択されているPython環境にFlake8 がインストールされていない場合だけ、拡張機能がバンドルしているflake8 (5.0.4)が利用されるとのこと。

CIで利用するにはパッケージを入れておく必要がありますが、書き捨てのちょっとしたプロジェクトなら、拡張機能を入れておくだけでいいかもしれません。

まあ、そういう場合はそもそもコードチェックツール使う必要もないのかもしれませんが…

設定値の変更

念のため、VSCode でFlake8がしっかり動作するように、設定を変更していきます。

まずはデフォルトのリンターを変更します。

デフォルトでPylint が有効になっているので、これを無効にしておきます。

VSCode の設定をひらいて、python.linting.pylintEnabled のチェックを外します。

設定でPylint を無効にする

代わりに、Flake8 を有効にします。

python.linting.Flake8 Enabled にチェックをつけます。

設定でFlake8 を有効にする

これで、基本的にはOKです。

こんな感じで、エディタ上とProblemsパネルにスタイル違反を表示してくれます。

VSCode 上でPEP8 に沿っていない記述がわかる

これで、問題のあるコードがすぐにわかります。

Blackとの併用の設定

さて、ここまででFlake8 の設定自体は終わりです。

しかし、「妥協を許さないフォーマッター」ことBlackと併用する場合、ルールの食い違いが起こってしまいます。

Black はルールの変更ができないので、Flake8 のルールを変更してあげる必要があります。

Black のドキュメントに対応方法が書いてあるので、それに従えばOKです。

https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html

設定ファイルとして.flake8 か、setup.cfg か、tox.ini を用意して、以下のように記述します。

すでに上記のファイルがある場合は、追記してください。

[flake8]
max-line-length = 88
extend-ignore = E203

残念ながらFlake8 はpyproject.toml の設定情報を読んでくれません。

pyproject-flake8 という、Flake8 のラッパーを導入することでpyproject.toml に設定を書くことができるようです。

.flake8 ファイルを使えば、Flake8 の設定ファイルであることが一目瞭然なので、あえてこのままでもいいのでは、と考えています。

ちなみに、上記の設定例ではmax-line-length が88になっていますが、1行88文字は意外と短いです。

Blackでも唯一変更できるルールなので、設定値を100とか120に変更する場合もあると思います。

その場合は、Flake8のほうもその設定に合わせておきましょう。

まとめ

PEP8 のさまざまなルールを瞬時にチェックしてくれるFlake8のご紹介でした。

コードスタイルの乱れは風紀の乱れ、ということで、勝手に風紀委員と思っています。

Flake8 には、maccabe というコードの複雑度を判定するパッケージも含まれています。

これも使ってみたいところですが、運用方法がややこしくなりそうなので、今のところは見送っています。

以上です。あなたのお役に立てると嬉しいです。

参考資料

https://qiita.com/fehde/items/723b619013dc86008acc

https://itc-engineering-blog.netlify.app/blogs/black-flake8

Python, Djangoをきちんと使いたい_04: Black を入れてフォーマットをかける

皆さまこんにちは、ウチイダです。

時間を見つけてはDjango で中規模以上のアプリケーションを開発するための環境構築について調べています。

前回の記事はこちら。

ウチイダの作業環境は以下です。

  • Windows 11 21H2
  • WSL2 Ubuntu20.04
  • GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

以降の内容は、この環境にPython/Djangoの開発環境を導入していく手順メモとなります。

Blackで、フォーマッターの下の平等を実現する

コードスタイルの一貫性を保つのは、読みやすさを維持するために重要です。でも、コーディングルールをきちんと決めるのがまず大変だったりします。

また、コーディングルールを気にかけながらコードを書くのはつらいです。

こういうのはツールに頼ってしまいたい部分ですね。

今回はBlack を利用して、自動フォーマットをかけるところまでやってみたいと思います。

パッケージの導入

過去の記事に続いて、poetry でインストールしていきます。

$ poetry add --dev black
Creating virtualenv python-black-sample in /home/y-uchiida/develop/python-black-sample/.venv
The --dev option is deprecated, use the `--group dev` notation instead.
Using version ^23.1.0 for black

Updating dependencies
Resolving dependencies... (0.5s)

Writing lock file

Package operations: 6 installs, 0 updates, 0 removals

  • Installing click (8.1.3)
  • Installing mypy-extensions (1.0.0)
  • Installing packaging (23.0)
  • Installing pathspec (0.11.0)
  • Installing platformdirs (3.1.0)
  • Installing black (23.1.0)

これだけでセットアップ完了です!

CLIから実行する

black <修正対象のファイルパス> で、自動フォーマットを実行できます。

こんな感じで、みるからにガタガタなファイルを作って…

def main():	
      print("this"      +      "is"      +      'main')
      return            0

コマンドを実行!

(python-black-sample-py3.11) $ black format_test.py 
reformatted format_test.py

All done! ✨ 🍰 ✨
1 file reformatted.

以下のように修正されました。

def main():
    print("this" + "is" + "main")
    return 0

Black の特徴

基本的な使い方がわかったところで、Black について知っておきましょう。

Blackは、ルールがとても厳格というか、選択の余地がないフォーマッターです。

ドキュメントの冒頭で、こんなことを書いています。

By using Black, you agree to cede control over minutiae of hand-formatting. In return, Black gives you speed, determinism, and freedom from pycodestyle nagging about formatting. You will save time and mental energy for more important matters.

https://black.readthedocs.io/en/stable/

ざっくり意訳すると、Blackが提供するコードスタイルに従うことで、手作業でのフォーマットや、書式設定をしなくてよくなるよ!ということです。

コードスタイルにこだわりがある人はとっつきづらいかもしれませんが、チーム開発では自動で統一されるメリットは大きいですね。

ちなみに、設定ファイルでデフォルトから変更できるルールは、2023年3月時点では1行あたりの文字数だけです。

公式リポジトリのpyproject.toml にも、それしか設定項目がありません。

https://github.com/psf/black/blob/main/pyproject.toml

「妥協を許さないフォーマッター」というだけのことはあります。

VSCode のBlack 拡張機能

次はVSCodeでBlackを利用する場合の設定手順です。

設定といっても、拡張機能をインストールするだけでした。

VSCode用 Black 拡張機能

Black のパッケージをインストールしていなくても、この拡張機能を有効にすればOKです。

preview ってついているのが若干気になりますが、基本的な動作には問題なさそうでした。

拡張機能を入れただけだと、Blackのルールでフォーマットされないので、少しだけ設定を編集します。

@lang:python defaultFormatter で検索すると表示される項目を、Black Formatter に指定します。

Black Formatter をデフォルトに指定

また、 python.formatting.provider のデフォルトがautopep8 になっているので、 black を指定しておきます。

autopep8 から black に変更

また、ファイルの保存時にblack でフォーマットがかかるように、Format On Saveの設定も有効にしておきます。

Format On Save のチェックをオンにする

これで、VSCodeの設定は完了です!

スペースがガタガタなファイルを、VSCode で保存してみると、きっちりそろえてくれます✨

まとめ

導入するだけですぐに使えるフォーマッター、Blackのご紹介でした。

コードスタイル疲れのない、快適なPythonライフを送れそうです。

OSSでの利用数もすごく増えているようで、Blackに慣れておくといろいろなPython のコードが読みやすくなるかもしれません。

以上です。あなたのお役に立てると嬉しいです。

参考資料

https://nobunobu1717.site/?p=1845

https://nujust.hatenablog.com/entry/2022/07/24/114715

Laravel でSession cookie が設定できない – .env のSESSION_DOMAIN設定を修正

皆さまこんにちは、ウチイダです。

先日、新規開発でLaravelの初期セットアップをしていた時につまづいた内容をメモします。

今回の開発は、LaravelをバックエンドのAPI サーバーとして、React で作られたSPAをフロントエンドに配置する構成でした。

Vite で起動したローカルのReactアプリケーション(localhost:5173) から、Laravelが動いているDockerコンテナ(localhost:80)に向けてリクエストをしたところ、警告が発生しました。

ResponseのSet-Cookie で警告が表示

レスポンス自体はちゃんと受け取れているようですが、Set-Cookieのところに警告アイコンが表示されています。

⚠️のアイコンにマウスオンしてみると、以下のようなメッセージが。

This attempt to Set-Cookie header was blocked because its domain attribute was invalid with regards to the current host url

現在のURLに対して、Set-Cookie のドメイン指定が不正なので、Cookieが保存できない、といった警告です。

レスポンスの内容をよく見ると、Set-Cookieのドメインプロパティが確かにおかしいです。

domain=.localhost

localhostの先頭に、. がついています。.env ファイルでSESSION_DOMAIN=.localhost と設定していることが原因でした。

以下のように修正したところ、解消しました。

# SESSION_DOMAIN=.localhost . がついているとNG
SESSION_DOMAIN=localhost

本番環境では、ReactとLaravelをサブドメインに分けて配置して運用する想定だったので、CORS対策としてドメインの先頭に.をつけていました。

Set-Cookie ヘッダーのdomain プロパティで、先頭に . をつけてドメイン指定すると、サブドメイン間でCookieを共有できるようになります。

この先頭の . を、ローカル用の .env からとり忘れていたのが原因でした。

localhost の指定では、.がついているとドメインを正しく認識できず、動かなくなってしまうのです。

ローカル用とサーバーにデプロイして使う.env の内容を分けて管理しておく必要がありますね。

以上です。あなたのお役に立てればうれしいです。

WSL2 が、wslg ユーザーでログインされたとき:慌てずに再起動すればOK

こんにちは、ウチイダです。

WSLのおかげでとても快適に開発ができるようになりましたが、たまにWSLならではのトラブルに見舞われることがあります。

今日も、心臓によくない事象が起こったので、メモしておきます。

突然、WSLのユーザーが変わってしまう

PCを起動してWSLを立ち上げたときに、いつもと少し違う画面が表示されました。

wslg というユーザーでログインしている

$ wslg [ ~ ] と、プロンプトの表示内容が違ううえ、いつものユーザー(y-uchiida)ではなく、wslg というユーザーでログインされています。

/etc/passwd をみると、y-uchiida のユーザーアカウントがありません。

ホームディレクトリも空っぽです。いろんなクライアントのコードとか入ってるのに…!

WSLの再起動

WSLのデータが消えてしまった!と、肝が冷えましたが、とりあえずWSLを再起動を試します。

PowerShellを起動して、以下を実行します。

wsl --shutdown

その後、ふたたびWindows TerminalからWSLに接続したところ、改善していました。

WSLの謎挙動ですね…

なにかあっても、まずは焦らず再起動。鉄則を再認識しました。

以上です。あなたのお役に立てればうれしいです。

seeders のサブディレクトリ内に配置したSeeder クラスを、artisan CLI から実行したい:–class にname space を指定する

皆さまこんにちは、ウチイダです。

LaravelのSeederが便利でよく使っています。

テスト用のレコードを生成する処理をまとめておくと、いろいろ使いまわしがしやすいです。

でも、困るのがファイル数が増えてきたときの取り扱いです。database/seeders ディレクトリに全部入れてしまうと、ファイルを探しづらくなってしまいます。

というわけで、Seederクラスをサブディレクトリに分けることにしました。

検証環境

  • Laravel v9.43.0
  • PHP v8.1.13
  • Windows11 21H2

サブディレクトリにSeeder クラスファイルを作る

artisan で生成するときに、サブディレクトリを含めて指定するだけでOKです。

$ sail artisan make:seed Subfolder/SampleSeeder

   INFO  Seeder [database/seeders/Subfolder/SampleSeeder.php] created successfully.  

database/seeders/Subfolder 配下に、Seeder クラスを作ってくれました。

artisan コマンドから、サブディレクトリのSeeder を直接呼び出す

ここからが本題です。artisan db:seed は、–class に実行するSeeder クラス名を指定することができます。

これを使って、サブディレクトリにあるSeeder を呼び出します。

ちょっとだけ修正して、テキストだけ表示するように変更します。

<?php

namespace Database\Seeders\Subfolder;

use Illuminate\Database\Seeder;

class SampleSeeder extends Seeder
{
    public function run()
    {
        echo "サブフォルダのSeeder だよ~\n";
    }
}

それでは、いざ実行!

# name space を記述しないとエラー
$ sail artisan db:seed --class='SampleSeeder'

   INFO  Seeding database.  


   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Database\Seeders\SampleSeeder] does not exist.

クラスの名前解決ができません。クラス名だけ書くと、Database/Seeders 内を探すようになっているようです。

では追加の名前空間を指定すると…?

# Seeders 以降のname space を記述してもエラー
$ sail artisan db:seed --class='Subfolder\SampleSeeder'

   INFO  Seeding database.  


   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Subfolder\SampleSeeder] does not exist.

これでもエラーです。

名前空間を指定する(–class に \ を含む文字列を渡す)と、Database/Seeders は使わなくなってしまいました。

仕方ないので、全部指定します。

# name space を全部書くと名前解決できる
$ sail artisan db:seed --class='Database\Seeders\Subfolder\SampleSeeder'

   INFO  Seeding database.  

サブフォルダのSeeder だよ~

今度は実行できています。これは面倒…!

少し調べてみたところ、composer.json のautoload の設定を変えることで対応するやり方がいくつか見つかりました。

しかし、更新日付が古く、おそらくLaravel5 か 6 のころの話だと思われます。

また、クラス名の解決の仕方はdb:seed の挙動なので、autoload の設定でどうにかなるものではないような気がしています。

とりあえずname space を全部書くか、artisan CLI からの直接実行はあきらめるか、のどちらかになりそうです。

以上です。あなたのお役に立てればうれしいです。

React TypeScript で flexWrap、flexDireciton がエラー: CSSProperties を指定して回避

皆さまこんにちは、ウチイダです。

表題の件でエラーに遭遇したので、対策をメモしておきます。

環境

  • React 18.2.0
  • Typescript 4.9.3
  • @types/React 18.0.26
  • Vite 3.2.5

事象

CSS in JS でスタイルを記述した際、flexWrapを含んだオブジェクトを変数に格納してから、style 属性に渡すとエラーが出ます。

style 属性にそのままオブジェクトを書いた場合はエラーになりません。

export const FlexStyleError = () => {
	const elementStyle = {
		flexWrap: 'wrap'
	};

	return (
		<>
			<div style={{ flexWrap: 'wrap' }}>これはセーフ</div>
			<div style={elementStyle}>オブジェクトで渡すとエラー</div>
		</>
	)
}

エラーメッセージはこんな感じ。flexWrapの値として、string 型は渡せないよ~と言われてます。

Type '{ flexWrap: string; }' is not assignable to type 'Properties<string | number, string & {}>'.
  Types of property 'flexWrap' are incompatible.
    Type 'string' is not assignable to type 'FlexWrap | undefined'.ts(2322)
index.d.ts(1869, 9): The expected type comes from property 'style' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'

ちなみに、flexDirection でも同じエラーが起こります。

原因:csstype の型定義が使えてないから?

flexWrap とflexDirection には、それぞれFlexWrap と FlexDirection という専用の型があります。

  export type FlexWrap = Globals | "nowrap" | "wrap" | "wrap-reverse";

指定の文字列リテラルのUnion型として定義されていて、オブジェクトに渡した内容が正しく型を認識できてないぽいです。

解決方法:推論に任せず指定する

原因は分かったけど、よい解決策がわかりません。

というわけでエラーメッセージで検索したら、GitHubでissue が立っていました。

flexDirection is not assignable to CSSProperties 

まさにこれだ~と思いながらレスを追っていくと、いくつか対策が書かれていました。

要するに、型推論がちゃんとされなくてエラーになっちゃってるので、明確に指定すれば大丈夫ということです。

個人的には、styleに渡すオブジェクト全体に、React.CSSProperties を指定するのがいいかなと思いました。

flexDirection 以外のプロパティで問題が出ても、対処できそうです。

export const FlexStyleError = () => {
	// const elementStyle = {
	// React.CSSProperties 型を指定
	const elementStyle: React.CSSProperties = {
		flexWrap: 'wrap'
	};

	return (
		<>
			<div style={{ flexWrap: 'wrap' }}>これはセーフ</div>
			<div style={elementStyle}>オブジェクトで渡すとエラー</div>
		</>
	)
}

エラーも出なくなったし、そのうえ、プロパティのヒントも出してくれるように!

ReactCSSProperties を型指定することで、ヒントが正確に出る

CSS in JS を使うときは、型指定するとよい感じにプロパティが書けそうです。

以上です。

あなたのお役に立てればうれしいです。

Python, Djangoをきちんと使いたい_03: mypy で型安全を得る

皆さまこんにちは、ウチイダです。

時間を見つけてはDjango で中規模以上のアプリケーションを開発するための環境構築について調べています。

前回の記事はこちら。

ウチイダの作業環境は以下です。

  • Windows 11 21H2
  • WSL2 Ubuntu20.04
  • GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)

以降の内容は、この環境にPython/Djangoの開発環境を導入していく手順メモとなります。

転ばぬ先の型チェック

今回は、型チェッカーを導入します。

TypeScript + React をやり始めてから、実行時エラーで悩むことが激減しました。

Pythonでもそういう開発体験ができるといいなあと思って、型チェッカーを使っていくことにしました。

Pythonでは、TypeScriptのような静的型付けの機能を持ったスーパーセット言語はなさそうですが、型ヒント(Type hinting)が機能としてついているので、これを使うと型不整合を検出できるようです。

型の不整合をチェックするツールとしては、mypy がメジャーなようなので、これを導入していきます。

http://mypy-lang.org/index.html

エラーチェックツールとしては、VSCodeの拡張機能であるPylance も人気があります。

しかし、こちらはあくまでVSCode上でチェックをしてくれるもので、CLIで任意のタイミングに実行することができません。

チーム開発で使うことを考えて、Gitのpre-commitやレビュー実施時にCLIから実行をすることを考えて、mypyを採用します。

おことわり

mypy の導入にあたってはスムーズに行かなくてけっこう試行錯誤しました。

うまくいかない経緯も何らかのお役に立てるかもしれないと思い、なるべくそのまま掲載しています。

シンプルな導入手順を知りたい方にとっては冗長かもしれません。そのうちきれいに手順をまとめようと思います。

mypy のインストール

Poetry で導入する場合の例です。

$ poetry add --group dev mypy
The --dev option is deprecated, use the `--group dev` notation instead.
Using version ^0.991 for mypy

Updating dependencies
Resolving dependencies... (0.3s)

Writing lock file

Package operations: 2 installs, 0 updates, 0 removals

  • Installing typing-extensions (4.4.0)
  • Installing mypy (0.991)

pip でインストールする場合は以下のようにコマンドを実行します。

$ pip install mypy

これだけで導入は完了です。

CLI からチェックを試す

ためしに、あえて型不整合があるスクリプトを書いて、それをチェックしてみます。

import datetime

var: datetime.datetime = "foo"

mypy でのチェックは、mypy <対象ファイル> で行います。

$ mypy mypy_test.py
mypy_test.py:3: error: Incompatible types in assignment (expression has type "str", variable has type "datetime")  [assignment]
Found 1 error in 1 file (checked 1 source file)

datetime と str で型エラーが出ました!

ところで、上記のスクリプトって実行時エラーにもならないんですね…

VS Code 上で警告を表示する

続いて、VS Codeのエディタ上に型不整合のエラーを表示していきます。

VS Code上の設定項目にmypy が入ってるので、これを有効にします。

Mypy Enabled にチェックを入れる

ウチイダこれだけでOKでした。

さらに、プロジェクト全体を自動でチェックしてくれるように、Mypyの拡張機能も導入してみます。

上記の設定だと、ひらいてるファイルのチェックしかしてくれないようなんですよね…

mypy をシステムグローバルにインストールしていない(プロジェクトごとの仮想環境にしかインストールしていない)場合、mypy daemon が見つからない、という警告が出る場合があります。

mypy daemon が見つからないエラー

公式ドキュメントを見てみると、mypy server プロセスを起動させて置きそれに型チェックをさせるしくみがあるようです。

VS Codeはこれと連携して、チェックをしているみたいですね。

https://mypy.readthedocs.io/en/stable/mypy_daemon.html

さらに、mypy の拡張機能の説明文を読んでみると、仮想環境上のmypy を利用する場合は、 mypy.RunUsingActiveInterpreter をEnable にするように、と書いてありました。

仮想環境のmypy を使う場合の指示

設定をしたところ、エラーが消えました!

Dmypy.Executable はデフォルト値のままでOKです。

これで基本の設定は完了です。

返り値の型指定がない関数の内部はチェックされない

基本の設定は完了…と思っていたのですが、まだもう少し続きます。

どんなパターンでエラーが出るのか、いろいろ試していたところ、間違っていそうなのにVS Code で警告されないものがありました。

str 型の変数に、わざわざint キャストした整数値を代入しています。

def main():
    num_string: str = int(2)
    print(f"test: {num_string}")


if __name__ == "__main__":
    main()

それでも、エラーになりません。

エディタ上でも、CLIでもエラーにならない

よく見ると noteのところに、untyped な関数の内部はデフォルトではチェックしないので、 –check-untyped-defs を使ってみて、と書いてあります。

オプションを加えてチェックを再実行したところ、エラーになりました。

–check-untyped-defs オプションをつけるとエラーになる

untyped function というのは、返り値の型を定義していない関数のことのようです。

というわけで、 main() の返り値としてNoneを指定してみます。

返り値を設定したら、エラー検出された

untyped function ではなくなったので、エディタ上でも検出してくれました。

VS Codeでのチェックにオプションを設定する

型注釈がない関数が、VS Code上で警告されないのはつらいです。

調べてみたところ、VS Code の設定から、 mypy のチェックオプションを設定できるようでした。

設定画面を開いて、 python.linting.mypyArgs から設定できます。

ひとまず、–check-untyped-defs を追加しました。

python.lintinh.mypyArgs に –check-untyped-defs を追加

すると、 main() の返り値に型注釈がなくてもエラーを検出してくれました!

unyped-function の内部も、エディタ上で警告されるようになった

mypy のチェックオプション

オプションとして設定できる項目はいろいろあるようです。

https://mypy.readthedocs.io/en/latest/command_line.html#specifying-what-to-type-check

Python の型ヒントの仕様とあわせて理解すれば、良い感じの制限を作れそうです。

VS Code の設定を共有する

VS Code をチームで統一して使っている場合、その動作も統一したくなります。

mypy はけっこう設定の作業項目が多いので、可能なら全員で同じ設定ファイルを共有してしまうのがよいと思います。

プロジェクト内に .vscode/settings.json を作って、Git リポジトリに共有するだけでいいのでお手軽ですね。

mypy の設定は、json でみると今のところこんな感じになっています。

{
  "python.linting.mypyEnabled": true,
  "mypy.runUsingActiveInterpreter": true,
  "python.linting.mypyArgs": [
    "--follow-imports=silent",
    "--ignore-missing-imports",
    "--show-column-numbers",
    "--no-pretty",
    "--check-untyped-defs"
  ]
}

もう少しきちんと設定ファイルを作りたいです。。。

まとめ

とりあえずCLIと、VS Code上での型不整合の検出ができるようになりました。

TypeScriptもそうですが、設定周りで覚えることが多いので、もっと使い慣れていく必要があるなと思いました…

というわけで、今回はここまで。

あなたのお役に立てればうれしいです。

参考資料

https://ohke.hateblo.jp/entry/2020/10/03/230000

https://mypy.readthedocs.io/en/latest/mypy_daemon.html

https://future-architect.github.io/articles/20201223/

https://mypy.readthedocs.io/en/latest/command_line.html#specifying-what-to-type-check

VSCode で、PythonのGotoDefinitionが動かない – Language Serverの設定を見直す

皆さまこんにちは、ウチイダです。

Pythonの環境設定をいろいろ試しているところで、タイトルの事象が発生しました。

VSCodeでは、コード上の変数やクラス名にカーソルを置いてF12を押すと、その定義を開いてくれる機能があります。

その機能がいつの間にか使えなくなっていました。

「定義が見つからない」と表示される

原因:LSPが設定できていなかった

定義へ移動する機能は、LSP(Language Server Protocol)によって実現されています。

詳細はこちらで…

https://github.com/microsoft/language-server-protocol

VSCodeで編集している内容に対して、このLanguage Serverを介して機能を提供する仕組みです。

そのため、Language Serverが動作していないといけないということになります。

通常はVSCode起動時に、指定されたLanguage Serverが起動するようになっているはずです。

そこで、VSCode の設定を確認してみたところ、Python のLanguage Server で「None」が選択されており、を起動しない設定になっていました。

これを「Default」に変更したところ、改善しました。

Mypyを導入する際に既定のLanguage Server であるPylanceと併存できるかいろいろ調べていたので、その時にやってしまったのかもしれません。

原因究明するまでに結構時間がかかってしまいました。

以上です。あなたのお役に立てればうれしいです。