Python: launch default mail client on the system - python

I'm fairly new to Python and I'm trying to write a plugin for a text editor.
I want to know if there is a way to launch default system E-Mail client from python code.

With pywin32:
import win32api
win32api.ShellExecute(0,'open','mailto:',None,None ,0)
Update
Ah, I misread your question and presumed you're on Win platform.
A platform independent solution would be open mailto link in a browser, like
import webbrowser
webbrowser.open('mailto:', new=1)
Update 2
Some additional research (in fact, first two pages of google search) revealed this excellent snippet:
#!/usr/bin/env python
'''Utilities for opening files or URLs in the registered default application
and for sending e-mail using the user's preferred composer.
'''
__version__ = '1.1'
__all__ = ['open', 'mailto']
import os
import sys
import webbrowser
import subprocess
from email.Utils import encode_rfc2231
_controllers = {}
_open = None
class BaseController(object):
'''Base class for open program controllers.'''
def __init__(self, name):
self.name = name
def open(self, filename):
raise NotImplementedError
class Controller(BaseController):
'''Controller for a generic open program.'''
def __init__(self, *args):
super(Controller, self).__init__(os.path.basename(args[0]))
self.args = list(args)
def _invoke(self, cmdline):
if sys.platform[:3] == 'win':
closefds = False
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
closefds = True
startupinfo = None
if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
sys.platform == 'darwin'):
inout = file(os.devnull, 'r+')
else:
# for TTY programs, we need stdin/out
inout = None
# if possible, put the child precess in separate process group,
# so keyboard interrupts don't affect child precess as well as
# Python
setsid = getattr(os, 'setsid', None)
if not setsid:
setsid = getattr(os, 'setpgrp', None)
pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
stderr=inout, close_fds=closefds,
preexec_fn=setsid, startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient,
# exo-open, xdg-open and open for OSX) immediately exit after lauching
# the specific application
returncode = pipe.wait()
if hasattr(self, 'fixreturncode'):
returncode = self.fixreturncode(returncode)
return not returncode
def open(self, filename):
if isinstance(filename, basestring):
cmdline = self.args + [filename]
else:
# assume it is a sequence
cmdline = self.args + filename
try:
return self._invoke(cmdline)
except OSError:
return False
# Platform support for Windows
if sys.platform[:3] == 'win':
class Start(BaseController):
'''Controller for the win32 start progam through os.startfile.'''
def open(self, filename):
try:
os.startfile(filename)
except WindowsError:
# [Error 22] No application is associated with the specified
# file for this operation: '<URL>'
return False
else:
return True
_controllers['windows-default'] = Start('start')
_open = _controllers['windows-default'].open
# Platform support for MacOS
elif sys.platform == 'darwin':
_controllers['open']= Controller('open')
_open = _controllers['open'].open
# Platform support for Unix
else:
import commands
# #WARNING: use the private API of the webbrowser module
from webbrowser import _iscommand
class KfmClient(Controller):
'''Controller for the KDE kfmclient program.'''
def __init__(self, kfmclient='kfmclient'):
super(KfmClient, self).__init__(kfmclient, 'exec')
self.kde_version = self.detect_kde_version()
def detect_kde_version(self):
kde_version = None
try:
info = commands.getoutput('kde-config --version')
for line in info.splitlines():
if line.startswith('KDE'):
kde_version = line.split(':')[-1].strip()
break
except (OSError, RuntimeError):
pass
return kde_version
def fixreturncode(self, returncode):
if returncode is not None and self.kde_version > '3.5.4':
return returncode
else:
return os.EX_OK
def detect_desktop_environment():
'''Checks for known desktop environments
Return the desktop environments name, lowercase (kde, gnome, xfce)
or "generic"
'''
desktop_environment = 'generic'
if os.environ.get('KDE_FULL_SESSION') == 'true':
desktop_environment = 'kde'
elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
desktop_environment = 'gnome'
else:
try:
info = commands.getoutput('xprop -root _DT_SAVE_MODE')
if ' = "xfce4"' in info:
desktop_environment = 'xfce'
except (OSError, RuntimeError):
pass
return desktop_environment
def register_X_controllers():
if _iscommand('kfmclient'):
_controllers['kde-open'] = KfmClient()
for command in ('gnome-open', 'exo-open', 'xdg-open'):
if _iscommand(command):
_controllers[command] = Controller(command)
def get():
controllers_map = {
'gnome': 'gnome-open',
'kde': 'kde-open',
'xfce': 'exo-open',
}
desktop_environment = detect_desktop_environment()
try:
controller_name = controllers_map[desktop_environment]
return _controllers[controller_name].open
except KeyError:
if _controllers.has_key('xdg-open'):
return _controllers['xdg-open'].open
else:
return webbrowser.open
if os.environ.get("DISPLAY"):
register_X_controllers()
_open = get()
def open(filename):
'''Open a file or an URL in the registered default application.'''
return _open(filename)
def _fix_addersses(**kwargs):
for headername in ('address', 'to', 'cc', 'bcc'):
try:
headervalue = kwargs[headername]
if not headervalue:
del kwargs[headername]
continue
elif not isinstance(headervalue, basestring):
# assume it is a sequence
headervalue = ','.join(headervalue)
except KeyError:
pass
except TypeError:
raise TypeError('string or sequence expected for "%s", '
'%s found' % (headername,
type(headervalue).__name__))
else:
translation_map = {'%': '%25', '&': '%26', '?': '%3F'}
for char, replacement in translation_map.items():
headervalue = headervalue.replace(char, replacement)
kwargs[headername] = headervalue
return kwargs
def mailto_format(**kwargs):
# #TODO: implement utf8 option
kwargs = _fix_addersses(**kwargs)
parts = []
for headername in ('to', 'cc', 'bcc', 'subject', 'body', 'attach'):
if kwargs.has_key(headername):
headervalue = kwargs[headername]
if not headervalue:
continue
if headername in ('address', 'to', 'cc', 'bcc'):
parts.append('%s=%s' % (headername, headervalue))
else:
headervalue = encode_rfc2231(headervalue) # #TODO: check
parts.append('%s=%s' % (headername, headervalue))
mailto_string = 'mailto:%s' % kwargs.get('address', '')
if parts:
mailto_string = '%s?%s' % (mailto_string, '&'.join(parts))
return mailto_string
def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None,
attach=None):
'''Send an e-mail using the user's preferred composer.
Open the user's preferred e-mail composer in order to send a mail to
address(es) that must follow the syntax of RFC822. Multiple addresses
may be provided (for address, cc and bcc parameters) as separate
arguments.
All parameters provided are used to prefill corresponding fields in
the user's e-mail composer. The user will have the opportunity to
change any of this information before actually sending the e-mail.
address - specify the destination recipient
cc - specify a recipient to be copied on the e-mail
bcc - specify a recipient to be blindly copied on the e-mail
subject - specify a subject for the e-mail
body - specify a body for the e-mail. Since the user will be able
to make changes before actually sending the e-mail, this
can be used to provide the user with a template for the
e-mail text may contain linebreaks
attach - specify an attachment for the e-mail. file must point to
an existing file
'''
mailto_string = mailto_format(**locals())
return open(mailto_string)
if __name__ == '__main__':
from optparse import OptionParser
version = '%%prog %s' % __version__
usage = (
'\n\n%prog FILENAME [FILENAME(s)] -- for opening files'
'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails'
)
parser = OptionParser(usage=usage, version=version, description=__doc__)
parser.add_option('-m', '--mailto', dest='mailto_mode', default=False,
action='store_true', help='set mailto mode. '
'If not set any other option is ignored')
parser.add_option('--cc', dest='cc', help='specify a recipient to be '
'copied on the e-mail')
parser.add_option('--bcc', dest='bcc', help='specify a recipient to be '
'blindly copied on the e-mail')
parser.add_option('--subject', dest='subject',
help='specify a subject for the e-mail')
parser.add_option('--body', dest='body', help='specify a body for the '
'e-mail. Since the user will be able to make changes '
'before actually sending the e-mail, this can be used '
'to provide the user with a template for the e-mail '
'text may contain linebreaks')
parser.add_option('--attach', dest='attach', help='specify an attachment '
'for the e-mail. file must point to an existing file')
(options, args) = parser.parse_args()
if not args:
parser.print_usage()
parser.exit(1)
if options.mailto_mode:
if not mailto(args, None, options.cc, options.bcc, options.subject,
options.body, options.attach):
sys.exit('Unable to open the e-mail client')
else:
for name in ('cc', 'bcc', 'subject', 'body', 'attach'):
if getattr(options, name):
parser.error('The "cc", "bcc", "subject", "body" and "attach" '
'options are only accepten in mailto mode')
success = False
for arg in args:
if not open(arg):
print 'Unable to open "%s"' % arg
else:
success = True
sys.exit(success)
Enjoy.

