Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Jan 31 15:23
    ashabhasa starred pureconfig/pureconfig
  • Jan 30 20:03

    ruippeixotog on master

    Update cats-effect, fs2 and htt… Merge pull request #448 from ba… (compare)

  • Jan 30 20:03
    ruippeixotog closed #448
  • Jan 30 08:05
    Mao1990 starred pureconfig/pureconfig
  • Jan 29 13:08
    bardurdam opened #448
  • Jan 29 10:20
    PatrykRudnicki starred pureconfig/pureconfig
  • Jan 28 18:52

    ruippeixotog on master

    Create a FluentConfigCursor Merge branch 'master' into flue… Fix yaml module on Scala 2.11 and 3 more (compare)

  • Jan 28 18:52
    ruippeixotog closed #443
  • Jan 28 18:02
    ruippeixotog synchronize #443
  • Jan 28 18:02

    ruippeixotog on fluent-cursor

    Create scalaz module for pureco… Merge branch 'master' into scal… Update module with latest Confi… and 19 more (compare)

  • Jan 27 14:09
    esumitra starred pureconfig/pureconfig
  • Jan 27 01:55

    ruippeixotog on master

    Create scalaz module for pureco… Merge branch 'master' into scal… Update module with latest Confi… and 6 more (compare)

  • Jan 27 01:55
    ruippeixotog closed #444
  • Jan 27 01:19
    ruippeixotog synchronize #444
  • Jan 27 01:19

    ruippeixotog on master

    Add cron4s module - add cron4s… Merge pull request #446 from ba… (compare)

  • Jan 27 01:19
    ruippeixotog closed #446
  • Jan 26 22:51
    ChernikovP synchronize #444
  • Jan 26 22:37
    bardurdam synchronize #446
  • Jan 26 22:36
    bardurdam commented #446
  • Jan 26 22:31
    bardurdam synchronize #446
nigredo-tori
@nigredo-tori
@ThijsBroersen
nigredo-tori
@nigredo-tori
Opened #599 to make sure this gets mitigated.
Thijs
@ThijsBroersen
@nigredo-tori thanks for your elaborate answer!
machinesleet
@machinesleet

Hi All, I'd like to be able to specify some custom behaviour when reading a date string from the config. Is it possible to look for a value when parsing (e.g. "currentTime") as opposed to "1980-01-01", catch the reader error, inspect the string, and then create the appropriate date as the current time if matching this string?

I've tried to implement a custom config reader, but struggling to debug it and achieve the above (if it's possible).

Joao Azevedo
@jcazevedo
@machinesleet: I think something in the lines of the following should do what you want:
implicit val customLocalDateCR: ConfigReader[LocalDate] = {
  ConfigReader[String].flatMap {
    case "currentTime" => _ => Right(LocalDate.now())
    case _ => configurable.localDateConfigConvert(DateTimeFormatter.ISO_LOCAL_DATE)
  }
}
machinesleet
@machinesleet

@jcazevedo Thank you - I had tried something along the lines of your suggestion, but also had a localDateConvert implicit defined like so:

implicit val localDateConvert = localDateConfigConvert(DateTimeFormatter.ISO_DATE)

It looks like this was interfering with the reader in some way.

machinesleet
@machinesleet
Ah OK, ConfigConvert extends ConfigReader :thumbsup:
Joao Azevedo
@jcazevedo
Yes. A ConfigConvert is both a ConfigReader and a ConfigWriter.
machinesleet
@machinesleet
Is there a version of the above that works for 2.11, after changing versions the block complains that there's a missing parameter type related to the _ in the currentTime case
Joao Azevedo
@jcazevedo
Yes. Scala 2.11 only has support for single abstract methods under the -Xexperimental flag.
The following should work on Scala 2.11+:
implicit val customLocalDateCR: ConfigReader[LocalDate] = {
  ConfigReader[String].flatMap {
    case "currentTime" => new ConfigReader[LocalDate] {
      def from(cur: ConfigCursor): Result[LocalDate] = Right(LocalDate.now())
    }
    case _ => configurable.localDateConfigConvert(DateTimeFormatter.ISO_LOCAL_DATE)
  }
}
machinesleet
@machinesleet
Hello again all, is there a way to do
val configSource = ConfigSource.defaultApplication
val configClasses = List(caseClass1, caseClass2)
val failedConfigLoads = configClasses.filter(classToLoad => 
configSource.at(classToLoad.classname).load[classToLoad].isLeft)
I have a companion object providing classnames, but the .load method doesn't seem to be valid syntax, or isn't picked up in this block
Also @jcazevedo thanks for your previous answer :)
machinesleet
@machinesleet
finally .load[classToLoad.type] does compile, but does not pick up config errors
Leif Wickland
@leifwickland
@machinesleet, something like this works for me:
import pureconfig._
import pureconfig.generic._
import pureconfig.generic.auto._
import scala.reflect.runtime.universe.TypeTag


