如何在不使用 eval 的情况下将字符串转换为 dateutil 工作日元组
how to convert a string to a dateutil weekday tuple without using eval
我正在使用 dateutil 根据输入文件生成计划。
我的配置文件如下所示:
[alarm1]
time = 8:00
days = MO
[alarm2]
time = 9:00
days = TU, WE
[alarm3]
time = 22:00
days = MO, WE, FR
etc..
我正在使用 dateutil 生成基于此的计划。
这是一些示例代码,为了简洁起见,我省略了控制流和导入代码。
from dateutil.rrule import *
from dateutil.parser import *
import datetime
import configparser
alarms = rruleset()
time = parse(alarm_parser.get(alarm_section, 'time')).time()
date = datetime.date.today()
alarm_time= datetime.datetime.combine(date, time)
days = '(' + alarm_parser.get(alarm_section, 'days') + ',)'
alarm_days = eval(days)
alarms.rrule(rrule(WEEKLY, dtstart = alarm_datetime, byweekday = alarm_days, count = 1))
感谢 eval,这段代码现在可以工作了 但是,eval 显然是有风险的。
我试过 rrulestr(),但该命令似乎不接受 byweekday = 作为参数的一部分。
如何在不使用 eval 的情况下将配置文件中的字符串转换为 rrule 可以使用的元组?我试过 ast.literal_eval,但出现以下错误
ValueError: malformed node or string: <_ast.Name object at 0xb68e2430>
执行此操作的简单方法是对此进行一些变体:
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
daymap = {'MO': MO, 'TU': TU, 'WE': WE, 'TH': TH, 'FR': FR, 'SA': SA, 'SU': SU}
daystr = 'TU, TH'
days = [daymap[day.strip()] for day in daystr.split(',')]
但是,您也可以通过 rrulestr
使用 BYDAY
(不是 BYWEEKDAY
)参数来完成此操作:
from dateutil.rrule import rrulestr
base_rrstr = ('DTSTART:{alarm_datetime:%Y%m%dT%H%M%S}\n' +
'FREQ={freq_str};COUNT={count_str};BYDAY={day_str}')
alarm_datetime = datetime.datetime.today()
freq_str = "WEEKLY"
count_str = "1"
day_str = "TU,TH"
crr = rrulestr(base_rrstr.format(alarm_datetime=alarm_datetime,
freq_str=freq_str,
count_str=count_str,
day_str=day_str))
我需要一个稍微复杂一点的 Paul 简单代码版本(可以处理括号内的偏移量,例如 "FR(+2)")。这是我想出的:
import re
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
_daymap = {"MO": MO, "TU": TU, "WE": WE, "TH": TH, "FR": FR, "SA": SA, "SU": SU}
_dayre = re.compile(r"(MO|TU|WE|TH|FR|SA|SU)(?=\(([-+]?[0-9]+)\))?")
def parsedays(daystr):
for day in daystr.split(","):
m = _dayre.match(day.strip())
if m:
weekday, offset = m.groups()
result = _daymap[weekday]
if offset:
result = result(int(offset))
yield result
def dumpdays(days):
return ",".join(str(d) for d in days)
使用 Python 3.7.3
测试
我正在使用 dateutil 根据输入文件生成计划。
我的配置文件如下所示:
[alarm1]
time = 8:00
days = MO
[alarm2]
time = 9:00
days = TU, WE
[alarm3]
time = 22:00
days = MO, WE, FR
etc..
我正在使用 dateutil 生成基于此的计划。
这是一些示例代码,为了简洁起见,我省略了控制流和导入代码。
from dateutil.rrule import *
from dateutil.parser import *
import datetime
import configparser
alarms = rruleset()
time = parse(alarm_parser.get(alarm_section, 'time')).time()
date = datetime.date.today()
alarm_time= datetime.datetime.combine(date, time)
days = '(' + alarm_parser.get(alarm_section, 'days') + ',)'
alarm_days = eval(days)
alarms.rrule(rrule(WEEKLY, dtstart = alarm_datetime, byweekday = alarm_days, count = 1))
感谢 eval,这段代码现在可以工作了 但是,eval 显然是有风险的。
我试过 rrulestr(),但该命令似乎不接受 byweekday = 作为参数的一部分。
如何在不使用 eval 的情况下将配置文件中的字符串转换为 rrule 可以使用的元组?我试过 ast.literal_eval,但出现以下错误
ValueError: malformed node or string: <_ast.Name object at 0xb68e2430>
执行此操作的简单方法是对此进行一些变体:
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
daymap = {'MO': MO, 'TU': TU, 'WE': WE, 'TH': TH, 'FR': FR, 'SA': SA, 'SU': SU}
daystr = 'TU, TH'
days = [daymap[day.strip()] for day in daystr.split(',')]
但是,您也可以通过 rrulestr
使用 BYDAY
(不是 BYWEEKDAY
)参数来完成此操作:
from dateutil.rrule import rrulestr
base_rrstr = ('DTSTART:{alarm_datetime:%Y%m%dT%H%M%S}\n' +
'FREQ={freq_str};COUNT={count_str};BYDAY={day_str}')
alarm_datetime = datetime.datetime.today()
freq_str = "WEEKLY"
count_str = "1"
day_str = "TU,TH"
crr = rrulestr(base_rrstr.format(alarm_datetime=alarm_datetime,
freq_str=freq_str,
count_str=count_str,
day_str=day_str))
我需要一个稍微复杂一点的 Paul 简单代码版本(可以处理括号内的偏移量,例如 "FR(+2)")。这是我想出的:
import re
from dateutil.rrule import MO, TU, WE, TH, FR, SA, SU
_daymap = {"MO": MO, "TU": TU, "WE": WE, "TH": TH, "FR": FR, "SA": SA, "SU": SU}
_dayre = re.compile(r"(MO|TU|WE|TH|FR|SA|SU)(?=\(([-+]?[0-9]+)\))?")
def parsedays(daystr):
for day in daystr.split(","):
m = _dayre.match(day.strip())
if m:
weekday, offset = m.groups()
result = _daymap[weekday]
if offset:
result = result(int(offset))
yield result
def dumpdays(days):
return ",".join(str(d) for d in days)
使用 Python 3.7.3
测试