joehooper / salesforce-python-toolkit

Automatically exported from code.google.com/p/salesforce-python-toolkit
GNU Lesser General Public License v3.0
0 stars 0 forks source link

Any plans on supporting the metadata API? #8

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
This is a great library.  Any plans on supporting the metadata API?

I tried to hack it up myself, but the trick is that the metadata WSDL does not 
define login/logout methods, so you have to connect with either the partner or 
enterprise WSDL.  I would like to avoid merging the login/logout definitions.  
Instead, I tried to login with the partner WSDL, then change the WSDL to 
metadata WSDL, buy overwriting the underlying Client object, but it didn't 
work. 

sf = SforceBaseClient(parterWsdlFile)    
result = sf.login(username, password, sectoken)
if '://' not in metaWsdlFile:
  if os.path.isfile(metaWsdlFile):
    metaWsdl = 'file://' + os.path.abspath(metaWsdlFile)
sf._sforce = Client(metaWsdl)
sf._sforce.set_options(location = result.metadataServerUrl)

header = sf.generateHeader('SessionHeader')
header.sessionId = result['sessionId']
sf.setSessionHeader(header)
sf._sessionId = result['sessionId']

Original issue reported on code.google.com by cw10...@gmail.com on 7 Feb 2011 at 3:34

GoogleCodeExporter commented 8 years ago
I meant to create this issue as type "enhancement", but I see no way to edit an 
existing issue, or even delete it (to re-create).

Original comment by cw10...@gmail.com on 7 Feb 2011 at 3:41

GoogleCodeExporter commented 8 years ago

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 7:05

