99import ssl
1010import urllib .parse
1111import urllib .request
12+ from typing import Any , Callable , Dict , Optional , Tuple , TYPE_CHECKING , TypeVar
1213
1314import imapclient
1415
1516
16- def getenv (name , default ) :
17+ def getenv (name : str , default : Optional [ str ]) -> Optional [ str ] :
1718 return os .environ .get ("imapclient_" + name , default )
1819
1920
20- def get_config_defaults ():
21+ def get_config_defaults () -> Dict [ str , Any ] :
2122 return {
2223 "username" : getenv ("username" , None ),
2324 "password" : getenv ("password" , None ),
@@ -36,7 +37,7 @@ def get_config_defaults():
3637 }
3738
3839
39- def parse_config_file (filename ) :
40+ def parse_config_file (filename : str ) -> argparse . Namespace :
4041 """Parse INI files containing IMAP connection details.
4142
4243 Used by livetest.py and interact.py
@@ -51,12 +52,13 @@ def parse_config_file(filename):
5152
5253 conf .alternates = {}
5354 for section in parser .sections ():
55+ # pylint: disable=no-member
5456 conf .alternates [section ] = _read_config_section (parser , section )
5557
5658 return conf
5759
5860
59- def get_string_config_defaults ():
61+ def get_string_config_defaults () -> Dict [ str , str ] :
6062 out = {}
6163 for k , v in get_config_defaults ().items ():
6264 if v is True :
@@ -69,14 +71,19 @@ def get_string_config_defaults():
6971 return out
7072
7173
72- def _read_config_section (parser , section ):
73- def get (name ):
74+ T = TypeVar ("T" )
75+
76+
77+ def _read_config_section (
78+ parser : configparser .ConfigParser , section : str
79+ ) -> argparse .Namespace :
80+ def get (name : str ) -> str :
7481 return parser .get (section , name )
7582
76- def getboolean (name ) :
83+ def getboolean (name : str ) -> bool :
7784 return parser .getboolean (section , name )
7885
79- def get_allowing_none (name , typefunc ) :
86+ def get_allowing_none (name : str , typefunc : Callable [[ str ], T ]) -> Optional [ T ] :
8087 try :
8188 v = parser .get (section , name )
8289 except configparser .NoOptionError :
@@ -85,10 +92,10 @@ def get_allowing_none(name, typefunc):
8592 return None
8693 return typefunc (v )
8794
88- def getint (name ) :
95+ def getint (name : str ) -> Optional [ int ] :
8996 return get_allowing_none (name , int )
9097
91- def getfloat (name ) :
98+ def getfloat (name : str ) -> Optional [ float ] :
9299 return get_allowing_none (name , float )
93100
94101 ssl_ca_file = get ("ssl_ca_file" )
@@ -121,7 +128,9 @@ def getfloat(name):
121128}
122129
123130
124- def refresh_oauth2_token (hostname , client_id , client_secret , refresh_token ):
131+ def refresh_oauth2_token (
132+ hostname : str , client_id : str , client_secret : str , refresh_token : str
133+ ) -> str :
125134 url = OAUTH2_REFRESH_URLS .get (hostname )
126135 if not url :
127136 raise ValueError ("don't know where to refresh OAUTH2 token for %r" % hostname )
@@ -136,14 +145,19 @@ def refresh_oauth2_token(hostname, client_id, client_secret, refresh_token):
136145 url , urllib .parse .urlencode (post ).encode ("ascii" )
137146 ) as request :
138147 response = request .read ()
139- return json .loads (response .decode ("ascii" ))["access_token" ]
148+ result = json .loads (response .decode ("ascii" ))["access_token" ]
149+ if TYPE_CHECKING :
150+ assert isinstance (result , str )
151+ return result
140152
141153
142154# Tokens are expensive to refresh so use the same one for the duration of the process.
143- _oauth2_cache = {}
155+ _oauth2_cache : Dict [ Tuple [ str , str , str , str ], str ] = {}
144156
145157
146- def get_oauth2_token (hostname , client_id , client_secret , refresh_token ):
158+ def get_oauth2_token (
159+ hostname : str , client_id : str , client_secret : str , refresh_token : str
160+ ) -> str :
147161 cache_key = (hostname , client_id , client_secret , refresh_token )
148162 token = _oauth2_cache .get (cache_key )
149163 if token :
@@ -154,7 +168,9 @@ def get_oauth2_token(hostname, client_id, client_secret, refresh_token):
154168 return token
155169
156170
157- def create_client_from_config (conf , login = True ):
171+ def create_client_from_config (
172+ conf : argparse .Namespace , login : bool = True
173+ ) -> imapclient .IMAPClient :
158174 assert conf .host , "missing host"
159175
160176 ssl_context = None
0 commit comments