salesforce-marketingcloud / fuelsdk-python Goto Github PK
View Code? Open in Web Editor NEWFuelSDK for python
License: Other
FuelSDK for python
License: Other
The wsdl file is getting opened with an un-needed write bit.
I'm following the example here: https://github.com/salesforce-marketingcloud/FuelSDK-Python/blob/master/objsamples/sample_triggeredsend.py under the # Send an email with TriggeredSend heading.
I know I have a valid Customer Key, but it consistently returns this error. Snippet:
client = FuelSDK.ET_Client(
debug=settings.DEBUG,
params={
'clientid': settings.get('API_CLIENT_ID'),
'clientsecret': settings.get('API_CLIENT_SECRET'),
}
)
triggered_send = FuelSDK.ET_TriggeredSend()
triggered_send.auth_stub = client
triggered_send.props = {'CustomerKey': email_code}
triggered_send.subscribers = [{'EmailAddress': email, 'SubscriberKey': subscriber_id}]
triggered_send.attributes = variables
result = triggered_send.send()
Here's a quick and dirty JSON representation of what I'm getting back:
{
"results": [
{
"status_code": "Error",
"status_message": "The Triggered Send Object must contain the Triggered Send ID or the Customer Key",
"ordinal_id": 0,
"error_core": 18002,
"new_id": 0
}
],
"code": 200,
"status": false,
"message": "Error",
"request_id": "<snip>"
}
Is it possible to get a new Pypi release now that 1c34101 is in? Providing configuration as a parameter to the ET_Client is exactly what we'd like to do in our application.
I just added some unit tests to another API client I use in my project. I used an excellent HTTP server mock utility called HTTPretty. It makes it easy to test an HTTP client against a fake server. You can return any arbitrary fake HTTP response and make assertions against the client's handling of those responses.
https://github.com/gabrielfalcao/HTTPretty
These tests were written only to test the basic functionality I needed (and some changes I made to the library, so they are not a good example of full tests, but a good starting point).
Could we get a new pypi release with 8601135 ? Would be much appreciated for pypi setup scripts.
I suggest adding the SDK to PyPI, this will make it much easier to use for Python developers who are used to installing dependencies using pip. This will require authoring a setup.py for distutils / setuptools.
http://docs.python.org/2/distutils/setupscript.html
If you are amiable to this, I would be happy to help with an initial setup.py.
It seems like None
is always passed as SaveOptions
for object manipulation calls, see for example (it's the first parameter to Create
):
https://github.com/ExactTarget/FuelSDK-Python/blob/master/FuelSDK/rest.py#L197
It would be really nice if options could be passed here somehow. In my specific case, I want to change SaveAction
to UpdateAdd
per:
But I guess other SaveOptions
could be useful too, so a general solution would be better.
I currently solve this by constructing my own SOAP call, which I would rather not, since this SDK is so nice otherwise :)
There is a bug in SUDS library to pick up proxy settings from the environment variables http_proxy & https_proxy. The authentification request use proper proxy but the actual SOAP call doesn't.
Explicit initiation of the client with proxy settings detected by urllib2 does solve the problem.
@amagar088 pls look at pull request for fix Pass proxy settings to suds library configuration
Updated to 0.9.3 from 0.9.2 and Triggered Sends started failing. Using code example from docs. Throw from FuelSDK/objects.py:127 .
Where do I start, there are countless issues with this API, let me address some of them here.
First is the need to patch an external module to fix issues with your API, you could bundling that package locally rather than relying on the user to install the package then modify it with your requirements.
There is no way to specify the location of the configuration file for the Client, it is just hard coded to a non absolute path.
########
##
## Setup web service connectivity by getting need config data, security tokens etc.
##
########
class ET_Client(object):
Okay, style wise, this really needs to be a document string. The bracket of comments look ugly and take up 5 lines.
It would be far nicer to read
class Client(object):
"""Setup web service connectivity by getting needed config data, security tokens etc."""
The naming scheme in this project is inconstant at best. The naming of every class in this library is prefixed with ET_
this is a redundant naming convention and isn't used in Python. Sometimes variables and functions are defined as self.authToken
and sometimes its self.refresh_token()
and sometimes its def determineStack(self):
It really doesn't matter which one is used but stick to a style and use it.
You are using an undefined variable before its defined. This will cause horrible errors during execution.
Are those comments or another language? If so why are they presented as nop strings?
## FIX THIS
Comments like this are just scary. At least throw me an undefined behaviour exception so I know something unplanned is happening.
Most scary are your init methods.
def __init__(self):
super
Has no effect at all.
If there is inherited behaviour these classes are relying on this could cause subtle breaks in the object.
When you have used super correctly you forgot to specify the where
clause.
You return values from __init__
in several places. This is going to cause runtime exceptions all over the place.
My lint and code smell tools alone detected 180 code issues, most of which were mostly naming and style violations but some of which are more obvious, let me list a few here
This is supposed to be a professional project. The code in this client library is horrid. I have spent a whole morning trying to modify it to bring it up to standard and I have given up after the mountain of major issues just kept piling up.
This code is totally unfit for production until someone really takes a chainsaw to it and cuts away everything that they can.
When building a search filter, ET_Get does not support the AdditionalOperands part of the ComplexFilterPart. I need to be able to search for data extensions using more than two search filters.
can a newer version be pushed please?
I get the following error out of the box:
file_url = 'file:///' + file_location
TypeError: cannot concatenate 'str' and 'bool' objects
The problem seems to be in the logic on line 124 of client.py:
if wsdl_file_local_location is not None:
file_location = wsdl_file_local_location
wsdl_file_local_location is False for me so file_location gets set to False instead of being set properly. Changing the above to the below fixes the problem for me.:
if wsdl_file_local_location:
file_location = wsdl_file_local_location
This feature appears not be supported. The ET_Get() class in the rest.py file does not set the 'ClientIDs' and 'QueryAllAccounts' properties of the 'RetrieveRequest' Object. It should expose those params in its _init() method.
The page Retrieving Folder Details references the property ET_Folder.filter. The correct name is "search_filter". I found this in the Python example tab but it may be in the other tabs as well.
User verified locally that removing the scope key/value pair eliminates the error.
A user is experiencing this issue. Wondering if the if/else at client.py:181 is out of date as it still uses "scope."
I've received the following exception against both the test and production APIs.
Exception: Unable to validate App Keys(ClientID/ClientSecret) provided: {'errorcode': 1, 'message': 'Unauthorized', 'documentation': ''}
We've been using Sentry to log the errors so I've seen this exception 31k times. I've ensured that I have the correct client id and client secret in all environments. The request seems to work fine to initially retrieve an access token, but then fails when refreshToken and scope are included in the json request payload.
The release notes for Java SDK are very clear how to add multiple rows to extension simultaneously. This python SDK is not clear. If it is possible to insert in batch, could you please add an example to
https://github.com/ExactTarget/FuelSDK-Python/blob/master/objsamples/sample_dataextension.py
suds.TypeNotFound: Type not found: '__AdditionalEmailAttribute1'
I have been getting this error when using the v1.0.0. branch.
Any idea what is going on? I can do some stuff, but when I attempt to send an email, then I get that error.
email.props = {"ID" : "151515151", "Name": "SDK Example, now Updated!"}
email.post()
ERROR:
suds.TypeNotFound: Type not found: '__AdditionalEmailAttribute1'
I am unsure of the license this code is released under. Please clear up this confusion by adding a LICENSE file to the root.
The excellent Python requests library bundles some of it's requirements within it's distribution (/packages subdir). I suggest doing the same with the patched up version of suds.
https://github.com/kennethreitz/requests/tree/master/requests/packages
That is of course if you cannot achieve the necessary results using monkey patching. I have not yet looked closely enough at the changes to know if that is possible.
This change seem only to regard Data Extension rows:
It would be nice with support for bulk operations on other object types as well, such as subscribers.
The documentation at https://code.exacttarget.com/apis-sdks/fuel-sdks/subscribers/subscriber-retrieve.html#pythonpost lists that we should be able to limit the number of fields returned. It explicitly states the property 'ID' can be used. If a call lists the props with only SubscriberKey, the results contain only the SubscriberKey. As soon as I add 'ID' to the list of props, the results return all fields.
Example:
debug = False
stubObj = ET_Client.ET_Client(False, debug)
getSubscriber = ET_Client.ET_Subscriber()
getSubscriber.auth_stub = stubObj
getSubscriber.props = ['ID','SubscriberKey','EmailAddress']
This will return all fields. Where as the following only returns the explicitly requested fields:
debug = False
stubObj = ET_Client.ET_Client(False, debug)
getSubscriber = ET_Client.ET_Subscriber()
getSubscriber.auth_stub = stubObj
getSubscriber.props = ['SubscriberKey','EmailAddress']
I'm not sure if this is an issue with API itself, the documentation being incorrect, or the SDK. If I can provide more info, please advise. I'm fairly new to Python, so please go easy on me.
Hi,
When I try to install suds 0.4 I get an error: "no module named client".
Is this a known issue?
Any work-arounds?
Is it possible to use "suds-jurko" instead?
I understand that it's their issue, but installing custom suds is part of the setting up "FuelSDK".
So, the problem is that with C# I could solve this issue with the following code:
private SoapClient CreateETFrameworkBinding(string endpointAddress, string username, string password)
{
// Create the binding
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "SoapBinding";
binding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 2147483647;
// Set the transport security to UsernameOverTransport for Plaintext usernames
var endpoint = new EndpointAddress(endpointAddress);
// Create the SOAP Client (and pass in the endpoint and the binding)
SoapClient etFramework = new SoapClient(binding, endpoint);
// Set the username and password
etFramework.ClientCredentials.UserName.UserName = username;
etFramework.ClientCredentials.UserName.Password = password;
return etFramework;
}
Now I'm trying to migrate to python the code, but so far I think that maybe I'm too dumb to really work with SOAP on python, so, here I'm trying to make this work with the Fuel Sdk. I look at the java repository and found that there's an option to use the username / password authentication rather than client ID / client Secret but in the python repository I just couln't figure it out how to connect with exacttarget.
Any lights?
I keep seeing the following error:
suds.client in process_reply
<suds.sax.document.Document object at 0x7fe04e4566d8>
If I restart my celery workers, than the error goes away, but I'm not sure why the restart would be necessary.
GitHub and PyPi seem to be out of sync.
0.9.3 is the only version on PyPi, but isn't tagged on github.
0.9.4 is the most recent tagged release on GitHub, but hasn't been pushed to PyPi.
Can this be resolved?
I am looking for an example of using the FuelSDK to query Clicks & Opens using a complex filter object to pull data for a range of dates (EventDate <= a date and >= to a date).
Specifically, consider the following line from a current sample (
https://github.com/ExactTarget/FuelSDK-Python/blob/master/objsamples/sample_openevent.py ) :
getOpenEvent.search_filter = {'Property' : 'EventDate','SimpleOperator' : 'greaterThan','DateValue' : retrieveDate}
Can an example be provided of what this might look like to pull data for open events between two dates?
Per issue #25, I believe complex operators are now supported but I am not sure how to use them.
is there a reason, this change has been made.
Im running a project which uses Flask-JWT==0.3.2 and it has the following requirement
flask-jwt 0.3.2 has requirement PyJWT<1.5.0,>=1.4.0, but you'll have pyjwt 1.5.0 which is incompatible.
so as you can see, this is a conflict with fuelsdk since fuelsdk requires pyjwt>=1.5.3
We're having issues trying to create Import Definitions with the FuelSDK for Python. We've managed to add another class in the objects.py class. Which allows us to read and delete.
class ET_Import(ET_CUDSupport):
def __init__(self):
super(ET_Import, self).__init__()
self.obj_type = 'ImportDefinition'
However, when we try to create an Import Definition, it returns with this error:
post_response: <FuelSDK.rest.ET_Post object at 0x1098f41d0>
code: 200
results: [(CreateResult){
StatusCode = "Error"
StatusMessage = "ID of the custom object cannot be empty."
OrdinalID = 0
ErrorCode = 43040
NewID = 0
Object =
(ImportDefinition){
PartnerKey = None
ObjectID = None
CustomerKey = "000001-22222-33333-44444-55555-66666"
Name = "Aaaaaaaaaaaaaaaaaaaaaaaa"
Description = "This is a test from Python"
AllowErrors = True
DestinationObject =
(APIObject){
PartnerKey = None
ID = 463703
ObjectID = None
}
FieldMappingType = "InferFromColumnHeadings"
FileSpec = "file_that_is_on_the_ftp.csv",
FileType = "Other"
Notification =
(AsyncResponse){
ResponseType = "email"
ResponseAddress = "my email address}"
}
RetrieveFileTransferLocation =
(FileTransferLocation){
PartnerKey = None
ObjectID = None
CustomerKey = "ExactTarget Enhanced FTP"
}
SubscriberImportType = "Email"
UpdateType = "AddAndUpdate"
Delimiter = ";"
}
}]
status: False
Here's what our call looks like:
def create_import_def(self):
create_imp_def = FuelSDK.ET_Import()
create_imp_def.auth_stub = self.myClient
list_id = 463703
create_imp_def.props = {
"CustomerKey": "000001-22222-33333-44444-55555-66666",
"Name": "Aaaaaaaaaaaaaaaaaaaaaaaa",
"Description": "This is a test from Python",
"DestinationObject": {
"ID": list_id
},
"AllowErrors": True,
"Notification": {
"ResponseType": "email",
"ResponseAddress": "{my email address}"
},
"RetrieveFileTransferLocation": {
"CustomerKey": "ExactTarget Enhanced FTP"
},
"UpdateType": "AddAndUpdate",
"FieldMappingType": "InferFromColumnHeadings",
"FileSpec": "file_that_is_on_the_ftp.csv",
"FileType": "Other",
"Delimiter": ";",
"SubscriberImportType": "Email"
}
post_response = create_imp_def.post()
print 'post_response: ', post_response
print "code:", post_response.code
#print "message:", post_response.message
#print "more_results:", post_response.more_results
#print "request_id", post_response.request_id
print "results:", post_response.results
print "status:", post_response.status
We've tried many different attempts to get this to work changing out various fields and values. We've even tried to manipulate the XML SOAP envelope to match what the FuelSDK-PHP uses before its sent out, but no luck.
The ID
field in the propslist for ET_OpenEvent is set to 0 when the value exceeds the 32 bit range.
i.e., The ID
field was unique and auto-incrementing for a while till it was within the int range post which it was statically only 0.
This field was used as the unique identifier of the event.
Get rid of the config.python file.
The suds is a problem, and I just comment out everything about Suds and Suds-patch, then it works.
But I just found many Python 2 in the code,
Is this package officially ready for Python 3? Or only for Python 2?
Running the following code:
import ET_Client
myclient = ET_Client.ET_Client()
triggeredsend = ET_Client.ET_TriggeredSend()
triggeredsend.auth_stub = myclient
results = triggeredsend.get()
print results
Gives me:
No handlers could be found for logger "suds.umx.typed"
Traceback (most recent call last):
File "/my/path/et.py", line 113, in <module>
results = triggeredsend.get()
File "/my/path/lib/python2.7/site-packages/FuelSDK/rest.py", line 288, in get
obj = ET_Get(self.auth_stub, self.obj_type, props, search_filter)
File "/my/path/lib/python2.7/site-packages/FuelSDK/rest.py", line 192, in __init__
response = auth_stub.soap_client.service.Retrieve(ws_retrieveRequest)
File "/my/path/lib/python2.7/site-packages/suds/client.py", line 538, in __call__
return client.invoke(args, kwargs)
File "/my/path/lib/python2.7/site-packages/suds/client.py", line 602, in invoke
result = self.send(soapenv)
File "/my/path/lib/python2.7/site-packages/suds/client.py", line 643, in send
result = self.succeeded(binding, reply.message)
File "/my/path/lib/python2.7/site-packages/suds/client.py", line 678, in succeeded
reply, result = binding.get_reply(self.method, reply)
File "/my/path/lib/python2.7/site-packages/suds/bindings/binding.py", line 156, in get_reply
result = self.replycomposite(rtypes, nodes)
File "/my/path/lib/python2.7/site-packages/suds/bindings/binding.py", line 230, in replycomposite
sobject = unmarshaller.process(node, resolved)
File "/my/path/lib/python2.7/site-packages/suds/umx/typed.py", line 66, in process
return Core.process(self, content)
File "/my/path/lib/python2.7/site-packages/suds/umx/core.py", line 48, in process
return self.append(content)
File "/my/path/lib/python2.7/site-packages/suds/umx/core.py", line 63, in append
self.append_children(content)
File "/my/path/lib/python2.7/site-packages/suds/umx/core.py", line 140, in append_children
cval = self.append(cont)
File "/my/path/lib/python2.7/site-packages/suds/umx/core.py", line 61, in append
self.start(content)
File "/my/path/lib/python2.7/site-packages/suds/umx/typed.py", line 80, in start
raise TypeNotFound(content.node.qname())
suds.TypeNotFound: Type not found: 'IsPlatformObject'
Nice wrapper, but I can't seem to find a reference to do an Extract request, only create, update and delete. Would it be possible to implement this? Thanks.
As described in the Salesforce documentation ( https://help.salesforce.com/articleView?id=mc_as_bounces.htm&type=5 ), Bounce event contains those following info :
"ClientID","SendID","SubscriberKey","SubscriberID","ListID","EventDate","EventType","BounceCategory","SMTPCode","BounceReason","BatchID","TriggeredSendExternalKey".
I want to get a dict with those columns, but when I specify columns I want to access in the properties, SubscriberID and ListID are not directectly accessible.
getBounceEvent.props = ["ClientID","SendID","SubscriberKey","SubscriberID","ListID","EventDate","EventType","BounceCategory","SMTPCode","BounceReason","BatchID","TriggeredSendExternalKey"]
results to :
Message: Error: The Request Property(s) SubscriberID,ListID do not match with the fields of BounceEvent retrieve
I reached my goal by calling each time a function that finds the SubscriberID with the SubscriberKey : SubscriberId = get_subscriber_id_with_key(SubscriberKey)
:
def get_subscriber_id_with_key(SubscriberKey):
import ET_Client
try:
debug = False
stubObj = ET_Client.ET_Client(False, debug)
getSub = ET_Client.ET_Subscriber()
getSub.auth_stub = stubObj
getSub.props = ["SubscriberKey", "Subscriber.ID"]
getSub.search_filter = {'Property' : 'SubscriberKey','SimpleOperator' : 'equals','Value' : SubscriberKey}
getResponse = getSub.get()
dict = getResponse.results
return dict[0][1]
except Exception as e:
print('Caught exception: ' + str(e.message))
print(e)
But it takes a way too much time...
Is there a best way to do it ?
I have a simple scrip that downloads all of the HTML in our account and writes it to individual files. However, it doesn't seem to be able to access emails that are built in Content Builder. Will this functionality be added in the future?
I have two questions about config.python and Windows.
First, how can I "declare environment variables so you can input the ClientID and Client Secret values provided when you registered your application"? I have multiple ET accounts and I want to easily change the values.
Second, where can I store config.python in Windows?
We are trying to run the calls found under https://code.exacttarget.com/apis-sdks/fuel-sdks/index.html. I am using the python examples from the website and using the below version of the libraries to send request to exact target
Create of SOAP message by the FuelSDK takes a constant 10- 15 seconds.
File: suds/client.py Function: create() which is called in FuelSDK/rest.py::auth_stub.soap_client.service.create(None, self.parse_props_into_ws_object(auth_stub, obj_type, props)), in turn calls the build().
File: suds/builder.py: build() creates a “data” object which is more than 19000 lines. This is what is causing the delay, but we don’t control both FuelSDK and suds library. Are we doing something wrong?
• We have set our AUTH_URL legacy parameter as 1, is it causing the issue? Legacy set to 0 is not working for us as it is throwing a “KeyError: 'legacyToken'”. Our config setting:
os.environ["FUELSDK_AUTH_URL"] = "https://auth.exacttargetapis.com/v1/requestToken?legacy=1"
I have tried this in multiple vm's and all of them are behaving the same way.
Any help will be appreciated.
I'm attempting to use a filter with left and right operands, but I get a KeyError: 'LeftOperand':
getFolder.search_filter = {'leftOperand': {'Property': 'Name', 'SimpleOperator': 'equal', 'Value': 'MyTestEmails'}, 'LogicalOperator': 'and', 'rightOperand': {'Property': 'ParentFolder', 'SimpleOperator' : 'equal', 'Value': 'my emails'}}
I don't see this capability but thought we might be able to add it.
I see the python3-support branch, and I can develop against it locally, but the version on PyPI doesn't support Python 3. Can you please release a version that works for Python 2 and 3 and push it to PyPI?
In the schema, contains appears to be a valid SimpleOperator:
https://github.com/ExactTarget/FuelSDK-Python/blob/855ca7d31788004c67dcc20b7ed9e951d707c008/FuelSDK/ExactTargetWSDL.xml#L490-L515
but the code:
import FuelSDK
client = FuelSDK.ET_Client(
params=dict(clientid=CLIENT_ID, clientsecret=CLIENT_SECRET)
)
event = FuelSDK.ET_Email()
event.auth_stub = client
event.search_filter = {'Property': 'name', 'SimpleOperator': 'contains', 'Value': 'test'}
response = event.get()
print response.message
results in
Error: "contains" is not a valid SimpleOperator for a retrieve Filter.
Hey,
I'm wondering if you guys noticed that when the Fuel SDK creates a SOAP request, it goes through extreme CPU usage. On a new macbook pro, it takes about 10 seconds to build an object. On a medium Amazon AMI, it takes over 1 minute. This is just to build a instantiate a Python object. It looks like it occurs in the suds library. Haven't spend too much time looking into it.
The usual name of the requirements file is requirements.txt. Following this convention will make it clear that this file contains pip compatible requirements that can be installed via pip.
pip install -r requirements.txt
Using the code from objsamples/sample_dataextension.py
, I tried to view the current columns on an existing data extension (I also tried the temporary data extension that is created during the sample script), but no data is returned during the call:
stubObj = ET_Client.ET_Client(False, False)
myDEColumn = ET_Client.ET_DataExtension_Column()
myDEColumn.auth_stub = stubObj
myDEColumn.props = ["Name"]
myDEColumn.search_filter = {'Property' : 'CustomerKey','SimpleOperator' : 'equals','Value' : 'INSERT_DATA_EXTENSION_NAME_HERE'}
getResponse = myDEColumn.get()
print getResponse.results
gives an empty list as the result.
If you can point me in the direction of what's wrong with this request, I'd be happy to create a PR for fixing it in the sample.
Is it possible to make asynchronous calls with FuelSDK? There's an article about it in the docs. I can't tell though if it's outdated.
I'd like to get a bunch of OpenEvent
for a given time span, but oftentimes there is just a lot of events, causing connection to be reset by peer. I think it would be better to send a request and then poll it for completion.
Based on a request, "How to do "Perform Email Send operation in python? I didn't find using python in following link:"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.