Keep on moving

あんまりまとまってないことを書きますよ

Python 3.11の新機能試す(1) - トレースバックのエラー位置の改善

app version
Python 3.11 rc1

本日試す機能

本日試すのはこちら。

PEP 657: Enhanced error locations in tracebacks 「トレースバックのエラー位置の改善」とでも訳すのがよさそう。

対応するPEP

peps.python.org

試してみたコード

from dataclasses import dataclass


@dataclass
class Point:
    x: int
    y: int


def manhattan_distance(p1, p2):
    return abs(p1.x - p2.x) + abs(p1.y - p2.y)


if __name__ == "__main__":
    p1 = Point(x=1, y=2)
    p2 = None  # Ouch!!! forget to initialize it for some reason

    print(manhattan_distance(p1, p2))

これを実行すると 3.10では

% python3.10 distance.py 
Traceback (most recent call last):
  File "/Users/masahito/src/python/try_3_11/distance.py", line 16, in <module>
    print(manhattan_distance(p1, p2))
  File "/Users/masahito/src/python/try_3_11/distance.py", line 9, in manhattan_distance
    return abs(p1.x - p2.x) + abs(p1.y - p2.y)
AttributeError: 'NoneType' object has no attribute 'x

どこでエラーになっているかはわからない。

けど、3.11で実行すると

% python3.11 distance.py
Traceback (most recent call last):
  File "/Users/masahito/src/python/try_3_11/distance.py", line 16, in <module>
    print(manhattan_distance(p1, p2))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/masahito/src/python/try_3_11/distance.py", line 9, in manhattan_distance
    return abs(p1.x - p2.x) + abs(p1.y - p2.y)
                      ^^^^
AttributeError: 'NoneType' object has no attribute 'x'

となって、エラーになっている行だけではなく、変数のどこで何が起こっている(今回の場合は変数がnone)のかが追いやすくなっていますね! これはなかなかいい

m1macbook air の環境をmacports -> homebrewに入れ替え

思うところがあってm1 macbook airを買ってからずっと使っていた macportsをやめてhomebrewに入れ替えてみた

対象 monteley 12.3

macportsをアンインストール

公式の以下の説明通りやればOKです。 guide.macports.org

注意点

ただし、rmコマンドで削除するときに以下のように permission denied が出た場合はセキュリティ設定をチェックしてみた方が良いです。

フルディスクアクセスを以下のようにターミナル(またはあなたがお使いのterminal application)にフルディスクアクセスを与えてください。

f:id:Ehren:20220410221100p:plain

homebrewをインストール

docs.brew.sh

前は apple sillicon用のインストール方法はintel版と違っていた気がしたのですが、 今は一緒のようです。

% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
% brew --version
Homebrew 3.4.5
Homebrew/homebrew-core (git revision 76904b3d872; last commit 2022-04-09)

Cloud Loggingでミュート(disable)しているアラートの一覧を表示する

こちらのブログを読んでいてCloud Loggingでミュート(disable)しているアラートの一覧を表示したくなった。

blog.luispc.com

やり方

gcloud commandを使うといけるっぽい.

cloud.google.com

アラートの名前を一覧表示する(jqを使用)

$ gcloud alpha monitoring policies list --project=PROJECT --filter=enabled:false --format=json \
 | jq '.[].displayName'

注意点

  • projectは必須
  • format optionはjsonyamlから選べる
  • 返り値は REST APIを参照

cloud.google.com

理想

qiita.com

Datadogみたいに一時ミュートできると本当はいいんだけどなぁ

Gradle で「詳細は、-Xlint:uncheckedオプションを指定して再コンパイルしてください」と表示されたときの対処(for build.gradle.kts)

レアキャラです。今回は久々なので小ネタです。

software version
Java 11.0.9.1
Gradle 7.3.3

Gradle で「詳細は、-Xlint:uncheckedオプションを指定して再コンパイルしてください」と表示される時があります。 build.gradleの時は以下の記事を参照。

qiita.com

ただ、この書き方だとbuild.gradle.kts(kotlinで書く方のやつ)だと動きません。 ではどう書くかというと以下のような感じになります

tasks {
    withType<JavaCompile> {
        options.compilerArgs.add("-Xlint:unchecked")
    }
}

先人に感謝

参考

https://discuss.gradle.org/t/what-is-xlint-deprecation-and-how-to-use-it/40270

Python 3.10触ってみた(1) ~asyncio#get_event_loop

こんにちは, ミュージシャンの卵です.

Python3.10のリリース予定日の2021-10-04が近づいていますね。 そろそろどの辺が変わるのかも含めて調査を始めています。 asyncioのコードを書いてみて軽い変更があったことを見つけました。

www.python.org

asyncio

Python3.10でasyncioのコードを書いてみたらこんなwarningが出るようになりました。

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')


loop = asyncio.get_event_loop() # ここでwarning
loop.run_until_complete(main())

DeprecationWarning: There is no current event loop loop = asyncio.get_event_loop()

調べた感じだとこういうことらしい

docs.python.org

asyncio.get_event_loop() now emits a deprecation warning if there is no running event loop. In the future it will be an alias of get_running_loop(). asyncio functions which implicitly create a Future or Task objects now emit a deprecation warning if there is no running event loop and no explicit loop argument is passed: ensure_future(), wrap_future(), gather(), shield(), as_completed() and constructors of Future, Task, StreamReader, StreamReaderProtocol. (Contributed by Serhiy Storchaka in bpo-39529.)

