2017-03-17 8 views
3

GitHub 속도 제한 예외를 처리하기 위해 컨텍스트 관리자를 작성하려고합니다. 본질적으로 오류 메시지를 듣고 싶을 때 동적으로 재설정 시간을 가져오고 (모두 GitHub API를 통해 수행됨) 해당 시간 동안 기다립니다. 어느 시점에서 프로그램을 다시 시작하고 작업을 완료하는 데 필요한만큼이 작업을 수행하고 싶습니다. 대신 계속 주위를 다시 선회의Context Manager로 API 속도 제한을 처리하는 방법은 무엇입니까?

@contextlib.contextmanager 
def api_rate_manager(api_obj: g3.GitHub): 
    # Check for the API ratelimit being exhausted. Limited to 5k 
    # requests per hour. 
    try: 
     yield 
    except GitHubError as e: 
     if 'rate limit exceeded' in e.msg.lower(): 
      info = g3.rate_limit()['resources']['core'] 
      reset = mu.convert_unix_timestamp(info.get('reset')) 
      delta = reset - datetime.now() 
      sleep(
       delta.seconds + 1) # Add a second to account for milliseconds 

현재 제대로 오류를 잡아 기다릴 것이다, 그러나 그것은 단지 (의미가) 프로그램을 종료 : 여기

는 내가 지금까지 가지고있는 것입니다. 나머지 한계가 무엇인지 확인하기 위해 코드에 체크를 할 수 있었고 그것이 0에 도달 할 때까지 기다릴 수는 있지만 컨텍스트 관리자를 연습하고 싶었습니다.

그것은 다음과 같은 방식으로 사용된다 :

 with api_rate_manager(gh): 
      for commit_iter in commit_iters: 
       handler: gu.EtagHandler = commit_iter.etag_handler 
       for commit in commit_iter: 
        if not commit: 
         continue 

        commit.refresh() 
        author_data: dict = commit.commit.author 
        data = { 
         'sha': commit.sha, 
         'author': author_data.get('name'), 
         'author_email': author_data.get('email'), 
         'create_date': author_data.get('date'), 
         'additions': commit.additions, 
         'deletions': commit.deletions, 
         'total': commit.total 
        } 
        mu.add_etl_fields(data) 
        writer.writerow(data) 
        has_data = True 
       etag: str = commit_iter.get_etag() 
       if etag: 
        logger.info(f'Etag for {commit_iter.name}: {etag}') 
        handler.store_in_db(etag=etag) 

답변

1

콘텍스트 관리자는 yield (발전기처럼) 사용하지만, 그것은 오직 한번 발생시킨다. See contextlib's documentation.

결과적으로 예외가 컨텍스트 관리자에서 catch 된 경우 yield 이후에 실행이 다시 시작되고 종료됩니다. 컨텍스트 관리자와 주 반복 순서를 뒤집을 수 있습니다. 아래 예를 참조하십시오.

콘텍스트 관리자 :

import contextlib 
from time import sleep 

@contextlib.contextmanager 
def api_rate_manager(): 
    try: 
     yield 
    except KeyError as e: 
     print('sleeping') 
     sleep(3) 

테스트 케이스 1 :

a = {0:0,1:2,2:4,3:6,5:10} 

with api_rate_manager(): 
    for i in range(8): 
     print(a[i]) 

출력 :

0 
2 
4 
6 
sleeping 

테스트 케이스 2 :

for i in range(8): 
    with api_rate_manager(): 
     print(a[i]) 

출력 :

0 
2 
4 
6 
sleeping 
10 
sleeping 
sleeping