The above-mentioned code only works in Python 2.
I've modified it to work for Python 3. The "attach" parameter is no longer supported for security reasons.
#!/usr/bin/env python3
'''Utilities for opening files or URLs in the registered default application
and for sending e-mail using the user's preferred composer.
https://stackoverflow.com/a/19779373/3211506
'''
__version__ = '1.1'
__all__ = ['open', 'mailto']
import os
import sys
import webbrowser
import subprocess
from email.utils import encode_rfc2231
_controllers = {}
_open = None
fileopen = open
class BaseController(object):
'''Base class for open program controllers.'''
def __init__(self, name):
self.name = name
def open(self, filename):
raise NotImplementedError
class Controller(BaseController):
'''Controller for a generic open program.'''
def __init__(self, *args):
super(Controller, self).__init__(os.path.basename(args[0]))
self.args = list(args)
def _invoke(self, cmdline):
if sys.platform[:3] == 'win':
closefds = False
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
else:
closefds = True
startupinfo = None
if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
sys.platform == 'darwin'):
inout = fileopen(os.devnull, 'r+')
else:
# for TTY programs, we need stdin/out
inout = None
# if possible, put the child precess in separate process group,
# so keyboard interrupts don't affect child precess as well as
# Python
setsid = getattr(os, 'setsid', None)
if not setsid:
setsid = getattr(os, 'setpgrp', None)
pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
stderr=inout, close_fds=closefds,
preexec_fn=setsid, startupinfo=startupinfo)
# It is assumed that this kind of tools (gnome-open, kfmclient,
# exo-open, xdg-open and open for OSX) immediately exit after lauching
# the specific application
returncode = pipe.wait()
if hasattr(self, 'fixreturncode'):
returncode = self.fixreturncode(returncode)
return not returncode
def open(self, filename):
if isinstance(filename, str):
cmdline = self.args + [filename]
else:
# assume it is a sequence
cmdline = self.args + filename
try:
return self._invoke(cmdline)
except OSError:
return False
# Platform support for Windows
if sys.platform[:3] == 'win':
class Start(BaseController):
'''Controller for the win32 start progam through os.startfile.'''
def open(self, filename):
try:
os.startfile(filename)
except WindowsError:
# [Error 22] No application is associated with the specified
# file for this operation: '<URL>'
return False
else:
return True
_controllers['windows-default'] = Start('start')
_open = _controllers['windows-default'].open
# Platform support for MacOS
elif sys.platform == 'darwin':
_controllers['open']= Controller('open')
_open = _controllers['open'].open
# Platform support for Unix
else:
import subprocess, stat
# #WARNING: use the private API of the webbrowser module
# from webbrowser import _iscommand
def _isexecutable(cmd):
if os.path.isfile(cmd):
mode = os.stat(cmd)[stat.ST_MODE]
if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH:
return True
return False
def _iscommand(cmd):
"""Return True if cmd is executable or can be found on the executable
search path."""
if _isexecutable(cmd):
return True
path = os.environ.get("PATH")
if not path:
return False
for d in path.split(os.pathsep):
exe = os.path.join(d, cmd)
if _isexecutable(exe):
return True
return False
class KfmClient(Controller):
'''Controller for the KDE kfmclient program.'''
def __init__(self, kfmclient='kfmclient'):
super(KfmClient, self).__init__(kfmclient, 'exec')
self.kde_version = self.detect_kde_version()
def detect_kde_version(self):
kde_version = None
try:
info = subprocess.getoutput('kde-config --version')
for line in info.splitlines():
if line.startswith('KDE'):
kde_version = line.split(':')[-1].strip()
break
except (OSError, RuntimeError):
pass
return kde_version
def fixreturncode(self, returncode):
if returncode is not None and self.kde_version > '3.5.4':
return returncode
else:
return os.EX_OK
def detect_desktop_environment():
'''Checks for known desktop environments
Return the desktop environments name, lowercase (kde, gnome, xfce)
or "generic"
'''
desktop_environment = 'generic'
if os.environ.get('KDE_FULL_SESSION') == 'true':
desktop_environment = 'kde'
elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
desktop_environment = 'gnome'
else:
try:
info = subprocess.getoutput('xprop -root _DT_SAVE_MODE')
if ' = "xfce4"' in info:
desktop_environment = 'xfce'
except (OSError, RuntimeError):
pass
return desktop_environment
def register_X_controllers():
if _iscommand('kfmclient'):
_controllers['kde-open'] = KfmClient()
for command in ('gnome-open', 'exo-open', 'xdg-open'):
if _iscommand(command):
_controllers[command] = Controller(command)
def get():
controllers_map = {
'gnome': 'gnome-open',
'kde': 'kde-open',
'xfce': 'exo-open',
}
desktop_environment = detect_desktop_environment()
try:
controller_name = controllers_map[desktop_environment]
return _controllers[controller_name].open
except KeyError:
if 'xdg-open' in _controllers:
return _controllers['xdg-open'].open
else:
return webbrowser.open
if os.environ.get("DISPLAY"):
register_X_controllers()
_open = get()
def open(filename):
'''Open a file or an URL in the registered default application.'''
return _open(filename)
def _fix_addersses(**kwargs):
for headername in ('address', 'to', 'cc', 'bcc'):
try:
headervalue = kwargs[headername]
if not headervalue:
del kwargs[headername]
continue
elif not isinstance(headervalue, str):
# assume it is a sequence
headervalue = ','.join(headervalue)
except KeyError:
pass
except TypeError:
raise TypeError('string or sequence expected for "%s", '
'%s found' % (headername,
type(headervalue).__name__))
else:
translation_map = {'%': '%25', '&': '%26', '?': '%3F'}
for char, replacement in list(translation_map.items()):
headervalue = headervalue.replace(char, replacement)
kwargs[headername] = headervalue
return kwargs
def mailto_format(**kwargs):
# #TODO: implement utf8 option
kwargs = _fix_addersses(**kwargs)
parts = []
for headername in ('to', 'cc', 'bcc', 'subject', 'body'):
if headername in kwargs:
headervalue = kwargs[headername]
if not headervalue:
continue
if headername in ('address', 'to', 'cc', 'bcc'):
parts.append('%s=%s' % (headername, headervalue))
else:
headervalue = encode_rfc2231(headervalue, charset="utf-8")[7:] # #TODO: check
parts.append('%s=%s' % (headername, headervalue))
mailto_string = 'mailto:%s' % kwargs.get('address', '')
if parts:
mailto_string = '%s?%s' % (mailto_string, '&'.join(parts))
return mailto_string
def mailto(address, to=None, cc=None, bcc=None, subject=None, body=None):
'''Send an e-mail using the user's preferred composer.
Open the user's preferred e-mail composer in order to send a mail to
address(es) that must follow the syntax of RFC822. Multiple addresses
may be provided (for address, cc and bcc parameters) as separate
arguments.
All parameters provided are used to prefill corresponding fields in
the user's e-mail composer. The user will have the opportunity to
change any of this information before actually sending the e-mail.
address - specify the destination recipient
cc - specify a recipient to be copied on the e-mail
bcc - specify a recipient to be blindly copied on the e-mail
subject - specify a subject for the e-mail
body - specify a body for the e-mail. Since the user will be able
to make changes before actually sending the e-mail, this
can be used to provide the user with a template for the
e-mail text may contain linebreaks
attach - specify an attachment for the e-mail. file must point to
an existing file (UNSUPPORTED)
'''
mailto_string = mailto_format(**locals())
return open(mailto_string)
if __name__ == '__main__':
from optparse import OptionParser
version = '%%prog %s' % __version__
usage = (
'\n\n%prog FILENAME [FILENAME(s)] -- for opening files'
'\n\n%prog -m [OPTIONS] ADDRESS [ADDRESS(es)] -- for sending e-mails'
)
parser = OptionParser(usage=usage, version=version, description=__doc__)
parser.add_option('-m', '--mailto', dest='mailto_mode', default=False,
action='store_true', help='set mailto mode. '
'If not set any other option is ignored')
parser.add_option('--cc', dest='cc', help='specify a recipient to be '
'copied on the e-mail')
parser.add_option('--bcc', dest='bcc', help='specify a recipient to be '
'blindly copied on the e-mail')
parser.add_option('--subject', dest='subject',
help='specify a subject for the e-mail')
parser.add_option('--body', dest='body', help='specify a body for the '
'e-mail. Since the user will be able to make changes '
'before actually sending the e-mail, this can be used '
'to provide the user with a template for the e-mail '
'text may contain linebreaks')
parser.add_option('--attach', dest='attach', help='specify an attachment '
'for the e-mail. file must point to an existing file')
(options, args) = parser.parse_args()
if not args:
parser.print_usage()
parser.exit(1)
if options.mailto_mode:
if not mailto(args, None, options.cc, options.bcc, options.subject,
options.body, options.attach):
sys.exit('Unable to open the e-mail client')
else:
for name in ('cc', 'bcc', 'subject', 'body', 'attach'):
if getattr(options, name):
parser.error('The "cc", "bcc", "subject", "body" and "attach" '
'options are only accepten in mailto mode')
success = False
for arg in args:
if not open(arg):
print('Unable to open "%s"' % arg)
else:
success = True
sys.exit(success)

