この記事は、Pythonista3 Advent Calendar 2022 の11日目の記事です。
一方的な偏った目線で、Pythonista3 を紹介していきます。
ほぼ毎日iPhone(Pythonista3)で、コーディングをしている者です。よろしくお願いします。
以下、私の2022年12月時点の環境です。
--- SYSTEM INFORMATION ---
* Pythonista 3.3 (330025), Default interpreter 3.6.1
* iOS 16.1.1, model iPhone12,1, resolution (portrait) 828.0 x 1792.0 @ 2.0) 828.0 x 1792.0 @ 2.0
他の環境(iPad や端末の種類、iOS のバージョン違い)では、意図としない挙動(エラーになる)なる場合もあります。ご了承ください。
ちなみに、model iPhone12,1
は、iPhone11 です。
探訪に最適な探訪ツールを使う(作る)
漫画ブラック・ジャックにて、ブラック・ジャックが自分自身でエキノコックスを抽出した開腹手術のエピソードがありました。
我々もPythonista3 で、Pythonista3 の中身を覗いてみましょう!!(?)
また、ブラック・ジャックですら自身を見るための鏡やメスなどを使っていたので、我々もprint
確認だけでは、辛い部分があるので、佳きツールを呼び出します。
注意事項
免責事項として書いています。
アプリやOS 内部構造を操作することになります。
変更や削除で、アプリやOS が起動不可になることもありえます。
不具合に関しては自己責任でお願い致します。
webbrowser
モジュール
21.1. webbrowser — Convenient Web-browser controller — Python 3.6.1 documentation
標準的な使用方法については割愛しますが、Pythonista3 用にwebbrowser
モジュールはカスタムされています。
そのカスタムされている機能をつかいます。
pythonista-url | App Extensions and Shortcuts — Python 3.6.1 documentation
挙動確認
from pathlib import Path
import webbrowser
origin_path = Path()
url = 'pythonista3://' + str(origin_path)
webbrowser.open(url)
なんということでしょう!
ディレクトリがGUI で表示されています。
GUI で見るScriptLibrary のようにも見えますが、前回探訪した際と同様に、GUI のScriptLibrary では確認できなかったフォルダも確認できます。
webbrowser.open
のurl
にpythonista3://
をつけることで、GUI でよびだせるようになるのです。
左上の<
で、戻ることもできます。
が、挙動が幾分バギーなので私はアプリを一度落として再起動させています。
もっと探訪を
GUI で確認できることにより、ディレクトリの行き来が容易になりました。
階層を指定できるようにすれば、さらに素敵ですね:
from pathlib import Path
import webbrowser
def parent_level(level_int):
return '../' * level_int
origin_path = Path()
level = 2
target_url = origin_path / parent_level(level)
webbrowser.open(f'pythonista3://{target_url}')
level
で上の階層を指定できるようにしました。
-
0
:Documents
-
1
:Pythonista3
-
2
:ID
(それぞれ-違う-英数字
)
と、登っていけます。
しかし、
-
3
:AppGroup
より上から、内容が見えなくなります。
ディレクトリの内容を読み取れませんでした。
このディレクトリを表示する権限がない可能性があります(例:別のアプリに属しているため)。
iOS 側の権限でアクセスできない場所もあるのです。
とこが、
-
8
:private
-
9
:(root)
は、アクセスが可能になっています。面白いですね。
9
がroot となるので、それ以降の数値を入れても9
と同じ結果となります。
補足
webbrowser.open
で使用しているorigin_path = Path()
は、「現在のpath」を示しているのではありません。
PosixPath
の.
を便宜的に呼び出ししています。
つまり、以下コードと呼び出しは同意義となります:
import webbrowser
webbrowser.open('pythonista3://.')
pythonista3://.
は、Documents
直下となります。
階層指定:
import webbrowser
def parent_level(level_int):
return '../' * level_int
origin_path = './'
level = 9
target_url = origin_path + parent_level(level)
webbrowser.open(f'pythonista3://{target_url}')
pathlib
でのメリットとしては、print
時に.resolve()
すれば絶対パスが確認できるところでしょうか。
from pathlib import Path
import webbrowser
def parent_level(level_int):
return '../' * level_int
origin_path = Path()
level = 2
target_url = origin_path / parent_level(level)
resolve_path = target_url.resolve()
#webbrowser.open(f'pythonista3://{target_url}')
階層の整理を
一度ディレクトリ階層の整理をましょう。アクセス不可だったフォルダもあるので、網羅的に確認します。
🙆♂️(9: root
└ 🙆♂️(8: private
└ 🙅♀️(7: var
└ 🙅♀️(6: mobile
└ 🙅♀️(5: Containers
└ 🙅♀️(4: Shared
└ 🙅♀️(3: AppGroup
└ 🙆♂️(2: それぞれ-違う-英数字
└ 🙆♂️(1: Pythonista3
└ 🙆♂️(0: Documents
アクセス可能が🙆♂️
で、不可を🙅♀️
としています。
表示用としてのコードは:
from pathlib import Path
def parent_level(level_int):
return '../' * level_int
def is_access(index):
_level = index + 1
_path = cwd_path / parent_level(deep - _level)
return True if list(_path.glob('*')) else False
cwd_path = Path().cwd()
directly_list = str(cwd_path).split('/')
deep = len(directly_list)
for n, d in enumerate(directly_list):
access = '🙆♂️' if is_access(n) else '🙅♀️'
if not d:
d = 'root'
output = f'{access}({deep - n -1}: {d}'
if n:
tab = ' ' * n
print(f'{tab} └ {output}')
else:
print(f'{output}')
このような構成になっているのですね。普段意識することがなくとも内部が見れるのは面白いですね。
え、待って。え、他にもパスが見えたんだけど?
ディレクトリ構造を意識して見ていると、普段見ている情報でも、気になる情報が出てきます。
先ほどの絶対パスを確認したinspector 情報です
絶対パスに気を取られていましたが、webbrowser
にvar/
とかありますね😎
詳細を見てみると、、、
/var/containers/Bundle/Application/それぞれ-違う-英数字/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/webbrowser.py
これは、探索しに行かなければならないですねぇ😎
(ちなみに)var
フォルダについて
いままでアクセスしていたvar
と、webbrowser
から見つけたvar
はフォルダ名は同じですが、違う階層にあるものです。
/(root)
├ .ba
├ .file
├ .mb
├ Applications
├ Developer
├ Library
├ System
├ bin
├ cores
├ dev
├ etc
├ private
├ etc
├ preboot
├ system_data
├ var ← 今までの「var」
└ xarts
├ sbin
├ tmp
├ usr
└ var ← これから探索する「var」
「あれ?どこの何をアクセスしようとしてたんだっけ?」という時に参照ください。
Pythonista3.app
ディレクトリへ行く
探索ルートとしては
-
.
:Documents
(便宜上のスタート位置)-
(root)/private/var/mobile/Containers/Shared/AppGroup/それぞれ-違う-英数字1/Pythonista3/Documents
-
(root)
は私が示しやすいように、追記してます
-
-
-
(root)
まで、階層を登る -
(root)/var/containers/Bundle/Application/それぞれ-違う-英数字2/Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/webbrowser.py
を目指し降りてゆく-
それぞれ-違う-英数字2
は、それぞれ-違う-英数字1
とは違う値
-
-
Pythonista3.app
で止まる -
webbrowser.open
で覗き見る
そのコードが:
from pathlib import Path
import webbrowser
def parent_level(level_int):
return '../' * level_int
# todo: 今回行きたいディレクトリパスを取得する処理
wbb_file_path = webbrowser.__file__ # webbrowser モジュールのファイルパス
wbb_path_list = wbb_file_path.split('/') # インデックスでアクセスできるように、ファイルパスをlist化
app_index = wbb_path_list.index(
'Pythonista3.app') # webbrowser 格納先の手前のPythonista3.app のインデックスを取得
app_path_list = wbb_path_list[:app_index + 1] # Pythonista3.app 以降の情報を排除
app_file_path = '.' + '/'.join(app_path_list) # Pythonista3.app までのディレクトリパスを作成
# todo: ここから、いつもの処理
origin_path = Path()
level = 9
hub_path = origin_path / parent_level(level)
target_path = hub_path / app_file_path
webbrowser.open(f'pythonista3:/{target_path}')
resolve_origin_path = origin_path.resolve()
resolve_target_path = target_path.resolve()
ほぼ、変数を外出ししているので、inspector より値確認ができます。
試しに、スタート位置のパスと、ゴール位置のパスを絶対パスとしているので確認してみてください。
resolve_origin_path = origin_path.resolve()
resolve_target_path = target_path.resolve()
アプリケーションの情報が入ってる
Documents
内のsite-packages
は、我々が追加できるモジュールが格納されるディレクトリでした。Pythonista3.app
内には、標準モジュールやPythonista3 アプリで事前に入っているモジュールが格納されていましたね。
Pythonista3.app
は、Pythonista3/Documents/
のPythonista3
ではありません。わかり辛いですが、、、
直下には、Pythonista3 のアイコン画像(それの色違い)やフォントなとなど様々なファイルがありました
他にも、画像や音のファイルが格納されているMedia
:
/private/var/containers/Bundle/Application/それぞれ-違う-英数字2/Pythonista3.app/Media/
Theme のjson ファイルが格納されているフォルダまで:
/private/var/containers/Bundle/Application/それぞれ-違う-英数字2/Pythonista3.app/Media/
Pythonista3 アプリを触っていればいるだけ「こんな所に、こんなファイルがあるのか」と、探訪が止まりませんね。
冒頭にもお伝えしましたが、これらのファイルの扱いは丁重におこなってくださいね。
何をどうしたら動かなくなる。など、判断がつかないものは自己責任でお願いします。
次回は
自分(Pythonista3)で自分の中身(Pythonista3)を見るなんて、なかなかスリリングな探訪でしたね。
今回は闇雲に、手当たり次第・見つけ次第で確認行きましたが、以下のようにiOS, iPadOS のベースの部分を理解すると目的に合わせた探し方もできるかもしれません。
iOSアプリケーションのフォルダ構成|【Swift】ARシューティングアプリを作ってみよう!|Techpit
今こそ復習したい、iOSアプリのディレクトリ構成 - Qiita
私自身はiOS アプリ開発の経験もないので、Pythonista3 をいじりながら「なるほどねー」と雰囲気で把握している感じです。ですので、理解違いで説明が違っている所が多いかもしれません。
また「ディレクトリ」「フォルダ」の記載ゆらぎが多々あったかと思われます。こちらも雰囲気で書いており重ねてお詫び申し上げます。。。
次回は、iOS 自体の探訪を中心に紹介したいと思います。
ここまで、読んでいただきありがとうございました。
せんでん
Discord
Pythonista3 の日本語コミュニティーがあります。みなさん優しくて、わからないところも親身に教えてくれるのでこの機会に覗いてみてください。
書籍
iPhone/iPad でプログラミングする最強の本。
その他
- サンプルコード
Pythonista3 Advent Calendar 2022 でのコードをまとめているリポジトリがあります。
コードのエラーや変なところや改善点など。ご指摘やPR お待ちしておりますー
なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー
やれるか、やれないか。ではなく、やるんだけども、紹介説明することは尽きないと思うけど、締め切り守れるか?って話よ!(クズ)
— pome-ta (@pome_ta93) November 4, 2022
Pythonista3 Advent Calendar 2022 https://t.co/JKUxA525Pt #Qiita
- GitHub
基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。