I'm trying to create a webhook with subscope of a specific column in one of my sheets in python with the following code:
my_webhook = smartsheet_client.Webhooks.create_webhook(
smartsheet.models.Webhook({
'name': 'test 10',
'callbackUrl': 'https://my_web.com/webhook/test10',
'scope': 'sheet',
'scopeObjectId': 0000000000000000,
'subscope': {'columnIds': [0000000000000000]},
'events': ['*.*'],
'version': 1
}))
And when I get the successfully created webhook with its ID, the subscope is missing from the response.
Does anyone have a clue what am I doing wrong?
I'm not very familiar with the Smartsheet Python SDK, but in general, I often find it helpful to look at the integration test code in the SDK's GitHub repo whenever I have a question about how to implement a certain operation using the SDK. In this case, the integration test for webhooks in the SDK repo shows the following code for creating a webhook:
def test_create_webhook(self, smart_setup):
smart = smart_setup['smart']
webhook = smart.models.Webhook()
webhook.name = 'My Webhook'
webhook.callback_url = 'https://www.smartsheet.com'
webhook.scope = 'sheet'
webhook.scope_object_id = smart_setup['sheet'].id
webhook.events.append('*.*')
webhook.version = 1
webhook.subscope = smart.models.WebhookSubscope({'column_ids': [smart_setup['sheet'].columns[0].id]})
action = smart.Webhooks.create_webhook(webhook)
assert action.message == 'SUCCESS'
assert isinstance(action.result, smart.models.Webhook)
TestWebhooks.webhook = action.result
Notice specifically that the way the subscope property is being set differs from what you've posted above. I'd suggest trying to model your code more after this code, to see if you can achieve the desired outcome.
Your code is virtually identical to mine, and subscopes weren't working for me either. I upgraded from smartsheet-python-sdk pip package 2.86 to 2.105, and now my webhook gets set properly. I also verified that the subscope setting works, which greatly reduces the number of events I have to process.
Here is my code (although it's essentially the same as yours).
def createSheetWebhook(name, sheet_id, target, subscope=[]):
new_webhook = smartsheet_client.Webhooks.create_webhook(
smartsheet.models.Webhook({
"name": F"sheet changes for {name}",
"callbackUrl": target,
"scope": 'sheet',
"scopeObjectId": sheet_id,
"subscope": {
"columnIds": subscope
},
"events": ['*.*'],
"version": 1
})
)
return new_webhook.result.id
Related
I am not able to find any code sample or relevant documentation on python library for google cloud
Want to restart managed instance groups all vms via cloud function.
To list instances I am using something like this
import googleapiclient.discovery
def list_instances(compute, project, zone):
result = compute.instances().list(project=project, zone=zone).execute()
return result['items'] if 'items' in result else None
in requirement file I have
google-api-python-client==2.31.0
google-auth==2.3.3
google-auth-httplib2==0.1.0
From command line this is possible via SDK ->
https://cloud.google.com/sdk/gcloud/reference/compute/instance-groups/managed/rolling-action/restart
gcloud compute instance-groups managed rolling-action restart NAME [--max-unavailable=MAX_UNAVAILABLE] [--region=REGION | --zone=ZONE] [GCLOUD_WIDE_FLAG …]
But in python I am not able to write any code.
This is an incomplete answer since the python docs are pretty unreadable to me.
Looking at the gcloud cli code (which I couldn't find an official repo for so I looked here),
the restart command is triggered by something called a "minimal action".
minimal_action = (client.messages.InstanceGroupManagerUpdatePolicy.
MinimalActionValueValuesEnum.RESTART)
In the Python docs, there's references to these fields in the applyUpdatesToInstances method.
So I think the relevant code is something similar to:
compute.instanceGroupManagers().applyUpdatesToInstances(
project=project,
zone=zone,
instanceGroupManager='NAME',
body={"allInstances": True, "minimalAction": "RESTART"},
)
There may or may not be a proper Python object for the body, the docs aren't clear.
And the result seems to be an Operation object of some kind, but I don't know if there's execute() method or not.
This is confusing, because gcloud compute instance-groups managed rolling-action is syntactic sugar that does two things:
It turns on Proactive updater, by setting appropriate UpdatePolicy on the InstanceGroupManager resource
And it changes version name on the same resource to trigger an update.
It is covered in the docs in https://cloud.google.com/compute/docs/instance-groups/rolling-out-updates-to-managed-instance-groups#performing_a_rolling_replace_or_restart
Compare the gcloud and API tabs to get the idea.
Unfortunately I am illiterate in Python, so I am not able to translate it into Python code :(.
Using the documentation that #Grzenio provided, use patch() method to restart the instance group. See patch documentation to check its parameters.
This could be written in python using the code below. I provided the required parameters project,zone,instanceGroupManager and body. The value of body is from the example in the documentation.
import googleapiclient.discovery
import json
project = 'your-project-id'
zone = 'us-central1-a' # the zone of your instance group
instanceGroupManager = 'instance-group-1' # instance group name
body = {
"updatePolicy": {
"minimalAction": "RESTART",
"type": "PROACTIVE"
},
"versions": [{
"instanceTemplate": "global/instanceTemplates/instance-template-1",
"name": "v2"
}]
}
compute = googleapiclient.discovery.build('compute', 'v1')
rolling_restart = compute.instanceGroupManagers().patch(
project=project,
zone=zone,
instanceGroupManager=instanceGroupManager,
body=body
)
restart_operation = rolling_restart.execute() # execute the request
print(json.dumps(restart_operation,indent=2))
This will return an operation object and the instance group should restart in the rolling fashion:
{
"id": "3206367254887659944",
"name": "operation-1638418246759-5d221f9977443-33811aed-eed3ee88",
"zone": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a",
"operationType": "patch",
"targetLink": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a/instanceGroupManagers/instance-group-1",
"targetId": "810482163278776898",
"status": "RUNNING",
"user": "serviceaccountused#your-project-id.iam.gserviceaccount.com",
"progress": 0,
"insertTime": "2021-12-01T20:10:47.654-08:00",
"startTime": "2021-12-01T20:10:47.670-08:00",
"selfLink": "https://www.googleapis.com/compute/v1/projects/your-project-id/zones/us-central1-a/operations/operation-1638418246759-5d221f9977443-33811aed-eed3ee88",
"kind": "compute#operation"
}
In an effort to bring some clarity, I'm asking this question here and sharing what I've learned so far.
First, if you want a simple, easy to develop transaction system, Braintree is it. Really easy, and plays very nicely with Django.
However, the subscription side of things has not been so clear. So, I'm sharing some code to get feedback on and help streamline.
First.. some assumptions.
Work Flow
The process for creating a subscription with the API is as follows:
(please don't send me documentation on how to do it in the control panel. A very broad description of the Subscription workflow can be found here: https://developers.braintreepayments.com/guides/recurring-billing/create/python)
Create a Client token with braintree.ClientToken.generate()
Create a customer with braintree.Customer.create() that adds a payment method
Get the customer id from the Customer.create() response
Create a subscription with braintree.Subscription.create() passing in the new customer and the new customer's token called payment_method_token
If you're wondering, this is Django and I'm trying to do this all in one view.
Sample Code
custy_result = braintree.Customer.create({
"first_name": self.request.POST.get('first_name'),
"last_name": self.request.POST.get('last_name'),
"company": self.request.POST.get('company_name'),
"email": self.request.POST.get('office_email'),
"phone": self.request.POST.get('office_phone'),
'payment_method_nonce': 'fake-valid-nonce', # for testing
"credit_card": {
"billing_address": {
"street_address": self.request.POST.get('address'),
"locality": self.request.POST.get('city'),
"region": self.request.POST.get('state'),
"postal_code": self.request.POST.get('postal'),
}
}
})
if custy_result.is_success:
print("Customer Success!")
else:
for error in custy_result.errors.deep_errors:
print(error.code)
print(error.message)
# Create the subscription in braintree
sub_result = braintree.Subscription.create({
"payment_method_token": "the_token", # <-- How do I get this token?
"plan_id": "the_plan_id_in_braintree"
})
if sub_result.is_success:
print("Subscription Success!")
else:
for error in sub_result.errors.deep_errors:
print(error.code)
print(error.message)
The Question(s)?
How do I get that token? What is "the_token"? Where does it come from?
I can't see how it's created and I can't see where it's pulled from. I want to do something like custy_result.customer.token but that is clearly wrong.
For reference, here is what I've been looking at in the documentation:
Customers
Payment Methods
Recurring Payments
Testing
Create Subscription
Customer.response
Credit Card Response
Your custy_result should have payment_methods attribute:
result = braintree.Subscription.create({
"payment_method_token": custy_result.payment_methods[0].token,
"plan_id": "planID"
})
Facebook's documentation on this seems quite scattered and poor. It's a pretty straight forward question but I can't find simple step by step instructions on how to set up permissions to be able to do things with campaigns programmatically in my python scripts.
I have tried both of the following approaches, both of which I have found in Facebooks examples but neither of which work.
The first approach I have tried is this:
campaign = Campaign(parent_id='12121212')
campaign.update({
Campaign.Field.name: 'My Campaign',
Campaign.Field.objective: Campaign.Objective.link_clicks,
})
campaign.remote_create(params={
'status': Campaign.Status.paused,
})
When I run this though I get an error from this line:
'status': Campaign.Status.paused,
The error says AttributeError: 'NoneType' object has no attribute 'call'.
I have also tried the following different approach:
my_app_id = '1212121212121212'
my_app_secret = 'g121g21g2g21g2g12g12'
my_access_token = '12121212121ig2j121kj1j3g1h2kj1h2k1h2j1h2k12hj12h1k21j2h1k2j12k12h1k2jh12k12h1kj2h1k212j1h2k12h1k2jh12kj12h1k2j'
FacebookAdsApi.init(my_app_id, my_app_secret, my_access_token)
me = AdUser(fbid='126712121')
my_accounts = list(me.get_ad_accounts())
print(my_accounts)
my_account = me.get_ad_accounts()[0]
campaign = objects.Campaign(parent_id = my_account.get_id_assured())
campaign[objects.Campaign.Field.name] = "Potato Campain" # sic
campaign[objects.Campaign.Field.configured_status] = objects.Campaign.Status.paused
But this gives me an error on the following line:
my_accounts = list(me.get_ad_accounts())
The error looks like so:
facebookads.exceptions.FacebookRequestError:
Message: Call was not successful
Method: GET
Path: https://graph.facebook.com/v2.8/643866195/adaccounts
Params: {'summary': 'true'}
Status: 400
Response:
{
"error": {
"message": "(#3) Application does not have the capability to make this API call.",
"code": 3,
"type": "OAuthException",
"fbtrace_id": "Gc2iAi7MwuD"
}
}
I just wanna get this working, what set up am I missing based on these errors? Thanks and i love you..
My approach to this question might be completely wrong, so please don't hesitate to correct it. I also added ATDD in the question title, because I am trying to test the output of my web api which is bigger than just a unit test.
I am using:
Google App Engine 1.7.1
GAE High Replication Datastore
Python 2.7.3
I setup my tests using the boilerplate code:
self.testbed = testbed.Testbed()
self.testbed.activate()
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=0)
self.testbed.init_datastore_v3_stub()
Then I call a mock object setup to setup my entities and persist them to the testbed datastore. I use a counter to add 5 artists with artist_id 1 - 5:
def add_mock_artist_with(self, artist_id, link_id, name):
new_artist = dto.Artist(key_name=str(artist_id),
name=name,
link_id= str(link_id))
new_artist.put()
My test is that my web api returns:
{
"artists": [
{
"artist": {
"name": "Artist 1",
"links": {
"self": {
"href": "https://my_server.com/artist/1/"
}
}
}
},
.
.
.
{
"artist": {
"name": "Artist 5",
"links": {
"self": {
"href": "https://my_server.com/artist/5/"
}
}
}
}
],
"links": {
"self": {
"href": "https://my_server.com/artists/"
}
}
}
Initially I thought that if I were to startup a new test bed every time I run the tests, I could count on my artists being entered sequentially into the data store and therefore would get ids 1 - 5. My tests passed initially, but over time started to fail because of ids not matching (I would get a link like: "href": "https://my_server.com/artist/78/"). I felt a little guilty relying on ids being generated sequentially, so I resolved to fix it. I stumbled upon the concept of a key being either a name or a generated id. I updated my templates for the returned JSON to use:
artist.key().id_or_name()
In the case of a mock object, I supplied the key name on construction with:
key_name=str(artist_id)
For non-mock construction, I did not include that line of code and let GAE assign the id.
Since my template used key().id_or_name() to output the property, all went well and the tests passed.
However, now when I test the return of an individual artist which would be available by following http://my_server.com/artist/5/, my test fails. To grab the artist out of the datastore, I use the following code:
def retrieve_artist_by(id):
artist = dto.Artist.get_by_id()
In production, this will work fine because it will all be id based. However, in my test, it is not finding anything because I have used the key_name=str(artist_id) in my mock construction, and the name is not the same as the id.
I was hoping for something similar to:
artist = dto.Artist.get_by_id_or_name()
Any ideas?
Perhaps not the answer you are looking for, but it's possible to find out if you are running on the production or deployment servers and execute a different code path.
In Python, how can I test if I'm in Google App Engine SDK?
http://code.google.com/appengine/docs/python/runtime.html#The%5FEnvironment
os.environ['SERVER_SOFTWARE'].startswith('Development')
Here is what I am using right now. I don't like it, but it should be performant in prod as I will be using generated ids. In test, if it doesn't find it by id, it will attempt to look up by name.
def retrieve_artist_by(id):
artist = dto.Artist.get_by_id(id)
if artist is None:
artist = dto.Artist.get_by_key_name(str(id))
return artist
I'm having trouble getting the Paypal Adaptive Payments API to work with GAE - I'm specifically going to be using Implicit Payments.
The error returned is that my api credentials are incorrect, but from what i've read I should be suspicious of the header format as well.
Here's the snippet of code - I'm using the urlfetch module in GAE:
headers = {
"X-PAYPAL-USERID" : "xxxx_123456789_biz_api1.xxxx.com",
"X-PAYPAL-SECURITY-PASSWORD" : "1234567890",
"X-PAYPAL-SECURITY-SIGNATURE" : "Ahg-XXXXXXXXXXXXXXXXXXXXXX",
"X-PAYPAL-REQUEST-DATA-FORMAT" : "JSON",
"X-PAYPAL-RESPONSE-DATA-FORMAT" : "JSON",
"X-PAYPAL-APPLICATION-ID" : "APP-80W284485P519543T"
}
request_body = {
"actionType" : "PAY",
"senderEmail" : "xxxx_123456789_biz_api1#xxxx.com",
"receiverList.receiver(0).email" : "xxxx_123456789_per#xxxx.com",
"receiverList.receiver(0).amount" : 100.00,
"currencyCode" : "USD",
"cancelUrl" : "some_url.com",
"returnUrl" : "some_url.com",
"requestEnvelope.errorLanguage" : "en_US"
}
url = "https://svcs.sandbox.paypal.com/AdaptivePayments/Pay"
result = urlfetch.fetch(url=url,payload=request_body,headers=headers)
I've Xed out some values, but everything I'm using is coming from the sandbox "API Credentials" section.
Is there a problem with the header format? Am I using the wrong set of credentials? Can I even use the sandbox to test Implicit Payments?
Any help is much appreciated.
Thanks!
For any of those having similar problems, follow the excellent tutorial located here:
Awesome Paypal Adaptive Payments Tutorial
The headers do tend to cause authentication errors if not formed correctly. I was pretty far off :)
go to your headers, and make a change like this
the key
'X-PAYPAL-USERID'
should become
'X-PAYPAL-SECURITY-USERID'.
You forgot to set the POST method inside the urlfetch.fetch call; without it, the payload data is ignored.
result = urlfetch.fetch(url=url,
payload=request_body,
method=urlfetch.POST,
headers=headers)
The urllib2.Request used in the Tutorial instead switches automatically from GET to POST when the request data is set.
req = urllib2.Request(self.request_url,paypal_request_data,header_data)