I'm currently doing a integration with WSDL, and such decided to go with Python using the Zeep library.
I'm trying to model the response with mypy
, so that it works with VSCode's Intellisense, as well as some giving me hints when I'm doing careless assignments or modifications. But I hit a roadblock when the WSDL responses is in a nested object, and I can't figure a way to type-hint it.
Sample response from WSDL:
{
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
I'm using the following snippet to type-hint:
class MethodResultType:
code: str
description: str
errorUUID: str
class AccountType:
accountId: int
accountName: str
availableCredit: float
class getAccounts:
result: MethodResultType
accounts: List[AccountType] # Attempt 1
accounts = TypedDict("accounts", {"accounts": List[AccountType]}) # Attempt 2
client = Client(os.getenv("API_URL"), wsse=user_name_token)
accountsResponse: getAccounts = client.service.getAccounts()
accounts = accountsResponse.accounts.accounts
# Attempt 1: "List[AccountType]" has no attribute "accounts"; maybe "count"?
# Attempt 2: "Type[accounts]" has no attribute "accounts"
For Attempt 1, the reason is obvious. But after trying Attempt 2, I don't know how to proceed anymore. What am I missing here?
Update: Following @Avi Kaminetzky's answer, I tried with following (playground):
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
print(result.result)
print(result.accounts)
But I'm getting error message from mypy:
"getAccounts" has no attribute "result"
"getAccounts" has no attribute "accounts"
Here's how you can add type hints to our function: Add a colon and a data type after each function parameter. Add an arrow ( -> ) and a data type after the function to specify the return data type.
Python's type hints provide you with optional static typing to leverage the best of both static and dynamic typing. Besides the str type, you can use other built-in types such as int , float , bool , and bytes for type hintings. To check the syntax for type hints, you need to use a static type checker tool.
First introduced in Python 3.5, Type Hints are the primary way Python developers annotate types to variables and functions. Type Hints — like the name suggests, do not enforce any type checks at the interpreter level. They are designed to be used by developers, IDEs, linters, type checkers, etc.
TypedDict was introduced in Python 3.8 to provide type Hints for Dictionaries with a Fixed Set of Keys. The TypedDict allows us to describe a structured dictionary/map with an expected set of named string keys mapped to values of particular expected types, which Python type-checkers like mypy can further use.
Updates derived from conversation in comments
class Foo(TypedDict)
.errorUUID
is an Optional[str]
.accounts
is type Dict[str, List[AccountType]]
since it has an inner (perhaps redundant) key also called accounts
.accountsResponse['accounts']['accounts']
.Here is a proposed solution:
from typing import List, TypedDict, Optional, Dict
class MethodResultType(TypedDict):
code: str
description: str
errorUUID: Optional[str]
class AccountType(TypedDict):
accountId: int
accountName: str
availableCredit: float
class getAccounts(TypedDict):
result: MethodResultType
accounts: Dict[str, List[AccountType]]
result: getAccounts = {
'result': {
'code': '1',
'description': 'Success',
'errorUUID': None
},
'accounts': {
'accounts': [
{
'accountId': 1,
'accountName': 'Ming',
'availableCredit': 1
}
]
}
}
See this MyPy playground: https://mypy-play.net/?mypy=latest&python=3.8&gist=dad62a9e2cecf4bad1088a2636690976
TypedDict is an extension to MyPy, make sure to install MyPy (plus extensions) and import TypedDict: from typing_extensions import TypedDict
.
From Python 3.8 you can import TypedDict directly from the typing module.
https://mypy.readthedocs.io/en/latest/more_types.html#typeddict https://www.python.org/dev/peps/pep-0589/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With