ざっくり訳すと

asyncio.get_event_loop()は、実行中のイベントループがない場合、 deprecationの警告を出すようになりました。asyncio.get_event_loop() は、将来的には get_running_loop() のエイリアスになります。

というわけで asyncio.get_event_loop()を呼ぶとこの警告が出るっぽい。

対策

github.com

どうやら asyncio.run だとこのwarningが出ないことがわかってきた。 というわけで サクッとサンプルを書きたい時は asyncio.run() を使い、 そうじゃない時はこんな感じでnew_event_loop -> set_event_loopするのが良いっぽい。

import asyncio

# ものすごく略したコード
loop = asyncio.new_event_loop()
try:
    asyncio.set_event_loop(loop)
    loop.run_until_complete(main())
finally:
    asyncio.set_event_loop(None)
    loop.close()

ソフトウェアの捨てられビリティ(Disposabiliy) 2021

こんにちは、魅惑の何かです。秋の夜長にポエムでも描いてみました。

 

夜にmagnoliakさんのこの辺のツイートをみててアウトプットしたいものを思い出したので忘れずに書いておきます。

 

背景

初期開発、リリース後に変更を加えていくことで変更のコストが大変になることが多い。

また途中で開発の(いろんな意味での)事情がかわり設計を変えたくなることも多いかなーと思い続けています。

ただ、すでに動いているシステムを変えるのは大変なんですよね。

じゃーどうするの

ソフトウェア自体は動きを止められても、毎日の経済活動を止めることはできない。

だから要は今あるものを動かしつつ、捨てる or やり直すことを前提に処理を書き続けるにはどうするかということを考えるのが良いかなと。

例えば並行でシステムAを動かしながら、同様の振る舞いをするシステムBを動かすなど。

まだまだ自分でも上手く言葉にならないのだけど、いつでも対象システムのマイグレーション(移行)ができるように備えていくのが良いのだと思う。

 

  1. この対象システムの裏側の制約を明らかにすること(例: このバッチはなぜこの時間から実行開始しているか、また後続システムではこの処理がいつまでに終わることを期待しているか)
  2. ビジネスロジックへの(少なくとも)ユニットテストの付加
  3. ここで行っている処理は短期、中期、長期で使うものなのか。(大体の場合生存期間がビジネスロジックは捨てられビリティをあげる必要あり。なぜならここの施策は短期間で変わるから)

 

まとめにならないまとめ

なーんてことを近頃考えながらお仕事をすることが多いです。

変更にコストがかかるような状態は本当にしんどく、保守する側の人は疲弊してしまうことが多いんですよね。ビジネスロジックも短期的に必要なものとか、経営方針で変わるものとか、長期で変わらないものとか本来分類できるはずなんですよね。捨てていいフラグとかをビジネスロジックに書いておくとかがあってもいいのかもなーと思ってます。

 

そのためには、やはり対象システムのやってることの明確化(ドキュメント化を含む)と最低限のユニットテストでもないとそもそもやり直すのも大変になりがちだよなーと思ってます。

 

最後に

今回の記事はプロトタイプみたいなものなのでどこかでまたupdateをかけたいなと思ってます。

Gradle+KotlinでのJavaのtarget versionの指定のしかたをまとめた

software version
gradle 7.2
Kotlin 1.5.30

Gradle+ Kotlinの環境でライブラリを書いていたらいつの間にか以下のようなwarningが出るようになってしまいました。

% ./gradlew test  

> Task :compileKotlin
'compileJava' task (current target is 11) and 'compileKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version.

> Task :compileTestKotlin
'compileTestJava' task (current target is 11) and 'compileTestKotlin' task (current target is 1.8) jvm target compatibility should be set to the same Java version.

TL;DR

Gradleに以下の設定を入れる。以下はJava8の場合で KotlinDSLを使う場合の例

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

// こちらの書き方でもOK
// java {
//    toolchain.languageVersion.set(JavaLanguageVersion.of(8))
// }

val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions.jvmTarget = "1.8" // javaの方とversionをあわせる

ググってみた

stackoverflow.com

どうもJavaのtarget versionとKotlinでのjvmTargetの値を両方指定しないといけないらしい。

toolchainの話が出てきたので調べてみたところどうもGradle 6.7から追加された概念らしい(後でもうちょい調べてみよう)

Gradle 6.7 で追加された Toolchain サポート - A Memorandum

Gradleはjava_homeで指定されているバージョンを使おうとするので私はadoptopenjdk11を使っていることもありtarget versionの互換性が〜〜〜というエラーが出るようになった様子。

というわけでこういう書き方をするようにbuild.gradle.ktsを書き直したところビルド時にwarningが出なくなりました。

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

// こちらの書き方でもOK
// java {
//    toolchain.languageVersion.set(JavaLanguageVersion.of(8))
// }

val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions.jvmTarget = "1.8" // javaの方とversionをあわせる

余談

ちなみに 私はm1 macを使っているせいか toolchain.languageVersion.set(JavaLanguageVersion.of(8)) と書くと adoptOpenJDKから aarch64版のopenjdk8をダウンロードしてくれようとするのですが、adoptopendjdkでは提供していないため ビルドしようとするとエラーになってしまうので toolchainを使っていません