2012-09-17 3 views
4

argparse을 사용하여 인수를 timedelta 개체로 변환하려고합니다. 내 프로그램은 사용자가 제공 한 문자열을 읽고 나중에 사용하기 위해 다양한 datetime 개체로 변환합니다. 그래도 filter_length 인수를 올바르게 처리 할 수 ​​없습니다. 내 코드 : timedelta 값으로 1을 전달 내가 프로그램을 실행Python argparse : 인수에서 timedelta 객체를 만드시겠습니까?

import datetime 
import time 
import argparse 

def mkdate(datestring): 
    return datetime.datetime.strptime(datestring, '%Y-%m-%d').date() 

def mktime(timestring): 
    return datetime.datetime.strptime(timestring, '%I:%M%p').time() 

def mkdelta(deltatuple): 
    return datetime.timedelta(deltatuple) 

parser = argparse.ArgumentParser() 
parser.add_argument('start_date', type=mkdate, nargs=1) 
parser.add_argument('start_time', type=mktime, nargs=1,) 
parser.add_argument('filter_length', type=mkdelta, nargs=1, default=datetime.timedelta(1))#default filter length is 1 day. 

는, (나는 단지 그것을 언젠가되고 싶은) :

> python program.py 2012-09-16 11:00am 1 

그러나 나는 다음과 같은 오류 얻을 :

>>> program.py: error: argument filter_length: invalid mkdelta value: '1' 

값이 유효하지 않은 이유를 모르겠습니다. 나는이 같은 자체에 mkdelta 함수를 호출하는 경우 :

mkdelta(1) 
print mkdelta(1) 

이 반환

datetime.timedelta(1) 
1 day, 0:00:00 

이것은 내가 찾고 값이 정확히이다. 누군가가 argparse을 사용하여 올바르게이 변환을 수행하는 방법을 알아낼 수 있습니까?

답변

4

함수가 문자열 인수를 처리하지 않습니다. 이는 argparse가 전달하는 문자열 인수입니다. 그것에 int() 전화 : 당신이 일 이상을 지원해야하는 경우 timedelta 인수로 전달 된 인수를 구문 분석하는 방법을 찾아야 할 것이다

def mkdelta(deltatuple): 
    return datetime.timedelta(int(deltatuple)) 

.

당신 수, 예를 들어, 지원 d, h, 일, 시간, 분, 초 나타 내기 위해 m 또는 s 포스트 픽스에 대한 :

_units = dict(d=60*60*24, h=60*60, m=60, s=1) 
def mkdelta(deltavalue): 
    seconds = 0 
    defaultunit = unit = _units['d'] # default to days 
    value = '' 
    for ch in list(str(deltavalue).strip()): 
     if ch.isdigit(): 
      value += ch 
      continue 
     if ch in _units: 
      unit = _units[ch] 
      if value: 
       seconds += unit * int(value) 
       value = '' 
       unit = defaultunit 
      continue 
     if ch in ' \t': 
      # skip whitespace 
      continue 
     raise ValueError('Invalid time delta: %s' % deltavalue) 
    if value: 
     seconds = unit * int(value) 
    return datetime.timedelta(seconds=seconds) 

이제 mkdelta 방법은 더 완전한 델타를 받아, 여전히 심지어 정수를 :

>>> mkdelta('1d') 
datetime.timedelta(1) 
>>> mkdelta('10s') 
datetime.timedelta(0, 10) 
>>> mkdelta('5d 10h 3m 10s') 
datetime.timedelta(5, 36190) 
>>> mkdelta(5) 
datetime.timedelta(5) 
>>> mkdelta('1') 
datetime.timedelta(1) 

기본 단위는 일입니다.

+0

그러나이 기능은 작동하지만 날짜를 함수에만 지정할 수 있습니다. 실제로는 전체 timedelta 표기법을 지원하지 않습니다. ([days [, seconds [, microseconds [, milliseconds [, minutes [, hours [, weeks]]]]]]). 나는 datetime 값의 전체 범위를 인수로 전달할 수 있어야합니다. 그 일을 어떻게 하죠? – user1675914

+0

텍스트 형식을 고안하거나 여러 명령 줄 스위치를 사용한 다음이를 timedelta 개체의 인수로 구문 분석해야합니다. –

+1

왜 전체 timedelta 표기법을 지원해야합니까? 귀하의 요구 사항에서 당신은 하루 부분 만 필요하다고 말합니다. 사용자가 더 많은 플래그를 지정하게하려면 nargs = '?'를 전달해야합니다. 이렇게하면 mkdelta는 나머지 인수가있는 문자열을받습니다. –

6

오류 메시지에 '1' 주위에 따옴표가 표시되어 있는지 확인하십시오. mkdelta에 문자열을 전달하는 반면 테스트 코드에서는 정수를 전달합니다.

+0

문자열이 아닌 객체를 인수로 전달하는 방법은 무엇입니까? – user1675914

+0

테스트 코드에서 간단하게'mkdelta ('1')'을 입력하십시오. 그렇지 않으면 Martijn Pieters가 deltatuple을 int로 형변환하여 제안한대로 코드를 수정하십시오. –

+0

또한, 그렇게한다면 deltatuple의 이름을 변경 하시겠습니까? –

2

사용자 지정 작업을 사용하여 나머지 모든 args를 수집하고이를 timedelta으로 파싱 할 수 있습니다.이것은 당신이 CLI를 작성할 수 있도록, 또한 등 --days, --seconds에 대한 선택적 인수를 제공 할 수있는 등

% test.py 2012-09-16 11:00am 2 3 4 5 
datetime.timedelta(2, 3, 5004) # args.filter_length 

으로 CLI 명령을 쓸 수

명령 등

% test.py 2012-09-16 11:00am --weeks 6 --days 0 
datetime.timedelta(42)   # args.filter_length 

% test.py 2012-09-16 11:00am --weeks 6.5 --days 0 
datetime.timedelta(45, 43200) 

import datetime as dt 
import argparse 

def mkdate(datestring): 
    return dt.datetime.strptime(datestring, '%Y-%m-%d').date() 

def mktime(timestring): 
    return dt.datetime.strptime(timestring, '%I:%M%p').time() 

class TimeDeltaAction(argparse.Action): 
    def __call__(self, parser, args, values, option_string = None): 
     # print '{n} {v} {o}'.format(n = args, v = values, o = option_string) 
     setattr(args, self.dest, dt.timedelta(*map(float, values))) 

parser = argparse.ArgumentParser() 
parser.add_argument('start_date', type = mkdate) 
parser.add_argument('start_time', type = mktime) 
parser.add_argument('--days', type = float, default = 1) 
parser.add_argument('--seconds', type = float, default = 0) 
parser.add_argument('--microseconds', type = float, default = 0) 
parser.add_argument('--milliseconds', type = float, default = 0) 
parser.add_argument('--minutes', type = float, default = 0) 
parser.add_argument('--hours', type = float, default = 0) 
parser.add_argument('--weeks', type = float, default = 0) 
parser.add_argument('filter_length', nargs = '*', action = TimeDeltaAction) 

args = parser.parse_args() 
if not args.filter_length: 
    args.filter_length = dt.timedelta(
     args.days, args.seconds, args.microseconds, args.milliseconds, 
     args.minutes, args.hours, args.weeks) 
print(repr(args.filter_length))