Keep on moving

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

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を使っていません

gh-extensionsを書いてみた

小ネタです。

ghコマンドが2.0.0になりました

forest.watch.impress.co.jp

で、mattnさんのこちらのTweetを見て一個ネタを思いついたので早速素振りがてら作ってみました。 何番煎じよと言わないでねw

mobile.twitter.com

作ったもの

github.com

いつでもきゅうり(Gherkin)がみられるコマンドです。

f:id:Ehren:20210828233638p:plain
gh erkin

Please enjoy!

Gradleで条件によってdependencyを変える

こんにちは, 僕です。

近頃 Apache Beam にたまにパッチを送るのを趣味で行っているのですが、そこで学んだtipsを紹介します。 今回のテーマはGradleを使っていて条件によってdependencyを変えたい的な要件です。

ちなみにGradleのバージョンは6以降が対象です。

TL;DR

github.com

条件によってGradleのdependencyを切り替える。

Gradleだとできそうだなーと思って調べたら結構簡単に見つかりました。

stackoverflow.com

こんな感じでgradleの実行時引数をとって分岐することができるとのこと。

$ gradle -Pgson dependencies --configuration implementation

これを利用すると呼び出しもとのgradleファイル内で変数を参照することも可能でした。 以下のような感じです。

// aaa.gradle
spark_scala_version = '2.12'
// bbb.gradle
//      aaa.gradleから呼ばれる
dependencies {
  // ...
  if(project.property("spark_scala_version").equals("2.11")){
    runtimeOnly library.java.jackson_module_scala_2_11
  } else {
    runtimeOnly library.java.jackson_module_scala_2_12
  }
  // ...

こんな感じで、Javaのバージョンによって参照するライブラリのバージョン分けることも可能なようです。 先人に感謝

Kotlinで書いたアプリのMaven Central Repository への公開手順(Gradle KotlinDSL 版)

- version
Date 2021.02.13
OpenJDK OpenJDK Runtime Environment Zulu11.43+1017-CA (build 11.0.9.1+1-LTS)
kotlin 1.4.30
gradle 6.8.2

Kotlinで書いたアプリのMaven Central Repository への公開手順(Gradle(KotlinDSL)版)

TL;DR

  • bintrayに公開していたものを移行するのは割と簡単
    • sonatypeへの登録は初回だけちょいと面倒かも(JIRAでissue作ったりが必要)
    • singingの追加
      • pgp keyの登録が必要
    • maven-publish pluginを使っていればアップロード先をbintray -> maven-centralに変える
  • 僕が使っているbuild.gradle.ktsを共有

流れ

こちらのブログが素晴らしく良くまとまっているので参照すると良いと思います。

blog1.mammb.com

  1. sonatype の JIRA で issue を通してリポジトリ作成を依頼
  2. GnuPG で jar を署名できる環境を作成
  3. Gradle プラグインリポジトリへ登録
  4. Repository Manager で Maven Central Repository へリリース

Tips

いくつか捕捉しておくと良さそうなことを書いておきます。

windowsを使っている方向け

windowsで表題の件をやりたい場合はこちらでgpg keyを作成すると良いと思います。 https://www.gpg4win.org/

gnupgmacportsで入れる

sudo port install gnupg2 # XCodeが必要

RSA keys may be between 1024 and 4096 bits long

ここは (3072) [デフォルト]になったみたいです。

すでにbintrayに公開済みのjarをmavencentralに移行

jfrog.com

JVM言語界隈に激震が走ったこの件について。 bintrayにpublishしているものをmaven centralに移行したい方は以下の感じになります

  1. sonatype の JIRA で issue を通してリポジトリ作成を依頼
  2. GnuPG で jar を署名できる環境を作成
  3. Gradle プラグインを変更してリポジトリへ登録
  4. Repository Manager で Maven Central Repository へリリース

build.gradle.ktsの書き換えは以下のような感じになります。

github.com

抜粋すると

plugins {
    ...
    signing // signingを追加. bintrayではこれが必要なかった
}
...
//    repositories {
//        maven {
//            name = "bintray"
//            val bintrayUsername = "masahitojp"
//            val bintrayRepoName = "maven"
//            val bintrayPackageName = "com.github.masahitojp.bqdatamapper4k"
//            setUrl("https://api.bintray.com/content/$bintrayUsername/$bintrayRepoName/$bintrayPackageName/${project.version};publish=0;override=1")
//            credentials {
//                username = project.findProperty("bintray_user") as String?
//                password = project.findProperty("bintray_api_key") as String?
//             }
//    }
    repositories {
        maven {
            name = "MavenCentral"
            val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots"
            url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
            credentials {
                username = project.findProperty("sonatypeUsername")?.toString() ?: ""
                password = project.findProperty("sonatypePassword")?.toString() ?: ""
            }
        }
    }
// PGP署名(Mavenセントラルリポジトリに公開するのに必要な署名形式)の追加
signing {
    sign(publishing.publications["maven"])
}

私がよく使っているbuild.gradle.ktsGradle(KotlinDSL)

plugins {
    val kotlinVersion = "1.4.30"
    kotlin("jvm") version kotlinVersion
    id("org.jetbrains.dokka") version "1.4.20" // Docにはdokkaを使う(ここは自分の好きなのに入れ替えてよし)
    `maven-publish`
    signing
}

group = 'Your Group Id'
version = 'X.X.X'
val artifactID = "プロジェクト名"

repositories {
    mavenCentral()
    jcenter() // dokka dependency
}

dependencies {

    // Use the Kotlin JDK 8 standard library.
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")


   // 必要ならライブラリがあれば追加

    // Use the Kotlin test library.
    testImplementation("org.jetbrains.kotlin:kotlin-test")

    // Use the Kotlin JUnit integration.
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}

// Configure existing Dokka task to output HTML to typical Javadoc directory
tasks.dokkaHtml.configure {
    outputDirectory.set(buildDir.resolve("javadoc"))
}

// Create dokka Jar task from dokka task output
val dokkaJar by tasks.creating(Jar::class) {
    group = JavaBasePlugin.DOCUMENTATION_GROUP
    description = "Assembles Kotlin docs with Dokka"
    archiveClassifier.set("javadoc")
    // dependsOn(dokka) not needed; dependency automatically inferred by from(dokka)
    from(tasks.dokkaHtml)
}

// Create sources Jar from main kotlin sources
val sourcesJar by tasks.creating(Jar::class) {
    description = "Assembles sources JAR"
    archiveClassifier.set("sources")
    from(sourceSets["main"].allSource)
}

artifacts {
    add("archives", sourcesJar)
    add("archives", dokkaJar)
}

val jar by tasks.getting(Jar::class) {
    manifest {
        attributes(
            "Implementation-Title" to project.name,
            "Implementation-Version" to project.version,
            "Implementation-Vendor" to "masahito.me",
            "Built-JDK" to "${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})",
            "Built-Gradle" to gradle.gradleVersion
        )
    }
}

val sonatypeUsername = project.findProperty("sonatypeUsername")?.toString() ?: ""
val sonatypePassword = project.findProperty("sonatypePassword")?.toString() ?: ""

publishing {
    publications {
        create<MavenPublication>("maven") {
            groupId = project.group.toString()
            from(components.findByName("kotlin"))
            artifact(sourcesJar)
            artifact(dokkaJar)
            pom {
                name.set(artifactId)
                description.set("BigQuery datamapper for Kotlin")
                url.set("https://github.com/masahitojp/bqdatamapper4k")
                licenses {
                    license {
                        name.set("Apache License, Version 2.0")
                        url.set("https://opensource.org/licenses/Apache-2.0")
                    }
                }
                developers {
                    developer {
                        id.set("Your ID")
                        name.set("Your name")
                        email.set("Your email address")
                    }
                }
                scm {
                    connection.set("scm:git:git@github.com:XXXXX.git")
                    developerConnection.set("scm:git:ssh://github.com:XXXXX.git")
                    url.set("https://github.com/XXXXX")
                }
            }
        }
    }
    repositories {
        maven {
            name = "MavenCentral"
            val releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2"
            val snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots"
            url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else releasesRepoUrl)
            credentials {
                username = sonatypeUsername
                password = sonatypePassword
            }
        }
    }
}

