How can I create instance of a namedtuple dynamically? is it possible?
Msg = collections.namedtuple('Msg', 'a b c')
...
mymsg = Msg(a=1,b=2,c=3)
msg_as_dict = mymsg._asdict()
msg_as_dict['recover_name'] = type(mymsg).__name__
How can I create Msg instance back from msg['recover_name'] on runtime?
UPDATE:
How can I get the type of the namedtuple in runtime? meaning, get "Msg" from exists instance.
This will work with no reflection required:
def test_tuple_builder(self):
from collections import namedtuple
name = "Foo"
attribs = "bar baz goo tar taz"
values = [100, "Hello", -1, "World", "1968"]
tpl_cls = namedtuple(name, attribs)
foo = tpl_cls(*values)
self.assertEqual(values[0], foo.bar)
self.assertEqual(values[1], foo.baz)
self.assertEqual(values[2], foo.goo)
self.assertEqual(values[3], foo.tar)
self.assertEqual(values[4], foo.taz)
print("We always use '{baz}, {tar}' as an example.".format(baz=foo.baz, tar=foo.tar))
All tests pass and the output:
We always use 'Hello, World' as an example.
Related
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.
I'm trying to create a field mapping to map fields from user-friendly names to member variables in a variety of domain objects. The larger context is that I'm building up an ElasticSearch query based on user-constructed rules stored in a database, but for the sake of MCVE:
class MyClass {
Integer amount = 123
}
target = new MyClass()
println "${target.amount}"
fieldMapping = [
'TUITION' : 'target.amount'
]
fieldName = 'TUITION'
valueSource = '${' + "${fieldMapping[fieldName]}" + '}'
println valueSource
value = Eval.me('valueSource')
The Eval fails. Here's the output:
123
${target.amount}
Caught: groovy.lang.MissingPropertyException: No such property: valueSource for class: Script1
groovy.lang.MissingPropertyException: No such property: valueSource for class: Script1
at Script1.run(Script1.groovy:1)
at t.run(t.groovy:17)
What's necessary to evaluate the generated variable name and return the value 123? It seems like the real problem is that it's not recognizing that valueSource has been defined, not the actual expression held in valueSource, but that could be wring, too.
You're almost there, but you need to use a slightly different mechanism: the GroovyShell. You can instantiate a GroovyShell and use it to evaluate a String as a script, returning the result. Here's your example, modified to work properly:
class MyClass {
Integer amount = 123
}
target = new MyClass()
fieldMapping = [
'TUITION' : 'target.amount'
]
fieldName = 'TUITION'
// These are the values made available to the script through the Binding
args = [target: target]
// Create the shell with the binding as a parameter
shell = new GroovyShell(args as Binding)
// Evaluate the "script", which in this case is just the string "target.amount".
// Inside the shell, "target" is available because you added it to the shell's binding.
result = shell.evaluate(fieldMapping[fieldName])
assert result == 123
assert result instanceof Integer
I am trying to parse an yaml file in Groovy. However I am facing issue while typecasting the result to Map object.
Here is my logic
import org.yaml.snakeyaml.Yaml
import java.util.Map
Reader reader = null
int tokenCount = 0
def Map map = null
StringTokenizer st = new java.util.StringTokenizer("Country.State.City", ".")
reader = new FileReader("filepath")
String val = null
Yaml yaml = new Yaml()
map = (Map) yaml.load(reader)
tokenCount = st.countTokens()
for (i=1; i < tokenCount; i++) {
String token = st.nextToken()
map = (Map) map.get(token)
}
val = map.get(st.nextToken()).toString()
However I am getting error at line:
map = (Map) map.get(token)
where it says:
"org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'some value' with class 'java.lang.String' to class 'java.util.Map' error at line: 15"..
Where I am going wrong?
your provided yaml file is syntactically incorrect. This is a fixed version:
location: C:\\Users\\amah11\\Desktop\\New folder
type: hi
Header:
Code:
Start: 0
End: 2
value: H00
Owner:
Start: 3
End: 5
value: AIM
User:
Start: 6
End: 8
Value: AIM
number: 1
Note that Code: **Static** in the original messes things up. And all the keys on the final level need a space after the : (e.g. Start:3 is wrong).
The actual error message is:
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'Static Start:0 End:2 value:H00' with class 'java.lang.String' to class 'java.util.Map'
which is rather clear in showing, that there is something wrong with the original file.
You might want to consider using an editor, that detects errors like this right away.
An alternative to the original code, would be the use of inject on the tokenizer:
def map = new Yaml().load(new FileReader("cardconfig.yml"))
println new StringTokenizer('Header.Code.End', '.').inject(map) { r, s -> r.get(s) }
BTW: you don't need to import java.util in groovy.
I am new to Groovy and I could not get around this issue. I appreciate any help.
I want to read a file from Groovy. While I am reading the content, for each line I want to substitute the string '${random_id}' and '${entryAuthor}' with different string values.
protected def doPost(String url, URL bodyFile, Map headers = new HashMap() ) {
StringBuffer sb = new StringBuffer()
def randomId = getRandomId()
bodyFile.eachLine { line ->
sb.append( line.replace("\u0024\u007Brandom_id\u007D", randomId)
.replace("\u0024\u007BentryAuthor\u007D", entryAuthor) )
sb.append("\n")
}
return doPost(url, sb.toString())
}
But I got the following error:
groovy.lang.MissingPropertyException:
No such property: random_id for class: tests.SimplePostTest
Possible solutions: randomId
at foo.test.framework.FooTest.doPost_closure1(FooTest.groovy:85)
at groovy.lang.Closure.call(Closure.java:411)
at groovy.lang.Closure.call(Closure.java:427)
at foo.test.framework.FooTest.doPost(FooTest.groovy:83)
at foo.test.framework.FooTest.doPost(FooTest.groovy:80)
at tests.SimplePostTest.Post & check Entry ID(SimplePostTest.groovy:42)
Why would it complain about a property, when I am not doing anything? I also tried "\$\{random_id\}", which works in Java String.replace(), but not in Groovy.
You are doing it the hard way. Just evaluate your file's contents with Groovy's SimpleTemplateEngine.
import groovy.text.SimpleTemplateEngine
def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
def binding = ["firstname":"Sam", "lastname":"Pullara", "city":"San Francisco", "month":"December", "signed":"Groovy-Dev"]
def engine = new SimpleTemplateEngine()
template = engine.createTemplate(text).make(binding)
def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'
assert result == template.toString()
you better use groovy.text.SimpleTemplateEngine class; check this for more details http://groovy.codehaus.org/Groovy+Templates
The issue here is that Groovy Strings will evaluate "${x}" by substituting the value of 'x', and we don't want that behaviour in this case. The trick is to use single-quotes which denote plain old Java Strings.
Using a data file like this:
${random_id} 1 ${entryAuthor}
${random_id} 2 ${entryAuthor}
${random_id} 3 ${entryAuthor}
Consider this code, which is analogous to the original:
// spoof HTTP POST body
def bodyFile = new File("body.txt").getText()
StringBuffer sb = new StringBuffer()
def randomId = "257" // TODO: use getRandomId()
def entryAuthor = "Bruce Eckel"
// use ' here because we don't want Groovy Strings, which would try to
// evaluate e.g. ${random_id}
String randomIdToken = '${random_id}'
String entryAuthorToken = '${entryAuthor}'
bodyFile.eachLine { def line ->
sb.append( line.replace(randomIdToken, randomId)
.replace(entryAuthorToken, entryAuthor) )
sb.append("\n")
}
println sb.toString()
The output is:
257 1 Bruce Eckel
257 2 Bruce Eckel
257 3 Bruce Eckel
Is it possible to have named parameters with default values in groovy? My plan is to make a sort of object factory, which can be called with no arguments at all in order to get an object with default values. Also, I'd need the functionality to explicitly set any of the params for the object. I believe this is possible with Python keyword arguments, for example.
The code I'm attempting with right now is something like below
// Factory method
def createFoo( name='John Doe', age=51, address='High Street 11') {
return new Foo( name, age, address )
}
// Calls
Foo foo1 = createFoo() // Create Foo with default values
Foo foo2 = createFoo( age:21 ) // Create Foo where age param differs from defaut
Foo foo3 = createFoo( name:'Jane', address:'Low Street 11' ) // You get the picture
// + any other combination available
The real app that I'm working on will have a lot more of parameters and thus a lot more combinations needed.
Thanks
UPDATE:
The factory method I'm planning is for testing purposes. Cannot really touch the actual Foo class and especially not it's default values.
#dmahapatro and #codelarks answere below had a good point in using a Map as a param that gave me an idea of a possible solution. I could create a map with the wanted defaults and override the needed values, and pass that to the factory method. This'll probably do the job and I'll go with that, unless I get a hint of a better approach.
My current approach below
defaults = [ name:'john', age:61, address:'High Street']
#ToString(includeFields = true, includeNames = true)
class Foo {
// Can't touch this :)
def name = ''
def age = 0
def address = ''
}
def createFoo( Map params ) {
return new Foo( params )
}
println createFoo( defaults )
println createFoo( defaults << [age:21] )
println createFoo( defaults << [ name:'Jane', address:'Low Street'] )
NOTE: leftShift operation ( << ) modifies the the original map, so in the above example age will be 21 in the last method call as well. In my case, this is not a problem as the defaults map can be created freshly each time in setup method.
Groovy does that for you by default (map constructor). You would not need a factory method. Here is an example
import groovy.transform.ToString
#ToString(includeFields = true, includeNames = true)
class Foo{
String name = "Default Name"
int age = 25
String address = "Default Address"
}
println new Foo()
println new Foo(name: "John Doe")
println new Foo(name: "Max Payne", age: 30)
println new Foo(name: "John Miller", age: 40, address: "Omaha Beach")
//Prints
Foo(name:Default Name, age:25, address:Default Address)
Foo(name:John Doe, age:25, address:Default Address)
Foo(name:Max Payne, age:30, address:Default Address)
Foo(name:John Miller, age:40, address:Omaha Beach)
UPDATE
#codelark's astrology :). In case the class is not accessible to set default values, you can do like
#ToString(includeFields = true, includeNames = true)
class Bar{
String name
int age
String address
}
def createBar(Map map = [:]){
def defaultMap = [name:'John Doe',age:51,address:'High Street 11']
new Bar(defaultMap << map)
}
println createBar()
println createBar(name: "Ethan Hunt")
println createBar(name: "Max Payne", age: 30)
println createBar(name: "John Miller", age: 40, address: "Omaha Beach")
//Prints
Bar(name:John Doe, age:51, address:High Street 11)
Bar(name:Ethan Hunt, age:51, address:High Street 11)
Bar(name:Max Payne, age:30, address:High Street 11)
Bar(name:John Miller, age:40, address:Omaha Beach)