+ Start a Discussion
Gareth DaviesGareth Davies 

Example Python Interface to Logon to Salesforce.com

Hello,

I spent an interesting day trying to find out why I could not use the wsdl file with SOAPpy (or with ZSI) then tried to
use SOAPpy calling using home-grown class definitions, but could not get that to work either - because SF.com
rejected the nesting of tags thrown up by SOAPpy - which I could not figure out how to turn-off.

In the end I wrote the following example code for doing it all by hand. If you are really stuck and need to develop in Python this may help you out:

Note I am not offering to support it, if someone would like to make it "safer", "tidier" and extend the data types
please post it back.

Best of Luck
Gareth

PS if you got SOAPpy or ZSI to work let me know how, as that would be neater.



########################################################
# Upside Outcomes Ltd, July 22nd 2004
#
# Example Python WebServices Code for Salesforce.com
#
# I tried using SOAPpy and ZSI but could not
#
# a> get the SF.com WSDL file to load
# b> get SF.com to take use the code generated by SOAPpy
# which put tags around the data objects, which through up complaints.
#
# This code allows you to create a login session. To go further you will need
# create objects for request and response messages for different operations
# Use this as a template and you should go OK.
#
# Copyright (c) Upside Outcomes Ltd www.upside-outcomes.com 2004
# You are free to use, copy, modify and distribute this code without charge provided that
# you do not
# 1. claim it to be your own or
# 2. claim that you own the copyright or
# 3. prevent others from doing the same
#
# And provided you include the following message:
#
# "Some of this code contains elements written by Upside Outcomes ltd. www.upside-outcomes.com "
#
#########################################################


import sys, httplib
from xml.sax import saxutils
from xml.sax import make_parser
from xml.sax.handler import feature_namespaces
from xml.sax import ContentHandler

SFNS='"urn:enterprise.soap.sforce.com"'
SFSERVER="https://www.salesforce.com/services/Soap/c/4.0"
USER="YOURNAME"
PASS="YOURPASSWORD"



def NormaliseWhiteSpace(text):
"Remove redundant whitespace from a string"
return ' '.join(text.split())



############################# Message Receiver #######


class LoginResponse (ContentHandler):
def __init__ (self):

#Initialise State Flags
self.inEnvelope=0
self.inBody=0
self.inLoginResponse=0
self.inResult=0
self.inServerUrl=0
self.inSessionId=0
self.inUserId=0
######### Data Space"
self.namespace=""
self.serverUrl=""
self.sessionId=""
self.userId=""

def startElement (self, name, attr):
if name == 'soapenv:Envelope': self.inEnvelope=1
if name == 'soapenv:Body': self.inBody=1
if name == 'logingResponse': self.inLoginResponse=1
if name == 'result': self.inResult=1
if name == 'serverUrl': self.inServerUrl=1
if name == 'sessionId': self.inSessionId=1
if name == 'userId': self.inUserId=1

def characters (self,ch):
if self.inServerUrl: self.serverUrl +=ch
if self.inSessionId: self.sessionId +=ch
if self.inUserId: self.userId += ch

def endElement (self, name ):
if name == 'soapenv:Envelope': self.inEnvelope=0
if name == 'soapenv:Body': self.inBody=0
if name == 'logingResponse': self.inLoginResponse=0
if name == 'result': self.inResult=0
if name == 'serverUrl': self.inServerUrl=0
if name == 'sessionId': self.inSessionId=0
if name == 'userId': self.inUserId=0


################### Message sender ####################

class Request:
def __init__ (self):
self.namespace=SFNS
self.objectType="null"
self.dataTypes=[]
self.data={}

def StartWS (self):
return '''


'''
def StopWS (self):
return """


"""
def SOAPMessage (self):
outstr=self.StartWS() + "\n"
outstr+="\n"
for element in self.dataTypes:
outstr+=""+self.data[element]+"\n"
outstr += ""
outstr += self.StopWS()
return (outstr)
class LogonRequest (Request):
def __init__ (self,u="",p=""):