GoogleCodeExporter commented 8 years ago
Thanks!  hmmm...  I haven't ever used the Metadata API, but I can tell you that 
doing anything low-level with this stuff is a royal pain - that's why I wrote 
it!  :)  Just looking at this stuff makes my head hurt.  Anyway, I found this 
Java snippet 
(http://www.salesforce.com/us/developer/docs/api_meta/Content/meta_deploy.htm) 
that shows that your approach is correct in terms of logging in with the 
Enterprise client:

public class DeploySample {
    // binding for the Enterprise WSDL used for login() call  

    private SoapBindingStub binding;
    // binding for the metadata WSDL used for create() and checkStatus() calls  

The fundamental problem is going to be attaching the session key to each 
subsequent call, I suspect.  Depending on how many different calls you need to 
make, and the quirkiness of each, it may be easier to use Suds directly - some 
of the complexity comes from making sure absolutely everything in the API is 
supported, which you won't need.  I'm having trouble envisioning how this would 
work with Suds without hacking up the WSDLs...  Out of morbid curiosity, can 
you try extending the base client, adding a basic stub method like

  def delete(self, ids):
    '''
    Deletes one or more objects
    '''
    self._setHeaders('delete')
    return self._handleResultTyping(self._sforce.service.delete(ids))

  def emptyRecycleBin(self, ids):

and let me know what the output is?

Thanks for your interest!

David

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 7:44

GoogleCodeExporter commented 8 years ago
When you say, "base client", I am assuming you're referring to 
"sforce.SforceBaseClient" - this class already has a method, "delete" with 
exactly the code you quote.   I'm I missing what you're asking?

Original comment by cw10...@gmail.com on 7 Feb 2011 at 9:11

GoogleCodeExporter commented 8 years ago
ah, that was just an example, but basically I'm suggesting trying to subclass 
SforceBaseClient (in base.py), and override a method to see what happens, 
something like

class Foo(SforceBaseClient):
  def delete(self, ids):
    return self._sforce.service.delete(ids)

so you're basically just patching through the call to Suds, I'm curious what 
the output will be.

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 9:20

GoogleCodeExporter commented 8 years ago
Got it.  Here goes:

{{{
Error, caught suds.WebFault: Server raised fault: 'INVALID_SESSION_ID: Invalid 
Session ID found in SessionHeader: Illegal Session' 
No handlers could be found for logger "suds.client"
Traceback (most recent call last):
  File "/Users/cwolf/Documents/workspace/xlstest/src/sfmeta.py", line 393, in ?
    loginToSalesforce(username, password, sectoken)
  File "/Users/cwolf/Documents/workspace/xlstest/src/sfmeta.py", line 121, in loginToSalesforce
    sf.delete(['a015000000YrzWj'])
  File "/Users/cwolf/Documents/workspace/xlstest/src/sfmeta.py", line 101, in delete
    return self._sforce.service.delete(ids)
  File "build/bdist.macosx-10.3-fat/egg/suds/client.py", line 539, in __call__
  File "build/bdist.macosx-10.3-fat/egg/suds/client.py", line 598, in invoke
  File "build/bdist.macosx-10.3-fat/egg/suds/client.py", line 633, in send
  File "build/bdist.macosx-10.3-fat/egg/suds/client.py", line 684, in failed
  File "build/bdist.macosx-10.3-fat/egg/suds/bindings/binding.py", line 238, in get_fault
suds.WebFault: Server raised fault: 'INVALID_SESSION_ID: Invalid Session ID 
found in SessionHeader: Illegal Session'
}}}

Original comment by cw10...@gmail.com on 7 Feb 2011 at 9:35

GoogleCodeExporter commented 8 years ago
BTW, a bit off-topic, but here's what I used your project for:
http://trac-hacks.org/wiki/TicketToSalesforcePlugin

I wish google-code used Trac instead of this half-baked issue-tracker here. 
(Can't edit issues, can't edit comments, Wiki markup not consistently honored)

Original comment by cw10...@gmail.com on 7 Feb 2011 at 9:54

GoogleCodeExporter commented 8 years ago
ok, before 

    return self._sforce.service.delete(ids)

add

    self._setHeaders()

and let's see what happens.

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 9:56

GoogleCodeExporter commented 8 years ago
Very cool!  I used an open-source project to make my open-source project which 
is used by your open-source project.  And yes, Trac would be awesome :-/

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 10:08

GoogleCodeExporter commented 8 years ago
Yep.  That worked.  Then I changed my original hack to:

    if '://' not in metaWsdlFile:
      if os.path.isfile(metaWsdlFile):
        metaWsdl = 'file://' + os.path.abspath(metaWsdlFile)
    sf._sforce = Client(metaWsdl)
    sf._sforce.set_options(location = result.metadataServerUrl)

    sf._setHeaders()

..then I called a metadata API ("listmetadata"):

        obj = sf._sforce.factory.create('ListMetadataQuery')
        obj.type = 'CustomObject'
        args = []
        args.append(obj)
        result = sf._sforce.service.listMetadata(args, 20.0)

        print result

And it totally worked!  Of course I'm dropping down into suds to make the call, 
but I see where this is going...    

Original comment by cw10...@gmail.com on 7 Feb 2011 at 10:11

GoogleCodeExporter commented 8 years ago
Awesome!  really, it's not much different from what the Toolkit does for most 
calls, you're just attaching the HTTP headers as needed and dropping down.  A 
lot of what the Toolkit handles is normalizing the objects that get returned, 
as it's often inconsistent, but as long as you don't run into any weirdness for 
the calls that you need, great!

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 10:19

GoogleCodeExporter commented 8 years ago
If I find the time to properly implement a subclass of SforceBaseClient, 
"SforceMetadataClient", which implements metadata methods - would you accept 
the patch?  (Assuming my code is not too horrible)  I would base it off 0.3.9 
since 0.4.0 appears broken.

Original comment by cw10...@gmail.com on 7 Feb 2011 at 10:36

GoogleCodeExporter commented 8 years ago
To be honest, I think you'll find that 80% of what you'll need to do is dead 
simple and the other 20% is very, very difficult.  I'd be especially hesitant 
because you'd need to do threading for deploy().  That said, you are of course 
more than welcome to share what you've come up with, provided it's compatible 
with Suds 0.3.6-0.3.9, has unit tests in the ballpark of what I have in 
tests/base.py, and is documented to the extent that I've done so in the 
EXAMPLES file.  

David

Original comment by dlanst...@gmail.com on 7 Feb 2011 at 11:08

GoogleCodeExporter commented 8 years ago
Right, in my prior comment, I was referring to suds, not your code, when 
mentioning 0.3.9 and 0.4.0.  There's nothing wrong with having certain 
standards, and if what I come up with doesn't fit in - no hard feelings.  I 
will be lucky to find the time anyway...

BTW, thanks a lot for your timely help on this matter.

Original comment by cw10...@gmail.com on 7 Feb 2011 at 11:21