Pygithub: دعم حد معدل البحث

تم إنشاؤها على ١٠ أبريل ٢٠١٧  ·  13تعليقات  ·  مصدر: PyGithub/PyGithub

يبدو أن دالة get_rate_limit ستعيد ما يعتبره Github حد المعدل "الأساسي". ومع ذلك ، هناك حدود معدل مختلفة للبحث في التعليمات البرمجية. انظر هنا .

في الوقت الحالي ، لا توجد طريقة للحصول على حدود معدل رمز البحث بقدر ما أستطيع أن أقول.

feature request

التعليق الأكثر فائدة

بالنسبة للأشخاص الذين وصلوا إلى هنا من محرك البحث ، قمت بتعديل وظيفة @ 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

يمكن استخدام هذه الوظيفة على النحو التالي:

@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)

ال 13 كومينتر

أرى نفس المشكلة. هنا نص صغير يوضح المشكلة.

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 هذه الميزة ضرورية لتطبيق أحاول إنشائه

brentshermana لتطبيقك ، ضع في اعتبارك فحص رؤوس حدود المعدل (من آخر رد ؛ انظر في المثال أعلاه) أو استقصاء نقطة النهاية /rate_limit بنفسك. يحتوي على معلومات حول جميع أنواع حدود الأسعار ولا يتم احتسابه ضمن أي حد للسعر.

في النهاية ، سيكون من الرائع لو أن PyGithub لا تقوم فقط بتحليل rate ولكن أيضًا تحلل resources مما يعود /rate_limit . المعلومات موجودة ، فهي غير متاحة لمستهلكي المكتبة للأسف.

وأيضًا ، يجب أن تُرجع القائمة المرقمة الحد الأقصى لسعر البحث عن الكود إذا كانت تُرجع نتائج مثل هذا البحث ، أي ما يتم تخزينه في _headers['x-ratelimit-*'] .

راجع للشغل: لقد لاحظت للتو ، الحقل rate من JSON الذي تم إرجاعه بواسطة /rate_limit تم إهماله والمعلومات الموجودة في resources هي البديل الموصى به: https://developer.github.com/ v3 / rate_limit / # إهمال -إشعار

أنا أفعل ذلك بالضبط. إذا أراد أي شخص تكييف هذا ومحاولة تقديم طلب سحب ، فلديك مباركتي:

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)

أواجه مشكلة حيث يتوقف تكراري على النتائج من search_issues بعد 1020 نتيجة عندما يجب أن يكون هناك 1869 نتيجة. السيناريو الخاص بي يتوقف عند نفس النقطة في كل مرة. هل يمكن أن تكون هذه مشكلة تحديد السعر؟

أنا لا أحصل على خطأ ، النتائج فقط نفدت. إذا وضعت سلسلة الاستعلام الخاصة بي مباشرة في واجهة الويب GitHub ، فأنا أرى جميع النتائج البالغ عددها 1869 ، كما هو متوقع. 1020 من مضاعفات العدد 30 ، مما يجعلني أتساءل عما إذا كانت مشكلة ترقيم الصفحات؟

الكود كما يلي:

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)

شكرًا جزيلاً على أي نصائح يمكنك مشاركتها بشأن الخطأ الذي قد يحدث هنا.

لقد حاولت أيضًا التكرار من خلال issues.reversed لمعرفة ما إذا كان سيبدأ في نهاية نتائجي المتوقعة 1869. ومع ذلك ، في هذه الحالة ، أحصل فقط على 30 مشكلة ، من الصفحة الأولى من النتائج.

في مزيد من التحقيق ، يبدو أنني أجري 1000 نتيجة لكل حد بحث .

ماذا عن تقديم طريقة أخرى get_search_rate_limit() لحد معدل البحث بينما get_rate_limit() الحالي سيحلل آخر حد للسعر "الأساسي" الذي اقترحه Github: https://developer.github.com/ الإصدار 3 / rate_limit /

يتوفر حد معدل واجهة برمجة تطبيقات البحث وحد معدل GraphQL الآن. طريقة واحدة للجميع.

بشكل افتراضي سوف يظهر لك حد المعدل "الأساسي". يمكنك أيضًا الحصول على حد معدل البحث / الرسم البياني من خلال الوصول إلى السمات المعنية.

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)

تبدو رائعة ، شكراsfdye!

لمحاكاة وظيفة انتظار brentshermana لتجنب مشاكل تحديد معدل البحث ، يمكنك الآن القيام بشيء مثل هذا:

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!"

لاحظ أن استدعاء get_rate_limit() سيحدث تأخيرًا بسيطًا ، لذلك قد ترغب في تقليل عدد مرات استدعاء هذا.

بالنسبة للأشخاص الذين وصلوا إلى هنا من محرك البحث ، قمت بتعديل وظيفة @ 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

يمكن استخدام هذه الوظيفة على النحو التالي:

@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)

نسخة معدلة من مصمم pokey's أعلاه لتأخذ في الاعتبار الأساسية / البحث / الرسم البياني.
تمت إضافة مهلة 30 ثانية لأن Github لا تعيد ضبط حد المعدل بالضبط في الوقت الذي تقوله.

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

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات