FolderDictというディレクトリ構造的にオブジェクトを保持できる辞書を作った話

なんだかんだディレクトリチックにオブジェクト管理したくなりますよね。ディレクトリ構造って使い慣れてて便利ですし。ということでこの前見つけた[PathDict](https://qiita.com/GesonAnko/items/4ac94618e469fc6c6335)を使ってチャチャっと作りました。(いろんな人が似たようなの作りまくっていますが)
PyPIに上げてpip でインストールできるようにしたので使ってみてください。

### URL
PyPI:https://pypi.org/project/folder-dict/
Github: https://github.com/Geson-anko/folder_dict

以下は和訳したREADMEとそこに書き足りなかったことです。
# インストール
Pythonのバージョンは3.9以降に対応しています。
```
pip install folder-dict
```
それかリポジトリをクローンして
```
pip install -e .
```

# 使い方
### いい感じの例
```py
from folder_dict import FolderDict
user =  {
    "name": "Joe",
	"age": 22,
	"hobbies": ["Playing football", "Podcasts"],
    "friends": {
		"Sue": {"age": 30},
    	"Ben": {"age": 35},
	    }
}
fd = FolderDict(user, sep="/")
print(fd["name"]) # Joe
print(fd["friends/Sue"]["age"]) # 30
print(fd["age", "friends/Ben/age"]) # 22, 35

# 割り当て
fd["sex/real"] = "male"
fd["/sex/virtual"] = "female"

print(fd.list()) # 全てのパスを返します。
# [
#     /name,
#     /age,
#     /hobbies,
#     /friends/Sue/age,
#     /friends/Ben/age,
#     /sex/real,
#     /sex/virtual
# ]
```

### インポートと初期化
dict, PathDict, FolderDictのいずれかで初期化します。
```py
from folder_dict import FolderDict
fd = FolderDict(sep="/") 
# sepはデフォルトで "/". キーワード専用引数
fd = FolderDict({"age":10})
--> FolderDict({"age": 10})
```


### 取得する
```py 
user =  {
    "name": "Joe",
	"age": 22,
	"hobbies": ["Playing football", "Podcasts"],
    "friends": {
		"Sue": {"age": 30},
    	"Ben": {"age": 35},
	    }
}

fd = FolderDict(user, sep="/")
> fd["name"]
--> Joe

> fd["friend/Sue/age"]
--> 30

> fd["/friend/Ben"]
--> FolderDict({
    "age": 30,
})
```

複数のパスで同時に取得もできます。
```py
> fd["name", "age","friends/Ben/age"]
--> ("Joe", 22, 35)
```

### 割り当てる
```py
fd = FolderDict(sep="/")
fd["path/to/obj_name"] = 10

> fd["path/to/obj_name"]
10
```

もちろん複数同時に割り当てることもできます。
```py
fd["a/b", "c/d"] = (0,1)
> fd
--> FolderDict({
    "a/b": 0,
    "c/d": 1
})
```

## リストアップする
FolderDictが持つ全てのパスを返します。
```py
fd["a/b", "c/d"] = (0,1)
> fd.list()
--> ["/a/b", "/c/d"]
```

### ダイレクトカード
ちょっとわかりにくいのですが、`~`でパスの構造に関係なく特定の文字列で始まったり終わったりするパスを選択して取得できます。(私の次のプロダクトで必要な機能がコレ）

```py
fd["a/b/c", "d/e/f/abc", "g/h/c", "a/i"] = (1,2,3,4)
> fd.list("~c") # 最後がcで終わるやつ
--> ["/a/b/c", "/d/e/f/abc", "/a/h/c"]

> fd.list("a~") # 最初がaで始まるやつ fd.list("/a")も同じ
--> ["/a/b/c", "/a/i"]

> fd.list("a~c") # aで始まってbで終わるやつ
--> ["/a/b/c"]

> fd.list("~/c") # 階層的に最後がcのやつ
--> ["/a/b/c", "/a/h/c"]
```
ちなみに`~`だと不都合が生じる場合は`<FolderDict>.direct_char`に`~`ではない文字を割り当てれば良いです。
```py
fd.direct_char = "-"
```

## その他プロパティ
```py
fd["a/b","a/c"] = (1,2)

# 辞書で返します
> fd.dict 
--> {'a': {'b': 1, 'c': 2}}

# PathDictにして返します。
> fd.PathDict 
-->PathDict({
  "a": {
    "b": 1,
    "c": 2  
  }
})

# パスのセパレータを返します。
> fd.sep
--> '/'

```

### `__repr__`とか`__str__`とか
こんな感じ
```py
> fd
--> FolderDict(sep='/', [
    /path/to/a.txt = 'a',
    /path/to/b.txt = 'b',
    /path/to/c.bin = b'c'
])
```
# 未実装(2022/4/14現在)
個人的に実装したかったけど使わないので後回しにしてるやつです。
### ワイルドカード
`glob.glob`の`*`使うやつ
```py
fd["path/to/a.txt", "path/to/b.txt", "path/to/c.bin"] = "a","b",b"c"
> fd.list("path/to/*.txt")
--> ["path/to/a.txt", "path/to/b.txt"]
```


# 注意点
このライブラリまだバージョン`0.*.*`なので大きな仕様変更があるかもしれません。（できるだけしたくないですが）

# まとめ
FolderDictっていうディレクトリ構造チックにオブジェクトを登録できる辞書を作りましたとさ。
もしよければ使ってみてください！