2017-11-21 5 views
2

このループを非同期にする方法は?私は今のGitHub APIで働いている、とここにすべてがリスト内の各レポの要求を引っ張るフェッチ機能だ

async def get_all_pulls(repos, api): 
    pulls = [] 
    for repo in repos: 
     try: 
      async for pull in api.getiter(f'/repos/{org}/{repo}/pulls?state=all'): 
       pull['repo'] = repo 
       if pull not in pulls: 
        pulls.append(pull) 
     except Exception: 
      print(f"Bad repo/no access=> [{repo}]") 
      continue 

    return pulls 

すべてが正常に動作しますが、1つの小さな問題、それは理由の多くの時間を要しreposの繰り返し(30個あるとしましょう)。

私はそれがこの(これを使用しているとき、私は宣言の中で、forループを取り除くのです確実なもの)好き非同期作るしようとしていた

:私は など

 # gather all prs for all repos 

     tasks = [asyncio.ensure_future(get_all_pulls_for_repo(api, repo)) for repo in repos] 
     results = await asyncio.gather(*tasks) 
     # unwrap list of lists 
     for res in results: 
      all_pull_requests += res 

をしかし、私はクラッシュを取得し、レポが悪いと言って私はここで何か重要なことを逃していると思うが、何を得ることはできない。

なぜasync for loopでクラッシュするのですか?そして私はそれを働かせることができますか?

UPDATE1: get_all_reviewsでトレースバック:

Traceback (most recent call last): 
    File "/home/metal/Documents/projects/-git/async_git_tool.py", line 193, in <module> 
    loop.run_until_complete(main()) 
    File "/home/metal/.pyenv/versions/3.6.0/lib/python3.6/asyncio/base_events.py", line 466, in run_until_complete 
    return future.result() 
    File "/home/metal/Documents/projects/-git/async_git_tool.py", line 113, in main 
    reviewed = await get_all_reviews(created, api, ss_programmers) 
    File "/home/metal/Documents/projects/-git/async_git_tool.py", line 181, in get_all_reviews 
    async for review in api.getiter(f'/repos/{org}/{pr_repo}/pulls/{pr_number}/reviews'): 
    File "/home/metal/Documents/projects/-git/venv/lib/python3.6/site-packages/gidgethub/abc.py", line 85, in getiter 
    data, more = await self._make_request("GET", url, url_vars, b"", accept) 
    File "/home/metal/Documents/projects/-git/venv/lib/python3.6/site-packages/gidgethub/abc.py", line 66, in _make_request 
    data, self.rate_limit, more = sansio.decipher_response(*response) 
    File "/home/metal/Documents/projects/-git/venv/lib/python3.6/site-packages/gidgethub/sansio.py", line 284, in decipher_response 
    rate_limit = RateLimit.from_http(headers) 
    File "/home/metal/Documents/projects/-git/venv/lib/python3.6/site-packages/gidgethub/sansio.py", line 226, in from_http 
    limit = int(headers["x-ratelimit-limit"]) 
    File "multidict/_multidict.pyx", line 140, in multidict._multidict._Base.__getitem__ 
    File "multidict/_multidict.pyx", line 135, in multidict._multidict._Base._getone 
KeyError: "Key not found: 'x-ratelimit-limit'" 

はここfuncitonそのものです:

async def get_all_reviews(pulls, api, programmers): 
    reviewed_pulls = [] 
    for pull in pulls: 
     pr_repo = pull['repo'] 
     pr_number = str(pull['number']) 

     async for review in api.getiter(f'/repos/{org}/{pr_repo}/pulls/{pr_number}/reviews'): 
      if review['user']['login'] not in programmers \ 
        and pull not in reviewed_pulls: 
       reviewed_pulls.append(pull) 

    return reviewed_pulls 

と私はそのように呼んでいる:

reviewed = await get_all_reviews(softserve_created, api, ss_programmers) 
+0

Github APIを使用するために使用する具体的なモジュールは何ですか? –

+0

@MikhailGerasimov私は_Gidgegethub_(http://gidgethub.readthedocs.io/en/stable/)を使用しています – Roman

答えて

1

アイデアあなたは私のためにうまく働いた:

import asyncio 
import aiohttp 
import gidgethub 
from gidgethub.aiohttp import GitHubAPI 


# TODO 
# paste your token to have rate limits 
# https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/ 
TOKEN = '...' 


async def get_all_pulls_for_repo(gh, org, repo): 
    pulls = [] 
    async for pull in gh.getiter(f'/repos/{org}/{repo}/pulls?state=all'): 
     pulls.append(pull) 
     await gh.sleep(0.1) # avoid RateLimitExceeded, you should count it somehow 
    return pulls 


async def main(): 
    org = 'brettcannon' 
    repos = ['gidgethub', 'caniusepython3', 'importlib_resources'] 

    async with aiohttp.ClientSession() as session: 
     gh = GitHubAPI(session, 'requester', oauth_token=TOKEN) 
     tasks = [ 
      asyncio.ensure_future(get_all_pulls_for_repo(gh, org, repo)) 
      for repo 
      in repos 
     ] 
     results = await asyncio.gather(*tasks) 

    for res in results: 
     for pull in res: 
      print(pull['url']) 


loop = asyncio.get_event_loop() 
try: 
    loop.run_until_complete(main()) 
finally: 
    loop.run_until_complete(loop.shutdown_asyncgens()) 
    loop.close() 

リクエストのトークンを作成して貼り付けると、PR URLのリストが表示されます。

+0

sleep()はget_all_pullsで問題を取り除くためにうまくいきましたが、まだget_all_reviewsにトレースバックがあります。トップ、ありがとう。 – Roman

+0

plus私はreposでレポにnon-asyncを使用している場合、合計9983個のプルリクエストを取得していて、非同期の場合は – Roman

+1

@Romanというエラーが表示されますそれはgidgethubのバグです - https://github.com/brettcannon/gidgethub/issues/25あなたが取り出すPRの数は、gidgethubがどのように動作するかにも関係していると思います。 –

関連する問題