Why can't I modify a construction environment from within a pseudo builder (AddMethod)? - scons

I need to modify a set of variables in multiple construction environments so I decided the cleanest way would be to create a method that does that.
Instead of a vanilla python function I've tried to use the AddMethod in the construction environment object since it seems to be the way of doing such things in scons.
However, it appears that methods of construction environments are unable to modify this environment.
Here's an example where I tested a few ways of changing a variable in a construction environment:
env1 = Environment(VAR='foo')
def changeVal(env, newval):
env['VAL'] = newval
env1.AddMethod(changeVal, 'ChangeVal')
env2 = env1.Clone(VAR='bar')
env3 = env2.Clone()
env3['VAR'] = 'baz'
env4 = env3.Clone()
env4.ChangeVal('qux')
print(env1['VAR'], env2['VAR'], env3['VAR'], env4['VAR'])
The result is foo bar baz baz while I would expect foo bar baz qux.
Why is that?

Pretty sure you have a typo in your example:
env1 = Environment(VAR='foo')
def changeVal(env, newval):
env['VAL'] = newval
env1.AddMethod(changeVal, 'ChangeVal')
env2 = env1.Clone(VAR='bar')
env3 = env2.Clone()
env3['VAR'] = 'baz'
env4 = env3.Clone()
env4.ChangeVal('qux')
print(env1['VAR'], env2['VAR'], env3['VAR'], env4['VAR'])
Specifically
def changeVal(env, newval):
env['VAR'] = newval
#. ^^^--- You have VAL here, but check for VAR later.

Related

python function with modular variable