signing {
    sign(publishing.publications["maven"])
}

まとめ

  • bintrayに公開していたものを移行するのは割と簡単
    • sonatypeへの登録は初回だけちょいと面倒かも(JIRAでissue作ったりが必要)
    • singingの追加
      • pgp keyの登録が必要
    • maven-publish pluginを使っていればアップロード先をbintray -> maven-centralに変える
  • 僕が使っているbuild.gradle.ktsを共有

上記をしました。すでにsonatypeにアカウントを作っていればそんなに大変なことはないと思います。 ちょっと古かったりしますがまとめ直してくれていたりする素敵なかたがたくさんいたので僕は1時間くらいで作業を終えることができました。 先人たちに感謝。

karabiner-elementsとM1 MacBook Airでの問題が解決された

- version
macos Big Sur 11.6
karabiner elements 13.7.1

2021-09-16 update: 無事対解決 タイトルも s/解決されつつある/解決された/g とした


2021-03-04 update: バージョンが上がったが、状況変わらず

https://github.com/pqrs-org/Karabiner-Elements/issues/2517#issuecomment-787000561

こちらによると BigSur 11.3(beta)に上げると解消されたとのこと。macOS側に原因があるということなのかなぁ.


Krabiner Elements v13.1.0をインストールしているとMacを再起動やシステム終了した際に画面がピンクになり、 kernel panicになることが報告されてます。

gori.me

が、Karabiner ElementsのBeta版を使うことでこの件が修正され、正常に動作した方がいるようです。(M1 mac miniらしい)

github.com

I don't see this issue anymore after updating to 13.3.1 with M1 Mac mini and Big sur 11.2. Not sure if this is same for everyone, but anyways thanks a lot for dev team for providing this awesome app!

TL;DR

  • Karabiner-Elements beta版を使う(本日時点では 13.3.1)
  • ただし効果は人による(少なくともkarabiner-elementsを[システム終了]する前に終了すれば問題が出ない)

Krabiner-Elements Beta の使い方

  1. Krabiner-Elementsで [preference] を開く
  2. misc > [Check for beta update] を押下する

f:id:Ehren:20210208234736p:plain

  1. これだけで治る人がいるみたいですが、私の環境ではkarabiner-elementsを終了する -> システム終了 とすることで問題が出なくなりました。(因みにM1 Macbook Air)

Karabiner Elements causes Apple silicon MacBook Air to crash during system shutdown · Issue #2517 · pqrs-org/Karabiner-Elements · GitHub

参考

engisuke.hatenablog.com

先人とKarabiner-Elements開発者に感謝