Scala CompiledScript reuse - scala

I am trying to use Scala ScriptEngine (2.11) to run Scala script in Java.
The script uses the bindings provided to the engine.
Script is used multiple times with different bindings.
For this, I am using CompiledScript.
The script runs fine for the first time and uses the bindings.
But, when the same CompiledScript is rerun using new bindings, the result does not change.
What I observed is that the script actually does not run the second time. It just uses the stored engine state.
The following is the code snippet:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("scala");
Bindings bindings = engine.createBindings();
bindings.put("firstVal", 209);
bindings.put("secondVal", 30);
bindings.put("sumUtil", new Sum());
CompiledScript script = ((Compilable)engine).compile(
"var sum = sumUtil.asInstanceOf[com.myutils.Sum]\n"+
"var firstInt = firstVal.asInstanceOf[Integer]\n"+
"var secondInt = secondVal.asInstanceOf[Integer]\n"+
"sum.add(firstInt, secondInt)\n"
);
Integer res1 = (Integer) script.eval(bindings);
System.out.println("Result 1: "+res1);
bindings = engine.createBindings();
bindings.put("firstVal", 2);
bindings.put("secondVal", 3);
Integer res2 = (Integer) script.eval(bindings);
System.out.println("Result 2: "+res2);
The output is:
firstVal: Object = 209
secondVal: Object = 30
sumUtil: Object = com.myutils.Sum#71136646
Result 1: 239
firstVal: Object = 2
secondVal: Object = 3
Result 2: 239
The expectation is that Result 2 is "5" instead of 239.
Am I doing anything wrong here?
Thanks in advance

Related

Function in pytest file works only with hard coded values

I have the below test_dss.py file which is used for pytest:
import dataikuapi
import pytest
def setup_list():
client = dataikuapi.DSSClient("{DSS_URL}", "{APY_KEY}")
client._session.verify = False
project = client.get_project("{DSS_PROJECT}")
# Check that there is at least one scenario TEST_XXXXX & that all test scenarios pass
scenarios = project.list_scenarios()
scenarios_filter = [obj for obj in scenarios if obj["name"].startswith("TEST")]
return scenarios_filter
def test_check_scenario_exist():
assert len(setup_list()) > 0, "You need at least one test scenario (name starts with 'TEST_')"
#pytest.mark.parametrize("scenario", setup_list())
def test_scenario_run(scenario, params):
client = dataikuapi.DSSClient(params['host'], params['api'])
client._session.verify = False
project = client.get_project(params['project'])
scenario_id = scenario["id"]
print("Executing scenario ", scenario["name"])
scenario_result = project.get_scenario(scenario_id).run_and_wait()
assert scenario_result.get_details()["scenarioRun"]["result"]["outcome"] == "SUCCESS", "test " + scenario[
"name"] + " failed"
My issue is with setup_list function, which able to get only hard coded values for {DSS_URL}, {APY_KEY}, {PROJECT}. I'm not able to use PARAMS or other method like in test_scenario_run
any idea how I can pass the PARAMS also to this function?
The parameters in the mark.parametrize marker are read at load time, where the information about the config parameters is not yet available. Therefore you have to parametrize the test at runtime, where you have access to the configuration.
This can be done in pytest_generate_tests (which can live in your test module):
#pytest.hookimpl
def pytest_generate_tests(metafunc):
if "scenario" in metafunc.fixturenames:
host = metafunc.config.getoption('--host')
api = metafuc.config.getoption('--api')
project = metafuc.config.getoption('--project')
metafunc.parametrize("scenario", setup_list(host, api, project))
This implies that your setup_list function takes these parameters:
def setup_list(host, api, project):
client = dataikuapi.DSSClient(host, api)
client._session.verify = False
project = client.get_project(project)
...
And your test just looks like this (without the parametrize marker, as the parametrization is now done in pytest_generate_tests):
def test_scenario_run(scenario, params):
scenario_id = scenario["id"]
...
The parametrization is now done at run-time, so it behaves the same as if you had placed a parametrize marker in the test.
And the other test that tests setup_list now has also to use the params fixture to get the needed arguments:
def test_check_scenario_exist(params):
assert len(setup_list(params["host"], params["api"], params["project"])) > 0,
"You need at least ..."

Mirth String Handling

