Zapier: Code not returning all values expected - python

I am working with Code by Zapier and having trouble telling if my regex is wrong or some other part is wrong ( I think the latter)
I am pulling a URL, this URL has several 9 digit IDs that get appended to the end of the URL. I was told to try and extract these IDs and rebuild the URLs so we can post API calls for each of them.
I am a Python newb but so far I have this but it only returns the first 9 digit ID, I am hoping for an array so I can rebuild the URLS with each specific ID. This is my code so far:
import re
urls = re.findall(r'\b\d+\b', input_data['input'])
return [
{'url': url} for url in urls
]
The input _data would be "https://api.helpscout.net/v1/conversations/123456789,098765432.json"
As I said, it just returns the first ID. I know I don't have the code to rebuild the URLs or anything just trying to take it one step at a time!
IS my regex incorrect or the way I am returning them? Thanks!

David here, from the Zapier Platform team. I've got good news and bad news.
Good news is, your regex works! So no sweat there. Downside, you're running into a weird corner case with code steps. It's not documented because we don't encourage its use (it's confusing, as you can tell). When you return an array from a code step, it functions like a trigger. That is, subsequent steps run for each item in the array (but the UI only shows the first).
If that's the desired behavior, you can safely ignore the weird test and complete the zap. If you don't want to fan out, you should instead parse out the comma separated string and act on it later.
If you need more direction, let me know a bit about what your other actions are and I can advise from there.
Side note, the reason you're seeing the error message with Willem's function above is that your python code must either set the output variable to a value or return an object. Either of return get_digits(input_data['input']) or output = get_digits(input_data['input']) should work.

The code works correct on my machine:
import re
def get_digits(s):
return [{'url':url} for url in re.findall(r'\b\d+\b',s)]
If I then call this with the sample input, I get:
>>> get_digits("https://api.helpscout.net/v1/conversations/123456789,098765432.json")
[{'url': '123456789'}, {'url': '098765432'}]
So a list with two dictionaries. Each dictionary contains one key, a 'url' that is associated with the string that contains one or more digits.
In case you want to match only nine-digit sequences, you can make the regex more restrictive (but this can only decrease the number of matches):
import re
def get_digits(s):
return [{'url':url} for url in re.findall(r'\b\d{9}\b',s)]

Argh so frustrating, I decided to try JavaScript and multiple methods don't output anything
<script>
var str = "https://api.helpscout.net/v1/conversations/382411278,374879346,374879343.json";
var tickets = str.match(/\d{9}/g);
for(var i = 0; i<tickets.length; i++)
{
document.write("https://api.helpscout.net/v1/conversations/"+tickets[i]+".json</br>")
}
or
<p id="demo"></p>
<script>
function myFunction() {
var str = "https://api.helpscout.net/v1/conversations/382411278,374879346,374879343.json";
var tickets = str.match(/\d{9}/g);
for(var i = 0; i<tickets.length; i++)
{
document.getElementById("demo").innerHTML +="https://api.helpscout.net/v1/conversations/" +tickets[i] + "<br />"
}
}
</script>

Related

Write a custom JSON interpreter for a file that looks like json but isnt using Python

