Pygithub: Suchratenbegrenzung unterstützen

Erstellt am 10. Apr. 2017  ·  13Kommentare  ·  Quelle: PyGithub/PyGithub

Es scheint, dass die get_rate_limit-Funktion das zurückgibt, was Github als das „Core“-Ratenlimit betrachtet. Es gibt jedoch unterschiedliche Ratenbegrenzungen für die Suche nach Code. Siehe hier .

Im Moment gibt es keine Möglichkeit, die Ratenbegrenzungen für Suchcodes zu erhalten, soweit ich das beurteilen kann.

feature request

Hilfreichster Kommentar

Für Leute, die über die Suchmaschine hier landen, habe ich die Funktion von @bbi-yggy ein wenig modifiziert:

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

Diese Funktion kann wie folgt verwendet werden:

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

Alle 13 Kommentare

Ich sehe das gleiche Problem. Hier ist ein kleines Skript, das das Problem veranschaulicht.

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 Diese Funktion ist für eine Anwendung erforderlich, die ich erstellen möchte

@brentshermana Für Ihre Anwendung sollten Sie erwägen, die Kopfzeilen für die Ratenbegrenzung zu überprüfen (der letzten Antwort; siehe mein Beispiel oben) oder den /rate_limit -Endpunkt selbst abzufragen. Das enthält Informationen über alle Arten von Ratenbegrenzungen und zählt nicht zu einer Ratenbegrenzung.

Schließlich wäre es schön, wenn PyGithub nicht nur rate parsen würde, sondern auch resources aus dem, was /rate_limit zurückgibt. Die Informationen sind vorhanden, sie werden den Benutzern der Bibliothek leider nicht zur Verfügung gestellt.

Außerdem sollte die paginierte Liste die Ratenbegrenzung für die Codesuche zurückgeben, wenn sie Ergebnisse einer solchen Suche zurückgibt, dh was auch immer in _headers['x-ratelimit-*'] gespeichert ist.

Übrigens: Mir ist gerade aufgefallen, dass das Feld rate von JSON, das von /rate_limit zurückgegeben wird, veraltet ist und Informationen in resources die empfohlene Alternative sind: https://developer.github.com/ v3/rate_limit/#deprecation -notice

Ich mache genau das. Wenn jemand dies anpassen und versuchen möchte, eine Pull-Anforderung zu stellen, haben Sie meinen Segen:

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)

Ich habe ein Problem, bei dem meine Iteration über die Ergebnisse von search_issues nach 1020 Ergebnissen stoppt, wenn es 1869 Ergebnisse geben sollte. Mein Skript stoppt jedes Mal an der gleichen Stelle. Könnte dies ein ratenbegrenzendes Problem sein?

Ich erhalte keinen Fehler, die Ergebnisse laufen einfach aus. Wenn ich meine Abfragezeichenfolge direkt in die GitHub-Weboberfläche einfüge, sehe ich wie erwartet alle 1869-Ergebnisse. 1020 ist ein Vielfaches von 30, weshalb ich mich frage, ob es sich um ein Paginierungsproblem handelt?

Code ist wie folgt:

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)

Vielen Dank für alle Tipps, die Sie teilen können, was hier schief laufen könnte.

Ich habe auch versucht, durch issues.reversed zu iterieren, um zu sehen, ob es am Ende meiner erwarteten 1869-Ergebnisse beginnen würde. In diesem Fall bekomme ich jedoch nur 30 Ausgaben von der ersten Ergebnisseite.

Bei weiteren Nachforschungen scheint es, dass ich das Limit von 1000 Ergebnissen pro Suche erreiche .

Was ist, wenn wir eine weitere Methode get_search_rate_limit() für das Suchratenlimit bereitstellen, während das vorhandene get_rate_limit() das neueste von Github vorgeschlagene "Core"-Ratenlimit analysiert: https://developer.github.com/ v3/rate_limit/

Das Ratenlimit für die Such-API und das GraphQL-Ratenlimit sind jetzt verfügbar. Eine Methode für alle.

Standardmäßig zeigt es Ihnen die "Core"-Ratenbegrenzung an. Sie können auch ein Such-/Graphql-Ratenlimit erhalten, indem Sie auf die entsprechenden Attribute zugreifen.

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)

Sieht toll aus, danke @sfdye!

Um die Wartefunktion von @brentshermana zu emulieren, um Probleme mit der Begrenzung der Suchrate zu vermeiden, können Sie jetzt Folgendes tun:

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

Beachten Sie, dass das Aufrufen get_rate_limit() zu einer kleinen Verzögerung führt, daher sollten Sie die Anzahl der Aufrufe minimieren.

Für Leute, die über die Suchmaschine hier landen, habe ich die Funktion von @bbi-yggy ein wenig modifiziert:

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

Diese Funktion kann wie folgt verwendet werden:

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

Modifizierte Version von pokey's decorator oben, um core/search/graphql zu berücksichtigen.
Außerdem wurde eine 30-Sekunden-Verzögerung hinzugefügt, da Github das Ratenlimit nicht genau zum angegebenen Zeitpunkt zurücksetzt.

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

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

diegotejadav picture diegotejadav  ·  5Kommentare

Borkason picture Borkason  ·  4Kommentare

mlainez picture mlainez  ·  7Kommentare

nixoz2k7 picture nixoz2k7  ·  7Kommentare

psychemedia picture psychemedia  ·  5Kommentare