Pygithub: Mendukung batas tingkat pencarian

Dibuat pada 10 Apr 2017  ·  13Komentar  ·  Sumber: PyGithub/PyGithub

Tampaknya fungsi get_rate_limit akan mengembalikan apa yang dianggap Github sebagai batas kecepatan 'inti'. Namun, ada batasan tarif yang berbeda untuk kode pencarian. Lihat di sini .

Saat ini tidak ada cara untuk mendapatkan batas tingkat kode pencarian sejauh yang saya tahu.

feature request

Komentar yang paling membantu

Untuk orang yang mendarat di sini dari mesin pencari, saya sedikit memodifikasi fungsi @bbi-yggy:

from datetime import datetime, timezone

def rate_limited_retry(github):
    def decorator(func):
        def ret(*args, **kwargs):
            for _ in range(3):
                try:
                    return func(*args, **kwargs)
                except RateLimitExceededException:
                    limits = github.get_rate_limit()
                    reset = limits.search.reset.replace(tzinfo=timezone.utc)
                    now = datetime.now(timezone.utc)
                    seconds = (reset - now).total_seconds()
                    print(f"Rate limit exceeded")
                    print(f"Reset is in {seconds:.3g} seconds.")
                    if seconds > 0.0:
                        print(f"Waiting for {seconds:.3g} seconds...")
                        time.sleep(seconds)
                        print("Done waiting - resume!")
            raise Exception("Failed too many times")
        return ret
    return decorator

Fungsi ini dapat digunakan sebagai berikut:

@rate_limited_retry(github)
def run_query(import_string):
    query_string = f"language:Python \"{import_string}\""
    return list(github.search_code(query_string))

results = run_query(import_string)

Semua 13 komentar

Saya melihat masalah yang sama. Berikut adalah skrip kecil yang mencontohkan masalah.

import os
from datetime import datetime
from github import Github

# Login
TOKEN = os.getenv("GITHUB_ACCESS_TOKEN")
github = Github(TOKEN)