I'm using the code below to try and strip the file extension off the incoming file and replace it with "ACK";
Can't use .lastIndexOf as it's not available in Rhino.
var _filename = String(sourceMap.get('originalFilename'));
pos = -1;
var search = ".";
for(var i = 0; i < _filename.length - search.length; i++) {
if (_filename.substr(i, search.length) == search) {
pos = i;
}
}
logger.info('_pos:' + _pos);
Every time I get a pos value of -1
i.e. Last full stop position not found.
BUT if I hardcode the filename in as "2020049.259317052.HC.P.F3M147-G" it works perfectly.
Is it something to do with the sourceMap.get('originalFilename') supplying a non-string or different
character set ?
This was tested on mirth 3.5. Rhino does, in fact, have String.prototype.lastIndexOf for all mirth versions going back to at least mirth 3.0. You were correctly converting the java string from the sourceMap to a javascript string, however, it is not necessary in this case.
Java strings share String.prototype methods as long as there is not a conflict in method name. Java strings themselves have a lastIndexOf method, so that is the one being called in my answer. The java string is able to then borrow the slice method from javascript seamlessly. The javascript method returns a javascript string.
If for some reason the filename starts with a . and doesn't contain any others, this won't leave you with a blank filename.
var filename = $('originalFilename');
var index = filename.lastIndexOf('.');
if (index > 0) filename = filename.slice(0, index);
logger.info('filename: ' + filename);
That being said, I'm not sure why your original code wasn't working. When I replaced the first line with
var originalFilename = new java.lang.String('2020049.259317052.HC.P.F3M147-G');
var _filename = String(originalFilename);
It gave me the correct pos value of 22.
New Answer
After reviewing and testing what agermano said he is correct.
In your sample code you are setting pos = i but logging _pos
New answer var newFilename = _filename.slice(0, _filename.lastIndexOf('.'))
Older Answer
First, you are mixing JavaScript types and Java types.
var _filename = String(sourceMap.get('originalFilename'));
Instead, do
var _filename = '' + sourceMap.get('originalFilename');
This will cause a type conversion from Java String to JS string.
Secondly, there is an easier way to do what you are trying to do.
var _filenameArr = ('' + sourceMap.get('originalFilename')).split('.');
_filenameArr.pop() // throw away last item
var _filename = _filenameArr.join('.') // rejoin the array with out the last item
logger.info('_filename:' + _filename)

dbutils.notebook.run not working for mapping arguments

Suppose I have 2 notebooks of which the first is the main and the second is for testing.
In the main, I have the following
dbutils.notebook.run("testing", timeoutSeconds = 60, arguments = Map("var" -> "1234"))
In testing:
%scala
println(s"Donut price = $var")
And in Main run the notebook. There is error:
You can pass arguments to DataImportNotebook and run different notebooks (DataCleaningNotebook or ErrorHandlingNotebook) based on the result from DataImportNotebook.
val status = dbutils.notebook.run("DataImportNotebook", timeoutSeconds
= 60, argumenrs = Map ("x" -> "1234"))
println("Status: " + status)
In scala, the variables are declared as follows:
The following are examples of value definitions:
var $price = 1234
println("Donut price:" + $price)
For more details, refer "Scala - How to declare variables" and "Databricks - Notebook workflows".
Hope this helps.

cgi.parse_multipart function throws TypeError in Python 3