Request.__init__(self)

self.ObjectType="login"
self.dataTypes=["username","password"]
self.data["username"]=u
self.data["password"]=p




####################


def Logon():

########### a=LogonRequest(USER,PASS)
Soapmessage = a.SOAPMessage()
blen = len(Soapmessage)
requestor = httplib.HTTP("www.salesforce.com", 80)
requestor.putrequest("POST", SFSERVER)
requestor.putheader("Host", "www.salesforce.com")
requestor.putheader('Content-Type", "text/plain; charset=utf-8')
requestor.putheader("Content-Length", str(blen))
requestor.putheader("SOAPAction", "")
requestor.endheaders()
requestor.send(Soapmessage)

#############


(status_code, message, reply_headers) = requestor.getreply()
reply_body = requestor.getfile().read()

print "status code:", status_code
print "status message:", message

############
# Set up the XML parser
p=make_parser()
message=LoginResponse()
p.setFeature(feature_namespaces, 0)
p.setContentHandler(message)
p.feed(reply_body)
print "SessionID: " + str(message.sessionId)
print "ServerURL: " + str(message.serverUrl)
print "UserId: " + str(message.userId)



if __name__ == "__main__":
Logon()
Gareth DaviesGareth Davies

Cut and Paste removed the indentign information.

Either put it back in or send an email to the autoresponder sfpython@upside-outcomes.com and it will send you a copy.

solonsolon

Hi Gaerth,

how far did you go with ZSI? My first try gives me this result:

Python 2.3.3 (#51, Dec 18 2003, 20:22:39) [MSC v.1200 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ZSI import ServiceProxy
>>> from ZSI.wstools.WSDLTools import WSDLReader
>>>
>>> user="xxxxxxxxxxxxxxxxxxxxxx"
>>> passwd="xxxxxxxxxxx"
>>>
>>> wsdl=WSDLReader().loadFromURL("partner.wsdl.xml")
>>> proxy=ServiceProxy(wsdl=wsdl)
Traceback (most recent call last):
  File "", line 1, in ?
  File "E:\PYTHON23\lib\site-packages\ZSI\ServiceProxy.py", line 55, in __init__
    callinfo = wstools.WSDLTools.callInfoFromWSDL(self._port, item.name)
  File "E:\PYTHON23\lib\site-packages\ZSI\wstools\WSDLTools.py", line 1099, in callInfoFromWSDL
    part = messages[item.message].parts[item.part]
  File "E:\PYTHON23\Lib\site-packages\ZSI\wstools\Utility.py", line 570, in __getitem__
    return self.data[key]
KeyError: u'tns:Header'
>>>

Using Python 2.3.3 and ZSI 1.5.0

Tweaking the wsdl (partner) file by changing all "tns:Header" to "Header" allows me to get the ServiceProxy class instantiated.

 Next step for me was to try a login which was so far without success for me. I am posting here the result (this is after changing in client.py from ZSI line 93 to self.port=int(port) ):

>>> from ZSI import ServiceProxy
>>> from ZSI.wstools.WSDLTools import WSDLReader
>>>
>>> user="xxxxxxxxxxxxxxxxxxxxxx"
>>> passwd="xxxxxxxxxxx"
>>>
>>> wsdl=WSDLReader().loadFromURL("partner.wsdl.xml")
>>> proxy=ServiceProxy(wsdl=wsdl)
>>> proxy.login()
Traceback (most recent call last):
  File "", line 1, in ?
  File "E:\PYTHON23\lib\site-packages\ZSI\ServiceProxy.py", line 279, in __call__
    return self.parent()._call(self.__name__, *args, **kwargs)
  File "E:\PYTHON23\lib\site-packages\ZSI\ServiceProxy.py", line 87, in _call
    apply(getattr(binding, callinfo.methodName), args)
  File "E:\PYTHON23\lib\site-packages\ZSI\client.py", line 28, in __call__
    requesttypecode=TC.Any(self.name, aslist=1))
  File "E:\PYTHON23\lib\site-packages\ZSI\client.py", line 143, in RPC
    self.Send(url, opname, obj, **kw)
  File "E:\PYTHON23\lib\site-packages\ZSI\client.py", line 210, in Send
    self.h.connect()
  File "E:\Python23\lib\httplib.py", line 985, in connect
    ssl = socket.ssl(sock, self.key_file, self.cert_file)
  File "E:\PYTHON23\lib\socket.py", line 73, in ssl
    return _realssl(sock, keyfile, certfile)