hie,
I'm writing my first big python program (3.8) and I try to use a function for several uses (same work but with different targets from existing attributes)
I hope it's clear enough.
here the wanted Job :
it's inside a QT5 GUI (QApplication)
class GuiSuperQuizz(QWidget, QApplication):
...
...
def ajout_pts_blindtest(self, nbr):
x = nbr
x = str(x)
eval("team" + x).ajou_pts(int(self.point_blindtest))
eval("self.score_equip_" + x).setText(str(eval("team" + x).point)) # bug is here
eval("self.gest_score_equip_" + x).setText(str(eval("team" + x).point))
print(eval("team" + x).point)
self.continu[0] = False
self.en_pause[0] = False
self.records_scores()
The interpreter do not recognize the attribute "score_equip_1" and give me an error
AttributeError: 'GuiSuperQuizz' object has no attribute 'score_equip_1'
Yet, I know that attribute works well with this other function that work fine
def ajout_pts_rap_team1(self):
team1.ajou_pts(int(self.point_rap))
self.score_equip_1.setText(str(team1.point))
self.gest_score_equip_1.setText(str(team1.point))
print(team1.point)
self.continu[0] = False
self.en_pause[0] = False
self.aff_ligne4()
self.records_scores()
For not writing 4 functions to target 4 variables that are just incremented (it's a Quizz game with 4 players) I try try to concatenate in 1 function that arrange targets.
if I test the same logic on a very simple lines that works:
test1 = 456
def test(nbr):
x = nbr
x=str(x)
print(eval("test"+x))
test(1)
456
If anyone got some explanations ....

How to evaluate a String which one like a classname.methodname in SoapUI with Groovy?

I have groovy code as below:
def randomInt = RandomUtil.getRandomInt(1,200);
log.info randomInt
def chars = (("1".."9") + ("A".."Z") + ("a".."z")).join()
def randomString = RandomUtil.getRandomString(chars, randomInt) //works well with this code
log.info randomString
evaluate("log.info new Date()")
evaluate('RandomUtil.getRandomString(chars, randomInt)') //got error with this code
I want to evaluate a String which one like a {classname}.{methodname} in SoapUI with Groovy, just like above, but got error here, how to handle this and make it works well as I expect?
I have tried as blew:
evaluate('RandomUtil.getRandomString(chars, randomInt)') //got error with this code
Error As below:
Thu May 23 22:26:30 CST 2019:ERROR:An error occurred [No such property: getRandomString(chars, randomInt) for class: com.hypers.test.apitest.util.RandomUtil], see error log for details
The following code:
log = [info: { println(it) }]
class RandomUtil {
static def random = new Random()
static int getRandomInt(int from, int to) {
from + random.nextInt(to - from)
}
static String getRandomString(alphabet, len) {
def s = alphabet.size()
(1..len).collect { alphabet[random.nextInt(s)] }.join()
}
}
randomInt = RandomUtil.getRandomInt(1, 200)
log.info randomInt
chars = ('a'..'z') + ('A'..'Z') + ('0'..'9')
def randomString = RandomUtil.getRandomString(chars, 10) //works well with this code
log.info randomString
evaluate("log.info new Date()")
evaluate('RandomUtil.getRandomString(chars, randomInt)') //got error with this code
emulates your code, works, and produces the following output when run:
~> groovy solution.groovy
70
DDSQi27PYG
Thu May 23 20:51:58 CEST 2019
~>
I made up the RandomUtil class as you did not include the code for it.
I think the reason you are seeing the error you are seeing is that you define your variables char and randomInt using:
def chars = ...
and
def randomInt = ...
this puts the variables in local script scope. Please see this stackoverflow answer for an explanation with links to documentation of different ways of putting things in the script global scope and an explanation of how this works.
Essentially your groovy script code is implicitly an instance of the groovy Script class which in turn has an implicit Binding instance associated with it. When you write def x = ..., your variable is locally scoped, when you write x = ... or binding.x = ... the variable is defined in the script binding.
The evaluate method uses the same binding as the implicit script object. So the reason my example above works is that I omitted the def and just typed chars = and randomInt = which puts the variables in the script binding thus making them available for the code in the evaluate expression.
Though I have to say that even with all that, the phrasing No such property: getRandomString(chars, randomInt) seems really strange to me...I would have expected No such method or No such property: chars etc.
Sharing the code for for RandomUtil might help here.

How can I find out the place of an artifact in groovy

I have the following groovy dependency declared:
#GrabResolver(name='mymirror', root='http://myartifactory/public/')
#Grab(group='groupid', module='artifactid', version='1.2.3')
println //What should I write here to see: c:\Users....m2....artifactid.jar
How can I get the location of the downloaded resolved artifact in groovy?
#Grab(group='net.sourceforge.plantuml', module='plantuml', version='8049')
import groovy.grape.Grape
def grape = Grape.getInstance()
def r = grape.listDependencies(this.getClass().getClassLoader())
println r
println grape.resolve(r[0])
prints
[[group:net.sourceforge.plantuml, module:plantuml, version:8049]]
[file:/C:/Users/dm/.groovy/grapes/net.sourceforge.plantuml/plantuml/jars/plantuml-8049.jar]
By default, Grape stores a cache of the jars on ~/.groovy/grapes. So, I think you can do something like this:
#GrabResolver(name='mymirror', root='http://myartifactory/public/')
#Grab(group='groupid', module='artifactid', version='1.2.3')
String grapeCacheDir = "${System.getProperty('user.home')}/.groovy/grapes"
String group = 'groupid'
String module = 'artifactid'
String version = '1.2.3'
File myJar = new File("$grapeCacheDir/$group/$module/jars/${module}-${version}.jar")
println myJar.path
It's not a preety solution, but I can't think in any other options.

Parameter aliasing

when implementing Origen::Parameters, I understood the importance of defining a 'default' set. But, in essence, my real default is named something different. So I implemented a hack of a parameter alias:
Origen.top_level.define_params :default do |params|
params.tconds.override = 1
params.tconds.override_lev_equ_set = 1
params.tconds.override_lev_spec_set = 1
params.tconds.override_levset = 1
params.tconds.override_seqlbl = 'my_pattern'
params.tconds.override_testf = 'tm_3'
params.tconds.override_tim_spec_set = 'bist_xxMhz'
params.tconds.override_timset = '1,1,1,1,1,1,1,1'
params.tconds.site_control = 'parallel:'
params.tconds.site_match = 2
end
Origen.top_level.define_params :cpu_mbist_hr, inherit: :default do |params|
# way of aliasing parameter names
end
Is there a proper method of parameter aliasing that is just not documented?
There is no other way to do this currently, though I would be open to a PR to enable something like:
default_params = :cpu_mbist_hr
If you don't want them to be called :default in this case though, then maybe you don't really want them to be the default anyway.
e.g. adding this immediately after you define them would effectively give you an alternative default and would do pretty much the same job as the proposed API above:
# self is required here to help Ruby know that you are calling the params= API
# and not defining a local variable called params
self.params = :cpu_mbist_hr

scons: overriding build options for one file

Easy question but I don't know the answer.
Let's say I have a scons build where my CCFLAGS includes -O1. I have one file needsOptimization.cpp where I would like to override the -O1 with -O2 instead. How could I do this in scons?
update: this is what I ended up doing based on bialix's answer:
in my SConscript file:
Import('env');
env2 = env.Clone();
env2.Append(CCFLAGS=Split('-O2 --asm_listing'));
sourceFiles = ['main.cpp','pwm3phase.cpp'];
sourceFiles2 = ['serialencoder.cpp','uartTestObject.cpp'];
objectFiles = [];
objectFiles.append(env.Object(sourceFiles));
objectFiles.append(env2.Object(sourceFiles2));
...
previously this file was:
Import('env');
sourceFiles = ['main.cpp','pwm3phase.cpp','serialencoder.cpp','uartTestObject.cpp'];
objectFiles = env.Object(sourceFiles);
...
Use Object() builder for fine-grained control over compilation, and then pass these objects to Program() builder.
E.g. instead of:
env = Environment()
env.Program(target='foo', source=['foo.cpp', 'bar.cpp', 'needsOptimisation.cpp'])
You need to use following:
env = Environment()
env_o1 = env.Clone()
env_o1.Append(CCFLAGS = '-O1')
env_o2 = env.Clone()
env_o2.Append(CCFLAGS = '-O2')
# extend these lists if needed
SRC_O1 = ['foo.cpp', 'bar.cpp']
SRC_O2 = ['needsOptimisation.cpp']
obj_o1 = [env_o1.Object(i) for i in SRC_O1]
obj_o2 = [env_o2.Object(i) for i in SRC_O2]
env.Program(target='foo', source=obj_o1+obj_o2)
You can avoid creation of separate clone of env variable if you provide CCFLAGS='-O2' right in the Object() call:
obj_o2 = [env.Object(i, CCFLAGS=env['CCFLAGS'] + ['-O2']) for i in SRC_O2]
Avoiding creating of a separate env variable requires (ref: bialix's answer) needs something like this.
obj_o2 = env.Object(SRC_O2, CCFLAGS=env['CCFLAGS'] + ['-O2']);
If you just do this (or in the for loop like bialix does)
obj_o2 = env.Object(SRC_O2, CCFLAGS='-O2');
then you lose all the builtin flags.

Resources