class HasConfigReader[A:TypeTag](implicit D : Derivation[ConfigReader[A]]) {
  val d: Derivation[ConfigReader[A]] = D
  override def toString = implicitly[TypeTag[A]].toString
  def classname = implicitly[TypeTag[A]].tpe.toString
}

case class I(i: Int, ii: Int)
case class S(s: String)

object A {
  def main(a: Array[String]): Unit = {
    val configSource = ConfigSource.defaultApplication
    val l = List(new HasConfigReader[I], new HasConfigReader[S])
    val fails = l.filter(c => configSource.at(c.classname).load(c.d).isLeft)
    fails.foreach(println)
  }
}
Using TypeTag is optional.
Vincent van Donselaar
@vanDonselaar

Hi, I'm having trouble with reading byte arrays/vectors from config files. I copied the snippet from https://pureconfig.github.io/docs/combinators.html but pureconfig doesn't seem to support Byte:

- missing a ConfigWriter instance for type Vector[Byte], because:
  - missing a ConfigWriter instance for type Byte

Am I missing something?

Grigorii Chudnov
@gchudnov

Hi
a question: if I want to contribute config converters for some akka-http case classes, should I contribute to pureconfig-akka (with adding akka-http dependency) or create a new module especially for akka-http ?

I'm thinking of a new module for akka-http but wanted to clarify..

machinesleet
@machinesleet
@leifwickland Thank you, I think there's an issue with c.classname picking up the full com.etc path and not the final name e.g. "I", "S", as per your example.
Grigorii Chudnov
@gchudnov
@vanDonselaar do you have an code? just tried the example on https://pureconfig.github.io/docs/combinators.html and it works (scala 2.12.7, library: "0.12.1")
Joao Azevedo
@jcazevedo
@vanDonselaar: According to that error message, you seem to require a ConfigWriter (or a ConfigConvert) somewhere in your code. The examples on the documentation only use ConfigReaders.
If you really need a ConfigWriter for Vector[Byte], you can follow a similar strategy and piggyback on the ConfigWriter for Strings:
implicit val byteVectorWriter: ConfigWriter[Vector[Byte]] =
  ConfigWriter[String].contramap(_.map(_.toChar).mkString)
@gchudnov: Hi!
@gchudnov: I think a module especially for akka-http is more appropriate. :)
Grigorii Chudnov
@gchudnov
@jcazevedo got it, thank you!
nigredo-tori
@nigredo-tori
@vanDonselaar, a small correction to what @jcazevedo has told you. Unless your byte vector is indeed a string of characters, I suggest you go with a more idiomatic approach. I'd write Vector[Byte] as a HOCON array of integers. This way you'll only need
implicit val byteWriter: ConfigWriter[Byte] =
  ConfigWriter[Int].contramap(_.toInt)
Also, we might want to add that to the library itself.
Joao Azevedo
@jcazevedo
Yes, I agree.
I gave that ConfigWriter example to match the ConfigReader for Vector[Byte] we have as an example in the docs.
Which might not be the best example in the first place. :sweat_smile:
Vincent van Donselaar
@vanDonselaar

Thanks all! Those suggestions were very helpful and I managed to solve my problem by bringing these two in scope:

implicit val byteArrayConvert: ConfigConvert[Array[Byte]] =
  ConfigConvert[String].xmap[Array[Byte]](Hex.decodeHex, b => Hex.encodeHexString(b, false))
implicit val byteHexConvert: ConfigConvert[Byte] =
  ConfigConvert[String].xmap[Byte](Hex.decodeHex(_).head, b => Hex.encodeHexString(Array(b), false))

This allows me to put bytes and byte arrays in my config by expressing them as hex strings.

Leif Wickland
@leifwickland
@machinesleet If you only want the class's name without the namespace/package, call getSimpleName on the Class instance for it. You can get that a variety of ways. Here's one that uses ClassTag:
package foo.bar.baz

import pureconfig._
import pureconfig.generic._
import pureconfig.generic.auto._
import scala.reflect.ClassTag


class HasConfigReader[A:ClassTag](implicit D : Derivation[ConfigReader[A]]) {
  val d: Derivation[ConfigReader[A]] = D
  override def toString = classname
  def classname = implicitly[ClassTag[A]].runtimeClass.getSimpleName
}

case class I(i: Int, ii: Int)
case class S(s: String)