socket.sslerror: (1, 'error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol')
>>>

Annotations:

Why did I call login() withotu arguments: At this stage I had no idea in which form the function wanted to have the arguments (2 strings, 1 tuple, ...)

I hope we can exchange some Python+ZSI+sForce experience.

Solon.

Gareth DaviesGareth Davies
Hi there Solon,

Thanks for the post. I have not tried ZSI yet - Sticking with SOAPpy until I understand the errors. You were right though replacing tns:Header with Header did allow the SOAPpy libs to read the wsdl file. Not sure if it made sense of it yet.....

I just tried a to use the login function, but no joy. I hope to get some time to look at this again this week.

In the mean time send me your email to: info@upside-outcomes.com and I'll keep you updated with developments. We can post back once we have cracked it.

(if anyone else wants to contribute to the cracking of the python problem drop me an email too) and I'll set up a reflector until we have it cracked.

Gareth.
Gareth DaviesGareth Davies
THis is close to working......

This is the code I used:

#####################################
import SOAPpy
from SOAPpy import WSDL
from SOAPpy import SOAPProxy

server = WSDL.Proxy('partner.wsdl')

class loginrequest:
def __init__ (self,u="",p=""):
self.username=u
self.password=p


url="https://www.salesforce.com/services/Soap/c/4.0"
namespace="urn:enterprise.soap.sforce.com"

SOAPpy.Config.debug=1
loginstring=loginrequest("MYUSER","MYPASS")

ls=server.login(loginstring)
print ls

################################

This is the SOAP Debug Message it generates (Note if I put wrong User/Pass then I get
error 500 - so this is validating part of the response. I think it is close to working)

#####

*** Outgoing HTTP headers **********************************************
POST /services/Soap/u/4.0 HTTP/1.0
Host: www.salesforce.com
User-agent: SOAPpy 0.11.4 (http://pywebsvcs.sf.net)
Content-type: text/xml; charset="UTF-8"
Content-length: 562
SOAPAction: "login"
************************************************************************
*** Outgoing SOAP ******************************************************





XXXXXX
XXXXXX




************************************************************************
######################RESPONSE######

code= 200
msg= OK
headers= Server: Resin/3.0.s040331

Content-Type: text/xml; charset=utf-8

Connection: close

Date: Tue, 10 Aug 2004 23:06:06 GMT


content-type= text/xml; charset=utf-8
data=



ns1:Server.NoService
The AXIS engine could not find a target service to invoke! targetService is u/4.0





############################

The target outgoing SOAP from the manual is:

POST https://www.salesforce.com/services/Soap/c/4.0 HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol
1.1.4322.573)
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Content-Length: 367
Expect: 100-continue
Host: www.salesforce.com


xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://
www.w3.org/2001/XMLSchema">


user@domain.com
secret




#################################
Which should be answered by this:
#################################

HTTP/1.1 200 OK
Server: sfdc
Content-Type: text/xml; charset=utf-8
Transfer-Encoding: chunked
Date: Wed, 07 Jul 2004 17:36:19 GMT


xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance">



https://na1.salesforce.com/services/Soap/c/4.0serverUrl>

z1E_NI80RXGyM48GB2etyLuR8DBeG4lyRk_MTjFeOxPed0_jXlNKOSU
00530000000tt6MAAY



Gareth DaviesGareth Davies
Is it just me - or is cutting and pasting code and responses just not working?
Send me an email and I will send you the listing...
G.