I'm trying to make an exercise from Udacity's Full Stack Foundations course. I have the do_POST method inside my subclass from BaseHTTPRequestHandler, basically I want to get a post value named message submitted with a multipart form, this is the code for the method:
def do_POST(self):
try:
if self.path.endswith("/Hello"):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers
ctype, pdict = cgi.parse_header(self.headers['content-type'])
if ctype == 'multipart/form-data':
fields = cgi.parse_multipart(self.rfile, pdict)
messagecontent = fields.get('message')
output = ""
output += "<html><body>"
output += "<h2>Ok, how about this?</h2>"
output += "<h1>{}</h1>".format(messagecontent)
output += "<form method='POST' enctype='multipart/form-data' action='/Hello'>"
output += "<h2>What would you like to say?</h2>"
output += "<input name='message' type='text'/><br/><input type='submit' value='Submit'/>"
output += "</form></body></html>"
self.wfile.write(output.encode('utf-8'))
print(output)
return
except:
self.send_error(404, "{}".format(sys.exc_info()[0]))
print(sys.exc_info() )
The problem is that the cgi.parse_multipart(self.rfile, pdict) is throwing an exception: TypeError: can't concat bytes to str, the implementation was provided in the videos for the course, but they're using Python 2.7 and I'm using python 3, I've looked for a solution all afternoon but I could not find anything useful, what would be the correct way to read data passed from a multipart form in python 3?
I've came across here to solve the same problem like you have.
I found a silly solution for that.
I just convert 'boundary' item in the dictionary from string to bytes with an encoding option.
ctype, pdict = cgi.parse_header(self.headers['content-type'])
pdict['boundary'] = bytes(pdict['boundary'], "utf-8")
if ctype == 'multipart/form-data':
fields = cgi.parse_multipart(self.rfile, pdict)
In my case, It seems work properly.
To change the tutor's code to work for Python 3 there are three error messages you'll have to combat:
If you get these error messages
c_type, p_dict = cgi.parse_header(self.headers.getheader('Content-Type'))
AttributeError: 'HTTPMessage' object has no attribute 'getheader'
or
boundary = pdict['boundary'].decode('ascii')
AttributeError: 'str' object has no attribute 'decode'
or
headers['Content-Length'] = pdict['CONTENT-LENGTH']
KeyError: 'CONTENT-LENGTH'
when running
c_type, p_dict = cgi.parse_header(self.headers.getheader('Content-Type'))
if c_type == 'multipart/form-data':
fields = cgi.parse_multipart(self.rfile, p_dict)
message_content = fields.get('message')
this applies to you.
Solution
First of all change the first line to accommodate Python 3:
- c_type, p_dict = cgi.parse_header(self.headers.getheader('Content-Type'))
+ c_type, p_dict = cgi.parse_header(self.headers.get('Content-Type'))
Secondly, to fix the error of 'str' object not having any attribute 'decode', it's because of the change of strings being turned into unicode strings as of Python 3, instead of being equivalent to byte strings as in Python 3, so add this line just under the above one:
p_dict['boundary'] = bytes(p_dict['boundary'], "utf-8")
Thirdly, to fix the error of not having 'CONTENT-LENGTH' in pdict just add these lines before the if statement:
content_len = int(self.headers.get('Content-length'))
p_dict['CONTENT-LENGTH'] = content_len
Full solution on my Github:
https://github.com/rSkogeby/web-server
I am doing the same course and was running into the same problem. Instead of getting it to work with cgi I am now using the parse library. This was shown in the same course just a few lessons earlier.
from urllib.parse import parse_qs
length = int(self.headers.get('Content-length', 0))
body = self.rfile.read(length).decode()
params = parse_qs(body)
messagecontent = params["message"][0]
And you have to get rid of the enctype='multipart/form-data' in your form.
In my case I used cgi.FieldStorage to extract file and name instead of cgi.parse_multipart
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
})
print('File', form['file'].file.read())
print('Name', form['name'].value)
Another hack solution is to edit the source of the cgi module.
At the very beginning of the parse_multipart (around the 226th line):
Change the usage of the boundary to str(boundary)
...
boundary = b""
if 'boundary' in pdict:
boundary = pdict['boundary']
if not valid_boundary(boundary):
raise ValueError('Invalid boundary in multipart form: %r'
% (boundary,))
nextpart = b"--" + str(boundary)
lastpart = b"--" + str(boundary) + b"--"
...

Dynamically generate new named class from string with coffeescript

I have looked around and have found a number of questions which approach using-a-string-to-define-the-class-name and dynamic-class-generation-in-coffeescript> but neither of them exactly address my problem, so I am wondering whether I making some fundamental mistake in my approach to the problem.
In the loop below I am looping through some data parsed from JSON. For each set of data I want to extend my class Robot with string = new Robot where string is a string.
Currently my code does not produce any errors, and successfully creates new Robots but since their name is a string, trying to access them with robot1.move() or robot2.doSomeOtherClassyThing() does not work and tells me they are undefined.
This seems like it should not require a verbose helper function to make it work. What am I missing here?
createRobots: -> # process robot commands
createXcoord = missionData.xCoord
createYcoord = missionData.yCoord
createOrient = missionData.orientation
createInstru = missionData.robotInstructions
for command in createOrient
robot = 'robot' + (_i + 1)
name = robot
robot = new Robot \ # create named Robot
name
, createXcoord[_i]
, createYcoord[_i]
, createOrient[_i]
, createInstru[_i]
console.log(robot)
I think what is happening is that the variable "robot = 'string' is written over when the robot = new Robot is declared.
The outcome I am hoping for is string1 = new Robot, "string2 = new Robot". Does that make sense? jsfiddle.net/7EN5y/1
You need to add them to a context. If you want them to be global, create a variable like this:
# Either the browser root, or the CommonJS (e.g. Node) module root
root = window or exports
If you want an object that holds robots, add such an object to the root.
root.robots = []
Then when creating robots, add them to such an object.
robot = 'robot' + (_i + 1)
name = robot
robot = new Robot # ...
root[name] = robot # or robots[name] = robot
You may then use code like robot1.move(), or robots.robot1.move() (depending on if you attached them to the root or not).