I have python script (3rd party script) calling getpass.
I need to use a script to provide the password. Simple piping doesn't work because getpass, according to the doc, reads from /dev/tty.
I'm by no means a shell or python expert, so is there a way (without modifying the .py script that uses getpass) to provide the password via bash\shell script?
2 Answers
This is basically designed to get input from the keyboard. If you don't want that, and you can't change the script to read it from a correctly-permissioned configuration file instead, then I would just monkeypatch out the getpass call entirely.
from mock import patch
with patch('path.to.import.getpass') as mock:
mock.return_value = 'hunter2'
# call your script
To elaborate on "call your script", if this script has a proper entry point, e.g. generated from setuptools, then look in the source to find the underlying function that is called. You may import the module and call the same function directly to "run" the script. However, if the script is just a bunch of module level code, then you'll have to use exec and explicitly pass in a scope including the monkeypatch.
9 Comments
getpass is concerned).exec could be a catch-all.getpass.getpass() and they can't modify the script.getpass asks for input (IE blocks and is not suitable for scriptable use) -- without modifying the source that calls getpass. The solution @wim gave is just a minimal example. One could get the return_value for the mocked getpass by other means than hard-coding if they want. I don't think hard-coded/plaintext was necessarily part of the issue here, but maybe OP can clarify.'hunter2' can come from another script or a permissioned file if necessary. My point here is not to try and defeat getpass (difficult), but to just patch it out in the first place (easy).If you cannot rely on mock for whatever reason, you can use a simple context manager:
class NeuteredGetpass:
def __init__(self, new_pwd):
def noop(*args, **kwargs):
return new_pwd
self.oldpass = getpass.getpass
self.newpass = noop
def __enter__(self):
getpass.getpass = self.newpass
def __exit__(self, exc_type, exc_val, exc_tb):
getpass.getpass = self.oldpass
use_this_pass = NeuteredGetpass
with use_this_pass('password_from_shell_script'):
# do your stuff
...