object A {
  def main(a: Array[String]): Unit = {
    val configSource = ConfigSource.defaultApplication
    val l = List(new HasConfigReader[I], new HasConfigReader[S])
    val fails = l.filter(c => configSource.at(c.classname).load(c.d).isLeft)
    fails.foreach(println)
  }
}
machinesleet
@machinesleet
Great, thank you! I was doing something similar in the original case class with getSimpleName. Are there any tutorials / guides you would recommend for reflection/implicits (e.g. parts of the above code that make me think "this is voodoo")? Or is it a case of experimentation?
Andrey Bobylev
@XoJIoD89
heya guys
please advise if I can provide a custom path for a single field in a config? i.e. I have a.b.c = "string" and I need only the c part w/o nesting it into two other case classes
Leif Wickland
@leifwickland
@machinesleet
I like this page for general theory: https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html
I end up wandering through the API docs to figure out what's available beyond that.
Sorry I don't have a better answer
Leif Wickland
@leifwickland
In general, TypeTag is for when you need accurate information after type erasure, i.e. you need to know details about a generic type. ClassTag is for all other occasions.
@XoJIoD89, can you use HOCON's substitution ability to reference a common value in multiple places?
theOneTrueC="foo"
a.b.c = ${theOneTrueC}
someOtherC = ${theOneTrueC}
fizz.buzz.thatOtherC = ${theOneTrueC}
Andrey Bobylev
@XoJIoD89
@leifwickland oh, thanks, didn't think in that direction :)
machinesleet
@machinesleet
@leifwickland Is there a way of going from String (case class name) to TypeTag that would fit with your previous examples? I've tried something similar to this: https://stackoverflow.com/questions/23785439/getting-typetag-from-a-classname-string?rq=1 but again struggling to implement
Leif Wickland
@leifwickland
@machinesleet I don't think you can get a TypeTag from a string but you can get a Class[_]. Although to do that you'd have to use the full package name, not the simple name.
It seems like what you're trying to do is dynamically select some configs that might be present. The limiting factor that you're going to run into is that you have to allow the compile to know all the types that you might try to load at compile time. If you can define that then you could do something like define an ADT where each member holds the Derivation[ConfigureReader[A]] for the type the member relates to. You could use enumeratum to produce a mapping from string to ADT member.
package foo.bar.baz

import pureconfig._
import pureconfig.generic._
import pureconfig.generic.auto._
import scala.reflect.runtime.universe.TypeTag
import scala.reflect.ClassTag
import enumeratum._

class HasConfigReader[A:ClassTag](implicit D : Derivation[ConfigReader[A]]) {
  val d: Derivation[ConfigReader[A]] = D
  override def toString = classname
  def classname = implicitly[ClassTag[A]].runtimeClass.getSimpleName
}

case class IConf(i: Int, ii: Int)
case class SConf(s: String)

object A {
  def main(a: Array[String]): Unit = {
   val configSource = ConfigSource.defaultApplication
   val l = List("i", "s").map(ConfigType.vMap.apply)
   val fails = l.filter(c => configSource.at(c.entryName).load(c.der).isLeft)
   fails.map(_.entryName).foreach(println)
  }
}

sealed abstract class ConfigType[A: ConfigType.DerConRead: TypeTag] extends EnumEntry with EnumEntry.Lowercase {
  val tt: TypeTag[IConf] = implicitly
  val der: Derivation[ConfigReader[IConf]] = implicitly
}
object ConfigType extends Enum[ConfigType[_]] {
  type DerConRead[A] = Derivation[ConfigReader[A]]
  case object I extends ConfigType[IConf]
  case object S extends ConfigType[SConf]
  val values = findValues
  val vMap = values.map(_.entryName).zip(values).toMap
}
geoHeil
@geoHeil
I have a weird isssue for a complex configuration. Here pureconfig fails to compile for both scala 2.12 and 2.11. A reproducible example is available at pureconfig/pureconfig#644 is there any other solution than reducing the complexity of the configuration?
Leif Wickland
@leifwickland
@geoHeil I regret to inform you that I can't reproduce your problem.
/tmp/pureconfig-debugging$ ./gradlew clean compileScala

BUILD SUCCESSFUL in 17s
2 actionable tasks: 2 executed
@geoHeil Just for comparison I created a build.sbt and compiled your project too. It was also successful for both scala 2.11 and 2.12.
Joao Azevedo
@jcazevedo
@geoHeil: I was able to reproduce your issue and fix it in my machine (see https://github.com/pureconfig/pureconfig/issues/644#issuecomment-559446385). You seem to have run into similar issues in the past (pureconfig/pureconfig#391, for example), and the fix is the same. When in doubt, try increasing the thread stack size for the JVM running the compiler.
geoHeil
@geoHeil
Thank you so much for this help! @jcazevedo how did you figure this out?
Joao Azevedo
@jcazevedo
It's a recurring issue for compiler-heavy libraries that do typeclass derivation, such as PureConfig.