What I need to do is to write a module that can read and write files that use the PDX script language. This language looks alot like json but has enough differences that a custom encoder/decoder is needed to do anything with those files (without a mess of regex substitutions which would make maintenance hell). I originally went with just reading them as txt files, and use regex to find and replace things to convert it to valid json. This lead me to my current point, where any additions to the code requires me to write far more code than I would want to, just to support some small new thing. So using a custom json thing I could write code that shows what valid key:value pairs are, then use that to handle the files. To me that will be alot less code and alot easier to maintain.
So what does this code look like? In general it looks like this (tried to put all possible syntax, this is not an example of a working file):
#key = value # this is the definition for the scripted variable
key = {
# This is a comment. No multiline comments
function # This is a single key, usually optimize_memory
# These are the accepted key:value pairs. The quoted version is being phased out
key = "value"
key = value
key = #key # This key is using a scripted variable, defined either in the file its in or in the `scripted_variables` folder. (see above for example on how these are initially defined)
# type is what the key type is. Like trigger:planet_stability where planet_stability is a trigger
key = type:key
# Variables like this allow for custom names to be set. Mostly used for flags and such things
[[VARIABLE_NAME]
math_key = $VARIABLE_NAME$
]
# this is inline math, I dont actually understand how this works in the script language yet as its new. The "<" can be replaced with any math symbol.
# Valid example: planet_stability < #[ stabilitylevel2 + 10 ]
key < #[ key + 10 ]
# This is used alot to handle code blocks. Valid example:
# potential = {
# exists = owner
# owner = {
# has_country_flag = flag_name
# }
# }
key = {
key = value
}
# This is just a list. Inline brackets are used alot which annoys me...
key = { value value }
}
The major differences between json and PDX script is the nearly complete lack of quotations, using an equals sign instead of a colon for separation and no comma's at the end of the lines. Now before you ask me to change the PDX code, I cant. Its not mine. This is what I have to work with and cant make any changes to the syntax. And no I dont want to convert back and forth as I have already mentioned this would require alot of work. I have attempted to look for examples of this, however all I can find are references to convert already valid json to a python object, which is not what I want. So I cant give any examples of what I have already done, as I cant find anywhere to even start.
Some additional info:
Order of key:value pairs does not technically matter, however it is expected to be in a certain order, and when not in that order causes issues with mods and conflict solvers
bool properties always use yes or no rather than true or false
Lowercase is expected and in some cases required
Math operators are used as separators as well, eg >=, <= ect
The list of syntax is not exhaustive, but should contain most of the syntax used in the language
Past work:
My last attempts at this all revolved around converting it from a text file to a json file. This was alot of work just to get a small piece of this to work.
Example:
potential = {
exists = owner
owner = {
is_regular_empire = yes
is_fallen_empire = no
}
NOR = {
has_modifier = resort_colony
has_modifier = slave_colony
uses_habitat_capitals = yes
}
}
And what i did to get most of the way to json (couldnt find a way to add quotes)
test_string = test_string.replace("\n", ",")
test_string = test_string.replace("{,", "{")
test_string = test_string.replace("{", "{\n")
test_string = test_string.replace(",", ",\n")
test_string = test_string.replace("}, ", "},\n")
test_string = "{\n" + test_string + "\n}"
# Replace the equals sign with a colon
test_string = test_string.replace(" =", ":")
This resulted in this:
{
potential: {
exists: owner,
owner: {
is_regular_empire: yes,
is_fallen_empire: no,
},
NOR: {
has_modifier: resort_colony,
has_modifier: slave_colony,
uses_habitat_capitals: yes,
},
}
}
Very very close yes, but in no way could I find a way to add the quotations to each word (I think I did try a regex sub, but wasnt able to get it to work, since this whole thing is just one unbroken string), making this attempt stuck and also showing just how much work is required just to get a very simple potential block to mostly work. However this is not the method I want anymore, one because its alot of work and two because I couldnt find anything to finish it. So a custom json interpreter is what I want.
The classical approach (potentially leading to more code, but also more "correctness"/elegance) is probably to build a "recursive descent parser", from a bunch of conditionals/checks, loops and (sometimes recursive?) functions/handlers to deal with each of the encountered elements/characters on the input stream. An implicit parse/call tree might be sufficient if you directly output/print the JSON equivalent, or otherwise you could also create a representation/model in memory for later output/conversion.
Related book recommendation could be "Language Implementation Patterns" by Terence Parr, me avoiding to promote my own interpreters and introductory materials :-) In case you need further help, maybe write me?

Python auto-indentation in ScintillaNET

