I am new to python and JS. I am trying to call a python method from a js code. The python code is supposed to do some calculation and returns me the results which is array of arrays (e.g., [[1,3],[3, 5]]). I have looked at few answers such as this. However, I was not able to solve my problem. Below is what I have so far:
JS code : This sends string "start" to my python code.
var a = $.post("/mlModel", {
Ml_list: JSON.stringify("start"),
contentType: "application/json",
dataType: "json"
});
console.log(JSON.parse(a));
Python Code: Python code gets the string "start", does some process, and return the results in the form of array of arrays [[2,4],[2,6]]
enter code here
#app.route('/mlModel', methods = ['POST'])
def get_post_MlModel():
jsdata = request.form['Ml_list']
jsdata = json.loads(jsdata)
jsdata = ast.literal_eval(json.dumps(jsdata))
// I send "start" to calculate method and it returns data = [[2,3],[1,3]]
data = calculate(jsdata)
return json.dumps(data)
When I run this code, this returns me "Unexpected token o in JSON at position 1"
Any idea?
jQuery.post is an asynchronous operation so a isn't ready yet when you try to use the JSON in the response. try using a callback which is called when the request is finished
$.post("/mlModel", {
Ml_list: JSON.stringify("start"),
contentType: "application/json",
dataType: "json"
}).done(function(data) {
console.log("success " + JSON.parse(data));
}).fail(function(jqXHR, textStatus, errorThrown) {
console.error( "failure " + errorThrown );
})
Here's the typical python and javascript code used while sending and receiving objects over the server. The example below sends a string ("start") from the client and returns a list of sequential index pairs as lists.
On the python side:
#app.route('/testQuery', methods=['POST'])
def testQuery():
queryString = request.form['queryString']
outputList = []
for i in range(0,len(queryString)):
char = queryString[i]
outputList.append([i,(i+1)])
return jsonify({
"outputList" : outputList
})
On the javascript side:
$.post("/testQuery", {"queryString": "start"})
.done(function (response) {
console.log(response)
});
Hope that helps.
Related
I'd like to call a Python function from JavaScript code, because there isn't an alternative in JavaScript for doing what I want. Is this possible? Could you adjust the below snippet to work?
JavaScript code:
var tag = document.getElementsByTagName("p")[0];
text = tag.innerHTML;
// Here I would like to call the Python interpreter with Python function
arrOfStrings = openSomehowPythonInterpreter("~/pythoncode.py", "processParagraph(text)");
~/pythoncode.py contains functions using advanced libraries that don't have an easy to write equivalent in JavaScript:
import nltk # is not in JavaScript
def processParagraph(text):
...
nltk calls
...
return lst # returns a list of strings (will be converted to JavaScript array)
All you need is to make an ajax request to your pythoncode.
You can do this with jquery http://api.jquery.com/jQuery.ajax/, or use just javascript
$.ajax({
type: "POST",
url: "~/pythoncode.py",
data: { param: text}
}).done(function( o ) {
// do something
});
From the document.getElementsByTagName I guess you are running the javascript in a browser.
The traditional way to expose functionality to javascript running in the browser is calling a remote URL using AJAX. The X in AJAX is for XML, but nowadays everybody uses JSON instead of XML.
For example, using jQuery you can do something like:
$.getJSON('http://example.com/your/webservice?param1=x¶m2=y',
function(data, textStatus, jqXHR) {
alert(data);
}
)
You will need to implement a python webservice on the server side. For simple webservices I like to use Flask.
A typical implementation looks like:
#app.route("/your/webservice")
def my_webservice():
return jsonify(result=some_function(**request.args))
You can run IronPython (kind of Python.Net) in the browser with silverlight, but I don't know if NLTK is available for IronPython.
Communicating through processes
Example:
Python: This python code block should return random temperatures.
# sensor.py
import random, time
while True:
time.sleep(random.random() * 5) # wait 0 to 5 seconds
temperature = (random.random() * 20) - 5 # -5 to 15
print(temperature, flush=True, end='')
Javascript (Nodejs): Here we will need to spawn a new child process to run our python code and then get the printed output.
// temperature-listener.js
const { spawn } = require('child_process');
const temperatures = []; // Store readings
const sensor = spawn('python', ['sensor.py']);
sensor.stdout.on('data', function(data) {
// convert Buffer object to Float
temperatures.push(parseFloat(data));
console.log(temperatures);
});
Typically you would accomplish this using an ajax request that looks like
var xhr = new XMLHttpRequest();
xhr.open("GET", "pythoncode.py?text=" + text, true);
xhr.responseType = "JSON";
xhr.onload = function(e) {
var arrOfStrings = JSON.parse(xhr.response);
}
xhr.send();
You cannot run .py files from JavaScript without the Python program like you cannot open .txt files without a text editor. But the whole thing becomes a breath with a help of a Web API Server (IIS in the example below).
Install python and create a sample file test.py
import sys
# print sys.argv[0] prints test.py
# print sys.argv[1] prints your_var_1
def hello():
print "Hi" + " " + sys.argv[1]
if __name__ == "__main__":
hello()
Create a method in your Web API Server
[HttpGet]
public string SayHi(string id)
{
string fileName = HostingEnvironment.MapPath("~/Pyphon") + "\\" + "test.py";
Process p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\Python27\python.exe", fileName + " " + id)
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
p.Start();
return p.StandardOutput.ReadToEnd();
}
And now for your JavaScript:
function processSayingHi() {
var your_param = 'abc';
$.ajax({
url: '/api/your_controller_name/SayHi/' + your_param,
type: 'GET',
success: function (response) {
console.log(response);
},
error: function (error) {
console.log(error);
}
});
}
Remember that your .py file won't run on your user's computer, but instead on the server.
Despite what some replies and comments suggest, there are a number of ways for using Python on the front-end. For your question in particular, see this reply.
I have been using an http.get() to make calls to the SounbdCloud API method to receive a JSON object that I would like to pass to the browser. I can confirm that the data I receive is an object, since I the typeof() method I call on the data prints out that it is an object.
var getTracks = http.get("http://api.soundcloud.com/tracks.json?q="+query+"&client_id=CLIENT_ID", function(tracks) {
tracks.on('data', function (chunk) {
console.log(typeof(chunk)); // where I determine that I receive an object
res.send(chunk);
});
//console.log(tracks.data);
}).on("error", function(e){
console.log("Got error: "+e);
});
But when I check the data I receive in the AJAX request I make in the browser, I find that the data received has a type of String (again, I know this by calling typeof())
$('#search').click(function(e){
e.preventDefault();
var q = $("#query").val();
$.ajax({
url: '/search',
type: 'POST',
data: {
"query": q
},
success: function(data){
alert(typeof(data));
alert(data);
},
error: function(xhr, textStatus, err){
alert(err);
}
})
});
I would appreciate the help, since I do not know where the problem is, or whether I am looking for the answer in the wrong places (perhaps it has something to do with my usage of SoundCloud's HTTP API)
JSON is a string. I assume you need an Object representing your JSON string.
Simply use the following method.
var obj = JSON.parse(data);
Another example would be:
var jsonStr = '{"name":"joe","age":"22","isRobot":"false"}';
var jsonObj = JSON.parse(jsonStr);
jsonObj.name //joe
jsonObj.age // 22
I'm new to Flask and AJAX and my current challenge is that when I make an AJAX request to the server my result is undefined. I am using deferred objects to keep track of several asynchronous requests, and all are working except for the AJAX function shown below. The other two are non-AJAX. Likely problem areas in the code below are marked with >>>>
For context, I am writing the backend to a one-page animation in the browser. The template remains the same regardless of any requests (clicks) from the viewer or any data requests the animation makes on its own programmatically (periodic adding and subtracting of visual material).
Flask/Python:
from flask import Response, json, render_template
from app import app
from motifs import get_motif_list
# >>>> can/should I use two functions aimed at the same route? Not sure how to both render the template and pass data
#app.route('/')
def index():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript:
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/",
dataType: "json", // >>>> when I comment this out I get an error, when I leave it in I get a parsererror
success: deferredData.resolve(),
complete: function(xhr, textStatus) {
console.log("AJAX REquest complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data >>>> currently undefined!!!
};
// DEFERRED OBJECTS
// used to perform a callback after multiple asynchronous functions
var deferredData = getData();
var deferredWindow = windowLoaded();
var deferredImages = loadImages();
// SINGLE CALLBACK AFTER MULTIPLE ASYNCHRONOUS FUNCTIONS
$.when( deferredWindow, deferredData, deferredImages ).done( function( window, data, images ) {
console.log("The window has loaded - " + window); // successful!
console.log("The data are: " + data); // >>>> undefined!
console.log("The images are: " + images); // successful!
});
UPDATE:
Thanks to #Jason P the success function in the getData AJAX call is now success: function(data) { deferredData.resolve(data); } and the result is no longer undefined! Alas, it's not my data, either. I think I may have a bug (or a conceptual misunderstanding) in my Flask code because the request returns the complete text of my html template instead of my JSON data. Thoughts?
UPDATE 2
Also #Jason P's suggestion I changed the route url in Flask and the AJAX request to an alternate route: /ajax to avoid a potential(?!) clash with the template rendering. However, the request still returns the full text of my html template. Perhaps I also need to differentiate the python/flask function names? ...will try that next. Updated code below.
Python/Flask:
#app.route('/ajax')
def index():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript AJAX url property changed to:
url: '/ajax'
UPDATE 3
I differentiated the python/flask function names so that the /ajax route function is now called ajax(), and the root route '/' function is still called index(). The JSON object now renders to the screen (instead of being passed in as a variable) and nothing from the javascript renders (presumably now missing the template rendering?)
RESOLVED
Following on comments by #Jason P the call is finally resolved and functioning. Wheew! Here is the final code:
Flask/Python
from flask import Response, json, render_template
from app import app
from motifs import get_motif_list
#app.route('/ajax')
def ajax():
motifs = get_motif_list(10)
return Response(json.dumps(motifs), mimetype='application/json')
#app.route("/")
def index():
return render_template("index.html")
JavaScript:
function getData() {
var deferredData = new jQuery.Deferred();
$.ajax({
type: "GET",
url: "/ajax",
// dataType: "json",
success: function(data) {
deferredData.resolve(data);
},
error: function (data) {
debugger;
alert("Error");
},
complete: function(xhr, textStatus) {
console.log("AJAX Request complete -> ", xhr, " -> ", textStatus);
}
});
return deferredData; // contains the passed data
};
// all else in the script remains the same as above...
Thanks!
This line:
success: deferredData.resolve()
Immediately executes resolve().
Try this instead:
success: function(data) { deferredData.resolve(data); }
i'm trying to develop Firefox extension
problem :
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "file.php",
onComplete: function (response) {
var List = response.json;
}
});
I want to use this request function to parse json to an array (List here) from php file.
The php my php file echo json form correctly, but I can't transform the data into javascript array to be able to use it in my addon.
if there is a better idea than using this function to do it please tell me :)
try this: MDN - JSON Object
JSON.parse and JSON.stringify
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "file.php",
onComplete: function (response) {
var List = JSON.parse(response.json);
}
});
it's very important to use double quotes.
If you are having a problem with JSON.parse. Copy your array to scratchpad and then run JSON.stringify on it and then make sure your php file matches the strignified result.
if Addon-SDK doesnt have JSON then you gotta require the module if there is one. If there isn't one than require('chrome') and grab the component HERE
There's a bug in Noitidarts code.
why JSON.parse the request.json? If you want to parse do it on request.text
However no need to json.parse as the request module tries to parse and if successful retuns request.json
see here:
var Request = require("sdk/request").Request;
var latestTweetRequest = Request({
url: "https://api.twitter.com/1/statuses/user_timeline.json?screen_name=mozhacks&count=1",
onComplete: function (response) {
var tweet = response.json[0];
console.log("User: " + tweet.user.screen_name);
console.log("Tweet: " + tweet.text);
}
});
// Be a good consumer and check for rate limiting before doing more.
Request({
url: "http://api.twitter.com/1/account/rate_limit_status.json",
onComplete: function (response) {
if (response.json.remaining_hits) {
latestTweetRequest.get();
} else {
console.log("You have been rate limited!");
}
}
}).get();
so the likely problem is that your php is not outputting a json string that json.parse can read. make sure to use ". figure out what your php file should return by running json.stringify on a dummy object. ie:
var obj = {myarr:[1,8,9,7,89,0,'ji'],strr:'khhkjh',anothrtObj:{1:45,56:8}};
alert(JSON.stringify(obj)) //{"myarr":[1,8,9,7,89,0,"ji"],"strr":"khhkjh","anothrtObj":{"1":45,"56":8}}
so now in your php make sure your outputted text mateches this format
{"myarr":[1,8,9,7,89,0,"ji"],"strr":"khhkjh","anothrtObj":{"1":45,"56":8}}
if your php outputs something like below JSON.parse will fail on it so request.json will be null
{myarr:[1,8,9,7,89,0,"ji"],strr:"khhkjh",anothrtObj:{"1":45,"56":8}}
or
{'myarr':[1,8,9,7,89,0,"ji"],'strr':"khhkjh",'anothrtObj':{"1":45,"56":8}}
or
{'myarr':[1,8,9,7,89,0,'ji'],'strr':'khhkjh','anothrtObj':{'1':45,'56':8}}
I have scoured this site and elsewhere trying to solve the problem I am having with jsonp. To start things off, here's the code that I have:
url = "http://mydomain.com/return_json";
$.ajax({
url: url, // + '?callback=?' --I realized this is not necessary with dataType: 'jsonp'
dataType: 'jsonp',
crossDomain: true,
error: function(xhr, status, error) {
console.log(xhr);
console.log(status);
console.log(error);
},
success: function(dataWeGotViaJsonp){
var text = '';
var len = dataWeGotViaJsonp.length;
for(var i=0;i<len;i++){
item = dataWeGotViaJsonp[i];
text += '<p>' + item + '</p>';
}
$('#action_target').html(text);
}
});
On the sending side, the /return_json url is a Django site that is sending json data the following way:
def return_json(request):
data = [{'testing': 'testing'}, {'one': 1, 'two': 2, 'three': 3}]
return HttpResponse( json.dumps(data), content_type="application/javascript" )
As you can see in the JavaScript, I'm indescriminately dumping everything into the console on error. Here is the output of that:
Object { readyState=4, status=200, statusText="success"}
parsererror
Error: jQuery110207276483389928793_1377030169256 was not called
The 'net' area of firebug shows that the url was:
http://mydomain.com/return_json? callback=jQuery110209170565296948737_1377029879665&_=1377029879666
It also shows that valid JSON is in the response. It even has a JSON section with a pretty-fied output. So, obviously my problem is that the jQuery auto-generated callback function is there, but not getting called. I get the same result using the $.ajax and $.getJSON methods set up for jsonp. The only thing I can think of at this point is that I'm supposed to wrap the json data in a function somehow on the sender's side, but I was under the impression that the receiver takes care of that. If anyone can see what I'm doing wrong, it would be much appreciated.
=================================UPDATE WITH FULL ANSWER========================
Hamish has the correct answer below, although it just needs two minor tweaks. Here is how you can send data in JSONP format using Django:
def return_json(request):
# ^--------I didn't need a parameter in this situation
json_data = ["one", "two", "three"]
return render_to_response("uitest/jsonp_template.html", Context({
'callback': request.GET.get('callback'),
'json': mark_safe(json.dumps( json_data )),
# ^------------------------------This keeps your JSON from getting mangled in
# URL
}), mimetype="application/javascript")
#^---------------------This closing parentheses was missing in Hamish's answer at the time
# of this writing.
A JSONP response is actually a script response - something like:
callbackFunctionName([{'testing': 'testing'}, {'one': 1, 'two': 2, 'three': 3}]);
Create a template that returns a application/javascript response with a function call to function request.GET.get('callback') with the body of the JSON as the only argument.
Something like:
def return_jsonp(request, json_data)
return render_to_response("jsonp_template.html", Context({
'callback': request.GET.get('callback'),
'json': json.dumps(json_data),
}, mimetype="application/javascript")
Where jsonp_template.html is just:
{{ callback }}({{ json }});