Related

WaitForSingleObject not working - invalid handle

I'm currently righting a code for client that can download files from a cloud. The client downloads the file temporarily and when the file is closed (terminated) it gets sent back to the cloud.
Here is the full code:
import socket
import os
from OpenFile import *
from Registry_Change import *
import win32con
import win32api
import win32event
from win32com.shell import shellcon
from win32com.shell.shell import ShellExecuteEx
class Application(object):
def __init__(self):
"""
:param request: the request of the file to receive from server
"""
# initiates request (clicked file path)
self.request = sys.argv[SECOND]
reg = Read_Registry()
ip, port = reg.get_ip_port()
self.ip = ip
self.port = port
# initiates socket
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.ip, self.port))
# sends the request to the server
Application.send_request_to_server(self.sock, "DOWNLOAD_FILE " + self.request)
format = Application.read_server_response(self.sock).decode()
self.path_file = self.download(format)
self.start_file_and_wait()
self.sock.close()
except Exception as msg:
print(win32api.GetLastError())
print("connection error:", msg)
#staticmethod
def valid_file(path):
"""
checks if the path is a file that exists
"""
if os.path.isfile(path):
return True
return False
#staticmethod
def delete_file(file_path):
"""
deletes file
"""
os.remove(file_path)
#staticmethod
def read_server_response(server_socket_choice):
"""
reads the length and according to that, it reads the rest
of the message
"""
try:
length_of_message = server_socket_choice.recv(BYTE).decode()
if length_of_message.isdigit():
return server_socket_choice.recv(int(length_of_message))
except Exception as msg:
print("at read_server_response:", msg)
return SERVER_FELL
#staticmethod
def send_request_to_server(server_socket, request):
"""
Send the request to the server.
First the length of the request (2 digits), then the request itself
Example: '04EXIT'
Example: '12DIR c:\cyber'
"""
server_socket. \
send((str(len(request)).zfill(MSG_FILL) + request).encode())
def download(self, format):
"""
saves the given chunks to a file in the client
"""
try:
file = Application.new_format_path(self.request, format)
new_location = Application.make_new_file_path(TEMPORARY_FILES, file)
# check if the file is valid
check_len = self.sock.recv(BYTE).decode()
check = self.sock.recv(int(check_len))
if check != FILE_DOESNT_EXIST:
client_file = open(new_location, 'wb')
# write what we took out
client_file.write(check)
done = False
while not done:
byte_message_len = self.sock.recv(BYTE)
length = byte_message_len.decode()
if length.isdigit():
real_len = int(length)
data = self.sock.recv(real_len)
if data == FILE_END:
done = True
else:
client_file.write(data)
client_file.close()
return new_location
else:
return 'nothing'
except Exception as msg:
print("at download:", msg)
def upload(self, file_path):
"""
Sends a file from the server to the client
"""
if Application.valid_file(file_path):
client_file = open(file_path, 'rb')
content = client_file.read(BYTE_NUMBER)
while content != b'':
Application.send_binary_response_to_server(content, self.sock)
content = client_file.read(BYTE_NUMBER)
client_file.close()
Application.send_binary_response_to_server(FILE_END, self.sock)
Application.delete_file(file_path)
Application.make_imaginary_file(file_path)
return Application.read_server_response(self.my_socket)
else:
Application.send_response_to_server(FILE_DOESNT_EXIST, self.sock)
return FILE_DOESNT_EXIST
#staticmethod
def make_new_file_path(new_path, folder):
"""
:param new_path: new path of file to merge
:return: the new path
"""
comp = folder.split("\\")
return new_path + "\\" + comp[END]
#staticmethod
def new_format_path(path, format):
"""
:param format: the new format
:return: the same path but with new format
"""
path_format = path.split('.')
path_format[SECOND] = format
return ".".join(path_format)
def start_file_and_wait(self):
"""
:param fname: the file path - temporary
:return: opens and continues when closed
"""
rc = ShellExecuteEx(
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
nShow=win32con.SW_SHOW,
lpFile=self.path_file)
hproc = rc['hProcess']
win32event.WaitForSingleObject(hproc, win32event.INFINITE)
win32api.CloseHandle(hproc)
app = Application()
Now, the win32event.WaitForSingleObject(hproc, win32event.INFINITE) command does not work, and returns the error: "(6, 'WaitForSingleObject', 'The handle is invalid.')".
When I tried to use the start_file_and_wait(self) function in a separate file, it worked:
def start_file_wait(fname):
import win32con
import win32api
import win32event
from win32com.shell import shellcon
from win32com.shell.shell import ShellExecuteEx
rc = ShellExecuteEx(
fMask=shellcon.SEE_MASK_NOCLOSEPROCESS,
nShow=win32con.SW_SHOW,
lpFile=fname)
hproc = rc['hProcess']
win32event.WaitForSingleObject(hproc, win32event.INFINITE)
win32api.CloseHandle(hproc)
def main():
start_file_wait("E:\\12\\alice-chapter-1.txt")
print("hi")
if __name__ == '__main__':
main()
I don't know how to fix it. can someone help me?
Thanks!
It doesn't work on files that aren't text files
As you said, You did not specify a suitable verb for ShellExecuteEx, according to the parameter:
lpVerb :
... This parameter can be NULL, in which case the default verb is
used if available. If not, the "open" verb is used. If neither verb is
available, the system uses the first verb listed in the registry.
It may fail and return an invalid hProcess handle if it cannot find the associated application to open the file. You should specify a valid verb according to the file you open. Or specify the executable file of the app corresponding to the file as lpFile, and specify the file as lpParameters.
You could refer to the following document:
Launching Applications

