2323import base64
2424import hashlib
2525import logging
26+ import netrc
27+ import os
2628import sys
2729from urllib .parse import urlparse
2830
@@ -256,6 +258,7 @@ def __init__(
256258 base_url = None ,
257259 auth = None ,
258260 ca_cert_data = None ,
261+ use_netrc = False ,
259262 ** client_kwargs
260263 ):
261264 """Create a Rest Client object"""
@@ -266,6 +269,15 @@ def __init__(
266269 auth , ca_cert_data = ca_cert_data , ** client_kwargs
267270 )
268271 self ._auth_key = None
272+
273+ # If .netrc should be considered, use it to preload username and/or password
274+ if use_netrc and not (username and password ):
275+ netrc_user , netrc_pass = self ._get_netrc_auth (base_url )
276+ if username is None and netrc_user :
277+ username = netrc_user
278+ if password is None and netrc_pass :
279+ password = netrc_pass
280+
269281 self ._user_pass = (username , password )
270282 self ._session_location = None
271283 self ._cert_data = ca_cert_data
@@ -286,6 +298,49 @@ def __exit__(self, exc_type, exc_val, exc_tb):
286298 """Close the connection"""
287299 self .logout ()
288300
301+ def _get_netrc_auth (self , url ):
302+ """Get username and password from a .netrc if available"""
303+
304+ # inspired by request's get_netrc_auth
305+
306+ hostname = urlparse (url ).netloc .split (":" )[0 ] # ignore port if present
307+
308+ path = None
309+
310+ try :
311+ path = os .environ ["NETRC" ]
312+ except KeyError :
313+ for name in (".netrc" , "_netrc" ):
314+ try :
315+ path = os .path .expanduser (f"~/{ name } " )
316+ except KeyError :
317+ break
318+
319+ if os .path .exists (path ):
320+ break
321+
322+ if not path :
323+ LOGGER .error ("Requested use of .netrc, but no .netrc found" )
324+
325+ try :
326+ login , account , pwd = netrc .netrc (path ).authenticators (hostname )
327+ except FileNotFoundError as exc :
328+ LOGGER .error (
329+ f"Requested use of .netrc, but file inaccessible at '{ path } '" , exc )
330+ return (None , None )
331+ except netrc .NetrcParseError as exc :
332+ LOGGER .error (
333+ f"Requested use of .netrc, but parsing failed for '{ path } '" , exc )
334+ return (None , None )
335+ except ValueError :
336+ LOGGER .info (f"No matching entry found in '{ path } ' for: { hostname } " )
337+ return (None , None )
338+
339+ if login :
340+ return (login , pwd )
341+
342+ return (account , pwd )
343+
289344 def _get_auth_type (self , auth_param , ca_cert_data = None , ** client_kwargs ):
290345 """Get the auth type based on key args or positional argument.
291346 Defaults to session auth."""
0 commit comments