Skip to content

Commit

Permalink
Allow for arbitrary metadata to be encoded into a bundle (#334)
Browse files Browse the repository at this point in the history
* * Add meta field to Bundle, allowing arbitrary metadata to be encoded into bundle
* Add unit-test for ensuring bundle serialization / deserialization works as expected
* Fix issue with incorrect default setting of BasicType in Value when parsing from JSON

* Update bundle-protobuf submodule

* Rewrite meta unit tests to work with Scala 2.10
  • Loading branch information
clocklear authored and hollinwilkins committed Feb 20, 2018
1 parent 7e8f02e commit 48fb3dd
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 13 deletions.
7 changes: 5 additions & 2 deletions bundle-ml/src/main/scala/ml/combust/bundle/BundleWriter.scala
Expand Up @@ -11,9 +11,11 @@ import scala.util.Try
case class BundleWriter[Context <: HasBundleRegistry,
Transformer <: AnyRef](root: Transformer,
name: Option[String] = None,
format: SerializationFormat = SerializationFormat.Json) {
format: SerializationFormat = SerializationFormat.Json,
meta: Option[ml.bundle.Attributes] = None) {
def name(value: String): BundleWriter[Context, Transformer] = copy(name = Some(value))
def format(value: SerializationFormat): BundleWriter[Context, Transformer] = copy(format = value)
def meta(value: ml.bundle.Attributes): BundleWriter[Context, Transformer] = copy(meta = Some(value))

def save(file: BundleFile)
(implicit context: Context): Try[Bundle[Transformer]] = {
Expand All @@ -23,6 +25,7 @@ Transformer <: AnyRef](root: Transformer,

BundleSerializer(context, file).write(Bundle(name = n,
format = format,
root = root))
root = root,
meta = meta))
}
}
16 changes: 11 additions & 5 deletions bundle-ml/src/main/scala/ml/combust/bundle/dsl/Bundle.scala
Expand Up @@ -101,12 +101,14 @@ object Bundle {

def apply[Transformer <: AnyRef](name: String,
format: SerializationFormat,
root: Transformer): Bundle[Transformer] = {
root: Transformer,
meta: Option[ml.bundle.Attributes] = None): Bundle[Transformer] = {
apply(BundleInfo(uid = UUID.randomUUID(),
name = name,
format = format,
version = Bundle.version,
timestamp = LocalDateTime.now().toString), root)
timestamp = LocalDateTime.now().toString,
meta = meta), root)
}
}

Expand All @@ -116,7 +118,8 @@ object BundleInfo {
name = bundle.name,
format = SerializationFormat.fromBundle(bundle.format),
version = bundle.version,
timestamp = bundle.timestamp)
timestamp = bundle.timestamp,
meta = bundle.meta)
}
}

Expand All @@ -132,13 +135,16 @@ case class BundleInfo(uid: UUID,
name: String,
format: SerializationFormat,
version: String,
timestamp: String) {
timestamp: String,
meta: Option[ml.bundle.Attributes]) {
def asBundle: ml.bundle.Bundle = {
ml.bundle.Bundle(uid = uid.toString,
name = name,
format = format.asBundle,
version = version,
timestamp = timestamp)
timestamp = timestamp,
meta = meta
)
}
}

Expand Down
Expand Up @@ -39,7 +39,7 @@ trait JsonSupport {
case JsString("double") => BasicType.DOUBLE
case JsString("string") => BasicType.STRING
case JsString("byte_string") => BasicType.BYTE_STRING
case JsString("unknown") => BasicType.Unrecognized(100)
case JsString("unknown") => BasicType.UNDEFINED
case _ => deserializationError("invalid basic type")
}

Expand Down Expand Up @@ -290,6 +290,6 @@ trait JsonSupport {

implicit val bundleNodeFormat: RootJsonFormat[Node] = jsonFormat2(Node.apply)
implicit val bundleModelFormat: RootJsonFormat[Model] = jsonFormat2(Model.apply)
implicit val bundleBundleInfoFormat: RootJsonFormat[Bundle] = jsonFormat5(Bundle.apply)
implicit val bundleBundleInfoFormat: RootJsonFormat[Bundle] = jsonFormat6(Bundle.apply)
}
object JsonSupport extends JsonSupport
Expand Up @@ -2,12 +2,13 @@ package ml.combust.bundle.serializer

import java.net.URI

import ml.combust.bundle.{BundleFile, BundleRegistry, TestUtil}
import ml.bundle.Attributes
import ml.combust.bundle.dsl.Bundle
import ml.combust.bundle.test.TestSupport._
import ml.combust.bundle.test._
import ml.combust.bundle.test.ops._
import ml.combust.bundle.{BundleFile, BundleRegistry, TestUtil, dsl}
import org.scalatest.FunSpec
import TestSupport._
import ml.combust.bundle.dsl.Bundle
import resource._

import scala.util.Random
Expand Down Expand Up @@ -122,6 +123,29 @@ class BundleSerializationSpec extends FunSpec {
}
}
}

describe("with metadata") {
it("serializes and deserializes any metadata we want to send along with the bundle") {
val uri = new URI(s"$prefix:${TestUtil.baseDir}/lr_bundle_meta.$format$suffix")
val meta = new Attributes().withList(Map(
"keyA" dsl.Value.string("valA").value,
"keyB" dsl.Value.double(1.2).value,
"keyC" dsl.Value.stringList(Seq("listValA", "listValB")).value
))
for(file <- managed(BundleFile(uri))) {
lr.writeBundle.name("my_bundle").
format(format).
meta(meta).
save(file)

val bundleRead = file.loadBundle().get

// These are written this way explicitly for compatibility with Scala 2.10
assert(!bundleRead.info.meta.isEmpty)
assert(bundleRead.info.meta.get.equals(meta))
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion bundle-protobuf
Submodule bundle-protobuf updated 1 files
+1 −0 bundle.proto

0 comments on commit 48fb3dd

Please sign in to comment.