yowsup - Integrating sending and receiving

Background:
I would like to integrate yowsup to my home automation project. I have seen a simple sample on how to receive messages and after some minor changes it is working fine.
Issue:
My problem starts when it comes to integrate the send message feature. Those are the two files I am using:
run.py
from layer import EchoLayer
from yowsup.layers.auth import YowAuthenticationProtocolLayer
from yowsup.layers.protocol_messages import YowMessagesProtocolLayer
from yowsup.layers.protocol_receipts import YowReceiptProtocolLayer
from yowsup.layers.protocol_acks import YowAckProtocolLayer
from yowsup.layers.protocol_presence import YowPresenceProtocolLayer
from yowsup.layers.network import YowNetworkLayer
from yowsup.layers.coder import YowCoderLayer
from yowsup.common import YowConstants
from yowsup.layers import YowLayerEvent
from yowsup.stacks import YowStack, YOWSUP_CORE_LAYERS
from yowsup import env
CREDENTIALS = ("phone", "pwd")
if __name__ == "__main__":
layers = (
EchoLayer,
(YowAuthenticationProtocolLayer, YowMessagesProtocolLayer, YowReceiptProtocolLayer, YowAckProtocolLayer, YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
# Program main loop
stack.loop()
layer.py
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
import threading
import logging
logger = logging.getLogger(__name__)
class EchoLayer(YowInterfaceLayer):
#ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):
#send receipt otherwise we keep receiving the same message over and over
print str(messageProtocolEntity.getFrom()) + ' - ' + str(messageProtocolEntity.getBody())
receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
self.toLower(receipt)
#ProtocolEntityCallback("send_message")
def sendMessage(self, destination, message, messageProtocolEntity):
outgoingMessageProtocolEntity = TextMessageProtocolEntity(
message,
to = destination + "#s.whatsapp.net")
self.toLower(outgoingMessageProtocolEntity)
#ProtocolEntityCallback("receipt")
def onReceipt(self, entity):
ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
self.toLower(ack)
# List of (jid, message) tuples
PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"
def __init__(self):
super(EchoLayer, self).__init__()
self.ackQueue = []
self.lock = threading.Condition()
#ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
self.lock.acquire()
for target in self.getProp(self.__class__.PROP_MESSAGES, []):
phone, message = target
if '#' in phone:
messageEntity = TextMessageProtocolEntity(message, to = phone)
elif '-' in phone:
messageEntity = TextMessageProtocolEntity(message, to = "%s#g.us" % phone)
else:
messageEntity = TextMessageProtocolEntity(message, to = "%s#s.whatsapp.net" % phone)
self.ackQueue.append(messageEntity.getId())
self.toLower(messageEntity)
self.lock.release()
#ProtocolEntityCallback("ack")
def onAck(self, entity):
self.lock.acquire()
if entity.getId() in self.ackQueue:
self.ackQueue.pop(self.ackQueue.index(entity.getId()))
if not len(self.ackQueue):
logger.info("Message sent")
#raise KeyboardInterrupt()
self.lock.release()
Questions:
Where am I supposed to call the send_message method, so I can send messages wherever I need it?
Is there a regular event (triggering every second or something) which I could use to send my messages?
#ProtocolEntityCallback("send_message")
def sendMessage(self, destination, message, messageProtocolEntity):
outgoingMessageProtocolEntity = TextMessageProtocolEntity(
message,
to = destination + "#s.whatsapp.net")
self.toLower(outgoingMessageProtocolEntity)
In the avove code sendMessage to be called, protocolEntity.getTag() == "send_message" has to be True. You don't need it to send message.
layer.py
from yowsup.layers.interface import YowInterfaceLayer, ProtocolEntityCallback
from yowsup.layers.protocol_messages.protocolentities import TextMessageProtocolEntity
from yowsup.layers.protocol_receipts.protocolentities import OutgoingReceiptProtocolEntity
from yowsup.layers.protocol_acks.protocolentities import OutgoingAckProtocolEntity
from yowsup.layers.protocol_presence.protocolentities import PresenceProtocolEntity
import threading
import logging
logger = logging.getLogger(__name__)
recv_msg = []
class EchoLayer(YowInterfaceLayer):
def __init__(self):
super(EchoLayer, self).__init__()
self.ackQueue = []
self.lock = threading.Condition()
#ProtocolEntityCallback("message")
def onMessage(self, messageProtocolEntity):
if messageProtocolEntity.getType() == 'text':
recv_msg.append((messageProtocolEntity.getFrom(),messageProtocolEntity.getBody()))
#send receipt otherwise we keep receiving the same message over and over
receipt = OutgoingReceiptProtocolEntity(messageProtocolEntity.getId(), messageProtocolEntity.getFrom())
self.toLower(receipt)
#ProtocolEntityCallback("receipt")
def onReceipt(self, entity):
ack = OutgoingAckProtocolEntity(entity.getId(), "receipt", "delivery")
self.toLower(ack)
# List of (jid, message) tuples
PROP_MESSAGES = "org.openwhatsapp.yowsup.prop.sendclient.queue"
#ProtocolEntityCallback("success")
def onSuccess(self, successProtocolEntity):
self.lock.acquire()
for target in self.getProp(self.__class__.PROP_MESSAGES, []):
phone, message = target
if '#' in phone:
messageEntity = TextMessageProtocolEntity(message, to = phone)
elif '-' in phone:
messageEntity = TextMessageProtocolEntity(message, to = "%s#g.us" % phone)
else:
messageEntity = TextMessageProtocolEntity(message, to = "%s#s.whatsapp.net" % phone)
self.ackQueue.append(messageEntity.getId())
self.toLower(messageEntity)
self.lock.release()
#ProtocolEntityCallback("ack")
def onAck(self, entity):
self.lock.acquire()
if entity.getId() in self.ackQueue:
self.ackQueue.pop(self.ackQueue.index(entity.getId()))
if not len(self.ackQueue):
self.lock.release()
logger.info("Message sent")
raise KeyboardInterrupt()
self.lock.release()
To send message define a function send_message in the stack run.py. You can also import run.py and use it's function from other script.
from layer import EchoLayer, recv_msg
CREDENTIALS = ("phone", "pwd")
def send_message(destination, message):
'''
destination is <phone number> without '+'
and with country code of type string,
message is string
e.g send_message('11133434343','hello')
'''
messages = [(destination, message)]
layers = (EchoLayer,
(YowAuthenticationProtocolLayer,
YowMessagesProtocolLayer,
YowReceiptProtocolLayer,
YowAckProtocolLayer,
YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
stack.setProp(EchoLayer.PROP_MESSAGES, messages)
stack.setProp(YowAuthenticationProtocolLayer.PROP_PASSIVE, True)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
try:
# Program main loop
stack.loop()
except AuthError as e:
print('Authentication error %s' % e.message)
sys.exit(1)
def recv_message():
layers = ( EchoLayer,
(YowAuthenticationProtocolLayer, YowMessagesProtocolLayer,
YowReceiptProtocolLayer, YowAckProtocolLayer,
YowPresenceProtocolLayer)
) + YOWSUP_CORE_LAYERS
stack = YowStack(layers)
# Setting credentials
stack.setProp(YowAuthenticationProtocolLayer.PROP_CREDENTIALS, CREDENTIALS)
# WhatsApp server address
stack.setProp(YowNetworkLayer.PROP_ENDPOINT, YowConstants.ENDPOINTS[0])
stack.setProp(YowCoderLayer.PROP_DOMAIN, YowConstants.DOMAIN)
stack.setProp(YowCoderLayer.PROP_RESOURCE, env.CURRENT_ENV.getResource())
# Sending connecting signal
stack.broadcastEvent(YowLayerEvent(YowNetworkLayer.EVENT_STATE_CONNECT))
try:
# Program main loop
stack.loop()
except AuthError as e:
print('Authentication error %s' % e.message)
sys.exit(1)
if __name__ == '__main__':
if len(sys.argv) == 1:
print('%s send number message\nrecv\n' % sys.argv[0])
sys.exit(1)
if sys.argv[1] == 'send':
try:
send_message(sys.argv[2],sys.argv[3])
except KeyboardInterrupt:
print('closing')
sys.exit(0)
if sys.argv[1] == 'recv':
try:
recv_message()
except KeyboardInterrupt:
print('closing')
sys.exit(0)
for m in recv_msg:
print('From %s:\n%s\n' % m)
Now you can send message by calling send_message('1234567890','Howdy') and recieve message by calling recv_message().

import python with __main__ method

I have a python script that have __main__ statement and took all values parametric.
I want to import and use it in my own script.
Actually I can import but don't know how to use it.
As you see below, __main__ is a bit complicated and rewriting it will take time because I even don't know what does most of code mean.
Want to know is there any way to import and use the code as a function?
import os
import sys
import time
import base64
from urllib2 import urlopen
from urllib2 import Request
from urllib2 import HTTPError
from urllib import urlencode
from urllib import quote
from exceptions import Exception
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
from email.encoders import encode_noop
from api_util import json2python, python2json
class MalformedResponse(Exception):
pass
class RequestError(Exception):
pass
class Client(object):
default_url = 'http://nova.astrometry.net/api/'
def __init__(self,
apiurl = default_url):
self.session = None
self.apiurl = apiurl
def get_url(self, service):
return self.apiurl + service
def send_request(self, service, args={}, file_args=None):
'''
service: string
args: dict
'''
if self.session is not None:
args.update({ 'session' : self.session })
print 'Python:', args
json = python2json(args)
print 'Sending json:', json
url = self.get_url(service)
print 'Sending to URL:', url
# If we're sending a file, format a multipart/form-data
if file_args is not None:
m1 = MIMEBase('text', 'plain')
m1.add_header('Content-disposition', 'form-data; name="request-json"')
m1.set_payload(json)
m2 = MIMEApplication(file_args[1],'octet-stream',encode_noop)
m2.add_header('Content-disposition',
'form-data; name="file"; filename="%s"' % file_args[0])
#msg.add_header('Content-Disposition', 'attachment',
# filename='bud.gif')
#msg.add_header('Content-Disposition', 'attachment',
# filename=('iso-8859-1', '', 'FuSballer.ppt'))
mp = MIMEMultipart('form-data', None, [m1, m2])
# Makie a custom generator to format it the way we need.
from cStringIO import StringIO
from email.generator import Generator
class MyGenerator(Generator):
def __init__(self, fp, root=True):
Generator.__init__(self, fp, mangle_from_=False,
maxheaderlen=0)
self.root = root
def _write_headers(self, msg):
# We don't want to write the top-level headers;
# they go into Request(headers) instead.
if self.root:
return
# We need to use \r\n line-terminator, but Generator
# doesn't provide the flexibility to override, so we
# have to copy-n-paste-n-modify.
for h, v in msg.items():
print >> self._fp, ('%s: %s\r\n' % (h,v)),
# A blank line always separates headers from body
print >> self._fp, '\r\n',
# The _write_multipart method calls "clone" for the
# subparts. We hijack that, setting root=False
def clone(self, fp):
return MyGenerator(fp, root=False)
fp = StringIO()
g = MyGenerator(fp)
g.flatten(mp)
data = fp.getvalue()
headers = {'Content-type': mp.get('Content-type')}
if False:
print 'Sending headers:'
print ' ', headers
print 'Sending data:'
print data[:1024].replace('\n', '\\n\n').replace('\r', '\\r')
if len(data) > 1024:
print '...'
print data[-256:].replace('\n', '\\n\n').replace('\r', '\\r')
print
else:
# Else send x-www-form-encoded
data = {'request-json': json}
print 'Sending form data:', data
data = urlencode(data)
print 'Sending data:', data
headers = {}
request = Request(url=url, headers=headers, data=data)
try:
f = urlopen(request)
txt = f.read()
print 'Got json:', txt
result = json2python(txt)
print 'Got result:', result
stat = result.get('status')
print 'Got status:', stat
if stat == 'error':
errstr = result.get('errormessage', '(none)')
raise RequestError('server error message: ' + errstr)
return result
except HTTPError, e:
print 'HTTPError', e
txt = e.read()
open('err.html', 'wb').write(txt)
print 'Wrote error text to err.html'
def login(self, apikey):
args = { 'apikey' : apikey }
result = self.send_request('login', args)
sess = result.get('session')
print 'Got session:', sess
if not sess:
raise RequestError('no session in result')
self.session = sess
def _get_upload_args(self, **kwargs):
args = {}
for key,default,typ in [('allow_commercial_use', 'd', str),
('allow_modifications', 'd', str),
('publicly_visible', 'y', str),
('scale_units', None, str),
('scale_type', None, str),
('scale_lower', None, float),
('scale_upper', None, float),
('scale_est', None, float),
('scale_err', None, float),
('center_ra', None, float),
('center_dec', None, float),
('radius', None, float),
('downsample_factor', None, int),
('tweak_order', None, int),
('crpix_center', None, bool),
# image_width, image_height
]:
if key in kwargs:
val = kwargs.pop(key)
val = typ(val)
args.update({key: val})
elif default is not None:
args.update({key: default})
print 'Upload args:', args
return args
def url_upload(self, url, **kwargs):
args = dict(url=url)
args.update(self._get_upload_args(**kwargs))
result = self.send_request('url_upload', args)
return result
def upload(self, fn, **kwargs):
args = self._get_upload_args(**kwargs)
try:
f = open(fn, 'rb')
result = self.send_request('upload', args, (fn, f.read()))
return result
except IOError:
print 'File %s does not exist' % fn
raise
def submission_images(self, subid):
result = self.send_request('submission_images', {'subid':subid})
return result.get('image_ids')
def overlay_plot(self, service, outfn, wcsfn, wcsext=0):
from astrometry.util import util as anutil
wcs = anutil.Tan(wcsfn, wcsext)
params = dict(crval1 = wcs.crval[0], crval2 = wcs.crval[1],
crpix1 = wcs.crpix[0], crpix2 = wcs.crpix[1],
cd11 = wcs.cd[0], cd12 = wcs.cd[1],
cd21 = wcs.cd[2], cd22 = wcs.cd[3],
imagew = wcs.imagew, imageh = wcs.imageh)
result = self.send_request(service, {'wcs':params})
print 'Result status:', result['status']
plotdata = result['plot']
plotdata = base64.b64decode(plotdata)
open(outfn, 'wb').write(plotdata)
print 'Wrote', outfn
def sdss_plot(self, outfn, wcsfn, wcsext=0):
return self.overlay_plot('sdss_image_for_wcs', outfn,
wcsfn, wcsext)
def galex_plot(self, outfn, wcsfn, wcsext=0):
return self.overlay_plot('galex_image_for_wcs', outfn,
wcsfn, wcsext)
def myjobs(self):
result = self.send_request('myjobs/')
return result['jobs']
def job_status(self, job_id, justdict=False):
result = self.send_request('jobs/%s' % job_id)
if justdict:
return result
stat = result.get('status')
if stat == 'success':
result = self.send_request('jobs/%s/calibration' % job_id)
print 'Calibration:', result
result = self.send_request('jobs/%s/tags' % job_id)
print 'Tags:', result
result = self.send_request('jobs/%s/machine_tags' % job_id)
print 'Machine Tags:', result
result = self.send_request('jobs/%s/objects_in_field' % job_id)
print 'Objects in field:', result
result = self.send_request('jobs/%s/annotations' % job_id)
print 'Annotations:', result
result = self.send_request('jobs/%s/info' % job_id)
print 'Calibration:', result
return stat
def sub_status(self, sub_id, justdict=False):
result = self.send_request('submissions/%s' % sub_id)
if justdict:
return result
return result.get('status')
def jobs_by_tag(self, tag, exact):
exact_option = 'exact=yes' if exact else ''
result = self.send_request(
'jobs_by_tag?query=%s&%s' % (quote(tag.strip()), exact_option),
{},
)
return result
if __name__ == '__main__':
import optparse
parser = optparse.OptionParser()
parser.add_option('--server', dest='server', default=Client.default_url,
help='Set server base URL (eg, %default)')
parser.add_option('--apikey', '-k', dest='apikey',
help='API key for Astrometry.net web service; if not given will check AN_API_KEY environment variable')
parser.add_option('--upload', '-u', dest='upload', help='Upload a file')
parser.add_option('--wait', '-w', dest='wait', action='store_true', help='After submitting, monitor job status')
parser.add_option('--wcs', dest='wcs', help='Download resulting wcs.fits file, saving to given filename; implies --wait if --urlupload or --upload')
parser.add_option('--kmz', dest='kmz', help='Download resulting kmz file, saving to given filename; implies --wait if --urlupload or --upload')
parser.add_option('--urlupload', '-U', dest='upload_url', help='Upload a file at specified url')
parser.add_option('--scale-units', dest='scale_units',
choices=('arcsecperpix', 'arcminwidth', 'degwidth', 'focalmm'), help='Units for scale estimate')
#parser.add_option('--scale-type', dest='scale_type',
# choices=('ul', 'ev'), help='Scale bounds: lower/upper or estimate/error')
parser.add_option('--scale-lower', dest='scale_lower', type=float, help='Scale lower-bound')
parser.add_option('--scale-upper', dest='scale_upper', type=float, help='Scale upper-bound')
parser.add_option('--scale-est', dest='scale_est', type=float, help='Scale estimate')
parser.add_option('--scale-err', dest='scale_err', type=float, help='Scale estimate error (in PERCENT), eg "10" if you estimate can be off by 10%')
parser.add_option('--ra', dest='center_ra', type=float, help='RA center')
parser.add_option('--dec', dest='center_dec', type=float, help='Dec center')
parser.add_option('--radius', dest='radius', type=float, help='Search radius around RA,Dec center')
parser.add_option('--downsample', dest='downsample_factor', type=int, help='Downsample image by this factor')
parser.add_option('--parity', dest='parity', choices=('0','1'), help='Parity (flip) of image')
parser.add_option('--tweak-order', dest='tweak_order', type=int, help='SIP distortion order (default: 2)')
parser.add_option('--crpix-center', dest='crpix_center', action='store_true', default=None, help='Set reference point to center of image?')
parser.add_option('--sdss', dest='sdss_wcs', nargs=2, help='Plot SDSS image for the given WCS file; write plot to given PNG filename')
parser.add_option('--galex', dest='galex_wcs', nargs=2, help='Plot GALEX image for the given WCS file; write plot to given PNG filename')
parser.add_option('--substatus', '-s', dest='sub_id', help='Get status of a submission')
parser.add_option('--jobstatus', '-j', dest='job_id', help='Get status of a job')
parser.add_option('--jobs', '-J', dest='myjobs', action='store_true', help='Get all my jobs')
parser.add_option('--jobsbyexacttag', '-T', dest='jobs_by_exact_tag', help='Get a list of jobs associated with a given tag--exact match')
parser.add_option('--jobsbytag', '-t', dest='jobs_by_tag', help='Get a list of jobs associated with a given tag')
parser.add_option( '--private', '-p',
dest='public',
action='store_const',
const='n',
default='y',
help='Hide this submission from other users')
parser.add_option('--allow_mod_sa','-m',
dest='allow_mod',
action='store_const',
const='sa',
default='d',
help='Select license to allow derivative works of submission, but only if shared under same conditions of original license')
parser.add_option('--no_mod','-M',
dest='allow_mod',
action='store_const',
const='n',
default='d',
help='Select license to disallow derivative works of submission')
parser.add_option('--no_commercial','-c',
dest='allow_commercial',
action='store_const',
const='n',
default='d',
help='Select license to disallow commercial use of submission')
opt,args = parser.parse_args()
if opt.apikey is None:
# try the environment
opt.apikey = os.environ.get('AN_API_KEY', None)
if opt.apikey is None:
parser.print_help()
print
print 'You must either specify --apikey or set AN_API_KEY'
sys.exit(-1)
args = {}
args['apiurl'] = opt.server
c = Client(**args)
c.login(opt.apikey)
if opt.upload or opt.upload_url:
if opt.wcs or opt.kmz:
opt.wait = True
kwargs = dict(
allow_commercial_use=opt.allow_commercial,
allow_modifications=opt.allow_mod,
publicly_visible=opt.public)
if opt.scale_lower and opt.scale_upper:
kwargs.update(scale_lower=opt.scale_lower,
scale_upper=opt.scale_upper,
scale_type='ul')
elif opt.scale_est and opt.scale_err:
kwargs.update(scale_est=opt.scale_est,
scale_err=opt.scale_err,
scale_type='ev')
elif opt.scale_lower or opt.scale_upper:
kwargs.update(scale_type='ul')
if opt.scale_lower:
kwargs.update(scale_lower=opt.scale_lower)
if opt.scale_upper:
kwargs.update(scale_upper=opt.scale_upper)
for key in ['scale_units', 'center_ra', 'center_dec', 'radius',
'downsample_factor', 'tweak_order', 'crpix_center',]:
if getattr(opt, key) is not None:
kwargs[key] = getattr(opt, key)
if opt.parity is not None:
kwargs.update(parity=int(opt.parity))
if opt.upload:
upres = c.upload(opt.upload, **kwargs)
if opt.upload_url:
upres = c.url_upload(opt.upload_url, **kwargs)
stat = upres['status']
if stat != 'success':
print 'Upload failed: status', stat
print upres
sys.exit(-1)
opt.sub_id = upres['subid']
if opt.wait:
if opt.job_id is None:
if opt.sub_id is None:
print "Can't --wait without a submission id or job id!"
sys.exit(-1)
while True:
stat = c.sub_status(opt.sub_id, justdict=True)
print 'Got status:', stat
jobs = stat.get('jobs', [])
if len(jobs):
for j in jobs:
if j is not None:
break
if j is not None:
print 'Selecting job id', j
opt.job_id = j
break
time.sleep(5)
success = False
while True:
stat = c.job_status(opt.job_id, justdict=True)
print 'Got job status:', stat
if stat.get('status','') in ['success']:
success = (stat['status'] == 'success')
break
time.sleep(5)
if success:
c.job_status(opt.job_id)
# result = c.send_request('jobs/%s/calibration' % opt.job_id)
# print 'Calibration:', result
# result = c.send_request('jobs/%s/tags' % opt.job_id)
# print 'Tags:', result
# result = c.send_request('jobs/%s/machine_tags' % opt.job_id)
# print 'Machine Tags:', result
# result = c.send_request('jobs/%s/objects_in_field' % opt.job_id)
# print 'Objects in field:', result
#result = c.send_request('jobs/%s/annotations' % opt.job_id)
#print 'Annotations:', result
retrieveurls = []
if opt.wcs:
# We don't need the API for this, just construct URL
url = opt.server.replace('/api/', '/wcs_file/%i' % opt.job_id)
retrieveurls.append((url, opt.wcs))
if opt.kmz:
url = opt.server.replace('/api/', '/kml_file/%i/' % opt.job_id)
retrieveurls.append((url, opt.kmz))
for url,fn in retrieveurls:
print 'Retrieving file from', url, 'to', fn
f = urlopen(url)
txt = f.read()
w = open(fn, 'wb')
w.write(txt)
w.close()
print 'Wrote to', fn
opt.job_id = None
opt.sub_id = None
if opt.sdss_wcs:
(wcsfn, outfn) = opt.sdss_wcs
c.sdss_plot(outfn, wcsfn)
if opt.galex_wcs:
(wcsfn, outfn) = opt.galex_wcs
c.galex_plot(outfn, wcsfn)
if opt.sub_id:
print c.sub_status(opt.sub_id)
if opt.job_id:
print c.job_status(opt.job_id)
#result = c.send_request('jobs/%s/annotations' % opt.job_id)
#print 'Annotations:', result
if opt.jobs_by_tag:
tag = opt.jobs_by_tag
print c.jobs_by_tag(tag, None)
if opt.jobs_by_exact_tag:
tag = opt.jobs_by_exact_tag
print c.jobs_by_tag(tag, 'yes')
if opt.myjobs:
jobs = c.myjobs()
print jobs
#print c.submission_images(1)
No, there is no clean way to do so. When the module is being imported, it's code is executed and all global variables are set as attributes to the module object. So if part of the code is not executed at all (is guarded by __main__ condition) there is no clean way to get access to that code. You can however run code of this module with substituted __name__ but that's very hackish.
You should refactor this module and move whole __main__ part into a method and call it like this:
def main():
do_everything()
if __name__ == '__main__':
main()
This way consumer apps will be able to run code without having to run it in a separate process.
Use the runpy module in the Python 3 Standard Library
See that data can be passed to and from the called script
# top.py
import runpy
import sys
sys.argv += ["another parameter"]
module_globals_dict = runpy.run_path("other_script.py",
init_globals = globals(), run_name="__main__")
print(module_globals_dict["return_value"])
# other_script.py
# Note we did not load sys module, it gets passed to this script
script_name = sys.argv[0]
print(f"Script {script_name} loaded")
if __name__ == "__main__":
params = sys.argv[1:]
print(f"Script {script_name} run with params: {params}")
return_value = f"{script_name} Done"
by what your saying you want to call a function in the script that is importing the module so try:
import __main__
__main__.myfunc()

How can I use rapportive.py in django

I am using rapportive in my python django projects. I am getting an error saying no information found
The file is listed below:
import sys
import logging
from textwrap import dedent
# Requests, from python-requests.org
from docopt import docopt
# pylint: disable=C0103
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
# pylint: enable=C0103
STATUS_URL = 'https://rapportive.com/login_status?user_email={0}'
URL = 'https://profiles.rapportive.com/contacts/email/{0}'
# pylint: disable=R0903
class Profile(object):
"""
Profile object for collecting profile information before printing
"""
def __init__(self, person):
if person:
self.name = person.get('name')
self.jobinfo = [
(occupation.get('job_title'), occupation.get('company'))
for occupation in person.get('occupations', [])
]
self.memberships = [
(membership.get('site_name'), membership.get('profile_url'))
for membership in person.get('memberships', [])
]
self.success = person.get('success')
def __str__(self):
return dedent("""
Name: {0}
{1}
{2}
""").format(
self.name,
"\n".join(
"{0} {1}".format(title, company)
for title, company in self.jobinfo),
"\n".join(
"\t{0} {1}".format(site_name, url)
for site_name, url in self.memberships)
)
def request(email):
'''
rapportive_request(email): Sends a query to the undocumented Rapportive API
Returns the response as a dict
'''
status_url = STATUS_URL.format(email)
response = requests.get(status_url).json()
session_token = response.get('session_token')
# fail gracefully if there is an error
if 'error' in response:
return response['error']
elif response['status'] == 200 and session_token:
logger.debug('Session token: {0}'.format(session_token))
url = URL.format(email)
headers = {'X-Session-Token': session_token}
response = requests.get(url, headers=headers).json()
if response.get('success') != 'nothing_useful':
return Profile(response.get('contact'))
return {}
def ___process_email(email, output_file=None):
"""
Find email address in rapportive and print profile info
if found
"""
profile = request(email)
if profile and profile.success != 'nothing_useful':
logger.info('Found match for {0}'.format(email))
print(profile)
if output_file:
output_file.write(summary + '\n')
else:
print("No information found\n")
def main():
'''
main(): Expect a list of email addresses via stdin
and check them with the Rapportive API
'''
options = docopt(__doc__, version="0.1.0")
logging.basicConfig(
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M')
if options["--verbose"]:
logger.setLevel(logging.DEBUG)
email = options.get("--email")
args = [email] if email else [line.rstrip() for line in sys.stdin]
output = options.get("--output")
output = output and open(output, "w")
for arg in args:
___process_email(arg, output)
if __name__ == '__main__':
main()
It seems working on my machine.
Just a few things:
the import request seems missing
in the function ___process_email the summary variable in not define, I suppose it's summary = str(profile)
an error in the indentation return Profile(response.get('contact')
You got your error form the request function, the if response.get('success') != 'nothing_useful' must always be False.
Have you seen this blog - there are some examples and some emails that's can be used.
I used this one and I go a result jmwright798#gmail.com

Why wont my Simple CGI Server handle AJAX Post requests?

I have created my own CGI python server script (that serves on port 8000) by following a tutorial. The server works beautifully if I want to generate web pages from python scripts, or serve a native HTML page BUT it doesn't work for when I make an AJAX POST request?
If I make an AJAX request to the python file aaa.py (using the javascript below) my server prints out the following error text:
Code 501, message can only POST to to CGI scripts
"POST /aaa.py HTTP/1.1" 501 -
What do you think I need to do to allow my python cgi server to allow/handle AJAX requests?
My CGI server:
__version__ = "0.4"
__all__ = ["CGIHTTPRequestHandler"]
import os
import sys
import urllib
import BaseHTTPServer
import SimpleHTTPServer
import select
class CGIHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
"""Complete HTTP server with GET, HEAD and POST commands.
GET and HEAD also support running CGI scripts.
The POST command is *only* implemented for CGI scripts.
"""
# Determine platform specifics
have_fork = hasattr(os, 'fork')
have_popen2 = hasattr(os, 'popen2')
have_popen3 = hasattr(os, 'popen3')
# pretend we don't have these to force execution in process
have_fork = 0
# Make rfile unbuffered -- we need to read one line and then pass
# the rest to a subprocess, so we can't use buffered input.
rbufsize = 0
def do_POST(self):
"""Serve a POST request.
This is only implemented for CGI scripts.
"""
if self.is_cgi():
self.run_cgi()
else:
self.send_error(501, "Can only POST to CGI scripts")
def send_head(self):
"""Version of send_head that support CGI scripts"""
if self.is_cgi():
return self.run_cgi()
else:
return SimpleHTTPServer.SimpleHTTPRequestHandler.send_head(self)
def is_cgi(self):
"""Test whether self.path corresponds to a CGI script.
Return a tuple (dir, rest) if self.path requires running a
CGI script, None if not. Note that rest begins with a
slash if it is not empty.
The default implementation tests whether the path
begins with one of the strings in the list
self.cgi_directories (and the next character is a '/'
or the end of the string).
"""
path = self.path
for x in self.cgi_directories:
i = len(x)
if path[:i] == x and (not path[i:] or path[i] == '/'):
self.cgi_info = path[:i], path[i+1:]
return True
return False
cgi_directories = ['/cgi-bin', '/htbin']
def is_executable(self, path):
"""Test whether argument path is an executable file."""
return executable(path)
def is_python(self, path):
"""Test whether argument path is a Python script."""
head, tail = os.path.splitext(path)
return tail.lower() in (".py", ".pyw")
def run_cgi(self):
"""Execute a CGI script."""
dir, rest = self.cgi_info
i = rest.rfind('?')
if i >= 0:
rest, query = rest[:i], rest[i+1:]
else:
query = ''
# i = rest.find('/')
# if i >= 0:
# script, rest = rest[:i], rest[i:]
# else:
# script, rest = rest, ''
script = rest
scriptname = dir + '/' + script
scriptfile = self.translate_path(scriptname)
if not os.path.exists(scriptfile):
self.send_error(404, "No such CGI script (%s)" % `scriptname`)
return
if not os.path.isfile(scriptfile):
self.send_error(403, "CGI script is not a plain file (%s)" %
`scriptname`)
return
ispy = self.is_python(scriptname)
if not ispy:
if not (self.have_fork or self.have_popen2 or self.have_popen3):
self.send_error(403, "CGI script is not a Python script (%s)" %
`scriptname`)
return
if not self.is_executable(scriptfile):
self.send_error(403, "CGI script is not executable (%s)" %
`scriptname`)
return
# Reference: http://hoohoo.ncsa.uiuc.edu/cgi/env.html
# XXX Much of the following could be prepared ahead of time!
env = {}
env['SERVER_SOFTWARE'] = self.version_string()
env['SERVER_NAME'] = self.server.server_name
env['GATEWAY_INTERFACE'] = 'CGI/1.1'
env['SERVER_PROTOCOL'] = self.protocol_version
env['SERVER_PORT'] = str(self.server.server_port)
env['REQUEST_METHOD'] = self.command
uqrest = urllib.unquote(rest)
env['PATH_INFO'] = uqrest
env['PATH_TRANSLATED'] = self.translate_path(uqrest)
env['SCRIPT_NAME'] = scriptname
if query:
env['QUERY_STRING'] = query
host = self.address_string()
if host != self.client_address[0]:
env['REMOTE_HOST'] = host
env['REMOTE_ADDR'] = self.client_address[0]
# XXX AUTH_TYPE
# XXX REMOTE_USER
# XXX REMOTE_IDENT
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length
accept = []
for line in self.headers.getallmatchingheaders('accept'):
if line[:1] in "\t\n\r ":
accept.append(line.strip())
else:
accept = accept + line[7:].split(',')
env['HTTP_ACCEPT'] = ','.join(accept)
ua = self.headers.getheader('user-agent')
if ua:
env['HTTP_USER_AGENT'] = ua
co = filter(None, self.headers.getheaders('cookie'))
if co:
env['HTTP_COOKIE'] = ', '.join(co)
# XXX Other HTTP_* headers
if not self.have_fork:
# Since we're setting the env in the parent, provide empty
# values to override previously set values
for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH',
'HTTP_USER_AGENT'):
###, 'HTTP_COOKIE' -- removed by S.
env.setdefault(k, "")
# for key in env.keys():
# print key + " '" + env[key] + "'"
os.environ.update(env)
self.send_response(200, "Script output follows")
decoded_query = query.replace('+', ' ')
if self.have_fork:
# Unix -- fork as we should
args = [script]
if '=' not in decoded_query:
args.append(decoded_query)
nobody = nobody_uid()
self.wfile.flush() # Always flush before forking
pid = os.fork()
if pid != 0:
# Parent
pid, sts = os.waitpid(pid, 0)
# throw away additional data [see bug #427345]
while select.select([self.rfile], [], [], 0)[0]:
if not self.rfile.read(1):
break
if sts:
self.log_error("CGI script exit status %#x", sts)
return
# Child
try:
try:
os.setuid(nobody)
except os.error:
pass
os.dup2(self.rfile.fileno(), 0)
os.dup2(self.wfile.fileno(), 1)
os.execve(scriptfile, args, os.environ)
except:
self.server.handle_error(self.request, self.client_address)
os._exit(127)
elif self.have_popen2 or self.have_popen3:
# Windows -- use popen2 or popen3 to create a subprocess
import shutil
if self.have_popen3:
popenx = os.popen3
else:
popenx = os.popen2
cmdline = scriptfile
if self.is_python(scriptfile):
interp = sys.executable
if interp.lower().endswith("w.exe"):
# On Windows, use python.exe, not pythonw.exe
interp = interp[:-5] + interp[-4:]
cmdline = "%s -u \"%s\"" % (interp, cmdline)
if '=' not in query and '"' not in query:
cmdline = '%s "%s"' % (cmdline, query)
self.log_message("command: %s", cmdline)
try:
nbytes = int(length)
except (TypeError, ValueError):
nbytes = 0
files = popenx(cmdline, 'b')
fi = files[0]
fo = files[1]
if self.have_popen3:
fe = files[2]
if self.command.lower() == "post" and nbytes > 0:
data = self.rfile.read(nbytes)
fi.write(data)
# throw away additional data [see bug #427345]
while select.select([self.rfile._sock], [], [], 0)[0]:
if not self.rfile._sock.recv(1):
break
fi.close()
shutil.copyfileobj(fo, self.wfile)
if self.have_popen3:
errors = fe.read()
fe.close()
if errors:
self.log_error('%s', errors)
sts = fo.close()
if sts:
self.log_error("CGI script exit status %#x", sts)
else:
self.log_message("CGI script exited OK")
else:
# Other O.S. -- execute script in this process
save_argv = sys.argv
save_stdin = sys.stdin
save_stdout = sys.stdout
save_stderr = sys.stderr
try:
try:
sys.argv = [scriptfile]
if '=' not in decoded_query:
sys.argv.append(decoded_query)
sys.stdout = self.wfile
sys.stdin = self.rfile
execfile(scriptfile, {"__name__": "__main__"})
finally:
sys.argv = save_argv
sys.stdin = save_stdin
sys.stdout = save_stdout
sys.stderr = save_stderr
except SystemExit, sts:
self.log_error("CGI script exit status %s", str(sts))
else:
self.log_message("CGI script exited OK")
nobody = None
def nobody_uid():
"""Internal routine to get nobody's uid"""
global nobody
if nobody:
return nobody
try:
import pwd
except ImportError:
return -1
try:
nobody = pwd.getpwnam('nobody')[2]
except KeyError:
nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
return nobody
def executable(path):
"""Test for executable file."""
try:
st = os.stat(path)
except os.error:
return False
return st.st_mode & 0111 != 0
def test(HandlerClass = CGIHTTPRequestHandler,
ServerClass = BaseHTTPServer.HTTPServer):
SimpleHTTPServer.test(HandlerClass, ServerClass)
if __name__ == '__main__':
test()
Code in aaa.py:
#!/usr/bin/env python
import cgitb; cgitb.enable()
import cgi
import os
print "Content-Type: text/html\n"
input_data = cgi.FieldStorage()
print "hello"
My AJAX/ Javascript:
function onTest( dest, params )
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById( "bb" ).innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST",dest,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send( params );
}
when you use the python http cgi server, cgi scripts have to be under the subdir (from you server script ) /cgi-bin

Categories

Resources