i am working on a Winforms application with ScintillaNET. I realized that ScintillaNET itself has no auto-indentation feature. You would have to create one yourself. I have searched online and found a solution to auto-indenting with curly brackets: Auto-indenting with curly brackets.
I decided to make an auto indentation feature for python in ScintillaNET. Since Python's syntax does not use curly brackets, but instead a :, the referenced code does not apply. So to i tried to make use of the InsertChecked feature to check for auto-indenting triggers before a new line. Basically if the user types a : and afterwards adds a new line \n, that is an indication that a condition/class or definition is defined.
To make sure that we don't misinterpret what the user is trying to do, say that in Python, you do string[1:2] to get a substring, then this feature will not apply. We can make sure by doing the following.
if (caretPosition != 0 && caretPosition != ScintillaControl.Text.Length) //if not at the end or start
{
}
But so far, i have a function that just auto indents after : but does not increment that indent by 4 per last line. It's weird because it should be able to get the last line length, then add by 4 (indent). It's very hard to explain, i have provided a GIF image below:
So, anyone have a better implementation of what i'm trying to figure out? Or a function that takes the last line length then adds auto indents once a trigger char appears? Here's my code:
private void textarea_InsertCheck(object sender, InsertCheckEventArgs e)
{
if ((e.Text.EndsWith("\r") || e.Text.EndsWith("\n")))
{
var curLine = TextArea.LineFromPosition(e.Position);
var curLineText = TextArea.Lines[curLine].Text;
var indent = Regex.Match(curLineText, #"");
if (Regex.IsMatch(curLineText, #":"))
e.Text += '\t';
}
}
Help me on this one guys.
Alright, i see that no one has an idea to implement this, but THANK GOD i've been doing some research and found this old thread invisible to search engines that explains what i'm looking for: https://github.com/jacobslusser/ScintillaNET/issues/137
Whew.

Find documents which contain a particular value - Mongo, Python

I'm trying to add a search option to my website but it doesn't work. I looked up solutions but they all refer to using an actual string, whereas in my case I'm using a variable, and I can't make those solutions work. Here is my code:
cursor = source.find({'title': search_term}).limit(25)
for document in cursor:
result_list.append(document)
Unfortunately this only gives back results which match the search_term variable's value exactly. I want it to give back any results where the title contains the search term - regardless what other strings it contains. How can I do it if I want to pass a variable to it, and not an actual string? Thanks.
You can use $regex to do contains searches.
cursor = collection.find({'field': {'$regex':'regular expression'}})
And to make it case insensitive:
cursor = collection.find({'field': {'$regex':'regular expression', '$options'‌​:'i'}})
Please try cursor = source.find({'title': {'$regex':search_term}}).limit(25)
$text
You can perform a text search using $text & $search. You first need to set a text index, then use it:
$ db.docs.createIndex( { title: "text" } )
$ db.docs.find( { $text: { $search: "search_term" } } )
$regex
You may also use $regex, as answered here: https://stackoverflow.com/a/10616781/641627
$ db.users.findOne({"username" : {$regex : ".*son.*"}});
Both solutions compared
Full Text Search vs. Regular Expressions
... The regular expression search takes longer for queries with just a
few results while the full text search gets faster and is clearly
superior in those cases.

how do I modify a url that I pick at random in python

I have an app that will show images from reddit. Some images come like this http://imgur.com/Cuv9oau, when I need to make them look like this http://i.imgur.com/Cuv9oau.jpg. Just add an (i) at the beginning and (.jpg) at the end.
You can use a string replace:
s = "http://imgur.com/Cuv9oau"
s = s.replace("//imgur", "//i.imgur")+(".jpg" if not s.endswith(".jpg") else "")
This sets s to:
'http://i.imgur.com/Cuv9oau.jpg'
This function should do what you need. I expanded on #jh314's response and made the code a little less compact and checked that the url started with http://imgur.com as that code would cause issues with other URLs, like the google search I included. It also only replaces the first instance, which could causes issues.
def fixImgurLinks(url):
if url.lower().startswith("http://imgur.com"):
url = url.replace("http://imgur", "http://i.imgur",1) # Only replace the first instance.
if not url.endswith(".jpg"):
url +=".jpg"
return url
for u in ["http://imgur.com/Cuv9oau","http://www.google.com/search?q=http://imgur"]:
print fixImgurLinks(u)
Gives:
>>> http://i.imgur.com/Cuv9oau.jpg
>>> http://www.google.com/search?q=http://imgur
You should use Python's regular expressions to place the i. As for the .jpg you can just append it.

How to make a request to the Intersango API

I'm trying to figure out what's the correct URL format for the Intersango API (which is poorly documented). I'm programming my client in C#, but I'm looking at the Python example and I'm a little confused as to what is actually being placed in the body of the request:
def make_request(self,call_name,params):
params.append(('api_key',self.api_key)) // <-- How does this get serialized?
body = urllib.urlencode(params)
self.connect()
try:
self.connection.putrequest('POST','/api/authenticated/v'+self.version+'/'+call_name+'.php')
self.connection.putheader('Connection','Keep-Alive')
self.connection.putheader('Keep-Alive','30')
self.connection.putheader('Content-type','application/x-www-form-urlencoded')
self.connection.putheader('Content-length',len(body))
self.connection.endheaders()
self.connection.send(body)
response = self.connection.getresponse()
return json.load(response)
//...
I can't figure out this piece of code: params.append(('api_key',self.api_key))
Is it some kind of a dictionary, something that gets serialized to JSON, comma delimited, or exactly how does it get serialized? What would the body look like when the parameters are encoded and assigned to it?
P.S. I don't have anything that I can run the code with so I can debug it, but I'm just hoping that this is simple enough to understand for somebody that knows Python and they would be able to tell me what's happening on that line of code.
params is a list of 2-element lists. The list would look like ((key1, value1), (key2, value2), ...)
params.append(('api_key',self.api_key)) adds another 2-element list to the existing params list.
Finally, urllib.urlencode takes this list and converts it into a propert urlencoded string. In this case, it will return a string key1=value1&key2=value2&api_key=23423. If there are any special characters in your keys or values, urlencode will %encode them. See documentation for urlencode
I tried to get the C# code working, and it kept failing with exception {"The remote server returned an error: (417) Expectation Failed."}. I finally found what the problem is. You could read about it in depth here
In short, the way to make C# access Intersango API is to add following code:
System.Net.ServicePointManager.Expect100Continue = false;
This code needs to only run once. This is a global setting, so it affects your full application, so beware that something else could break as a result.
Here's a sample code:
System.Net.ServicePointManager.Expect100Continue = false;
var address = "https://intersango.com/api/authenticated/v0.1/listAccounts.php";
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
var postBytes = Encoding.UTF8.GetBytes("api_key=aa75***************fd65785");
request.ContentLength = postBytes.Length;
var dataStream = request.GetRequestStream();
dataStream.Write(postBytes, 0, postBytes.Length);
dataStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Piece of cake
instead of params.append(('api_key',self.api_key))
just write:
params['api_key']=self.api_key

Categories