Próbuję wymyślić, jak prawidłowo obsługiwać błędy w boto3.
Próbuję utworzyć użytkownika IAM:
def create_user(username, iam_conn):
try:
user = iam_conn.create_user(UserName=username)
return user
except Exception as e:
return e
Gdy wywołanie użytkownika create_user się powiedzie, otrzymuję zgrabny obiekt, który zawiera kod statusu HTTP wywołania API i dane nowo utworzonego użytkownika.
Przykład:
{'ResponseMetadata':
{'HTTPStatusCode': 200,
'RequestId': 'omitted'
},
u'User': {u'Arn': 'arn:aws:iam::omitted:user/omitted',
u'CreateDate': datetime.datetime(2015, 10, 11, 17, 13, 5, 882000, tzinfo=tzutc()),
u'Path': '/',
u'UserId': 'omitted',
u'UserName': 'omitted'
}
}
To działa świetnie. Ale kiedy to się nie powiedzie (na przykład, jeśli użytkownik już istnieje), po prostu dostaję obiekt typu botocore.exceptions.ClientError z samym tekstem, aby powiedzieć mi, co poszło nie tak.
Przykład: ClientError („Wystąpił błąd (EntityAlreadyExists) podczas wywoływania operacji CreateUser: Użytkownik z pominiętą nazwą już istnieje.”,)
To (AFAIK) bardzo utrudnia obsługę błędów, ponieważ nie mogę po prostu włączyć wynikowego kodu stanu HTTP (409 dla użytkownika już istnieje zgodnie z dokumentacją API AWS dla IAM). To sprawia, że myślę, że muszę robić coś w niewłaściwy sposób. Optymalnym sposobem byłoby, aby boto3 nigdy nie zgłaszał wyjątków, ale juty zawsze zwracają obiekt odzwierciedlający przebieg wywołania API.
Czy ktoś może oświecić mnie w tej sprawie lub skierować mnie we właściwym kierunku?
Odpowiedzi:
Użyj odpowiedzi zawartej w wyjątku. Oto przykład:
Dykt odpowiedzi w wyjątku będzie zawierał:
['Error']['Code']
np. „EntityAlreadyExists” lub „ValidationError”['ResponseMetadata']['HTTPStatusCode']
np. 400['ResponseMetadata']['RequestId']
np. „d2b06652-88d7-11e5-99d0-812348583a35”['Error']['Message']
np. „Wystąpił błąd (EntityAlreadyExists) ...”['Error']['Type']
np. „Nadawca”Aby uzyskać więcej informacji, zobacz Obsługa błędów botocore .
[Zaktualizowano: 2018-03-07]
Zestaw AWS Python SDK zaczął ujawniać wyjątki usług na klientach (choć nie w zasobach ), które można jawnie wychwycić, dzięki czemu można teraz napisać ten kod w taki sposób:
Niestety obecnie nie ma dokumentacji dotyczącej tych wyjątków.
źródło
200
do czeku, ponieważ kod powrotu może być innym2xx
kodem stanu HTTP (np.204
Podczas usuwania skarbca lub archiwum,201
podczas tworzenia itp.). W najlepszym wypadku należy sprawdzić kod inny niż 4xx (np.statusCode < 400
), Ale to jest naprawdę kruche i i tak go nie polecam: najlepiej polegać naboto
zgłaszaniu wyjątków w kodzie.Uważam, że jest to bardzo przydatne, ponieważ wyjątki nie są udokumentowane, aby wyświetlić listę wszystkich wyjątków na ekranie tego pakietu. Oto kod, którego użyłem, aby to zrobić:
Co skutkuje w:
źródło
Po prostu aktualizacja problemu „bez wyjątków dotyczących zasobów”, na co wskazuje @jarmod (prosimy o aktualizację odpowiedzi, jeśli wydaje się, że poniżej)
Przetestowałem poniższy kod i działa dobrze. Używa „zasobów” do robienia rzeczy, ale łapie
client.exceptions
- chociaż „wygląda” nieco źle… sprawdza się dobrze, klasy wyjątków są wyświetlane i dopasowywane, gdy patrzy się na użycie debuggera w czasie wyjątku…Może nie dotyczyć wszystkich zasobów i klientów, ale działa w przypadku folderów danych (zwanych także segmentami s3).
Mam nadzieję że to pomoże...
źródło
s3.meta.client.exceptions.NoSuchBucket
s3
jest zasobem usługi, nps3 = boto3.resource('s3')
. Działa również dla rzeczywistych zasobów, takich jak wiadra:boto3.resource('s3').Bucket('bucket-name').meta.client.exceptions. ...
Jak już wspomniano kilka innych, można wychwycić niektóre błędy za pomocą klienta usługi (
service_client.exceptions.<ExceptionClass>
) lub resource (service_resource.meta.client.exceptions.<ExceptionClass>
), jednak nie jest to dobrze udokumentowane (także jakie wyjątki należą do których klientów). Oto więc, jak uzyskać pełne mapowanie w momencie pisania (styczeń 2020) w regionie UE (Irlandia) (eu-west-1
):Oto podzbiór dość dużego dokumentu:
źródło
Lub porównanie nazwy klasy, np
Ponieważ są one tworzone dynamicznie, nigdy nie można zaimportować klasy i złapać jej za pomocą prawdziwego języka Python.
źródło
except Exception as e
a następnie miałbym instrukcje if, aby określić konkretny wyjątek? Czym różni się to / lepsze od łapania określonych wyjątków? Jest więcej wierszy i trzeba by zaimportować bibliotekę, aby mimo to uzyskać nazwę klasy. Chyba, że chcesz ustawić na stałe nazwę wyjątku. Podsumowując, wydaje się, że to zły sposób.Jeśli wywołujesz API sign_up (AWS Cognito) za pomocą Python3, możesz użyć następującego kodu.
error.response [„Error”] [„Code”] będzie InvalidPasswordException, UsernameExistsException itp. Tak więc w funkcji głównej lub w miejscu, w którym wywołujesz funkcję, możesz napisać logikę, aby przekazać użytkownikowi znaczącą wiadomość.
Przykład odpowiedzi (error.response):
Więcej informacji: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cognito-idp.html#CognitoIdentityProvider.Client.sign_up
źródło
Jeśli masz do czynienia z prawdopodobnie nieprzyjaznym
logs
klientem ( CloudWatch Logsput-log-events
), to właśnie musiałem zrobić, aby poprawnie wychwycić wyjątki klienta Boto3:Działa to zarówno przy pierwszej próbie (z pustym LogStream), jak i kolejnych.
źródło
Po aktualizacji @ armod o dodawaniu wyjątków bezpośrednio do
client
obiektów. Pokażę, jak możesz zobaczyć wszystkie wyjątki zdefiniowane dla twojej klasy klienta.Wyjątki są generowane dynamicznie podczas tworzenia klienta za pomocą
session.create_client()
lubboto3.client()
. Wewnętrznie wywołuje metodębotocore.errorfactory.ClientExceptionsFactory._create_client_exceptions()
i wypełniaclient.exceptions
pole zbudowanymi klasami wyjątków.Wszystkie nazwy klas są dostępne w
client.exceptions._code_to_exception
słowniku, więc możesz wyświetlić listę wszystkich typów za pomocą następującego fragmentu:Mam nadzieję, że to pomoże.
źródło
Musisz coś zrobić, gdy problem nie zostanie rozwiązany. W tej chwili zwracasz faktyczny wyjątek. Na przykład, jeśli nie jest to problem, że użytkownik już istnieje i chcesz użyć go jako funkcji get_or_create, być może poradzisz sobie z tym, zwracając istniejący obiekt użytkownika.
To powiedziawszy, być może jest to problem dla twojej aplikacji, w którym to przypadku chcesz umieścić moduł obsługi wyjątków wokół kodu, który wywołał twoją funkcję użytkownika, i pozwól funkcji wywołującej określić, jak sobie z tym poradzić, na przykład pytając użytkownik, aby wprowadzić inną nazwę użytkownika lub cokolwiek, co ma sens dla Twojej aplikacji.
źródło