【Haskell】【Stack】Encountered error while migrating Pantry database

stackでHaskell入門していたら stack build 時に下のようなエラーに遭遇しました。

Encountered error while migrating Pantry database:
    SQLite3 returned ErrorNotFound while attempting to perform step: database disk image is malformed
Please report this on https://github.com/commercialhaskell/stack/issues
As a workaround you may delete Pantry database in /Users/dyoshikawa/.stack/pantry/pantry.sqlite3 triggering its recreation.
cp: /bin/bootstrap: No such file or directory
make: *** [all] Error 1

As a workaround you may delete Pantry database in /Users/dyoshikawa/.stack/pantry/pantry.sqlite3 triggering its recreation. cp: /bin/bootstrap: No such file or directory とあるので何らかの操作で ~/.stack/pantry/pantry.sqlite3 の内容がおかしくなってしまった際に発生するっぽい。

この通りにファイルを削除してみます。

rm ~/.stack/pantry/pantry.sqlite3

これで一旦解決しました。

【boto3】DynamoDBの自動テストで使えるかもしれないスニペット

LocalStackのようなエミュレータを活用したテストコードでよく使うやつ。

  • Python 3.8.3
  • boto3 1.16.14
  • pytest 6.1.2

ここで記載するサンプルメソッドは下のようなクラスに所属している前提になります。

import boto3
import mypy_boto3_dynamodb.service_resource as dynamodb_resources

class DynamoDefiner:
    dynamo: dynamodb_resources.DynamoDBServiceResource

    def __init__(self, endpoint_url: str = None):
        dynamo: dynamodb_resources.DynamoDBServiceResource = boto3.resource(
            "dynamodb", endpoint_url=endpoint_url
        )
        self.dynamo = dynamo

テーブルがない場合は作成

def create_my_table(self, table_name: str) -> None:
    # すでにテーブルがあるかチェック (二重にテーブルを作成しようとするとエラーになるため)
    tables = list(self.dynamo.tables.all().__iter__())
    if list(filter(lambda t: t.name == table_name, tables)):
        # すでにある場合は終了
        return

    self.dynamo.create_table(
        TableName=table_name,
        KeySchema=[
            {"AttributeName": "partition_key", "KeyType": "HASH"},
            {"AttributeName": "sort_key", "KeyType": "RANGE"},
        ],
        AttributeDefinitions=[
            {"AttributeName": "partition_key", "AttributeType": "S"},
            {"AttributeName": "sort_key", "AttributeType": "S"},
        ],
        BillingMode="PAY_PER_REQUEST",
        # GSI貼る場合
        GlobalSecondaryIndexes=[
            {
                "IndexName": "sort_key-index",
                "KeySchema": [
                    {"AttributeName": "sort_key", "KeyType": "HASH"},
                ],
                "Projection": {
                    "ProjectionType": "ALL",
                },
            },
        ],
    )

テーブルのItemを全件削除

def clear_my_table(self, table_name: str) -> None:
    my_table = self.dynamo.Table(table_name)
    # scanでItems取得
    scanning_result = my_table.scan()
    items = scanning_result["Items"]

    # 0件なら終了
    if not items:
        return

    # scanで取得したItemsを全件削除
    # TODO batch_writeに変えたら高速化できそう
    for item in items:
        shop_table.delete_item(
            Key={"shop_id": item["shop_id"], "sort_key": item["sort_key"]}
        )

    # 再帰
    self.clear_shop_table(table_name)

1回のscanで全件取得できるとは限らないため、取得しきれなかった場合は再帰呼び出しで繰り返すようにしています。

使い方

テストフレームワークはpytest、DynamoエミュレータはLocalStackを使用しているものとします。
setupでテスト毎に

  • テーブルがなければ作成
  • テーブルのクリア

をします。

import boto3
import mypy_boto3_dynamodb.service_resource as dynamodb_resources

class TestShopDynamoRepository(object):
    def setup_method(self) -> None:
        dynamoDefiner = DynamoDefiner(endpoint_url="http://localhost:4566")
        dynamoDefiner.create_shop_table("my-table")
        dynamoDefiner.clear_shop_table("my-table")

こうすると前のテストの状態に依存しないように各テストを実施できます。

参考

Python で DynamoDBを使う - Qiita

【Python】Pythonプロジェクトで良い感じに使えるMakefile

僕はこうしてます。

  • Python 3.8.3
  • Poerty 1.1.4
  • pytest 6.1.2
  • black 20.8b1
  • flake8 3.8.4 (mccabe: 0.6.1, pycodestyle: 2.6.0, pyflakes: 2.2.0)
  • mypy 0.790
