Manejar elegantemente GitHub API solicita excepciones -- python campo con error-handling campo con http campo con rest campo con git camp codereview Relacionados El problema

Elegantly handle github API requests exceptions


7
vote

problema

Español

Tengo este código que crea un equipo utilizando la API de GitHub y devuelve el Equipo-ID (éxito) o -1 (falla).

Mi problema es con el manejo de errores. Cuando la solicitud responda con un código de estado de error, trato de lidiar con algunos tipos diferentes de fallas. ¡Parece un desastre!

¿Hay alguna manera de hacerlo más legible / elegante?

También me gustaría saber si estoy capturando todas las excepciones razonables que pueden ser lanzadas por las solicitudes.

  def create_team(org,team_name):     '''     Try to create a team and return its id     if already exisits return id     '''     try:         data = {             "name": team_name,             "permission": "push"         }         headers = {'Authorization': 'token '+OAUTH_TOKEN}          response = requests.post(GH_API_URL+'orgs/'+org['login']+'/teams',                                     headers=headers,                                     data = json.dumps(data))          response.raise_for_status() #throw exception if request does not retun 2xx          #http status is 2xx, team must have been created         json_response = json.loads(response.text)         return json_response['id'] #get id of new team from response      except requests.exceptions.HTTPError as e:          if response.status_code == 422: #Unprocessable Entity              json_response = json.loads(response.text)             if json_response['errors'][0]['code'] == 'already_exists': #Unprocessable because already exists                 print(' not created, team already exists!!!')                  #get the id of existing team                 team_id = get_teamID_from_name(org, team_name)                  return team_id             else:  #Unprocessable for some other reason                 print(' HTTP error: '+str(e))          else: #other HTTP error != 422             print(' HTTP error: '+str(e))      except requests.exceptions.RequestException as e:         print('Connection error: '+str(e))        return -1   

En caso de que se estuviera preguntando por qué no puedo verificar la existencia del equipo antes de intentar crearlo. Esto se debe a que el caso normal de esta función es que los equipos aún no existen y la API de GitHub es bastante lenta. Como se representa, se tarda varios minutos en procesar a un grupo con 50 equipos y 100 estudiantes. La verificación de la existencia del equipo agregaría unos minutos más al tiempo de ejecución.

Original en ingles

I have this code which creates a team using the github API and returns the team-id(success) or -1(failure).

My problem is with the error handling. When the request responses with an error status code I try to deal with a few different types of failure. It looks like a mess!

Is there any way to make it more readable/elegant?

I'd also like to know if I am catching all the reasonable exceptions that can be thrown by requests.

def create_team(org,team_name):     '''     Try to create a team and return its id     if already exisits return id     '''     try:         data = {             "name": team_name,             "permission": "push"         }         headers = {'Authorization': 'token '+OAUTH_TOKEN}          response = requests.post(GH_API_URL+'orgs/'+org['login']+'/teams',                                     headers=headers,                                     data = json.dumps(data))          response.raise_for_status() #throw exception if request does not retun 2xx          #http status is 2xx, team must have been created         json_response = json.loads(response.text)         return json_response['id'] #get id of new team from response      except requests.exceptions.HTTPError as e:          if response.status_code == 422: #Unprocessable Entity              json_response = json.loads(response.text)             if json_response['errors'][0]['code'] == 'already_exists': #Unprocessable because already exists                 print(' not created, team already exists!!!')                  #get the id of existing team                 team_id = get_teamID_from_name(org, team_name)                  return team_id             else:  #Unprocessable for some other reason                 print(' HTTP error: '+str(e))          else: #other HTTP error != 422             print(' HTTP error: '+str(e))      except requests.exceptions.RequestException as e:         print('Connection error: '+str(e))        return -1 

In case you were wondering why I don't just check for the existence of the team BEFORE trying to create it. That's because the normal case for this function is that the teams do not already exist and the github API is quite slow. As it stands it takes several minutes to process a groups with 50 teams and 100 students. Checking for team existence would add a few more minutes to the runtime.

              
   
   

Lista de respuestas

4
 
vote

Una forma de acelerar ligeramente es reduciendo la sobrecarga del módulo requests . Actualmente, su código tiene que establecer una conexión una vez para cada equipo, volviendo a transmitir el código API de autenticación, etc. Este es un problema resuelto, puede usar sesiones .

Tendría que iniciarlo con un contexto-gerente en la función externa de usted (donde se basa en todos los nombres de equipos para crear) y pasar el objeto de sesión a la función create_team . < / p>

También barló un bloqueo del código try , debe tener solo la cantidad menos posible en allí, por lo que puede estar seguro de lo que elevó exactamente un error. También inserté los rendimientos tempranos, pero hay otras escuelas de pensamiento que prefieren una sola salida para las funciones al costo de tener más código en el bloque try .

También intenté incluir una implementación de huesos desnudos para su función externa, pero la suya puede ser un poco diferente, por supuesto.

