有些人遵循制定新年决议的传统。然而,一年时间太长了,所以我计划一个季度主题或轨迹。每个季度,我都会坐下来看看接下来三个月的季节,并决定在那段时间里我要做什么。
对于我最新的主题,我决定每天写日记。我喜欢有明确的承诺,所以我承诺每天写五分钟。我也喜欢有可观察的承诺,即使只是对我自己而言,所以我将我的条目放在 Git 中。
我决定围绕我的日记编写一些自动化程序,并转向我最喜欢的自动化工具:Jupyter。Jupyter 的一个有趣功能是 ipywidgets,这是一组用于 Jupyter Notebooks、JupyterLab 和 IPython 内核的交互式 HTML 小部件。
如果您想跟随本文中的代码进行操作,请注意使您的 Jupyter lab 实例支持小部件可能会有点令人沮丧。请按照 这些说明 进行设置。
导入 ipywidgets 模块
首先,您需要导入很多东西,例如 ipywidgets 和 Twisted。Twisted 模块有助于创建异步计时器
import twisted.internet.asyncioreactor
twisted.internet.asyncioreactor.install()
from twisted.internet import reactor, task
import ipywidgets, datetime, subprocess, functools, os
设置定时条目
使用 Twisted 实现计时器利用了 task.LoopingCall
。但是,结束循环调用的唯一方法是使用异常。倒计时时钟总是会停止,因此您需要一个自定义异常来指示“一切正常;计数器已完成”
class DoneError(Exception):
pass
现在您已经编写了异常,您可以编写计时器。第一步是创建一个带有文本标签小部件的 ipywidgets.Label
。循环使用 divmod
来计算分钟和秒,然后设置标签的文本值
def time_out_counter(reactor):
label = ipywidgets.Label("Time left: 5:00")
current_seconds = datetime.timedelta(minutes=5).total_seconds()
def decrement(count):
nonlocal current_seconds
current_seconds -= count
time_left = datetime.timedelta(seconds=max(current_seconds, 0))
minutes, left = divmod(time_left, minute)
seconds = int(left.total_seconds())
label.value = f"Time left: {minutes}:{seconds:02}"
if current_seconds < 0:
raise DoneError("finished")
minute = datetime.timedelta(minutes=1)
call = task.LoopingCall.withCount(decrement)
call.reactor = reactor
d = call.start(1)
d.addErrback(lambda f: f.trap(DoneError))
return d, label
从 Jupyter 小部件保存文本
下一步是编写一些东西,将您在日记中键入的文本保存到文件中并将其提交到 Git。此外,由于您将写日记五分钟,您需要一个小部件来为您提供书写空间(滚动始终是可能的,但一次看到更多文本会更好)。
这使用了小部件 Textarea
,这是一个您可以书写的文本字段,以及 Output
来提供反馈。这很重要,因为 git push
可能需要时间或失败,具体取决于网络。如果备份失败,则向用户发出反馈警报非常重要
def editor(fname):
textarea = ipywidgets.Textarea(continuous_update=False)
textarea.rows = 20
output = ipywidgets.Output()
runner = functools.partial(subprocess.run, capture_output=True, text=True, check=True)
def save(_ignored):
with output:
with open(fname, "w") as fpout:
fpout.write(textarea.value)
print("Sending...", end='')
try:
runner(["git", "add", fname])
runner(["git", "commit", "-m", f"updated {fname}"])
runner(["git", "push"])
except subprocess.CalledProcessError as exc:
print("Could not send")
print(exc.stdout)
print(exc.stderr)
else:
print("Done")
textarea.observe(save, names="value")
return textarea, output, save
continuous_update=False
是为了不保存和发送到 Git 的每个字符。相反,它会在您失去焦点时保存。该函数还返回 save
函数,因此可以显式调用它。
创建布局
最后,您可以使用 ipywidgets.VBox
将所有这些放在一起。这是一个包含几个小部件并垂直显示它们的东西。还有一些其他排列小部件的方法,但这很简单并且足够好
def journal():
date = str(datetime.date.today())
title = f"Log: Startdate {date}"
filename = os.path.join(f"{date}.txt")
d, clock = time_out_counter(reactor)
textarea, output, save = editor(filename)
box = ipywidgets.VBox([
ipywidgets.Label(title),
textarea,
clock,
output
])
d.addCallback(save)
return box
唷!您已经定义了一个用于写日记的函数,现在是时候尝试一下了。
journal()

(Moshe Zadka,CC BY-SA 4.0)
您有五分钟时间——开始写作吧!
评论已关闭。