lint:
    poetry run black --check ./src ./tests
    poetry run flake8 ./src ./tests --exclude __init__.py --ignore E402,E501,W503
    poetry run mypy ./src ./tests --config-file ./mypy.ini

test:
    poetry run pytest ./src ./tests

export:
    poetry export --output requirements.txt

vendor:
    pip -r requirements.txt -o vendor

【pytest】E ModuleNotFoundError: No module named 'src'

Pythonのモジュール解決周りは難解ですね・・・

  • Python 3.8.3
  • Poerty 1.1.4
  • pytest 6.1.2
$ poetry run pytest ./src ./tests
ImportError while importing test module 'project_dir/tests/foo/test_bar.py'.
Hint: make sure your test modules/packages have valid Python names.
# 省略
E   ModuleNotFoundError: No module named 'src'
project_dir
├ src
│  └ foo
│      └ bar.py
└ tests
    └ foo
        └ test_bar.py # ここでエラー
# project_dir/src/tests/foo/test_bar.py

from src.foo.bar import Bar

# 以下省略

この from src...src が見つけられないようです。

原因ですが、pytestはデフォルトで test* を満たすファイル名を探して実行しようとします。
そのため test* の名前のファイルが1つもない src 下をロードできていないのではないかと考えました。

解決策として、 src ディレクトリ直下に test* を満たす適当なファイルを作成します。
今回は test_init.py としました。
pytestにロードさえしてもらえれば良いのでファイルの中身は空です。

project_dir
├ src
│  ├ test_init.py # 空ファイルを追加
│  └ foo
│      └ bar.py
└ tests
    └ foo
        └ test_bar.py # ここでエラー

そうするとちゃんと src を読んでもらえるようになりました。

【mypy】Cannot find implementation or library stub for module named 'foo.bar'

  • Python 3.8.3
  • Poerty 1.1.4
  • mypy 0.790
$ poetry run mypy ./src
src/foo/__init__.py:1: error: Cannot find implementation or library stub for module named 'src/foo/bar'
src/foo/__init__.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports

こんなエラーが出ました。
この時のディレクトリ構成は下記。

project_dir
└ src
   └ foo
       ├ __init__.py # ここでエラー
       └ bar.py

この __init__.py の内容はこんな感じ。

# project_dir/src/foo/__init__.py

from src.foo.bar import Bar

ちゃんとsrc直下にも __init__.py を置いてあげないとmypyが辿れないようです。

project_dir
└ src
   ├ __init__.py # 追加
   └ foo
       ├ __init__.py
       └ bar.py

新しく作成した __init__.py の内容は空で良いです。

$ poetry run mypy ./src
Success: no issues found in xx source files

解決しました。

【AtCoder】abc179 C - A x B + C

atcoder.jp

youtu.be

解説動画を見ながら自分なりに噛み砕いたメモ。

A * B + C = N

式変形するとこうなる。

C = N - A * B

つまり、CはAとBが決まれば自動的に決まる。

なのでAとBの組み合わせだけを考えれば良いという状態に持っていきたい。
A * Bの範囲を確定させたいので、Cの値について考える。
まずCの値が0の場合、これはNG。
A, B, Cいずれも正整数という制約があり、0は正整数ではないから。
なのでCに入り得る最小の値は1なので、これを最初の式に代入すると、

A * B + 1 = N
A * B = N - 1

よって、

1 <= A * B <= N - 1

がいえる。
(ちなみに、Cは 1 <= C <= N - 1 )

ここでAに最小の正整数1を代入してみる。

1 <= 1 * B <= N - 1

この場合は、Bの範囲は

1 <= B <= N - 1

になる。

続いてA = 2の場合。

1 <= 2 * B <= N - 1

だから、Bの範囲は

1 <= B <= (N - 1) / 2

となる。
これはNにも具体的な数値を代入して考えてみるとわかりやすい。
もし N = 10 の場合、

1 <= 2 * B <= 10 - 1
1 <= 2 * B <= 9

となり、Bの範囲は 9 / 2 の商の小数点切り捨てが最大となるのがわかるはず。

1 <= B <= 9 / 2
1 <= B <= 4

考察の材料が揃ってきたので、AにもBにも代入せずに考えると、

1 <= A * B <= N - 1

Bについて、

1 <= B <= (N - 1) / 2

と一般化できる。

あとは、Aが取り得る全ての値について考え、合算すると答えになる。
Aの範囲は

1 <= A <= N - 1

なので、コードは下記のようになる。

#include <iostream>

typedef long long ll;

int main() {
    ll n;
    cin >> n;

    auto res = 0;
    for (auto a = 1; a <= n - 1; a++) {
        res += (n - 1) / a;
    }

    cout << res << endl;
    return 0;
}