He utilizado str.format , donde corresponde en lugar de una adición de cadena.

  import requests  OAUTH_TOKEN = "XXX" HEADERS = {'Authorization': 'token {}'.format(OAUTH_TOKEN)} GH_API_URL = "http://github.com/XXX"   def create_teams(org, team_names):     with requests.Session() as session:         session.headers.update(HEADERS)         for team_name in team_names:             create_team(session, org['login'], team_name)   def create_team(session, org_name, team_name):     '''     Try to create a team and return its id.     If it already exists return id     '''     data = {         "name": team_name,         "permission": "push"     }     url = '{}orgs/{}/teams'.format(GH_API_URL, org_name)     try:         response = session.post(url, data=json.dumps(data))         response.raise_for_status()  # throw exception if request does not return 2xx     except requests.exceptions.HTTPError as e:         if response.status_code == 422:  # Unprocessable Entity             json_response = json.loads(response.text)             # Unprocessable because already exists             if json_response['errors'][0]['code'] == 'already_exists':                 print('{} not created, team already exists!!!'.format(team_name))                 # get the id of existing team                 return get_teamID_from_name(session, org, team_name)         # Unprocessable for some other reason or other HTTP error != 422         print(' HTTP error: {}'.format(e))         return -1      except requests.exceptions.RequestException as e:         print('Connection error: {}'.format(e))         return -1      # http status is 2xx, team must have been created     json_response = json.loads(response.text)     return json_response['id']  # get id of new team from response   

 

One way to slightly speed-up is by reducing the overhead of the requests module. Currently your code has to establish a connection once for every team, re-transmitting the authentication API code and so on. This is a solved problem, you could use sessions.

You would have to start it with a context-manager in you outer function (where you loop over all of the team-names to create) and pass the session object to the create_team function.

I also shuffled some code out of the try block, you should have only the least possible amount in there, so you can be sure what exactly raised an error. I also inserted early returns, but there are other schools of thought which prefer a single exit for functions at the cost of having more code in the try block.

I also tried including a bare bones implementation for your outer function, but yours might be slightly different, of course.

I used str.format, where applicable instead of string addition.

import requests  OAUTH_TOKEN = "XXX" HEADERS = {'Authorization': 'token {}'.format(OAUTH_TOKEN)} GH_API_URL = "http://github.com/XXX"   def create_teams(org, team_names):     with requests.Session() as session:         session.headers.update(HEADERS)         for team_name in team_names:             create_team(session, org['login'], team_name)   def create_team(session, org_name, team_name):     '''     Try to create a team and return its id.     If it already exists return id     '''     data = {         "name": team_name,         "permission": "push"     }     url = '{}orgs/{}/teams'.format(GH_API_URL, org_name)     try:         response = session.post(url, data=json.dumps(data))         response.raise_for_status()  # throw exception if request does not return 2xx     except requests.exceptions.HTTPError as e:         if response.status_code == 422:  # Unprocessable Entity             json_response = json.loads(response.text)             # Unprocessable because already exists             if json_response['errors'][0]['code'] == 'already_exists':                 print('{} not created, team already exists!!!'.format(team_name))                 # get the id of existing team                 return get_teamID_from_name(session, org, team_name)         # Unprocessable for some other reason or other HTTP error != 422         print(' HTTP error: {}'.format(e))         return -1      except requests.exceptions.RequestException as e:         print('Connection error: {}'.format(e))         return -1      # http status is 2xx, team must have been created     json_response = json.loads(response.text)     return json_response['id']  # get id of new team from response 
 
 
 
 

Relacionados problema

4  Script de rubí para crear repos de git  ( Ruby script to create git repos ) 
Escribí mi primer script de rubí, por este tutorial . Crea un repo de git local y remoto. He estado trabajando durante aproximadamente 3 años con PHP, y de...

5  Base para la iteración sobre la historia del git  ( Base for iterating over git history ) 
Quería hacer algunas estadísticas sobre la historia de un repositorio de git. Al principio, intenté usar Gitpython, pero no era tan trivial como lo imaginaba....

4  Descarga un git repo sin .git carpeta  ( Download a git repo without git folder ) 
Viniendo de Python, JavaScript y PHP, me gustaría aprender a escribir Ruby en la forma en que se "supone". El código de Python bien escrito se llama "Pythonic...

8  Bash Script para clonar todos los repositores públicos o gistas para un usuario específico, opcionalmente a un directorio de elección  ( Bash script to clone all public repos or gists for a specified user optionally ) 
Escribí este script como una forma de hacer una copia de seguridad y / o descargar rápidamente un conjunto de repos o gistas de un usuario. No tengo ninguna p...

3  Restablecer archivos en GIT que se muestran como modificados pero no tienen cambios de acuerdo con "Git Diff"  ( Reset files in git which show as modified but have no changes according to git ) 
Este parece para estar funcionando, pero también es bastante lento y me parece un poco hackeado. IFS=$' ' for currentFile in $(git status | grep "modifi...

2  Programa de Kotlin para resumir Git Comets by Rogex Match  ( Kotlin program to summarize git commits by regex match ) 
Estoy tratando de aprender Kotlin. Vengo de algunos antecedentes en Java. Como ejercicio de aprendizaje, escribí este programa simple para resumir las ocurren...

10  Script de bash para simplificar el flujo de trabajo de implementación del GIT  ( Bash script to simplify git deployment workflow ) 
En mi empresa, sigo el siguiente flujo de trabajo. (Creo que se puede definir un tipo de 'integración continua'.) flujo de trabajo: Tenemos 3 sucursale...

10  Nivel faltante de profundidad técnica (ancestro común)  ( Missing level of technical depth common ancestor ) 
Recientemente le hemos dado una prueba de codificación en una compañía de TI de buena reputación. Hubo tres preguntas de codificación. me rechazaron diciend...

5  Herramienta para calcular el tiempo promedio que toma para una solicitud de tracción GitHub para fusionar  ( Tool to calculate the average time that takes for a github pull request to get m ) 
Estoy aprendiendo, y este es mi primer intento de una herramienta de línea de comandos que usa la API de GitHub para calcular el tiempo promedio que toma una ...

1  Git AutoUpandater  ( Git autoupdater ) 
En mi oficina, tenemos una herramienta de monitoreo interno que utilizamos en los sistemas de clientes para monitorear varios vitales y notificarnos a través ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos