前回の記事で、デバッグ用に現在時刻とか送信予定時刻などをprint()していたのですが、思いつきで「syslogにprint()していたものをDiscordに全部送信してしまえ」と思って変えたら、エラーが発生して2日ほど苦戦しておりました。
そのときの対処法を紹介したいと思います。
本題
エラーを吐いていたときのコード
@tasks.loop(seconds=60)
async def loop():
global time_set
global tem_set
w_list = ["月", "火", "水", "木", "金", "土", "日"] # 進化したよ!
now_t, now_dt = datetime.now().strftime('%H:%M'), w_list[datetime.now().weekday()]
ch = client.get_channel(771155766056452167)
await ch.send(f"現在の時刻:`{now_t}`/今日の曜日:`{now_dt}`/送信予定時刻:`{time_set}`/送信予定体温:`{tem_set}`")
if now_dt != "日": # 日曜日以外だったら送信するようにした
if now_t == time_set: # 送信予定時刻になった?
dt_now = datetime.now().strftime("%Y-%m-%d") # 現在時刻を2020-01-01の形で取得、dt_nowに格納
file_name = "cfg.json"
with open(file_name, "r", encoding="utf-8")as f:
cfg = json.load(f)
cfg["output"]["ans_1"] = f"{dt_now}"
cfg["output"]["ans_4"] = f"{tem_set}"
params = {"entry.{}".format(cfg["entry"][k]): cfg["output"][k] for k in cfg["entry"].keys()}
res = requests.get(cfg["form_url"] + "formResponse", params=params)
if res.status_code == 200:
await template_embed(message=768274673984208926, title="ログ情報", description=f"[URL]({res.url})",
name_1="完了状態", name_2="送信された体温", value_1="成功しました", color=discord.Color.green())
else:
res.raise_for_status()
await template_embed(message=768274673984208926, title="ログ情報", name_1="完了状態", name_2="送信予定だった体温",
value_1="エラーが発生しました。", color=discord.Color.red())
else:
if now_t == "21:00":
time_set = setting_time_set()
tem_set = set_tem()
await template_embed(message=768274673984208926, title="送信時刻更新のお知らせ", name_1="次回の送信予定時刻", name_2="送信予定の体温",
value_1=time_set, color=discord.Color.blue())
このコードを実際に動作させると、以下のようなエラーが出るんです。
最初は、IDのコピペミスかなと思っていたのですが、再度コピペしてもエラーを吐いたので何か別の要因があるのでは?と調べてみたら、ありましたよ!
client.get_channel()などの関数は、BOTの準備が完了するまでNoneを返します。
例えば、プログラムの冒頭でいきなりget_channel()をしていませんか?
これを避けるには、readyイベントが発生した「後」に取得を行う必要があります。
「えっ、あ、そういえば...」となりました(泣)
俺の2日はどこいった。
AttributeError: 'NoType' object has no attribute 'send'
対処法
対処法は意外と簡単でした、はい。
先程の記事のget_channel()
をする前に、wait_until_ready()
(リファレンス)を入れればいいだけです。
@tasks.loop(seconds=60)
async def loop():
global time_set
global tem_set
w_list = ["月", "火", "水", "木", "金", "土", "日"] # 進化したよ!
now_t, now_dt = datetime.now().strftime('%H:%M'), w_list[datetime.now().weekday()]
await client.wait_until_ready()
ch = client.get_channel(771155766056452167)
await ch.send(f"現在の時刻:`{now_t}`/今日の曜日:`{now_dt}`/送信予定時刻:`{time_set}`/送信予定体温:`{tem_set}`")
if now_dt != "日": # 日曜日以外だったら送信するようにした
if now_t == time_set: # 送信予定時刻になった?
dt_now = datetime.now().strftime("%Y-%m-%d") # 現在時刻を2020-01-01の形で取得、dt_nowに格納
file_name = "cfg.json"
with open(file_name, "r", encoding="utf-8")as f:
cfg = json.load(f)
cfg["output"]["ans_1"] = f"{dt_now}"
cfg["output"]["ans_4"] = f"{tem_set}"
params = {"entry.{}".format(cfg["entry"][k]): cfg["output"][k] for k in cfg["entry"].keys()}
res = requests.get(cfg["form_url"] + "formResponse", params=params)
if res.status_code == 200:
await template_embed(message=768274673984208926, title="ログ情報", description=f"[URL]({res.url})",
name_1="完了状態", name_2="送信された体温", value_1="成功しました", color=discord.Color.green())
else:
res.raise_for_status()
await template_embed(message=768274673984208926, title="ログ情報", name_1="完了状態", name_2="送信予定だった体温",
value_1="エラーが発生しました。", color=discord.Color.red())
else:
if now_t == "21:00":
time_set = setting_time_set()
tem_set = set_tem()
await template_embed(message=768274673984208926, title="送信時刻更新のお知らせ", name_1="次回の送信予定時刻", name_2="送信予定の体温",
value_1=time_set, color=discord.Color.blue())
あら、一発で解決()
まとめ
-
tasks.loop
内でget_channel()
などの関数を際にエラーが出るときは、wait_until_ready()
を入れれば治る。
すっごいざっくりしたまとめでごめんなさい...
同じような状況に陥っている人の助けになれば、幸いです。