With the following definition
trait = Trait('default',{key1 : val1, key2 : val2, ...})
is it possible to change afterwards the dictionary associating traits and their mapped counterparts? This would allow to have an object-wise mapping and not a class-wise mapping.
The answer is 'yes'. Consider the following program:
from traits.api import HasTraits, Trait
from traitsui.api import View
class A(HasTraits):
a = Trait(0,{0 : 'Zero', 1 : 'One'})
a = A()
a.configure_traits(view=View('a','a_'))
When run, you have a drop box with 0 and 1 and the corresponding text below.
It suffices to enter:
a.trait('a').handler.map = {0: 'new Zero', 1: 'new One'}
to have the new mapping
Related
For instance, I have some enums in my proto schema:
enum E1 {
UNKNOWN = 0;
OPTION_1 = 1;
OPTION_2 = 2;
OPTION_3 = 3;
}
enum E2 {
UNKNOWN = 0;
ANOTHER_OPTION_1 = 1;
ANOTHER_OPTION_2 = 2;
ANOTHER_OPTION_3 = 3;
}
message M {
E1 my_enum_1 = 1;
E2 my_enum_2 = 2;
}
I can generate scala classes with strings instead of enums by providing scalaPB TypeMappers:
TypeMapper(_.name)(E1.fromName(_).get)
TypeMapper(_.name)(E2.fromName(_).get)
But I don't want to copypaste same TypeMappers for any single Enum
Is there any way to make only one TypeMapper for all enums with scalaPB?
Yes, this can be done.
If you want to make ScalaPB use String for all enums within a package, you can add package-scoped options file to tell ScalaPB to set the scala-type for each enum to a String using field transformations:
// options.proto:
syntax = "proto3";
import "scalapb/scalapb.proto";
option (scalapb.options) = {
scope: PACKAGE,
field_transformations : [
{
when : {
type: TYPE_ENUM
}
set : {[scalapb.field] {type : 'String'}}
}
}
The next step will be to define a typemapper for all enums. Borrowing from Ivan's answer, this could be defined as follows:
implicit def enumMapper[E <: GeneratedEnum](implicit ec: GeneratedEnumCompanion[E]) =
TypeMapper[E, String](_.name)(ec.fromName(_).get)
If the above code is added to a package object in the same package as the generated code, or imported using the import option in ScalaPB, the typemapper will be found in implicit search.
You can't completely avoid defining TypeMapper for each enum type you have. But you could create a helper method to create TypeMapper instances.
For example
import scalapb.GeneratedEnum
import scalapb.GeneratedEnumCompanion
import scalapb.TypeMapper
def enumMapper[E <: GeneratedEnum: GeneratedEnumCompanion] = {
TypeMapper[E, String](_.name)(implicitly[GeneratedEnumCompanion[E]].fromName(_).get)
}
---UPDATE---
Following on #thesamet comment, if you add implicit to the method above and have it available in your implicit context, it will work.
This can be tested with following code that compiles
implicit def enumMapper...
val Enum1Mapper = implicitly[TypeMapper[E1]]
I am working in Scala programming language. I want to create custom annotations to annotate the fields of case class.
this thread show how to create it but there are two problems I am facing for my scenario
There can be . in the annotations. e.g. #abc.xyz
I want to create annotations without parameters. so I cannot create case classes
How can I do this?
Thanks
Ad. 1 - you can use backticks to have . in name but there I see 0 reasons why you should (you can just put xyz in abc package)
// possible but it's anti-pattern
class `abc.xyz` extends scala.annotation.StaticAnnotation
case class Test(
#`abc.xyz` field: String
)
// better
package my.abc
class xyz extends scala.annotation.StaticAnnotation
// elsewere
import my.abc
case class Test(
#abc.xyz field: String
)
Ad. 2 what annotations parameters have to do with case classes? Annotation does NOT have to be a case class. Some people use it because in macros they can use pattern matching on materialized annotation value, but that's it.
case class Foo() extends scala.annotation.StaticAnnotation
class Bar extends scala.annotation.StaticAnnotation
case class Test(
#Foo foo: String,
#Bar bar: String
)
[c3f36c25-2546-48b2-bd72-1b5e5dcae2ab, 1620247529, 6032, Amoma, 17256, false, Tui.com, 17149, false]
c3f36c25-2546-48b2-bd72-1b5e5dcae2a- userid
1620247529- timestamp
6032-parkid
Amoma-parkname
17256-cost
false -dinner
here .. park id is the maptype which includes amoma,mercury
amoma is the array type which includes cost and dinner .. Need to write the schema for this
Try below schema & if not working add some more sample data.
scala> case class Advertise(eurocents: Int,breakfast: Boolean)
defined class Advertise
scala> case class Advertisers(advertisers:Map[String,Seq[Advertise]])
defined class Advertisers
scala> case class Record(userId: String,unix_time: String,parkid:Map[String,Advertisers])
defined class Record
scala> val schema = Encoders.product[Record].schema
schema: org.apache.spark.sql.types.StructType = StructType(StructField(userId,StringType,true), StructField(unix_time,StringType,true), StructField(parkid,MapType(StringType,StructType(StructField(advertisers,MapType(StringType,ArrayType(StructType(StructField(eurocents,IntegerType,false), StructField(breakfast,BooleanType,false)),true),true),true)),true),true))
With the following code:
from traits.api import HasTraits, List, Int, Instance, on_trait_change
class A(HasTraits):
value = Int(0)
class B(HasTraits):
lst = List(Instance(A,()))
#on_trait_change('lst[]')
def _update(self):
print('changed')
'changed' is printed when the items are changed, as in:
b = B(lst = [A()])
How to make the event fired when the internals of the list items are changed, as in:
b.lst[0].value=1
You can listen to attributes of instances contained in an object using the syntax container:attribute_name. See below the decorator on the _item_update method:
from traits.api import HasTraits, List, Int, Instance, on_trait_change
class A(HasTraits):
value = Int(0)
class B(HasTraits):
lst = List(Instance(A,()))
#on_trait_change('lst[]')
def _update(self):
print('changed')
#on_trait_change('lst:value')
def _item_update(self, name, new):
print(name, new)
b = B(lst = [A()])
b.lst[0].value=1
This will print:
changed
('value', 1)
The "Semantics" section of the documentation shows all the possible patterns. The following section, on Notification Handler Signatures, lists out the possible listener method signatures.
I wrote a Scala source file called Vegetables.scala. What I am trying to accomplish from this code below is to understand how import clauses work. I typed in this program in Eclipse and started the Eclipse-based REPL.
What I would like to do is create a new object called Spinach that extends Vegetable, assign it to a val and eventually invoke the showColor method of object Vegetable, passing the Spinach object into it. I know the examples sounds absurd, but I simply trying to understand the concepts/mechanics of Scala right now. To this end I did the following in the REPL:
So this is what I did on the REPL and get an error.
import com.att.scala.Vegetables._
import java.awt.Color
val obj = object Spinach extends Vegetable { val name = "Spinach" val color = Color.GREEN }
<console>:1: error: illegal start of simple expression
val obj = object Spinach extends Vegetable { val name = "Spinach" val color = Color.GREEN }
^
The code for Vegetable.scala is below:
package com.att.scala
import java.awt.Color
trait Vegetable {
val name: String
val color: Color
}
object Vegetables {
object Asparagus extends Vegetable {
val name = "Asparagus"
val color = Color.GREEN
}
object Carrot extends Vegetable {
val name = "Carrot"
val color = Color.ORANGE
}
val veggiePlatter = List(Asparagus, Carrot)
def showColor(veggie: Vegetable) {
import veggie._
println("Entered showColor")
import veggie._
println("veggie color is " + color)
}
}
What might explain this error? Firstly, I am trying to understand what is the right way to make an object on the REPL and then assign it to a val. Once that is out of the way, I hope to pass that val in a parameter. Then, I would like to test the import clause inside the showColor to see if it indeed imports the members of the veggie parameter.
Defining an object is like defining a static member, or a class. You can't declare it and assign it to a variable at the same time. (And in fact you don't really need to, as the object can already be accessed via its name after it's defined.)
So your example would work in the REPL as:
import com.att.scala.Vegetables._
import java.awt.Color
object Spinach extends Vegetable { val name = "Spinach" val color = Color.GREEN }
which would define an object called Spinach. After that, you could call Vegetables.showColor(Spinach) to achieve your initial goal.
If you really wanted to assign it to a variable, you could call val obj = Spinach after you've declared the object, which would be valid (albeit not particularly useful - Spinach is already an unambiguous name for that thing, obj would effectively just be an alias.). Doing it on the same line that you declare the object though is illegal syntax.