# Get initial rate limit and reset time
rl1 = github.get_rate_limit().rate
print("RL1 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl1.limit, rl1.remaining, rl1.reset))
# RL1 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.

# Perform a search
results = github.search_code("Hello World")

# Rate limit of Github instance is unchanged after a search
rl2 = github.get_rate_limit().rate
print("RL2 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl2.limit, rl2.remaining, rl2.reset))
# RL2 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.

# The PaginatedList instance has a Requestor with the same info
rl3 = results._PaginatedList__requester.rate_limiting
rl3_reset = datetime.utcfromtimestamp(int(
        results._PaginatedList__requester.rate_limiting_resettime))
print("RL3 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl3[0], rl3[1], rl3_reset))
# RL3 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.

# However, the actual ContentFile results show a different limit
# The Requester of each individual result ...
result = results[0]
rl4 = result._requester.rate_limiting
rl4_reset = datetime.utcfromtimestamp(int(
        result._requester.rate_limiting_resettime))
print("RL4 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl4[1], rl4[0], rl4_reset))
# RL4 | Limit: 30, Remaining: 29, Reset: 2017-09-22 16:27:36.

# ... and headers stored in the content file directly show a different rate limit.
rl5_limit = result._headers['x-ratelimit-limit']
rl5_remaining = result._headers['x-ratelimit-remaining']
rl5_reset = datetime.utcfromtimestamp(int(
        result._headers['x-ratelimit-reset']))
print("RL5 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl5_limit, rl5_remaining, rl5_reset))
# RL5 | Limit: 30, Remaining: 29, Reset: 2017-09-22 16:27:36.

# In the end, the main Github instance still shows the original full rate limit
rl6 = github.get_rate_limit().rate
print("RL6 | Limit: {}, Remaining: {}, Reset: {}.".format(
    rl6.limit, rl6.remaining, rl6.reset))
# RL6 | Limit: 5000, Remaining: 5000, Reset: 2017-09-22 17:26:35.

+1 Fitur ini diperlukan untuk aplikasi yang saya coba buat

@brentshermana untuk aplikasi Anda, pertimbangkan untuk memeriksa header batas tarif (dari respons terakhir; lihat contoh saya di atas) atau polling sendiri titik akhir /rate_limit . Itu berisi informasi tentang semua jenis batas tarif dan tidak termasuk dalam batas tarif apa pun.

Akhirnya, akan lebih baik jika PyGithub tidak hanya mengurai rate tetapi juga mengurai resources dari apa yang dikembalikan /rate_limit . Informasi yang ada, sayangnya tidak tersedia untuk konsumen perpustakaan.

Juga, daftar yang diberi halaman harus mengembalikan batas kecepatan untuk pencarian kode jika mengembalikan hasil pencarian seperti itu, yaitu apa pun yang disimpan di _headers['x-ratelimit-*'] .

btw: Saya baru saja memperhatikan, bidang rate dari JSON yang dikembalikan oleh /rate_limit tidak digunakan lagi dan informasi dalam resources adalah alternatif yang disarankan: https://developer.github.com/ v3/rate_limit/#deprecation -pemberitahuan

Saya melakukan hal itu. Jika ada yang ingin mengadaptasi ini dan mencoba dan membuat permintaan tarik, Anda mendapat restu saya:

def wait(seconds):
    print("Waiting for {} seconds ...".format(seconds))
    time.sleep(seconds)
    print("Done waiting - resume!")

def api_wait():
    url = 'https://api.github.com/rate_limit'
    response = urlopen(url).read()
    data = json.loads(response.decode())
    if data['resources']['core']['remaining'] <= 10:  # extra margin of safety
        reset_time = data['resources']['core']['reset']
        wait(reset_time - time.time() + 10)
    elif data['resources']['search']['remaining'] <= 2:
        reset_time = data['resources']['search']['reset']
        wait(reset_time - time.time() + 10)

Saya mengalami masalah di mana iterasi saya atas hasil dari search_issues berhenti setelah 1020 hasil ketika seharusnya ada 1869 hasil. Skrip saya berhenti di titik yang sama setiap saat. Mungkinkah ini masalah pembatasan tarif?

Saya tidak mendapatkan kesalahan, hasilnya habis begitu saja. Jika saya memasukkan string kueri saya langsung ke antarmuka web GitHub maka saya melihat semua hasil 1869, seperti yang diharapkan. 1020 adalah kelipatan dari 30, yang membuat saya bertanya-tanya apakah ini masalah pagination?

Kode adalah sebagai berikut:

querystring = "type:pr is:closed repo:xxxx closed:2017-07-01..2018-06-30"
issues = git.search_issues(query=querystring, sort="updated", order="asc")
for issue in issues:
    pull = issue.as_pull_request()
    print "%s: %s" % (pull.number, pull.title)

Terima kasih banyak atas tip yang dapat Anda bagikan tentang apa yang mungkin salah di sini.

Saya juga mencoba mengulangi issues.reversed untuk melihat apakah itu akan dimulai pada akhir dari hasil 1869 yang saya harapkan. Namun dalam kasus ini saya hanya mendapatkan 30 masalah, dari halaman pertama hasil.

Pada penyelidikan lebih lanjut, tampaknya saya mengalami 1000 hasil per batas pencarian .

Bagaimana kalau kami menyediakan satu metode lagi get_search_rate_limit() untuk batas tingkat pencarian sementara get_rate_limit() yang ada akan mengurai batas tingkat "inti" terbaru yang disarankan oleh Github: https://developer.github.com/ v3/rate_limit/

Batas tingkat API Pencarian dan batas tingkat GraphQL tersedia sekarang. Satu metode untuk semua.

Secara default, ini akan menunjukkan kepada Anda batas kecepatan "inti". Anda juga bisa mendapatkan batas tingkat pencarian/graphql dengan mengakses atribut masing-masing.

r = g.get_rate_limit()
>>> r
RateLimit(core=Rate(remaining=4923, limit=5000))
>>> r.search
Rate(remaining=30, limit=30)
>>> r.graphql
Rate(remaining=5000, limit=5000)

Tampak hebat, terima kasih @sfdye!

Untuk meniru fungsi menunggu @brentshermana untuk menghindari masalah dengan pembatasan tingkat pencarian, Anda sekarang dapat melakukan sesuatu seperti ini:

from datetime import datetime

def api_wait_search(git):
  limits = git.get_rate_limit()
  if limits.search.remaining <= 2:
    seconds = (limits.search.reset - datetime.now()).total_seconds()
    print "Waiting for %d seconds ..." % (seconds)
    time.sleep(seconds)
    print "Done waiting - resume!"

Perhatikan bahwa menelepon get_rate_limit() akan menyebabkan penundaan kecil, jadi Anda mungkin ingin meminimalkan seberapa sering Anda menelepon ini.

Untuk orang yang mendarat di sini dari mesin pencari, saya sedikit memodifikasi fungsi @bbi-yggy:

from datetime import datetime, timezone

def rate_limited_retry(github):
    def decorator(func):
        def ret(*args, **kwargs):
            for _ in range(3):
                try:
                    return func(*args, **kwargs)
                except RateLimitExceededException:
                    limits = github.get_rate_limit()
                    reset = limits.search.reset.replace(tzinfo=timezone.utc)
                    now = datetime.now(timezone.utc)
                    seconds = (reset - now).total_seconds()
                    print(f"Rate limit exceeded")
                    print(f"Reset is in {seconds:.3g} seconds.")
                    if seconds > 0.0:
                        print(f"Waiting for {seconds:.3g} seconds...")
                        time.sleep(seconds)
                        print("Done waiting - resume!")
            raise Exception("Failed too many times")
        return ret
    return decorator

Fungsi ini dapat digunakan sebagai berikut:

@rate_limited_retry(github)
def run_query(import_string):
    query_string = f"language:Python \"{import_string}\""
    return list(github.search_code(query_string))

results = run_query(import_string)

Versi modifikasi dari pokey's decorator di atas dengan mempertimbangkan core/search/graphql.
Juga menambahkan penundaan 30 detik karena Github tidak mengatur ulang batas kecepatan tepat pada waktu yang disebutkan.

def rate_limited_retry():
    def decorator(func):
        def ret(*args, **kwargs):
            for _ in range(3):
                try:
                    return func(*args, **kwargs)
                except RateLimitExceededException:
                    limits = gh.get_rate_limit()
                    print(f"Rate limit exceeded")
                    print("Search:", limits.search, "Core:", limits.core, "GraphQl:", limits.graphql)

                    if limits.search.remaining == 0:
                        limited = limits.search
                    elif limits.graphql.remaining == 0:
                        limited = limits.graphql
                    else:
                        limited = limits.core
                    reset = limited.reset.replace(tzinfo=timezone.utc)
                    now = datetime.now(timezone.utc)
                    seconds = (reset - now).total_seconds() + 30
                    print(f"Reset is in {seconds} seconds.")
                    if seconds > 0.0:
                        print(f"Waiting for {seconds} seconds...")
                        time.sleep(seconds)
                        print("Done waiting - resume!")
            raise Exception("Failed too many times")
        return ret
    return decorator

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

nchammas picture nchammas  ·  3Komentar

psychemedia picture psychemedia  ·  5Komentar

kodeshpa picture kodeshpa  ·  3Komentar

hsluoyz picture hsluoyz  ·  3Komentar

jacquev6 picture jacquev6  ·  3Komentar