From e78a21b521db0a2c836aad576f446f5c2f0ccaf0 Mon Sep 17 00:00:00 2001 From: Ches Martin Date: Fri, 1 May 2020 18:28:27 +0700 Subject: [PATCH 1/6] Set version to 0.3.8-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e352aff2ad7..b84f87f191f 100644 --- a/pom.xml +++ b/pom.xml @@ -36,7 +36,7 @@ - 0.3.7 + 0.3.8-SNAPSHOT https://github.com/gojek/feast UTF-8 From f7314b7a43927061ff870f04d6075c945ce9e7f9 Mon Sep 17 00:00:00 2001 From: Willem Pienaar <6728866+woop@users.noreply.github.com> Date: Fri, 1 May 2020 21:17:53 +0800 Subject: [PATCH 2/6] Fix typos in change log --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c9db512dd4..59f936e6481 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## [v0.3.7](https://github.com/gojek/feast/tree/v0.3.7) (2020-05-01) -[Full Changelog](https://github.com/gojek/feast/compare/v0.4.7...v0.3.7) +[Full Changelog](https://github.com/gojek/feast/compare/v0.3.6...v0.3.7) **Merged pull requests:** @@ -15,7 +15,7 @@ [Full Changelog](https://github.com/gojek/feast/compare/v0.3.5...v0.3.6) -- Add support for file paths for providing entity rows during batch retrieval [\#375](https://github.com/gojek/feast/pull/376) ([voonhous](https://github.com/voonhous)) +- Add support for file paths for providing entity rows during batch retrieval [\#375](https://github.com/gojek/feast/pull/375) ([voonhous](https://github.com/voonhous)) ## [v0.3.5](https://github.com/gojek/feast/tree/v0.3.5) (2019-12-26) From 0eb9c569fe1fbebe6e818fa9c8204abeeb31c2cc Mon Sep 17 00:00:00 2001 From: Ches Martin Date: Sat, 23 May 2020 18:02:56 +0700 Subject: [PATCH 3/6] v0.3 backport: Add Java coverage reporting (#734) * Add Java code coverage reporting with JaCoCo * Define revision property when packaging jars in Dockerfile (#410) Co-authored-by: David Heryanto --- .dockerignore | 1 + Makefile | 5 +- core/pom.xml | 6 ++- docs/coverage/java/pom.xml | 87 +++++++++++++++++++++++++++++++++ infra/docker/core/Dockerfile | 2 +- infra/docker/serving/Dockerfile | 2 +- ingestion/pom.xml | 5 ++ pom.xml | 17 ++++++- sdk/java/pom.xml | 8 +-- serving/pom.xml | 7 ++- 10 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 docs/coverage/java/pom.xml diff --git a/.dockerignore b/.dockerignore index e9401f0cc9e..0e3b22687d0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ docs +!docs/coverage charts diff --git a/Makefile b/Makefile index 9f0742b2e6c..2994af900ab 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,9 @@ build-cli: $(MAKE) build-proto $(MAKE) -C cli build-all +test-java-with-coverage: + mvn test jacoco:report-aggregate + build-java: mvn clean verify @@ -48,4 +51,4 @@ clean-html: build-html: mkdir -p $(PROJECT_ROOT)/dist/python - cp -r $(PROJECT_ROOT)/sdk/python/docs/html/* $(PROJECT_ROOT)/dist/python \ No newline at end of file + cp -r $(PROJECT_ROOT)/sdk/python/docs/html/* $(PROJECT_ROOT)/dist/python diff --git a/core/pom.xml b/core/pom.xml index b56f74dea2e..6a1a20622f0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -32,6 +32,11 @@ + + org.jacoco + jacoco-maven-plugin + + org.springframework.boot spring-boot-maven-plugin @@ -183,7 +188,6 @@ org.mockito mockito-core - 2.23.0 test diff --git a/docs/coverage/java/pom.xml b/docs/coverage/java/pom.xml new file mode 100644 index 00000000000..3cc17d88425 --- /dev/null +++ b/docs/coverage/java/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + + + + dev.feast + feast-parent + ${revision} + ../../.. + + + Feast Coverage Java + feast-coverage + + + true + + + + + dev.feast + feast-ingestion + ${project.version} + + + + dev.feast + feast-core + ${project.version} + + + + dev.feast + feast-serving + ${project.version} + + + + dev.feast + feast-sdk + ${project.version} + + + + + + + org.jacoco + jacoco-maven-plugin + + + report-aggregate + prepare-package + + report-aggregate + + + + + + + + diff --git a/infra/docker/core/Dockerfile b/infra/docker/core/Dockerfile index 91ef030dc90..c4cfe34b71b 100644 --- a/infra/docker/core/Dockerfile +++ b/infra/docker/core/Dockerfile @@ -12,7 +12,7 @@ WORKDIR /build # the existing .m2 directory to $FEAST_REPO_ROOT/.m2 # ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" -RUN mvn --also-make --projects core,ingestion \ +RUN mvn --also-make --projects core,ingestion -Drevision=$REVISION \ -DskipTests=true --batch-mode package # # Unpack the jar and copy the files into production Docker image diff --git a/infra/docker/serving/Dockerfile b/infra/docker/serving/Dockerfile index 5605c8846de..3517183d782 100644 --- a/infra/docker/serving/Dockerfile +++ b/infra/docker/serving/Dockerfile @@ -12,7 +12,7 @@ WORKDIR /build # the existing .m2 directory to $FEAST_REPO_ROOT/.m2 # ENV MAVEN_OPTS="-Dmaven.repo.local=/build/.m2/repository -DdependencyLocationsEnabled=false" -RUN mvn --also-make --projects serving \ +RUN mvn --also-make --projects serving -Drevision=$REVISION \ -DskipTests=true --batch-mode package # ============================================================ diff --git a/ingestion/pom.xml b/ingestion/pom.xml index b6f1ea371a4..3f1309037bc 100644 --- a/ingestion/pom.xml +++ b/ingestion/pom.xml @@ -82,6 +82,11 @@ + + + org.jacoco + jacoco-maven-plugin + diff --git a/pom.xml b/pom.xml index b84f87f191f..b5eaee0d281 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ core serving sdk/java + docs/coverage/java @@ -432,9 +433,9 @@ org.apache.maven.plugins maven-surefire-plugin - 2.22.1 + 3.0.0-M4 - -Xms2048m -Xmx2048m -Djdk.net.URLClassPath.disableClassPathURLCheck=true + @{argLine} -Xms2048m -Xmx2048m -Djdk.net.URLClassPath.disableClassPathURLCheck=true IntegrationTest @@ -556,6 +557,18 @@ false + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + + prepare-agent + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/sdk/java/pom.xml b/sdk/java/pom.xml index e8a82a485fc..75d82edcc01 100644 --- a/sdk/java/pom.xml +++ b/sdk/java/pom.xml @@ -94,12 +94,8 @@ - maven-surefire-plugin - 2.22.2 - - - maven-failsafe-plugin - 2.22.2 + org.jacoco + jacoco-maven-plugin diff --git a/serving/pom.xml b/serving/pom.xml index 1e8d1b83a68..a17748519d9 100644 --- a/serving/pom.xml +++ b/serving/pom.xml @@ -40,6 +40,11 @@ + + org.jacoco + jacoco-maven-plugin + + org.springframework.boot spring-boot-maven-plugin @@ -249,11 +254,9 @@ test - org.mockito mockito-core - 2.23.0 test From ffe7ec805673a0694d93cde643961a74d3cf70ae Mon Sep 17 00:00:00 2001 From: Ches Martin Date: Sat, 23 May 2020 18:45:56 +0700 Subject: [PATCH 4/6] v0.3 backport: Add feature and feature set labels (#737) * Add feature and feature set labels Backports #536 to v0.3 * Fix feature labels test for round trip It appears that this test was only exercising the test setup code, not covering that labels work when applied. This change should be forward-ported to master. Co-authored-by: Suwinski, Krzysztof (Agoda) --- .../java/feast/core/model/FeatureSet.java | 30 +- .../src/main/java/feast/core/model/Field.java | 23 +- .../java/feast/core/util/TypeConversion.java | 3 - .../core/validators/FeatureSetValidator.java | 6 + .../feast/core/service/SpecServiceTest.java | 141 ++++-- .../feast/core/service/TestObjectFactory.java | 52 +++ .../feast/core/util/TypeConversionTest.java | 9 +- .../validators/FeatureSetValidatorTest.java | 81 ++++ protos/feast/core/FeatureSet.proto | 14 +- sdk/python/feast/core/CoreService_pb2.py | 16 +- sdk/python/feast/core/CoreService_pb2.pyi | 289 ++++++------ sdk/python/feast/core/CoreService_pb2_grpc.py | 367 +++++++++------ sdk/python/feast/core/FeatureSet_pb2.py | 178 +++++++- sdk/python/feast/core/FeatureSet_pb2.pyi | 140 ++++-- sdk/python/feast/core/Source_pb2.py | 10 +- sdk/python/feast/core/Source_pb2.pyi | 71 +-- sdk/python/feast/core/Store_pb2.py | 278 ++++++++++-- sdk/python/feast/core/Store_pb2.pyi | 254 ++++++++--- sdk/python/feast/loaders/ingest.py | 26 +- .../feast/serving/ServingService_pb2.py | 24 +- .../feast/serving/ServingService_pb2.pyi | 423 ++++++++++-------- .../feast/serving/ServingService_pb2_grpc.py | 249 +++++++---- sdk/python/feast/storage/Redis_pb2.py | 8 +- sdk/python/feast/storage/Redis_pb2.pyi | 24 +- .../feast/types/FeatureRowExtended_pb2.py | 14 +- .../feast/types/FeatureRowExtended_pb2.pyi | 70 +-- sdk/python/feast/types/FeatureRow_pb2.py | 8 +- sdk/python/feast/types/FeatureRow_pb2.pyi | 27 +- sdk/python/feast/types/Field_pb2.py | 8 +- sdk/python/feast/types/Field_pb2.pyi | 27 +- sdk/python/feast/types/Value_pb2.py | 10 +- sdk/python/feast/types/Value_pb2.pyi | 284 ++++++------ sdk/python/tests/test_client.py | 9 + tests/e2e/basic-ingest-redis-serving.py | 95 +++- 34 files changed, 2276 insertions(+), 992 deletions(-) create mode 100644 core/src/test/java/feast/core/service/TestObjectFactory.java create mode 100644 core/src/test/java/feast/core/validators/FeatureSetValidatorTest.java diff --git a/core/src/main/java/feast/core/model/FeatureSet.java b/core/src/main/java/feast/core/model/FeatureSet.java index 755ef687e32..6a6a7d91367 100644 --- a/core/src/main/java/feast/core/model/FeatureSet.java +++ b/core/src/main/java/feast/core/model/FeatureSet.java @@ -21,6 +21,7 @@ import feast.core.FeatureSetProto.EntitySpec; import feast.core.FeatureSetProto.FeatureSetSpec; import feast.core.FeatureSetProto.FeatureSpec; +import feast.core.util.TypeConversion; import feast.types.ValueProto.ValueType; import java.util.ArrayList; import java.util.HashMap; @@ -79,6 +80,10 @@ public class FeatureSet extends AbstractTimestampEntity implements Comparable entities, List features, - Source source) { + Source source, + Map labels) { this.id = String.format("%s:%s", name, version); this.name = name; this.version = version; @@ -97,6 +103,7 @@ public FeatureSet( this.entities = entities; this.features = features; this.source = source; + this.labels = TypeConversion.convertMapToJsonString(labels); } public static FeatureSet fromProto(FeatureSetSpec featureSetSpec) { @@ -104,7 +111,8 @@ public static FeatureSet fromProto(FeatureSetSpec featureSetSpec) { String id = String.format("%s:%d", featureSetSpec.getName(), featureSetSpec.getVersion()); List features = new ArrayList<>(); for (FeatureSpec feature : featureSetSpec.getFeaturesList()) { - features.add(new Field(id, feature.getName(), feature.getValueType())); + features.add( + new Field(id, feature.getName(), feature.getValueType(), feature.getLabelsMap())); } List entities = new ArrayList<>(); for (EntitySpec entity : featureSetSpec.getEntitiesList()) { @@ -117,7 +125,8 @@ public static FeatureSet fromProto(FeatureSetSpec featureSetSpec) { featureSetSpec.getMaxAge().getSeconds(), entities, features, - source); + source, + featureSetSpec.getLabelsMap()); } public FeatureSetSpec toProto() throws InvalidProtocolBufferException { @@ -136,6 +145,7 @@ public FeatureSetSpec toProto() throws InvalidProtocolBufferException { FeatureSpec.newBuilder() .setName(feature.getName()) .setValueType(ValueType.Enum.valueOf(feature.getType())) + .putAllLabels(feature.getLabels()) .build()); } return FeatureSetSpec.newBuilder() @@ -145,6 +155,7 @@ public FeatureSetSpec toProto() throws InvalidProtocolBufferException { .addAllEntities(entitySpecs) .addAllFeatures(featureSpecs) .setSource(source.toProto()) + .putAllLabels(TypeConversion.convertJsonStringToMap(labels)) .build(); } @@ -209,4 +220,17 @@ public boolean equalTo(FeatureSet other) { public int compareTo(FeatureSet o) { return Integer.compare(version, o.version); } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof FeatureSet)) { + return false; + } + FeatureSet other = (FeatureSet) obj; + + return this.equalTo(other) && labels.equals(other.labels); + } } diff --git a/core/src/main/java/feast/core/model/Field.java b/core/src/main/java/feast/core/model/Field.java index 3eaeb93e27a..5c031513d38 100644 --- a/core/src/main/java/feast/core/model/Field.java +++ b/core/src/main/java/feast/core/model/Field.java @@ -16,7 +16,9 @@ */ package feast.core.model; +import feast.core.util.TypeConversion; import feast.types.ValueProto.ValueType; +import java.util.Map; import java.util.Objects; import javax.persistence.Column; import javax.persistence.Entity; @@ -52,11 +54,15 @@ public class Field { @Column(name = "type", nullable = false) private String type; + // Labels that this field belongs to + @Column(name = "labels", columnDefinition = "text") + private String labels; + public Field() { super(); } - public Field(String featureSetId, String name, ValueType.Enum type) { + public Field(String featureSetId, String name, ValueType.Enum type, Map labels) { // TODO: Remove all mention of feature sets inside of this class! FeatureSet featureSet = new FeatureSet(); featureSet.setId(featureSetId); @@ -64,6 +70,15 @@ public Field(String featureSetId, String name, ValueType.Enum type) { this.id = String.format("%s:%s", featureSetId, name); this.name = name; this.type = type.toString(); + this.labels = TypeConversion.convertMapToJsonString(labels); + } + + public Field(String featureSetId, String name, ValueType.Enum type) { + this(featureSetId, name, type, null); + } + + public Map getLabels() { + return TypeConversion.convertJsonStringToMap(this.labels); } @Override @@ -75,11 +90,13 @@ public boolean equals(Object o) { return false; } Field field = (Field) o; - return name.equals(field.getName()) && type.equals(field.getType()); + return name.equals(field.getName()) + && type.equals(field.getType()) + && labels.equals(field.labels); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), id, featureSet, name, type); + return Objects.hash(super.hashCode(), id, featureSet, name, type, labels); } } diff --git a/core/src/main/java/feast/core/util/TypeConversion.java b/core/src/main/java/feast/core/util/TypeConversion.java index 5fe69819476..226c8a114a3 100644 --- a/core/src/main/java/feast/core/util/TypeConversion.java +++ b/core/src/main/java/feast/core/util/TypeConversion.java @@ -69,9 +69,6 @@ public static Map convertJsonStringToMap(String jsonString) { * @return json string corresponding to given map */ public static String convertMapToJsonString(Map map) { - if (map.isEmpty()) { - return "{}"; - } return gson.toJson(map); } diff --git a/core/src/main/java/feast/core/validators/FeatureSetValidator.java b/core/src/main/java/feast/core/validators/FeatureSetValidator.java index e14fde72cb7..a6fa4f47c5a 100644 --- a/core/src/main/java/feast/core/validators/FeatureSetValidator.java +++ b/core/src/main/java/feast/core/validators/FeatureSetValidator.java @@ -28,6 +28,9 @@ public class FeatureSetValidator { public static void validateSpec(FeatureSetSpec featureSetSpec) { + if (featureSetSpec.getLabelsMap().containsKey("")) { + throw new IllegalArgumentException("Feature set label keys must not be empty"); + } checkValidCharacters(featureSetSpec.getName(), "name"); checkUniqueColumns(featureSetSpec.getEntitiesList(), featureSetSpec.getFeaturesList()); for (EntitySpec entitySpec : featureSetSpec.getEntitiesList()) { @@ -35,6 +38,9 @@ public static void validateSpec(FeatureSetSpec featureSetSpec) { } for (FeatureSpec featureSpec : featureSetSpec.getFeaturesList()) { checkValidCharacters(featureSpec.getName(), "features::name"); + if (featureSpec.getLabelsMap().containsKey("")) { + throw new IllegalArgumentException("Feature label keys must not be empty"); + } } } diff --git a/core/src/test/java/feast/core/service/SpecServiceTest.java b/core/src/test/java/feast/core/service/SpecServiceTest.java index 6d112676350..6dbe940e0c5 100644 --- a/core/src/test/java/feast/core/service/SpecServiceTest.java +++ b/core/src/test/java/feast/core/service/SpecServiceTest.java @@ -36,10 +36,9 @@ import feast.core.CoreServiceProto.UpdateStoreRequest; import feast.core.CoreServiceProto.UpdateStoreResponse; import feast.core.FeatureSetProto; +import feast.core.FeatureSetProto.EntitySpec; import feast.core.FeatureSetProto.FeatureSetSpec; import feast.core.FeatureSetProto.FeatureSpec; -import feast.core.SourceProto.KafkaSourceConfig; -import feast.core.SourceProto.SourceType; import feast.core.StoreProto; import feast.core.StoreProto.Store.RedisConfig; import feast.core.StoreProto.Store.StoreType; @@ -53,10 +52,7 @@ import feast.core.model.Store; import feast.types.ValueProto.ValueType.Enum; import io.grpc.StatusRuntimeException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; +import java.util.*; import java.util.stream.Collectors; import org.junit.Before; import org.junit.Rule; @@ -82,26 +78,18 @@ public class SpecServiceTest { @Before public void setUp() { initMocks(this); - defaultSource = - new Source( - SourceType.KAFKA, - KafkaSourceConfig.newBuilder() - .setBootstrapServers("kafka:9092") - .setTopic("my-topic") - .build(), - true); + defaultSource = TestObjectFactory.defaultSource; FeatureSet featureSet1v1 = newDummyFeatureSet("f1", 1); FeatureSet featureSet1v2 = newDummyFeatureSet("f1", 2); FeatureSet featureSet1v3 = newDummyFeatureSet("f1", 3); FeatureSet featureSet2v1 = newDummyFeatureSet("f2", 1); - Field f3f1 = new Field("f3", "f3f1", Enum.INT64); - Field f3f2 = new Field("f3", "f3f2", Enum.INT64); - Field f3e1 = new Field("f3", "f3e1", Enum.STRING); + Field f3f1 = TestObjectFactory.CreateFeatureField("f3", "f3f1", Enum.INT64); + Field f3f2 = TestObjectFactory.CreateFeatureField("f3", "f3f2", Enum.INT64); + Field f3e1 = TestObjectFactory.CreateEntityField("f3", "f3e1", Enum.STRING); FeatureSet featureSet3v1 = - new FeatureSet( - "f3", 1, 100L, Arrays.asList(f3e1), Arrays.asList(f3f2, f3f1), defaultSource); + TestObjectFactory.CreateFeatureSet("f3", 1, Arrays.asList(f3e1), Arrays.asList(f3f2, f3f1)); featureSets = Arrays.asList(featureSet1v1, featureSet1v2, featureSet1v3, featureSet2v1, featureSet3v1); @@ -349,12 +337,12 @@ public void applyFeatureSetShouldIncrementFeatureSetVersionIfAlreadyExists() public void applyFeatureSetShouldNotCreateFeatureSetIfFieldsUnordered() throws InvalidProtocolBufferException { - Field f3f1 = new Field("f3", "f3f1", Enum.INT64); - Field f3f2 = new Field("f3", "f3f2", Enum.INT64); - Field f3e1 = new Field("f3", "f3e1", Enum.STRING); + Field f3f1 = TestObjectFactory.CreateFeatureField("f3", "f3f1", Enum.INT64); + Field f3f2 = TestObjectFactory.CreateFeatureField("f3", "f3f2", Enum.INT64); + Field f3e1 = TestObjectFactory.CreateEntityField("f3", "f3e1", Enum.STRING); FeatureSetProto.FeatureSetSpec incomingFeatureSet = - (new FeatureSet( - "f3", 5, 100L, Arrays.asList(f3e1), Arrays.asList(f3f2, f3f1), defaultSource)) + (TestObjectFactory.CreateFeatureSet( + "f3", 5, Arrays.asList(f3e1), Arrays.asList(f3f2, f3f1))) .toProto(); FeatureSetSpec expected = incomingFeatureSet; @@ -367,6 +355,100 @@ public void applyFeatureSetShouldNotCreateFeatureSetIfFieldsUnordered() assertThat(applyFeatureSetResponse.getFeatureSet().getName(), equalTo(expected.getName())); } + @Test + public void applyFeatureSetShouldAcceptFeatureLabels() throws InvalidProtocolBufferException { + List entitySpecs = new ArrayList<>(); + entitySpecs.add( + FeatureSetProto.EntitySpec.newBuilder() + .setName("entity1") + .setValueType(Enum.INT64) + .build()); + + Map featureLabels0 = + new HashMap() { + { + put("label1", "feast1"); + } + }; + + Map featureLabels1 = + new HashMap() { + { + put("label1", "feast1"); + put("label2", "feast2"); + } + }; + + List> featureLabels = new ArrayList<>(); + featureLabels.add(featureLabels0); + featureLabels.add(featureLabels1); + + List featureSpecs = new ArrayList<>(); + featureSpecs.add( + FeatureSpec.newBuilder() + .setName("feature1") + .setValueType(Enum.INT64) + .putAllLabels(featureLabels.get(0)) + .build()); + featureSpecs.add( + FeatureSpec.newBuilder() + .setName("feature2") + .setValueType(Enum.INT64) + .putAllLabels(featureLabels.get(1)) + .build()); + + FeatureSetSpec featureSetSpec = + FeatureSetSpec.newBuilder() + .setName("featureSetWithConstraints") + .addAllEntities(entitySpecs) + .addAllFeatures(featureSpecs) + .build(); + + ApplyFeatureSetResponse applyFeatureSetResponse = specService.applyFeatureSet(featureSetSpec); + FeatureSetSpec appliedFeatureSetSpec = applyFeatureSetResponse.getFeatureSet(); + + // appliedEntitySpecs needs to be sorted because the list returned by specService may not + // follow the order in the request + List appliedEntitySpecs = + new ArrayList<>(appliedFeatureSetSpec.getEntitiesList()); + appliedEntitySpecs.sort(Comparator.comparing(EntitySpec::getName)); + + // appliedFeatureSpecs needs to be sorted because the list returned by specService may not + // follow the order in the request + List appliedFeatureSpecs = + new ArrayList<>(appliedFeatureSetSpec.getFeaturesList()); + appliedFeatureSpecs.sort(Comparator.comparing(FeatureSpec::getName)); + + List> featureSpecsLabels = + appliedFeatureSpecs.stream().map(e -> e.getLabelsMap()).collect(Collectors.toList()); + assertThat(appliedEntitySpecs, equalTo(entitySpecs)); + assertThat(appliedFeatureSpecs, equalTo(featureSpecs)); + assertThat(featureSpecsLabels, equalTo(featureLabels)); + } + + @Test + public void applyFeatureSetShouldAcceptFeatureSetLabels() throws InvalidProtocolBufferException { + Map featureSetLabels = + new HashMap() { + { + put("description", "My precious feature set"); + } + }; + + FeatureSetSpec featureSetSpec = + FeatureSetSpec.newBuilder() + .setName("preciousFeatureSet") + .putAllLabels(featureSetLabels) + .build(); + + ApplyFeatureSetResponse applyFeatureSetResponse = specService.applyFeatureSet(featureSetSpec); + FeatureSetSpec appliedFeatureSetSpec = applyFeatureSetResponse.getFeatureSet(); + + Map appliedLabels = appliedFeatureSetSpec.getLabelsMap(); + + assertThat(appliedLabels, equalTo(featureSetLabels)); + } + @Test public void shouldUpdateStoreIfConfigChanges() throws InvalidProtocolBufferException { when(storeRepository.findById("SERVING")).thenReturn(Optional.of(stores.get(0))); @@ -406,10 +488,13 @@ public void shouldDoNothingIfNoChange() throws InvalidProtocolBufferException { } private FeatureSet newDummyFeatureSet(String name, int version) { - Field feature = new Field(name, "feature", Enum.INT64); - Field entity = new Field(name, "entity", Enum.STRING); - return new FeatureSet( - name, version, 100L, Arrays.asList(entity), Arrays.asList(feature), defaultSource); + Field feature = TestObjectFactory.CreateFeatureField(name, "feature", Enum.INT64); + Field entity = TestObjectFactory.CreateEntityField(name, "entity", Enum.STRING); + + FeatureSet fs = + TestObjectFactory.CreateFeatureSet( + name, version, Arrays.asList(entity), Arrays.asList(feature)); + return fs; } private Store newDummyStore(String name) { diff --git a/core/src/test/java/feast/core/service/TestObjectFactory.java b/core/src/test/java/feast/core/service/TestObjectFactory.java new file mode 100644 index 00000000000..a157c611d7c --- /dev/null +++ b/core/src/test/java/feast/core/service/TestObjectFactory.java @@ -0,0 +1,52 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2018-2020 The Feast Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feast.core.service; + +import feast.core.SourceProto; +import feast.core.model.FeatureSet; +import feast.core.model.Field; +import feast.core.model.Source; +import feast.types.ValueProto; +import java.util.HashMap; +import java.util.List; + +public class TestObjectFactory { + + public static Source defaultSource = + new Source( + SourceProto.SourceType.KAFKA, + SourceProto.KafkaSourceConfig.newBuilder() + .setBootstrapServers("kafka:9092") + .setTopic("my-topic") + .build(), + true); + + public static FeatureSet CreateFeatureSet( + String name, int version, List entities, List features) { + return new FeatureSet(name, version, 100L, entities, features, defaultSource, new HashMap<>()); + } + + public static Field CreateFeatureField( + String featureSetId, String name, ValueProto.ValueType.Enum valueType) { + return new Field(featureSetId, name, valueType, new HashMap()); + } + + public static Field CreateEntityField( + String featureSetId, String name, ValueProto.ValueType.Enum valueType) { + return new Field(featureSetId, name, valueType); + } +} diff --git a/core/src/test/java/feast/core/util/TypeConversionTest.java b/core/src/test/java/feast/core/util/TypeConversionTest.java index 75548f34653..02f0a7cee45 100644 --- a/core/src/test/java/feast/core/util/TypeConversionTest.java +++ b/core/src/test/java/feast/core/util/TypeConversionTest.java @@ -18,8 +18,7 @@ import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import com.google.protobuf.Timestamp; import java.util.*; @@ -70,6 +69,12 @@ public void convertMapToJsonStringShouldReturnJsonStringForGivenMap() { TypeConversion.convertMapToJsonString(input), hasJsonPath("$.key", equalTo("value"))); } + @Test + public void convertMapToJsonStringShouldReturnEmptyJsonForAnEmptyMap() { + Map input = new HashMap<>(); + assertThat(TypeConversion.convertMapToJsonString(input), equalTo("{}")); + } + @Test public void convertJsonStringToArgsShouldReturnCorrectListOfArgs() { Map input = new HashMap<>(); diff --git a/core/src/test/java/feast/core/validators/FeatureSetValidatorTest.java b/core/src/test/java/feast/core/validators/FeatureSetValidatorTest.java new file mode 100644 index 00000000000..e61c5aecdff --- /dev/null +++ b/core/src/test/java/feast/core/validators/FeatureSetValidatorTest.java @@ -0,0 +1,81 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright 2018-2020 The Feast Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package feast.core.validators; + +import feast.core.FeatureSetProto; +import feast.types.ValueProto; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class FeatureSetValidatorTest { + + @Rule public final ExpectedException expectedException = ExpectedException.none(); + + @Test + public void shouldThrowExceptionForFeatureLabelsWithAnEmptyKey() { + Map featureLabels = + new HashMap() { + { + put("", "empty_key"); + } + }; + + List featureSpecs = new ArrayList<>(); + featureSpecs.add( + FeatureSetProto.FeatureSpec.newBuilder() + .setName("feature1") + .setValueType(ValueProto.ValueType.Enum.INT64) + .putAllLabels(featureLabels) + .build()); + + FeatureSetProto.FeatureSetSpec featureSetSpec = + FeatureSetProto.FeatureSetSpec.newBuilder() + .setName("featureSetWithConstraints") + .addAllFeatures(featureSpecs) + .build(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Feature label keys must not be empty"); + FeatureSetValidator.validateSpec(featureSetSpec); + } + + @Test + public void shouldThrowExceptionForFeatureSetLabelsWithAnEmptyKey() { + + Map featureSetLabels = + new HashMap() { + { + put("", "empty_key"); + } + }; + + FeatureSetProto.FeatureSetSpec featureSetSpec = + FeatureSetProto.FeatureSetSpec.newBuilder() + .setName("featureSetWithConstraints") + .putAllLabels(featureSetLabels) + .build(); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Feature set label keys must not be empty"); + FeatureSetValidator.validateSpec(featureSetSpec); + } +} diff --git a/protos/feast/core/FeatureSet.proto b/protos/feast/core/FeatureSet.proto index a80ae36f088..9300020a3d0 100644 --- a/protos/feast/core/FeatureSet.proto +++ b/protos/feast/core/FeatureSet.proto @@ -42,14 +42,17 @@ message FeatureSetSpec { // List of features contained within this featureSet. repeated FeatureSpec features = 4; - // Features in this feature set will only be retrieved if they are found - // after [time - max_age]. Missing or older feature values will be returned + // Features in this feature set will only be retrieved if they are found + // after [time - max_age]. Missing or older feature values will be returned // as nulls and indicated to end user google.protobuf.Duration max_age = 5; // Optional. Source on which feature rows can be found. // If not set, source will be set to the default value configured in Feast Core. Source source = 6; + + // User defined metadata + map labels = 8; } message EntitySpec { @@ -66,4 +69,11 @@ message FeatureSpec { // Value type of the feature. feast.types.ValueType.Enum value_type = 2; + + // Reserve field numbers 15 and below for fields that will almost always be set + // https://developers.google.com/protocol-buffers/docs/proto3#assigning-field-numbers + reserved 3 to 15; + + // Labels for user defined metadata on a feature + map labels = 16; } diff --git a/sdk/python/feast/core/CoreService_pb2.py b/sdk/python/feast/core/CoreService_pb2.py index 69a5498d879..c7c288414cd 100644 --- a/sdk/python/feast/core/CoreService_pb2.py +++ b/sdk/python/feast/core/CoreService_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/core/CoreService.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -21,8 +19,8 @@ name='feast/core/CoreService.proto', package='feast.core', syntax='proto3', - serialized_options=_b('\n\nfeast.coreB\020CoreServiceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core'), - serialized_pb=_b('\n\x1c\x66\x65\x61st/core/CoreService.proto\x12\nfeast.core\x1a\x1b\x66\x65\x61st/core/FeatureSet.proto\x1a\x16\x66\x65\x61st/core/Store.proto\"5\n\x14GetFeatureSetRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\"H\n\x15GetFeatureSetResponse\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\"\x94\x01\n\x16ListFeatureSetsRequest\x12\x39\n\x06\x66ilter\x18\x01 \x01(\x0b\x32).feast.core.ListFeatureSetsRequest.Filter\x1a?\n\x06\x46ilter\x12\x18\n\x10\x66\x65\x61ture_set_name\x18\x01 \x01(\t\x12\x1b\n\x13\x66\x65\x61ture_set_version\x18\x02 \x01(\t\"K\n\x17ListFeatureSetsResponse\x12\x30\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32\x1a.feast.core.FeatureSetSpec\"a\n\x11ListStoresRequest\x12\x34\n\x06\x66ilter\x18\x01 \x01(\x0b\x32$.feast.core.ListStoresRequest.Filter\x1a\x16\n\x06\x46ilter\x12\x0c\n\x04name\x18\x01 \x01(\t\"6\n\x12ListStoresResponse\x12 \n\x05store\x18\x01 \x03(\x0b\x32\x11.feast.core.Store\"I\n\x16\x41pplyFeatureSetRequest\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\"\xb7\x01\n\x17\x41pplyFeatureSetResponse\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\x12:\n\x06status\x18\x02 \x01(\x0e\x32*.feast.core.ApplyFeatureSetResponse.Status\"/\n\x06Status\x12\r\n\tNO_CHANGE\x10\x00\x12\x0b\n\x07\x43REATED\x10\x01\x12\t\n\x05\x45RROR\x10\x02\"\x1c\n\x1aGetFeastCoreVersionRequest\".\n\x1bGetFeastCoreVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"6\n\x12UpdateStoreRequest\x12 \n\x05store\x18\x01 \x01(\x0b\x32\x11.feast.core.Store\"\x95\x01\n\x13UpdateStoreResponse\x12 \n\x05store\x18\x01 \x01(\x0b\x32\x11.feast.core.Store\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.feast.core.UpdateStoreResponse.Status\"$\n\x06Status\x12\r\n\tNO_CHANGE\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x32\xa0\x04\n\x0b\x43oreService\x12\x66\n\x13GetFeastCoreVersion\x12&.feast.core.GetFeastCoreVersionRequest\x1a\'.feast.core.GetFeastCoreVersionResponse\x12T\n\rGetFeatureSet\x12 .feast.core.GetFeatureSetRequest\x1a!.feast.core.GetFeatureSetResponse\x12Z\n\x0fListFeatureSets\x12\".feast.core.ListFeatureSetsRequest\x1a#.feast.core.ListFeatureSetsResponse\x12K\n\nListStores\x12\x1d.feast.core.ListStoresRequest\x1a\x1e.feast.core.ListStoresResponse\x12Z\n\x0f\x41pplyFeatureSet\x12\".feast.core.ApplyFeatureSetRequest\x1a#.feast.core.ApplyFeatureSetResponse\x12N\n\x0bUpdateStore\x12\x1e.feast.core.UpdateStoreRequest\x1a\x1f.feast.core.UpdateStoreResponseBO\n\nfeast.coreB\x10\x43oreServiceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3') + serialized_options=b'\n\nfeast.coreB\020CoreServiceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core', + serialized_pb=b'\n\x1c\x66\x65\x61st/core/CoreService.proto\x12\nfeast.core\x1a\x1b\x66\x65\x61st/core/FeatureSet.proto\x1a\x16\x66\x65\x61st/core/Store.proto\"5\n\x14GetFeatureSetRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\"H\n\x15GetFeatureSetResponse\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\"\x94\x01\n\x16ListFeatureSetsRequest\x12\x39\n\x06\x66ilter\x18\x01 \x01(\x0b\x32).feast.core.ListFeatureSetsRequest.Filter\x1a?\n\x06\x46ilter\x12\x18\n\x10\x66\x65\x61ture_set_name\x18\x01 \x01(\t\x12\x1b\n\x13\x66\x65\x61ture_set_version\x18\x02 \x01(\t\"K\n\x17ListFeatureSetsResponse\x12\x30\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32\x1a.feast.core.FeatureSetSpec\"a\n\x11ListStoresRequest\x12\x34\n\x06\x66ilter\x18\x01 \x01(\x0b\x32$.feast.core.ListStoresRequest.Filter\x1a\x16\n\x06\x46ilter\x12\x0c\n\x04name\x18\x01 \x01(\t\"6\n\x12ListStoresResponse\x12 \n\x05store\x18\x01 \x03(\x0b\x32\x11.feast.core.Store\"I\n\x16\x41pplyFeatureSetRequest\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\"\xb7\x01\n\x17\x41pplyFeatureSetResponse\x12/\n\x0b\x66\x65\x61ture_set\x18\x01 \x01(\x0b\x32\x1a.feast.core.FeatureSetSpec\x12:\n\x06status\x18\x02 \x01(\x0e\x32*.feast.core.ApplyFeatureSetResponse.Status\"/\n\x06Status\x12\r\n\tNO_CHANGE\x10\x00\x12\x0b\n\x07\x43REATED\x10\x01\x12\t\n\x05\x45RROR\x10\x02\"\x1c\n\x1aGetFeastCoreVersionRequest\".\n\x1bGetFeastCoreVersionResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\"6\n\x12UpdateStoreRequest\x12 \n\x05store\x18\x01 \x01(\x0b\x32\x11.feast.core.Store\"\x95\x01\n\x13UpdateStoreResponse\x12 \n\x05store\x18\x01 \x01(\x0b\x32\x11.feast.core.Store\x12\x36\n\x06status\x18\x02 \x01(\x0e\x32&.feast.core.UpdateStoreResponse.Status\"$\n\x06Status\x12\r\n\tNO_CHANGE\x10\x00\x12\x0b\n\x07UPDATED\x10\x01\x32\xa0\x04\n\x0b\x43oreService\x12\x66\n\x13GetFeastCoreVersion\x12&.feast.core.GetFeastCoreVersionRequest\x1a\'.feast.core.GetFeastCoreVersionResponse\x12T\n\rGetFeatureSet\x12 .feast.core.GetFeatureSetRequest\x1a!.feast.core.GetFeatureSetResponse\x12Z\n\x0fListFeatureSets\x12\".feast.core.ListFeatureSetsRequest\x1a#.feast.core.ListFeatureSetsResponse\x12K\n\nListStores\x12\x1d.feast.core.ListStoresRequest\x1a\x1e.feast.core.ListStoresResponse\x12Z\n\x0f\x41pplyFeatureSet\x12\".feast.core.ApplyFeatureSetRequest\x1a#.feast.core.ApplyFeatureSetResponse\x12N\n\x0bUpdateStore\x12\x1e.feast.core.UpdateStoreRequest\x1a\x1f.feast.core.UpdateStoreResponseBO\n\nfeast.coreB\x10\x43oreServiceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3' , dependencies=[feast_dot_core_dot_FeatureSet__pb2.DESCRIPTOR,feast_dot_core_dot_Store__pb2.DESCRIPTOR,]) @@ -87,7 +85,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.GetFeatureSetRequest.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -156,14 +154,14 @@ _descriptor.FieldDescriptor( name='feature_set_name', full_name='feast.core.ListFeatureSetsRequest.Filter.feature_set_name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='feature_set_version', full_name='feast.core.ListFeatureSetsRequest.Filter.feature_set_version', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -255,7 +253,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.ListStoresRequest.Filter.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -441,7 +439,7 @@ _descriptor.FieldDescriptor( name='version', full_name='feast.core.GetFeastCoreVersionResponse.version', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/core/CoreService_pb2.pyi b/sdk/python/feast/core/CoreService_pb2.pyi index 0bf897000bc..325a1765ad6 100644 --- a/sdk/python/feast/core/CoreService_pb2.pyi +++ b/sdk/python/feast/core/CoreService_pb2.pyi @@ -27,6 +27,7 @@ from typing import ( Optional as typing___Optional, Text as typing___Text, Tuple as typing___Tuple, + Union as typing___Union, cast as typing___cast, ) @@ -35,24 +36,36 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +builtin___str = str +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class GetFeatureSetRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... name = ... # type: typing___Text - version = ... # type: int + version = ... # type: builtin___int def __init__(self, *, name : typing___Optional[typing___Text] = None, - version : typing___Optional[int] = None, + version : typing___Optional[builtin___int] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeatureSetRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"name",u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeatureSetRequest: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeatureSetRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"version",b"version"]) -> None: ... +global___GetFeatureSetRequest = GetFeatureSetRequest class GetFeatureSetResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -64,16 +77,17 @@ class GetFeatureSetResponse(google___protobuf___message___Message): *, feature_set : typing___Optional[feast___core___FeatureSet_pb2___FeatureSetSpec] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeatureSetResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeatureSetResponse: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeatureSetResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> None: ... +global___GetFeatureSetResponse = GetFeatureSetResponse class ListFeatureSetsRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -87,33 +101,36 @@ class ListFeatureSetsRequest(google___protobuf___message___Message): feature_set_name : typing___Optional[typing___Text] = None, feature_set_version : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListFeatureSetsRequest.Filter: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set_name",u"feature_set_version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListFeatureSetsRequest.Filter: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set_name",b"feature_set_name",u"feature_set_version",b"feature_set_version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListFeatureSetsRequest.Filter: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_set_name",b"feature_set_name",u"feature_set_version",b"feature_set_version"]) -> None: ... + global___Filter = Filter @property - def filter(self) -> ListFeatureSetsRequest.Filter: ... + def filter(self) -> global___ListFeatureSetsRequest.Filter: ... def __init__(self, *, - filter : typing___Optional[ListFeatureSetsRequest.Filter] = None, + filter : typing___Optional[global___ListFeatureSetsRequest.Filter] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListFeatureSetsRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"filter"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"filter"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListFeatureSetsRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListFeatureSetsRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> None: ... +global___ListFeatureSetsRequest = ListFeatureSetsRequest class ListFeatureSetsResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -125,14 +142,16 @@ class ListFeatureSetsResponse(google___protobuf___message___Message): *, feature_sets : typing___Optional[typing___Iterable[feast___core___FeatureSet_pb2___FeatureSetSpec]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListFeatureSetsResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"feature_sets"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListFeatureSetsResponse: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"feature_sets",b"feature_sets"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListFeatureSetsResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_sets",b"feature_sets"]) -> None: ... +global___ListFeatureSetsResponse = ListFeatureSetsResponse class ListStoresRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -144,33 +163,36 @@ class ListStoresRequest(google___protobuf___message___Message): *, name : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListStoresRequest.Filter: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"name"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListStoresRequest.Filter: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListStoresRequest.Filter: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name"]) -> None: ... + global___Filter = Filter @property - def filter(self) -> ListStoresRequest.Filter: ... + def filter(self) -> global___ListStoresRequest.Filter: ... def __init__(self, *, - filter : typing___Optional[ListStoresRequest.Filter] = None, + filter : typing___Optional[global___ListStoresRequest.Filter] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListStoresRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"filter"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"filter"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListStoresRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListStoresRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"filter",b"filter"]) -> None: ... +global___ListStoresRequest = ListStoresRequest class ListStoresResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -182,14 +204,16 @@ class ListStoresResponse(google___protobuf___message___Message): *, store : typing___Optional[typing___Iterable[feast___core___Store_pb2___Store]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ListStoresResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"store"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ListStoresResponse: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ListStoresResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> None: ... +global___ListStoresResponse = ListStoresResponse class ApplyFeatureSetRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -201,39 +225,41 @@ class ApplyFeatureSetRequest(google___protobuf___message___Message): *, feature_set : typing___Optional[feast___core___FeatureSet_pb2___FeatureSetSpec] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ApplyFeatureSetRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ApplyFeatureSetRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ApplyFeatureSetRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> None: ... +global___ApplyFeatureSetRequest = ApplyFeatureSetRequest class ApplyFeatureSetResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - class Status(int): + class Status(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> ApplyFeatureSetResponse.Status: ... + def Value(cls, name: builtin___str) -> 'ApplyFeatureSetResponse.Status': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[ApplyFeatureSetResponse.Status]: ... + def values(cls) -> typing___List['ApplyFeatureSetResponse.Status']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, ApplyFeatureSetResponse.Status]]: ... - NO_CHANGE = typing___cast(ApplyFeatureSetResponse.Status, 0) - CREATED = typing___cast(ApplyFeatureSetResponse.Status, 1) - ERROR = typing___cast(ApplyFeatureSetResponse.Status, 2) - NO_CHANGE = typing___cast(ApplyFeatureSetResponse.Status, 0) - CREATED = typing___cast(ApplyFeatureSetResponse.Status, 1) - ERROR = typing___cast(ApplyFeatureSetResponse.Status, 2) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'ApplyFeatureSetResponse.Status']]: ... + NO_CHANGE = typing___cast('ApplyFeatureSetResponse.Status', 0) + CREATED = typing___cast('ApplyFeatureSetResponse.Status', 1) + ERROR = typing___cast('ApplyFeatureSetResponse.Status', 2) + NO_CHANGE = typing___cast('ApplyFeatureSetResponse.Status', 0) + CREATED = typing___cast('ApplyFeatureSetResponse.Status', 1) + ERROR = typing___cast('ApplyFeatureSetResponse.Status', 2) + global___Status = Status - status = ... # type: ApplyFeatureSetResponse.Status + status = ... # type: global___ApplyFeatureSetResponse.Status @property def feature_set(self) -> feast___core___FeatureSet_pb2___FeatureSetSpec: ... @@ -241,28 +267,34 @@ class ApplyFeatureSetResponse(google___protobuf___message___Message): def __init__(self, *, feature_set : typing___Optional[feast___core___FeatureSet_pb2___FeatureSetSpec] = None, - status : typing___Optional[ApplyFeatureSetResponse.Status] = None, + status : typing___Optional[global___ApplyFeatureSetResponse.Status] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ApplyFeatureSetResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",u"status"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> ApplyFeatureSetResponse: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set",u"status",b"status"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ApplyFeatureSetResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_set",b"feature_set",u"status",b"status"]) -> None: ... +global___ApplyFeatureSetResponse = ApplyFeatureSetResponse class GetFeastCoreVersionRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... def __init__(self, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeastCoreVersionRequest: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeastCoreVersionRequest: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeastCoreVersionRequest: ... def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... +global___GetFeastCoreVersionRequest = GetFeastCoreVersionRequest class GetFeastCoreVersionResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -272,14 +304,16 @@ class GetFeastCoreVersionResponse(google___protobuf___message___Message): *, version : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeastCoreVersionResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeastCoreVersionResponse: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeastCoreVersionResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"version",b"version"]) -> None: ... +global___GetFeastCoreVersionResponse = GetFeastCoreVersionResponse class UpdateStoreRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -291,37 +325,39 @@ class UpdateStoreRequest(google___protobuf___message___Message): *, store : typing___Optional[feast___core___Store_pb2___Store] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> UpdateStoreRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"store"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"store"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> UpdateStoreRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> UpdateStoreRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> None: ... +global___UpdateStoreRequest = UpdateStoreRequest class UpdateStoreResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - class Status(int): + class Status(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> UpdateStoreResponse.Status: ... + def Value(cls, name: builtin___str) -> 'UpdateStoreResponse.Status': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[UpdateStoreResponse.Status]: ... + def values(cls) -> typing___List['UpdateStoreResponse.Status']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, UpdateStoreResponse.Status]]: ... - NO_CHANGE = typing___cast(UpdateStoreResponse.Status, 0) - UPDATED = typing___cast(UpdateStoreResponse.Status, 1) - NO_CHANGE = typing___cast(UpdateStoreResponse.Status, 0) - UPDATED = typing___cast(UpdateStoreResponse.Status, 1) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'UpdateStoreResponse.Status']]: ... + NO_CHANGE = typing___cast('UpdateStoreResponse.Status', 0) + UPDATED = typing___cast('UpdateStoreResponse.Status', 1) + NO_CHANGE = typing___cast('UpdateStoreResponse.Status', 0) + UPDATED = typing___cast('UpdateStoreResponse.Status', 1) + global___Status = Status - status = ... # type: UpdateStoreResponse.Status + status = ... # type: global___UpdateStoreResponse.Status @property def store(self) -> feast___core___Store_pb2___Store: ... @@ -329,15 +365,16 @@ class UpdateStoreResponse(google___protobuf___message___Message): def __init__(self, *, store : typing___Optional[feast___core___Store_pb2___Store] = None, - status : typing___Optional[UpdateStoreResponse.Status] = None, + status : typing___Optional[global___UpdateStoreResponse.Status] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> UpdateStoreResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"store"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"status",u"store"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> UpdateStoreResponse: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"status",b"status",u"store",b"store"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> UpdateStoreResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"store",b"store"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"status",b"status",u"store",b"store"]) -> None: ... +global___UpdateStoreResponse = UpdateStoreResponse diff --git a/sdk/python/feast/core/CoreService_pb2_grpc.py b/sdk/python/feast/core/CoreService_pb2_grpc.py index c4d28087791..cd924146a79 100644 --- a/sdk/python/feast/core/CoreService_pb2_grpc.py +++ b/sdk/python/feast/core/CoreService_pb2_grpc.py @@ -5,143 +5,242 @@ class CoreServiceStub(object): - # missing associated documentation comment in .proto file - pass - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.GetFeastCoreVersion = channel.unary_unary( - '/feast.core.CoreService/GetFeastCoreVersion', - request_serializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionResponse.FromString, - ) - self.GetFeatureSet = channel.unary_unary( - '/feast.core.CoreService/GetFeatureSet', - request_serializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetResponse.FromString, - ) - self.ListFeatureSets = channel.unary_unary( - '/feast.core.CoreService/ListFeatureSets', - request_serializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsResponse.FromString, - ) - self.ListStores = channel.unary_unary( - '/feast.core.CoreService/ListStores', - request_serializer=feast_dot_core_dot_CoreService__pb2.ListStoresRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.ListStoresResponse.FromString, - ) - self.ApplyFeatureSet = channel.unary_unary( - '/feast.core.CoreService/ApplyFeatureSet', - request_serializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetResponse.FromString, - ) - self.UpdateStore = channel.unary_unary( - '/feast.core.CoreService/UpdateStore', - request_serializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreRequest.SerializeToString, - response_deserializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreResponse.FromString, - ) + """Missing associated documentation comment in .proto file""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetFeastCoreVersion = channel.unary_unary( + '/feast.core.CoreService/GetFeastCoreVersion', + request_serializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionResponse.FromString, + ) + self.GetFeatureSet = channel.unary_unary( + '/feast.core.CoreService/GetFeatureSet', + request_serializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetResponse.FromString, + ) + self.ListFeatureSets = channel.unary_unary( + '/feast.core.CoreService/ListFeatureSets', + request_serializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsResponse.FromString, + ) + self.ListStores = channel.unary_unary( + '/feast.core.CoreService/ListStores', + request_serializer=feast_dot_core_dot_CoreService__pb2.ListStoresRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.ListStoresResponse.FromString, + ) + self.ApplyFeatureSet = channel.unary_unary( + '/feast.core.CoreService/ApplyFeatureSet', + request_serializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetResponse.FromString, + ) + self.UpdateStore = channel.unary_unary( + '/feast.core.CoreService/UpdateStore', + request_serializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreRequest.SerializeToString, + response_deserializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreResponse.FromString, + ) class CoreServiceServicer(object): - # missing associated documentation comment in .proto file - pass - - def GetFeastCoreVersion(self, request, context): - """Retrieve version information about this Feast deployment - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetFeatureSet(self, request, context): - """Returns a specific feature set - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def ListFeatureSets(self, request, context): - """Retrieve feature set details given a filter. - - Returns all feature sets matching that filter. If none are found, - an empty list will be returned. - If no filter is provided in the request, the response will contain all the feature - sets currently stored in the registry. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def ListStores(self, request, context): - """Retrieve store details given a filter. - - Returns all stores matching that filter. If none are found, an empty list will be returned. - If no filter is provided in the request, the response will contain all the stores currently - stored in the registry. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def ApplyFeatureSet(self, request, context): - """Create or update and existing feature set. - - This function is idempotent - it will not create a new feature set if schema does not change. - If an existing feature set is updated, core will advance the version number, which will be - returned in response. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def UpdateStore(self, request, context): - """Updates core with the configuration of the store. - - If the changes are valid, core will return the given store configuration in response, and - start or update the necessary feature population jobs for the updated store. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') + """Missing associated documentation comment in .proto file""" + + def GetFeastCoreVersion(self, request, context): + """Retrieve version information about this Feast deployment + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetFeatureSet(self, request, context): + """Returns a specific feature set + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListFeatureSets(self, request, context): + """Retrieve feature set details given a filter. + + Returns all feature sets matching that filter. If none are found, + an empty list will be returned. + If no filter is provided in the request, the response will contain all the feature + sets currently stored in the registry. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListStores(self, request, context): + """Retrieve store details given a filter. + + Returns all stores matching that filter. If none are found, an empty list will be returned. + If no filter is provided in the request, the response will contain all the stores currently + stored in the registry. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ApplyFeatureSet(self, request, context): + """Create or update and existing feature set. + + This function is idempotent - it will not create a new feature set if schema does not change. + If an existing feature set is updated, core will advance the version number, which will be + returned in response. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateStore(self, request, context): + """Updates core with the configuration of the store. + + If the changes are valid, core will return the given store configuration in response, and + start or update the necessary feature population jobs for the updated store. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') def add_CoreServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'GetFeastCoreVersion': grpc.unary_unary_rpc_method_handler( - servicer.GetFeastCoreVersion, - request_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionResponse.SerializeToString, - ), - 'GetFeatureSet': grpc.unary_unary_rpc_method_handler( - servicer.GetFeatureSet, - request_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetResponse.SerializeToString, - ), - 'ListFeatureSets': grpc.unary_unary_rpc_method_handler( - servicer.ListFeatureSets, - request_deserializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsResponse.SerializeToString, - ), - 'ListStores': grpc.unary_unary_rpc_method_handler( - servicer.ListStores, - request_deserializer=feast_dot_core_dot_CoreService__pb2.ListStoresRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.ListStoresResponse.SerializeToString, - ), - 'ApplyFeatureSet': grpc.unary_unary_rpc_method_handler( - servicer.ApplyFeatureSet, - request_deserializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetResponse.SerializeToString, - ), - 'UpdateStore': grpc.unary_unary_rpc_method_handler( - servicer.UpdateStore, - request_deserializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreRequest.FromString, - response_serializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'feast.core.CoreService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) + rpc_method_handlers = { + 'GetFeastCoreVersion': grpc.unary_unary_rpc_method_handler( + servicer.GetFeastCoreVersion, + request_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionResponse.SerializeToString, + ), + 'GetFeatureSet': grpc.unary_unary_rpc_method_handler( + servicer.GetFeatureSet, + request_deserializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.GetFeatureSetResponse.SerializeToString, + ), + 'ListFeatureSets': grpc.unary_unary_rpc_method_handler( + servicer.ListFeatureSets, + request_deserializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.ListFeatureSetsResponse.SerializeToString, + ), + 'ListStores': grpc.unary_unary_rpc_method_handler( + servicer.ListStores, + request_deserializer=feast_dot_core_dot_CoreService__pb2.ListStoresRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.ListStoresResponse.SerializeToString, + ), + 'ApplyFeatureSet': grpc.unary_unary_rpc_method_handler( + servicer.ApplyFeatureSet, + request_deserializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetResponse.SerializeToString, + ), + 'UpdateStore': grpc.unary_unary_rpc_method_handler( + servicer.UpdateStore, + request_deserializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreRequest.FromString, + response_serializer=feast_dot_core_dot_CoreService__pb2.UpdateStoreResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'feast.core.CoreService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class CoreService(object): + """Missing associated documentation comment in .proto file""" + + @staticmethod + def GetFeastCoreVersion(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/GetFeastCoreVersion', + feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.GetFeastCoreVersionResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetFeatureSet(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/GetFeatureSet', + feast_dot_core_dot_CoreService__pb2.GetFeatureSetRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.GetFeatureSetResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ListFeatureSets(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/ListFeatureSets', + feast_dot_core_dot_CoreService__pb2.ListFeatureSetsRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.ListFeatureSetsResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ListStores(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/ListStores', + feast_dot_core_dot_CoreService__pb2.ListStoresRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.ListStoresResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def ApplyFeatureSet(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/ApplyFeatureSet', + feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.ApplyFeatureSetResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def UpdateStore(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.core.CoreService/UpdateStore', + feast_dot_core_dot_CoreService__pb2.UpdateStoreRequest.SerializeToString, + feast_dot_core_dot_CoreService__pb2.UpdateStoreResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/sdk/python/feast/core/FeatureSet_pb2.py b/sdk/python/feast/core/FeatureSet_pb2.py index 8c331db16b1..474a7c10ef9 100644 --- a/sdk/python/feast/core/FeatureSet_pb2.py +++ b/sdk/python/feast/core/FeatureSet_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/core/FeatureSet.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -22,14 +20,82 @@ name='feast/core/FeatureSet.proto', package='feast.core', syntax='proto3', - serialized_options=_b('\n\nfeast.coreB\017FeatureSetProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core'), - serialized_pb=_b('\n\x1b\x66\x65\x61st/core/FeatureSet.proto\x12\nfeast.core\x1a\x17\x66\x65\x61st/types/Value.proto\x1a\x17\x66\x65\x61st/core/Source.proto\x1a\x1egoogle/protobuf/duration.proto\"\xd4\x01\n\x0e\x46\x65\x61tureSetSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12(\n\x08\x65ntities\x18\x03 \x03(\x0b\x32\x16.feast.core.EntitySpec\x12)\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0b\x32\x17.feast.core.FeatureSpec\x12*\n\x07max_age\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\"\n\x06source\x18\x06 \x01(\x0b\x32\x12.feast.core.Source\"K\n\nEntitySpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\nvalue_type\x18\x02 \x01(\x0e\x32\x1b.feast.types.ValueType.Enum\"L\n\x0b\x46\x65\x61tureSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\nvalue_type\x18\x02 \x01(\x0e\x32\x1b.feast.types.ValueType.EnumBN\n\nfeast.coreB\x0f\x46\x65\x61tureSetProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3') + serialized_options=b'\n\nfeast.coreB\017FeatureSetProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core', + serialized_pb=b'\n\x1b\x66\x65\x61st/core/FeatureSet.proto\x12\nfeast.core\x1a\x17\x66\x65\x61st/types/Value.proto\x1a\x17\x66\x65\x61st/core/Source.proto\x1a\x1egoogle/protobuf/duration.proto\"K\n\x14SetOfFeatureSetSpecs\x12\x33\n\x0f\x66\x65\x61tureSetSpecs\x18\x01 \x03(\x0b\x32\x1a.feast.core.FeatureSetSpec\"\xbb\x02\n\x0e\x46\x65\x61tureSetSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12(\n\x08\x65ntities\x18\x03 \x03(\x0b\x32\x16.feast.core.EntitySpec\x12)\n\x08\x66\x65\x61tures\x18\x04 \x03(\x0b\x32\x17.feast.core.FeatureSpec\x12*\n\x07max_age\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\"\n\x06source\x18\x06 \x01(\x0b\x32\x12.feast.core.Source\x12\x36\n\x06labels\x18\x08 \x03(\x0b\x32&.feast.core.FeatureSetSpec.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"K\n\nEntitySpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\nvalue_type\x18\x02 \x01(\x0e\x32\x1b.feast.types.ValueType.Enum\"\xb0\x01\n\x0b\x46\x65\x61tureSpec\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\nvalue_type\x18\x02 \x01(\x0e\x32\x1b.feast.types.ValueType.Enum\x12\x33\n\x06labels\x18\x10 \x03(\x0b\x32#.feast.core.FeatureSpec.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42N\n\nfeast.coreB\x0f\x46\x65\x61tureSetProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3' , dependencies=[feast_dot_types_dot_Value__pb2.DESCRIPTOR,feast_dot_core_dot_Source__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,]) +_SETOFFEATURESETSPECS = _descriptor.Descriptor( + name='SetOfFeatureSetSpecs', + full_name='feast.core.SetOfFeatureSetSpecs', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='featureSetSpecs', full_name='feast.core.SetOfFeatureSetSpecs.featureSetSpecs', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=125, + serialized_end=200, +) + + +_FEATURESETSPEC_LABELSENTRY = _descriptor.Descriptor( + name='LabelsEntry', + full_name='feast.core.FeatureSetSpec.LabelsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='feast.core.FeatureSetSpec.LabelsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='feast.core.FeatureSetSpec.LabelsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=473, + serialized_end=518, +) + _FEATURESETSPEC = _descriptor.Descriptor( name='FeatureSetSpec', full_name='feast.core.FeatureSetSpec', @@ -40,7 +106,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.FeatureSetSpec.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -79,10 +145,17 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='labels', full_name='feast.core.FeatureSetSpec.labels', index=6, + number=8, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], - nested_types=[], + nested_types=[_FEATURESETSPEC_LABELSENTRY, ], enum_types=[ ], serialized_options=None, @@ -91,8 +164,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=126, - serialized_end=338, + serialized_start=203, + serialized_end=518, ) @@ -106,7 +179,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.EntitySpec.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -129,11 +202,48 @@ extension_ranges=[], oneofs=[ ], - serialized_start=340, - serialized_end=415, + serialized_start=520, + serialized_end=595, ) +_FEATURESPEC_LABELSENTRY = _descriptor.Descriptor( + name='LabelsEntry', + full_name='feast.core.FeatureSpec.LabelsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='feast.core.FeatureSpec.LabelsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='feast.core.FeatureSpec.LabelsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=473, + serialized_end=518, +) + _FEATURESPEC = _descriptor.Descriptor( name='FeatureSpec', full_name='feast.core.FeatureSpec', @@ -144,7 +254,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.FeatureSpec.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -155,10 +265,17 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='labels', full_name='feast.core.FeatureSpec.labels', index=2, + number=16, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], - nested_types=[], + nested_types=[_FEATURESPEC_LABELSENTRY, ], enum_types=[ ], serialized_options=None, @@ -167,27 +284,48 @@ extension_ranges=[], oneofs=[ ], - serialized_start=417, - serialized_end=493, + serialized_start=598, + serialized_end=774, ) +_SETOFFEATURESETSPECS.fields_by_name['featureSetSpecs'].message_type = _FEATURESETSPEC +_FEATURESETSPEC_LABELSENTRY.containing_type = _FEATURESETSPEC _FEATURESETSPEC.fields_by_name['entities'].message_type = _ENTITYSPEC _FEATURESETSPEC.fields_by_name['features'].message_type = _FEATURESPEC _FEATURESETSPEC.fields_by_name['max_age'].message_type = google_dot_protobuf_dot_duration__pb2._DURATION _FEATURESETSPEC.fields_by_name['source'].message_type = feast_dot_core_dot_Source__pb2._SOURCE +_FEATURESETSPEC.fields_by_name['labels'].message_type = _FEATURESETSPEC_LABELSENTRY _ENTITYSPEC.fields_by_name['value_type'].enum_type = feast_dot_types_dot_Value__pb2._VALUETYPE_ENUM +_FEATURESPEC_LABELSENTRY.containing_type = _FEATURESPEC _FEATURESPEC.fields_by_name['value_type'].enum_type = feast_dot_types_dot_Value__pb2._VALUETYPE_ENUM +_FEATURESPEC.fields_by_name['labels'].message_type = _FEATURESPEC_LABELSENTRY +DESCRIPTOR.message_types_by_name['SetOfFeatureSetSpecs'] = _SETOFFEATURESETSPECS DESCRIPTOR.message_types_by_name['FeatureSetSpec'] = _FEATURESETSPEC DESCRIPTOR.message_types_by_name['EntitySpec'] = _ENTITYSPEC DESCRIPTOR.message_types_by_name['FeatureSpec'] = _FEATURESPEC _sym_db.RegisterFileDescriptor(DESCRIPTOR) +SetOfFeatureSetSpecs = _reflection.GeneratedProtocolMessageType('SetOfFeatureSetSpecs', (_message.Message,), { + 'DESCRIPTOR' : _SETOFFEATURESETSPECS, + '__module__' : 'feast.core.FeatureSet_pb2' + # @@protoc_insertion_point(class_scope:feast.core.SetOfFeatureSetSpecs) + }) +_sym_db.RegisterMessage(SetOfFeatureSetSpecs) + FeatureSetSpec = _reflection.GeneratedProtocolMessageType('FeatureSetSpec', (_message.Message,), { + + 'LabelsEntry' : _reflection.GeneratedProtocolMessageType('LabelsEntry', (_message.Message,), { + 'DESCRIPTOR' : _FEATURESETSPEC_LABELSENTRY, + '__module__' : 'feast.core.FeatureSet_pb2' + # @@protoc_insertion_point(class_scope:feast.core.FeatureSetSpec.LabelsEntry) + }) + , 'DESCRIPTOR' : _FEATURESETSPEC, '__module__' : 'feast.core.FeatureSet_pb2' # @@protoc_insertion_point(class_scope:feast.core.FeatureSetSpec) }) _sym_db.RegisterMessage(FeatureSetSpec) +_sym_db.RegisterMessage(FeatureSetSpec.LabelsEntry) EntitySpec = _reflection.GeneratedProtocolMessageType('EntitySpec', (_message.Message,), { 'DESCRIPTOR' : _ENTITYSPEC, @@ -197,12 +335,22 @@ _sym_db.RegisterMessage(EntitySpec) FeatureSpec = _reflection.GeneratedProtocolMessageType('FeatureSpec', (_message.Message,), { + + 'LabelsEntry' : _reflection.GeneratedProtocolMessageType('LabelsEntry', (_message.Message,), { + 'DESCRIPTOR' : _FEATURESPEC_LABELSENTRY, + '__module__' : 'feast.core.FeatureSet_pb2' + # @@protoc_insertion_point(class_scope:feast.core.FeatureSpec.LabelsEntry) + }) + , 'DESCRIPTOR' : _FEATURESPEC, '__module__' : 'feast.core.FeatureSet_pb2' # @@protoc_insertion_point(class_scope:feast.core.FeatureSpec) }) _sym_db.RegisterMessage(FeatureSpec) +_sym_db.RegisterMessage(FeatureSpec.LabelsEntry) DESCRIPTOR._options = None +_FEATURESETSPEC_LABELSENTRY._options = None +_FEATURESPEC_LABELSENTRY._options = None # @@protoc_insertion_point(module_scope) diff --git a/sdk/python/feast/core/FeatureSet_pb2.pyi b/sdk/python/feast/core/FeatureSet_pb2.pyi index 5d93721fe16..01506cf6c4f 100644 --- a/sdk/python/feast/core/FeatureSet_pb2.pyi +++ b/sdk/python/feast/core/FeatureSet_pb2.pyi @@ -26,8 +26,11 @@ from google.protobuf.message import ( from typing import ( Iterable as typing___Iterable, + Mapping as typing___Mapping, + MutableMapping as typing___MutableMapping, Optional as typing___Optional, Text as typing___Text, + Union as typing___Union, ) from typing_extensions import ( @@ -35,16 +38,67 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + +class SetOfFeatureSetSpecs(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + + @property + def featureSetSpecs(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___FeatureSetSpec]: ... + + def __init__(self, + *, + featureSetSpecs : typing___Optional[typing___Iterable[global___FeatureSetSpec]] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> SetOfFeatureSetSpecs: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> SetOfFeatureSetSpecs: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"featureSetSpecs",b"featureSetSpecs"]) -> None: ... +global___SetOfFeatureSetSpecs = SetOfFeatureSetSpecs + class FeatureSetSpec(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + class LabelsEntry(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + key = ... # type: typing___Text + value = ... # type: typing___Text + + def __init__(self, + *, + key : typing___Optional[typing___Text] = None, + value : typing___Optional[typing___Text] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureSetSpec.LabelsEntry: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureSetSpec.LabelsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___LabelsEntry = LabelsEntry + name = ... # type: typing___Text - version = ... # type: int + version = ... # type: builtin___int @property - def entities(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[EntitySpec]: ... + def entities(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___EntitySpec]: ... @property - def features(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[FeatureSpec]: ... + def features(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___FeatureSpec]: ... @property def max_age(self) -> google___protobuf___duration_pb2___Duration: ... @@ -52,25 +106,30 @@ class FeatureSetSpec(google___protobuf___message___Message): @property def source(self) -> feast___core___Source_pb2___Source: ... + @property + def labels(self) -> typing___MutableMapping[typing___Text, typing___Text]: ... + def __init__(self, *, name : typing___Optional[typing___Text] = None, - version : typing___Optional[int] = None, - entities : typing___Optional[typing___Iterable[EntitySpec]] = None, - features : typing___Optional[typing___Iterable[FeatureSpec]] = None, + version : typing___Optional[builtin___int] = None, + entities : typing___Optional[typing___Iterable[global___EntitySpec]] = None, + features : typing___Optional[typing___Iterable[global___FeatureSpec]] = None, max_age : typing___Optional[google___protobuf___duration_pb2___Duration] = None, source : typing___Optional[feast___core___Source_pb2___Source] = None, + labels : typing___Optional[typing___Mapping[typing___Text, typing___Text]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FeatureSetSpec: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"max_age",u"source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"entities",u"features",u"max_age",u"name",u"source",u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureSetSpec: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"max_age",b"max_age",u"source",b"source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"entities",b"entities",u"features",b"features",u"max_age",b"max_age",u"name",b"name",u"source",b"source",u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureSetSpec: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"max_age",b"max_age",u"source",b"source"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"entities",b"entities",u"features",b"features",u"labels",b"labels",u"max_age",b"max_age",u"name",b"name",u"source",b"source",u"version",b"version"]) -> None: ... +global___FeatureSetSpec = FeatureSetSpec class EntitySpec(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -82,30 +141,59 @@ class EntitySpec(google___protobuf___message___Message): name : typing___Optional[typing___Text] = None, value_type : typing___Optional[feast___types___Value_pb2___ValueType.Enum] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> EntitySpec: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"name",u"value_type"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> EntitySpec: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"value_type",b"value_type"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> EntitySpec: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"value_type",b"value_type"]) -> None: ... +global___EntitySpec = EntitySpec class FeatureSpec(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + class LabelsEntry(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + key = ... # type: typing___Text + value = ... # type: typing___Text + + def __init__(self, + *, + key : typing___Optional[typing___Text] = None, + value : typing___Optional[typing___Text] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureSpec.LabelsEntry: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureSpec.LabelsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___LabelsEntry = LabelsEntry + name = ... # type: typing___Text value_type = ... # type: feast___types___Value_pb2___ValueType.Enum + @property + def labels(self) -> typing___MutableMapping[typing___Text, typing___Text]: ... + def __init__(self, *, name : typing___Optional[typing___Text] = None, value_type : typing___Optional[feast___types___Value_pb2___ValueType.Enum] = None, + labels : typing___Optional[typing___Mapping[typing___Text, typing___Text]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FeatureSpec: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"name",u"value_type"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureSpec: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"value_type",b"value_type"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureSpec: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"labels",b"labels",u"name",b"name",u"value_type",b"value_type"]) -> None: ... +global___FeatureSpec = FeatureSpec diff --git a/sdk/python/feast/core/Source_pb2.py b/sdk/python/feast/core/Source_pb2.py index e0d0dd64313..356a7df89c8 100644 --- a/sdk/python/feast/core/Source_pb2.py +++ b/sdk/python/feast/core/Source_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/core/Source.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -20,8 +18,8 @@ name='feast/core/Source.proto', package='feast.core', syntax='proto3', - serialized_options=_b('\n\nfeast.coreB\013SourceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core'), - serialized_pb=_b('\n\x17\x66\x65\x61st/core/Source.proto\x12\nfeast.core\"}\n\x06Source\x12$\n\x04type\x18\x01 \x01(\x0e\x32\x16.feast.core.SourceType\x12<\n\x13kafka_source_config\x18\x02 \x01(\x0b\x32\x1d.feast.core.KafkaSourceConfigH\x00\x42\x0f\n\rsource_config\"=\n\x11KafkaSourceConfig\x12\x19\n\x11\x62ootstrap_servers\x18\x01 \x01(\t\x12\r\n\x05topic\x18\x02 \x01(\t*$\n\nSourceType\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05KAFKA\x10\x01\x42J\n\nfeast.coreB\x0bSourceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3') + serialized_options=b'\n\nfeast.coreB\013SourceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core', + serialized_pb=b'\n\x17\x66\x65\x61st/core/Source.proto\x12\nfeast.core\"}\n\x06Source\x12$\n\x04type\x18\x01 \x01(\x0e\x32\x16.feast.core.SourceType\x12<\n\x13kafka_source_config\x18\x02 \x01(\x0b\x32\x1d.feast.core.KafkaSourceConfigH\x00\x42\x0f\n\rsource_config\"=\n\x11KafkaSourceConfig\x12\x19\n\x11\x62ootstrap_servers\x18\x01 \x01(\t\x12\r\n\x05topic\x18\x02 \x01(\t*$\n\nSourceType\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05KAFKA\x10\x01\x42J\n\nfeast.coreB\x0bSourceProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3' ) _SOURCETYPE = _descriptor.EnumDescriptor( @@ -103,14 +101,14 @@ _descriptor.FieldDescriptor( name='bootstrap_servers', full_name='feast.core.KafkaSourceConfig.bootstrap_servers', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='topic', full_name='feast.core.KafkaSourceConfig.topic', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/core/Source_pb2.pyi b/sdk/python/feast/core/Source_pb2.pyi index 0521ac34f80..1a0e87e7ba3 100644 --- a/sdk/python/feast/core/Source_pb2.pyi +++ b/sdk/python/feast/core/Source_pb2.pyi @@ -14,6 +14,7 @@ from typing import ( Optional as typing___Optional, Text as typing___Text, Tuple as typing___Tuple, + Union as typing___Union, cast as typing___cast, ) @@ -22,46 +23,58 @@ from typing_extensions import ( ) -class SourceType(int): +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +builtin___str = str +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + +class SourceType(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> SourceType: ... + def Value(cls, name: builtin___str) -> 'SourceType': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[SourceType]: ... + def values(cls) -> typing___List['SourceType']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, SourceType]]: ... - INVALID = typing___cast(SourceType, 0) - KAFKA = typing___cast(SourceType, 1) -INVALID = typing___cast(SourceType, 0) -KAFKA = typing___cast(SourceType, 1) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'SourceType']]: ... + INVALID = typing___cast('SourceType', 0) + KAFKA = typing___cast('SourceType', 1) +INVALID = typing___cast('SourceType', 0) +KAFKA = typing___cast('SourceType', 1) +global___SourceType = SourceType class Source(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - type = ... # type: SourceType + type = ... # type: global___SourceType @property - def kafka_source_config(self) -> KafkaSourceConfig: ... + def kafka_source_config(self) -> global___KafkaSourceConfig: ... def __init__(self, *, - type : typing___Optional[SourceType] = None, - kafka_source_config : typing___Optional[KafkaSourceConfig] = None, + type : typing___Optional[global___SourceType] = None, + kafka_source_config : typing___Optional[global___KafkaSourceConfig] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Source: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"kafka_source_config",u"source_config"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"kafka_source_config",u"source_config",u"type"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Source: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"kafka_source_config",b"kafka_source_config",u"source_config",b"source_config"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"kafka_source_config",b"kafka_source_config",u"source_config",b"source_config",u"type",b"type"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Source: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"kafka_source_config",b"kafka_source_config",u"source_config",b"source_config"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"kafka_source_config",b"kafka_source_config",u"source_config",b"source_config",u"type",b"type"]) -> None: ... def WhichOneof(self, oneof_group: typing_extensions___Literal[u"source_config",b"source_config"]) -> typing_extensions___Literal["kafka_source_config"]: ... +global___Source = Source class KafkaSourceConfig(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -73,11 +86,13 @@ class KafkaSourceConfig(google___protobuf___message___Message): bootstrap_servers : typing___Optional[typing___Text] = None, topic : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> KafkaSourceConfig: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"bootstrap_servers",u"topic"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> KafkaSourceConfig: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"bootstrap_servers",b"bootstrap_servers",u"topic",b"topic"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> KafkaSourceConfig: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"bootstrap_servers",b"bootstrap_servers",u"topic",b"topic"]) -> None: ... +global___KafkaSourceConfig = KafkaSourceConfig diff --git a/sdk/python/feast/core/Store_pb2.py b/sdk/python/feast/core/Store_pb2.py index c7f9e07d871..ef8c339d61d 100644 --- a/sdk/python/feast/core/Store_pb2.py +++ b/sdk/python/feast/core/Store_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/core/Store.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -13,15 +11,17 @@ _sym_db = _symbol_database.Default() +from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 DESCRIPTOR = _descriptor.FileDescriptor( name='feast/core/Store.proto', package='feast.core', syntax='proto3', - serialized_options=_b('\n\nfeast.coreB\nStoreProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core'), - serialized_pb=_b('\n\x16\x66\x65\x61st/core/Store.proto\x12\nfeast.core\"\xb9\x04\n\x05Store\x12\x0c\n\x04name\x18\x01 \x01(\t\x12)\n\x04type\x18\x02 \x01(\x0e\x32\x1b.feast.core.Store.StoreType\x12\x35\n\rsubscriptions\x18\x04 \x03(\x0b\x32\x1e.feast.core.Store.Subscription\x12\x35\n\x0credis_config\x18\x0b \x01(\x0b\x32\x1d.feast.core.Store.RedisConfigH\x00\x12;\n\x0f\x62igquery_config\x18\x0c \x01(\x0b\x32 .feast.core.Store.BigQueryConfigH\x00\x12=\n\x10\x63\x61ssandra_config\x18\r \x01(\x0b\x32!.feast.core.Store.CassandraConfigH\x00\x1a)\n\x0bRedisConfig\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x38\n\x0e\x42igQueryConfig\x12\x12\n\nproject_id\x18\x01 \x01(\t\x12\x12\n\ndataset_id\x18\x02 \x01(\t\x1a-\n\x0f\x43\x61ssandraConfig\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a-\n\x0cSubscription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\"@\n\tStoreType\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05REDIS\x10\x01\x12\x0c\n\x08\x42IGQUERY\x10\x02\x12\r\n\tCASSANDRA\x10\x03\x42\x08\n\x06\x63onfigBI\n\nfeast.coreB\nStoreProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3') -) + serialized_options=b'\n\nfeast.coreB\nStoreProtoZ/github.com/gojek/feast/sdk/go/protos/feast/core', + serialized_pb=b'\n\x16\x66\x65\x61st/core/Store.proto\x12\nfeast.core\x1a\x1egoogle/protobuf/duration.proto\"0\n\x0bSetOfStores\x12!\n\x06stores\x18\x01 \x03(\x0b\x32\x11.feast.core.Store\"\xff\x07\n\x05Store\x12\x0c\n\x04name\x18\x01 \x01(\t\x12)\n\x04type\x18\x02 \x01(\x0e\x32\x1b.feast.core.Store.StoreType\x12\x35\n\rsubscriptions\x18\x04 \x03(\x0b\x32\x1e.feast.core.Store.Subscription\x12\x35\n\x0credis_config\x18\x0b \x01(\x0b\x32\x1d.feast.core.Store.RedisConfigH\x00\x12;\n\x0f\x62igquery_config\x18\x0c \x01(\x0b\x32 .feast.core.Store.BigQueryConfigH\x00\x12=\n\x10\x63\x61ssandra_config\x18\r \x01(\x0b\x32!.feast.core.Store.CassandraConfigH\x00\x12\x33\n\x0bhive_config\x18\x0e \x01(\x0b\x32\x1c.feast.core.Store.HiveConfigH\x00\x1a)\n\x0bRedisConfig\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x1a\x38\n\x0e\x42igQueryConfig\x12\x12\n\nproject_id\x18\x01 \x01(\t\x12\x12\n\ndataset_id\x18\x02 \x01(\t\x1a\xa1\x02\n\x0f\x43\x61ssandraConfig\x12\x17\n\x0f\x62ootstrap_hosts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x12\x10\n\x08keyspace\x18\x03 \x01(\t\x12\x12\n\ntable_name\x18\x04 \x01(\t\x12V\n\x13replication_options\x18\x05 \x03(\x0b\x32\x39.feast.core.Store.CassandraConfig.ReplicationOptionsEntry\x12.\n\x0b\x64\x65\x66\x61ult_ttl\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x1a\x39\n\x17ReplicationOptionsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x8f\x01\n\nHiveConfig\x12\x15\n\rdatabase_name\x18\x01 \x01(\t\x12:\n\x07options\x18\x02 \x03(\x0b\x32).feast.core.Store.HiveConfig.OptionsEntry\x1a.\n\x0cOptionsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0cSubscription\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\t\"J\n\tStoreType\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05REDIS\x10\x01\x12\x0c\n\x08\x42IGQUERY\x10\x02\x12\r\n\tCASSANDRA\x10\x03\x12\x08\n\x04HIVE\x10\x04\x42\x08\n\x06\x63onfigBI\n\nfeast.coreB\nStoreProtoZ/github.com/gojek/feast/sdk/go/protos/feast/coreb\x06proto3' + , + dependencies=[google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,]) @@ -47,15 +47,50 @@ name='CASSANDRA', index=3, number=3, serialized_options=None, type=None), + _descriptor.EnumValueDescriptor( + name='HIVE', index=4, number=4, + serialized_options=None, + type=None), ], containing_type=None, serialized_options=None, - serialized_start=534, - serialized_end=598, + serialized_start=1060, + serialized_end=1134, ) _sym_db.RegisterEnumDescriptor(_STORE_STORETYPE) +_SETOFSTORES = _descriptor.Descriptor( + name='SetOfStores', + full_name='feast.core.SetOfStores', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='stores', full_name='feast.core.SetOfStores.stores', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=70, + serialized_end=118, +) + + _STORE_REDISCONFIG = _descriptor.Descriptor( name='RedisConfig', full_name='feast.core.Store.RedisConfig', @@ -66,7 +101,7 @@ _descriptor.FieldDescriptor( name='host', full_name='feast.core.Store.RedisConfig.host', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -89,8 +124,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=339, - serialized_end=380, + serialized_start=474, + serialized_end=515, ) _STORE_BIGQUERYCONFIG = _descriptor.Descriptor( @@ -103,14 +138,14 @@ _descriptor.FieldDescriptor( name='project_id', full_name='feast.core.Store.BigQueryConfig.project_id', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dataset_id', full_name='feast.core.Store.BigQueryConfig.dataset_id', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -126,8 +161,45 @@ extension_ranges=[], oneofs=[ ], - serialized_start=382, - serialized_end=438, + serialized_start=517, + serialized_end=573, +) + +_STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY = _descriptor.Descriptor( + name='ReplicationOptionsEntry', + full_name='feast.core.Store.CassandraConfig.ReplicationOptionsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='feast.core.Store.CassandraConfig.ReplicationOptionsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='feast.core.Store.CassandraConfig.ReplicationOptionsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=808, + serialized_end=865, ) _STORE_CASSANDRACONFIG = _descriptor.Descriptor( @@ -138,9 +210,9 @@ containing_type=None, fields=[ _descriptor.FieldDescriptor( - name='host', full_name='feast.core.Store.CassandraConfig.host', index=0, + name='bootstrap_hosts', full_name='feast.core.Store.CassandraConfig.bootstrap_hosts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -151,20 +223,122 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='keyspace', full_name='feast.core.Store.CassandraConfig.keyspace', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='table_name', full_name='feast.core.Store.CassandraConfig.table_name', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='replication_options', full_name='feast.core.Store.CassandraConfig.replication_options', index=4, + number=5, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='default_ttl', full_name='feast.core.Store.CassandraConfig.default_ttl', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=576, + serialized_end=865, +) + +_STORE_HIVECONFIG_OPTIONSENTRY = _descriptor.Descriptor( + name='OptionsEntry', + full_name='feast.core.Store.HiveConfig.OptionsEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='feast.core.Store.HiveConfig.OptionsEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='value', full_name='feast.core.Store.HiveConfig.OptionsEntry.value', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=965, + serialized_end=1011, +) + +_STORE_HIVECONFIG = _descriptor.Descriptor( + name='HiveConfig', + full_name='feast.core.Store.HiveConfig', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='database_name', full_name='feast.core.Store.HiveConfig.database_name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='options', full_name='feast.core.Store.HiveConfig.options', index=1, + number=2, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[_STORE_HIVECONFIG_OPTIONSENTRY, ], + enum_types=[ + ], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=440, - serialized_end=485, + serialized_start=868, + serialized_end=1011, ) _STORE_SUBSCRIPTION = _descriptor.Descriptor( @@ -177,14 +351,14 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.Store.Subscription.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='version', full_name='feast.core.Store.Subscription.version', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -200,8 +374,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=487, - serialized_end=532, + serialized_start=1013, + serialized_end=1058, ) _STORE = _descriptor.Descriptor( @@ -214,7 +388,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.core.Store.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -253,10 +427,17 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='hive_config', full_name='feast.core.Store.hive_config', index=6, + number=14, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], - nested_types=[_STORE_REDISCONFIG, _STORE_BIGQUERYCONFIG, _STORE_CASSANDRACONFIG, _STORE_SUBSCRIPTION, ], + nested_types=[_STORE_REDISCONFIG, _STORE_BIGQUERYCONFIG, _STORE_CASSANDRACONFIG, _STORE_HIVECONFIG, _STORE_SUBSCRIPTION, ], enum_types=[ _STORE_STORETYPE, ], @@ -269,19 +450,27 @@ name='config', full_name='feast.core.Store.config', index=0, containing_type=None, fields=[]), ], - serialized_start=39, - serialized_end=608, + serialized_start=121, + serialized_end=1144, ) +_SETOFSTORES.fields_by_name['stores'].message_type = _STORE _STORE_REDISCONFIG.containing_type = _STORE _STORE_BIGQUERYCONFIG.containing_type = _STORE +_STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY.containing_type = _STORE_CASSANDRACONFIG +_STORE_CASSANDRACONFIG.fields_by_name['replication_options'].message_type = _STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY +_STORE_CASSANDRACONFIG.fields_by_name['default_ttl'].message_type = google_dot_protobuf_dot_duration__pb2._DURATION _STORE_CASSANDRACONFIG.containing_type = _STORE +_STORE_HIVECONFIG_OPTIONSENTRY.containing_type = _STORE_HIVECONFIG +_STORE_HIVECONFIG.fields_by_name['options'].message_type = _STORE_HIVECONFIG_OPTIONSENTRY +_STORE_HIVECONFIG.containing_type = _STORE _STORE_SUBSCRIPTION.containing_type = _STORE _STORE.fields_by_name['type'].enum_type = _STORE_STORETYPE _STORE.fields_by_name['subscriptions'].message_type = _STORE_SUBSCRIPTION _STORE.fields_by_name['redis_config'].message_type = _STORE_REDISCONFIG _STORE.fields_by_name['bigquery_config'].message_type = _STORE_BIGQUERYCONFIG _STORE.fields_by_name['cassandra_config'].message_type = _STORE_CASSANDRACONFIG +_STORE.fields_by_name['hive_config'].message_type = _STORE_HIVECONFIG _STORE_STORETYPE.containing_type = _STORE _STORE.oneofs_by_name['config'].fields.append( _STORE.fields_by_name['redis_config']) @@ -292,9 +481,20 @@ _STORE.oneofs_by_name['config'].fields.append( _STORE.fields_by_name['cassandra_config']) _STORE.fields_by_name['cassandra_config'].containing_oneof = _STORE.oneofs_by_name['config'] +_STORE.oneofs_by_name['config'].fields.append( + _STORE.fields_by_name['hive_config']) +_STORE.fields_by_name['hive_config'].containing_oneof = _STORE.oneofs_by_name['config'] +DESCRIPTOR.message_types_by_name['SetOfStores'] = _SETOFSTORES DESCRIPTOR.message_types_by_name['Store'] = _STORE _sym_db.RegisterFileDescriptor(DESCRIPTOR) +SetOfStores = _reflection.GeneratedProtocolMessageType('SetOfStores', (_message.Message,), { + 'DESCRIPTOR' : _SETOFSTORES, + '__module__' : 'feast.core.Store_pb2' + # @@protoc_insertion_point(class_scope:feast.core.SetOfStores) + }) +_sym_db.RegisterMessage(SetOfStores) + Store = _reflection.GeneratedProtocolMessageType('Store', (_message.Message,), { 'RedisConfig' : _reflection.GeneratedProtocolMessageType('RedisConfig', (_message.Message,), { @@ -312,12 +512,33 @@ , 'CassandraConfig' : _reflection.GeneratedProtocolMessageType('CassandraConfig', (_message.Message,), { + + 'ReplicationOptionsEntry' : _reflection.GeneratedProtocolMessageType('ReplicationOptionsEntry', (_message.Message,), { + 'DESCRIPTOR' : _STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY, + '__module__' : 'feast.core.Store_pb2' + # @@protoc_insertion_point(class_scope:feast.core.Store.CassandraConfig.ReplicationOptionsEntry) + }) + , 'DESCRIPTOR' : _STORE_CASSANDRACONFIG, '__module__' : 'feast.core.Store_pb2' # @@protoc_insertion_point(class_scope:feast.core.Store.CassandraConfig) }) , + 'HiveConfig' : _reflection.GeneratedProtocolMessageType('HiveConfig', (_message.Message,), { + + 'OptionsEntry' : _reflection.GeneratedProtocolMessageType('OptionsEntry', (_message.Message,), { + 'DESCRIPTOR' : _STORE_HIVECONFIG_OPTIONSENTRY, + '__module__' : 'feast.core.Store_pb2' + # @@protoc_insertion_point(class_scope:feast.core.Store.HiveConfig.OptionsEntry) + }) + , + 'DESCRIPTOR' : _STORE_HIVECONFIG, + '__module__' : 'feast.core.Store_pb2' + # @@protoc_insertion_point(class_scope:feast.core.Store.HiveConfig) + }) + , + 'Subscription' : _reflection.GeneratedProtocolMessageType('Subscription', (_message.Message,), { 'DESCRIPTOR' : _STORE_SUBSCRIPTION, '__module__' : 'feast.core.Store_pb2' @@ -332,8 +553,13 @@ _sym_db.RegisterMessage(Store.RedisConfig) _sym_db.RegisterMessage(Store.BigQueryConfig) _sym_db.RegisterMessage(Store.CassandraConfig) +_sym_db.RegisterMessage(Store.CassandraConfig.ReplicationOptionsEntry) +_sym_db.RegisterMessage(Store.HiveConfig) +_sym_db.RegisterMessage(Store.HiveConfig.OptionsEntry) _sym_db.RegisterMessage(Store.Subscription) DESCRIPTOR._options = None +_STORE_CASSANDRACONFIG_REPLICATIONOPTIONSENTRY._options = None +_STORE_HIVECONFIG_OPTIONSENTRY._options = None # @@protoc_insertion_point(module_scope) diff --git a/sdk/python/feast/core/Store_pb2.pyi b/sdk/python/feast/core/Store_pb2.pyi index 726a9d5443e..3ee8e5928e1 100644 --- a/sdk/python/feast/core/Store_pb2.pyi +++ b/sdk/python/feast/core/Store_pb2.pyi @@ -5,6 +5,10 @@ from google.protobuf.descriptor import ( EnumDescriptor as google___protobuf___descriptor___EnumDescriptor, ) +from google.protobuf.duration_pb2 import ( + Duration as google___protobuf___duration_pb2___Duration, +) + from google.protobuf.internal.containers import ( RepeatedCompositeFieldContainer as google___protobuf___internal___containers___RepeatedCompositeFieldContainer, ) @@ -16,9 +20,12 @@ from google.protobuf.message import ( from typing import ( Iterable as typing___Iterable, List as typing___List, + Mapping as typing___Mapping, + MutableMapping as typing___MutableMapping, Optional as typing___Optional, Text as typing___Text, Tuple as typing___Tuple, + Union as typing___Union, cast as typing___cast, ) @@ -27,47 +34,83 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +builtin___str = str +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + +class SetOfStores(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + + @property + def stores(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___Store]: ... + + def __init__(self, + *, + stores : typing___Optional[typing___Iterable[global___Store]] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> SetOfStores: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> SetOfStores: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"stores",b"stores"]) -> None: ... +global___SetOfStores = SetOfStores + class Store(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - class StoreType(int): + class StoreType(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> Store.StoreType: ... + def Value(cls, name: builtin___str) -> 'Store.StoreType': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[Store.StoreType]: ... + def values(cls) -> typing___List['Store.StoreType']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, Store.StoreType]]: ... - INVALID = typing___cast(Store.StoreType, 0) - REDIS = typing___cast(Store.StoreType, 1) - BIGQUERY = typing___cast(Store.StoreType, 2) - CASSANDRA = typing___cast(Store.StoreType, 3) - INVALID = typing___cast(Store.StoreType, 0) - REDIS = typing___cast(Store.StoreType, 1) - BIGQUERY = typing___cast(Store.StoreType, 2) - CASSANDRA = typing___cast(Store.StoreType, 3) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'Store.StoreType']]: ... + INVALID = typing___cast('Store.StoreType', 0) + REDIS = typing___cast('Store.StoreType', 1) + BIGQUERY = typing___cast('Store.StoreType', 2) + CASSANDRA = typing___cast('Store.StoreType', 3) + HIVE = typing___cast('Store.StoreType', 4) + INVALID = typing___cast('Store.StoreType', 0) + REDIS = typing___cast('Store.StoreType', 1) + BIGQUERY = typing___cast('Store.StoreType', 2) + CASSANDRA = typing___cast('Store.StoreType', 3) + HIVE = typing___cast('Store.StoreType', 4) + global___StoreType = StoreType class RedisConfig(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... host = ... # type: typing___Text - port = ... # type: int + port = ... # type: builtin___int def __init__(self, *, host : typing___Optional[typing___Text] = None, - port : typing___Optional[int] = None, + port : typing___Optional[builtin___int] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Store.RedisConfig: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"host",u"port"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.RedisConfig: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"host",b"host",u"port",b"port"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.RedisConfig: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"host",b"host",u"port",b"port"]) -> None: ... + global___RedisConfig = RedisConfig class BigQueryConfig(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -79,33 +122,115 @@ class Store(google___protobuf___message___Message): project_id : typing___Optional[typing___Text] = None, dataset_id : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Store.BigQueryConfig: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_id",u"project_id"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.BigQueryConfig: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_id",b"dataset_id",u"project_id",b"project_id"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.BigQueryConfig: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"dataset_id",b"dataset_id",u"project_id",b"project_id"]) -> None: ... + global___BigQueryConfig = BigQueryConfig class CassandraConfig(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - host = ... # type: typing___Text - port = ... # type: int + class ReplicationOptionsEntry(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + key = ... # type: typing___Text + value = ... # type: typing___Text + + def __init__(self, + *, + key : typing___Optional[typing___Text] = None, + value : typing___Optional[typing___Text] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.CassandraConfig.ReplicationOptionsEntry: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.CassandraConfig.ReplicationOptionsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___ReplicationOptionsEntry = ReplicationOptionsEntry + + bootstrap_hosts = ... # type: typing___Text + port = ... # type: builtin___int + keyspace = ... # type: typing___Text + table_name = ... # type: typing___Text + + @property + def replication_options(self) -> typing___MutableMapping[typing___Text, typing___Text]: ... + + @property + def default_ttl(self) -> google___protobuf___duration_pb2___Duration: ... def __init__(self, *, - host : typing___Optional[typing___Text] = None, - port : typing___Optional[int] = None, + bootstrap_hosts : typing___Optional[typing___Text] = None, + port : typing___Optional[builtin___int] = None, + keyspace : typing___Optional[typing___Text] = None, + table_name : typing___Optional[typing___Text] = None, + replication_options : typing___Optional[typing___Mapping[typing___Text, typing___Text]] = None, + default_ttl : typing___Optional[google___protobuf___duration_pb2___Duration] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Store.CassandraConfig: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.CassandraConfig: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.CassandraConfig: ... def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"default_ttl",b"default_ttl"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"bootstrap_hosts",b"bootstrap_hosts",u"default_ttl",b"default_ttl",u"keyspace",b"keyspace",u"port",b"port",u"replication_options",b"replication_options",u"table_name",b"table_name"]) -> None: ... + global___CassandraConfig = CassandraConfig + + class HiveConfig(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + class OptionsEntry(google___protobuf___message___Message): + DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... + key = ... # type: typing___Text + value = ... # type: typing___Text + + def __init__(self, + *, + key : typing___Optional[typing___Text] = None, + value : typing___Optional[typing___Text] = None, + ) -> None: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.HiveConfig.OptionsEntry: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.HiveConfig.OptionsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___OptionsEntry = OptionsEntry + + database_name = ... # type: typing___Text + + @property + def options(self) -> typing___MutableMapping[typing___Text, typing___Text]: ... + + def __init__(self, + *, + database_name : typing___Optional[typing___Text] = None, + options : typing___Optional[typing___Mapping[typing___Text, typing___Text]] = None, + ) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"host",u"port"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.HiveConfig: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"host",b"host",u"port",b"port"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.HiveConfig: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"database_name",b"database_name",u"options",b"options"]) -> None: ... + global___HiveConfig = HiveConfig class Subscription(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -117,47 +242,54 @@ class Store(google___protobuf___message___Message): name : typing___Optional[typing___Text] = None, version : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Store.Subscription: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"name",u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Store.Subscription: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store.Subscription: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"version",b"version"]) -> None: ... + global___Subscription = Subscription name = ... # type: typing___Text - type = ... # type: Store.StoreType + type = ... # type: global___Store.StoreType @property - def subscriptions(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[Store.Subscription]: ... + def subscriptions(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___Store.Subscription]: ... @property - def redis_config(self) -> Store.RedisConfig: ... + def redis_config(self) -> global___Store.RedisConfig: ... @property - def bigquery_config(self) -> Store.BigQueryConfig: ... + def bigquery_config(self) -> global___Store.BigQueryConfig: ... @property - def cassandra_config(self) -> Store.CassandraConfig: ... + def cassandra_config(self) -> global___Store.CassandraConfig: ... + + @property + def hive_config(self) -> global___Store.HiveConfig: ... def __init__(self, *, name : typing___Optional[typing___Text] = None, - type : typing___Optional[Store.StoreType] = None, - subscriptions : typing___Optional[typing___Iterable[Store.Subscription]] = None, - redis_config : typing___Optional[Store.RedisConfig] = None, - bigquery_config : typing___Optional[Store.BigQueryConfig] = None, - cassandra_config : typing___Optional[Store.CassandraConfig] = None, + type : typing___Optional[global___Store.StoreType] = None, + subscriptions : typing___Optional[typing___Iterable[global___Store.Subscription]] = None, + redis_config : typing___Optional[global___Store.RedisConfig] = None, + bigquery_config : typing___Optional[global___Store.BigQueryConfig] = None, + cassandra_config : typing___Optional[global___Store.CassandraConfig] = None, + hive_config : typing___Optional[global___Store.HiveConfig] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Store: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"bigquery_config",u"cassandra_config",u"config",u"redis_config"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"bigquery_config",u"cassandra_config",u"config",u"name",u"redis_config",u"subscriptions",u"type"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Store: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"bigquery_config",b"bigquery_config",u"cassandra_config",b"cassandra_config",u"config",b"config",u"redis_config",b"redis_config"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"bigquery_config",b"bigquery_config",u"cassandra_config",b"cassandra_config",u"config",b"config",u"name",b"name",u"redis_config",b"redis_config",u"subscriptions",b"subscriptions",u"type",b"type"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions___Literal[u"config",b"config"]) -> typing_extensions___Literal["redis_config","bigquery_config","cassandra_config"]: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Store: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"bigquery_config",b"bigquery_config",u"cassandra_config",b"cassandra_config",u"config",b"config",u"hive_config",b"hive_config",u"redis_config",b"redis_config"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"bigquery_config",b"bigquery_config",u"cassandra_config",b"cassandra_config",u"config",b"config",u"hive_config",b"hive_config",u"name",b"name",u"redis_config",b"redis_config",u"subscriptions",b"subscriptions",u"type",b"type"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions___Literal[u"config",b"config"]) -> typing_extensions___Literal["redis_config","bigquery_config","cassandra_config","hive_config"]: ... +global___Store = Store diff --git a/sdk/python/feast/loaders/ingest.py b/sdk/python/feast/loaders/ingest.py index 527ab481fe0..9de411147e0 100644 --- a/sdk/python/feast/loaders/ingest.py +++ b/sdk/python/feast/loaders/ingest.py @@ -23,9 +23,7 @@ def _encode_pa_tables( - file: str, - fs: FeatureSet, - row_group_idx: int, + file: str, feature_set: str, fields: dict, row_group_idx: int ) -> List[bytes]: """ Helper function to encode a PyArrow table(s) read from parquet file(s) into @@ -42,8 +40,11 @@ def _encode_pa_tables( File directory of all the parquet file to encode. Parquet file must have more than one row group. - fs (feast.feature_set.FeatureSet): - FeatureSet describing parquet files. + feature_set (str): + Feature set reference in the format f"{project}/{name}:{version}". + + fields (dict[str, enum.Enum.ValueType]): + A mapping of field names to their value types. row_group_idx(int): Row group index to read and encode into byte like FeatureRow @@ -63,13 +64,10 @@ def _encode_pa_tables( # Preprocess the columns by converting all its values to Proto values proto_columns = { - field_name: pa_column_to_proto_column(field.dtype, - table.column(field_name)) - for field_name, field in fs.fields.items() + field_name: pa_column_to_proto_column(dtype, table.column(field_name)) + for field_name, dtype in fields.items() } - feature_set = f"{fs.name}:{fs.version}" - # List to store result feature_rows = [] @@ -125,9 +123,13 @@ def get_feature_row_chunks( Iterable list of byte encoded FeatureRow(s). """ + feature_set = f"{fs.name}:{fs.version}" + + field_map = {field.name: field.dtype for field in fs.fields.values()} + pool = Pool(max_workers) - func = partial(_encode_pa_tables, file, fs) - for chunk in pool.imap_unordered(func, row_groups): + func = partial(_encode_pa_tables, file, feature_set, field_map) + for chunk in pool.imap(func, row_groups): yield chunk return diff --git a/sdk/python/feast/serving/ServingService_pb2.py b/sdk/python/feast/serving/ServingService_pb2.py index e7258f5a7d5..e252b0bcd77 100644 --- a/sdk/python/feast/serving/ServingService_pb2.py +++ b/sdk/python/feast/serving/ServingService_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/serving/ServingService.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -23,8 +21,8 @@ name='feast/serving/ServingService.proto', package='feast.serving', syntax='proto3', - serialized_options=_b('\n\rfeast.servingB\017ServingAPIProtoZ2github.com/gojek/feast/sdk/go/protos/feast/serving'), - serialized_pb=_b('\n\"feast/serving/ServingService.proto\x12\rfeast.serving\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x17\x66\x65\x61st/types/Value.proto\"\x1c\n\x1aGetFeastServingInfoRequest\"{\n\x1bGetFeastServingInfoResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12-\n\x04type\x18\x02 \x01(\x0e\x32\x1f.feast.serving.FeastServingType\x12\x1c\n\x14job_staging_location\x18\n \x01(\t\"u\n\x11\x46\x65\x61tureSetRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x15\n\rfeature_names\x18\x03 \x03(\t\x12*\n\x07max_age\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\"\x93\x03\n\x18GetOnlineFeaturesRequest\x12\x36\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32 .feast.serving.FeatureSetRequest\x12\x46\n\x0b\x65ntity_rows\x18\x02 \x03(\x0b\x32\x31.feast.serving.GetOnlineFeaturesRequest.EntityRow\x12!\n\x19omit_entities_in_response\x18\x03 \x01(\x08\x1a\xd3\x01\n\tEntityRow\x12\x34\n\x10\x65ntity_timestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12M\n\x06\x66ields\x18\x02 \x03(\x0b\x32=.feast.serving.GetOnlineFeaturesRequest.EntityRow.FieldsEntry\x1a\x41\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.Value:\x02\x38\x01\"\x87\x01\n\x17GetBatchFeaturesRequest\x12\x36\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32 .feast.serving.FeatureSetRequest\x12\x34\n\x0e\x64\x61taset_source\x18\x02 \x01(\x0b\x32\x1c.feast.serving.DatasetSource\"\x8c\x02\n\x19GetOnlineFeaturesResponse\x12J\n\x0c\x66ield_values\x18\x01 \x03(\x0b\x32\x34.feast.serving.GetOnlineFeaturesResponse.FieldValues\x1a\xa2\x01\n\x0b\x46ieldValues\x12P\n\x06\x66ields\x18\x01 \x03(\x0b\x32@.feast.serving.GetOnlineFeaturesResponse.FieldValues.FieldsEntry\x1a\x41\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.Value:\x02\x38\x01\";\n\x18GetBatchFeaturesResponse\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"0\n\rGetJobRequest\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"1\n\x0eGetJobResponse\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"\xb3\x01\n\x03Job\x12\n\n\x02id\x18\x01 \x01(\t\x12$\n\x04type\x18\x02 \x01(\x0e\x32\x16.feast.serving.JobType\x12(\n\x06status\x18\x03 \x01(\x0e\x32\x18.feast.serving.JobStatus\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12\x11\n\tfile_uris\x18\x05 \x03(\t\x12.\n\x0b\x64\x61ta_format\x18\x06 \x01(\x0e\x32\x19.feast.serving.DataFormat\"\xb2\x01\n\rDatasetSource\x12>\n\x0b\x66ile_source\x18\x01 \x01(\x0b\x32\'.feast.serving.DatasetSource.FileSourceH\x00\x1aO\n\nFileSource\x12\x11\n\tfile_uris\x18\x01 \x03(\t\x12.\n\x0b\x64\x61ta_format\x18\x02 \x01(\x0e\x32\x19.feast.serving.DataFormatB\x10\n\x0e\x64\x61taset_source*o\n\x10\x46\x65\x61stServingType\x12\x1e\n\x1a\x46\x45\x41ST_SERVING_TYPE_INVALID\x10\x00\x12\x1d\n\x19\x46\x45\x41ST_SERVING_TYPE_ONLINE\x10\x01\x12\x1c\n\x18\x46\x45\x41ST_SERVING_TYPE_BATCH\x10\x02*6\n\x07JobType\x12\x14\n\x10JOB_TYPE_INVALID\x10\x00\x12\x15\n\x11JOB_TYPE_DOWNLOAD\x10\x01*h\n\tJobStatus\x12\x16\n\x12JOB_STATUS_INVALID\x10\x00\x12\x16\n\x12JOB_STATUS_PENDING\x10\x01\x12\x16\n\x12JOB_STATUS_RUNNING\x10\x02\x12\x13\n\x0fJOB_STATUS_DONE\x10\x03*;\n\nDataFormat\x12\x17\n\x13\x44\x41TA_FORMAT_INVALID\x10\x00\x12\x14\n\x10\x44\x41TA_FORMAT_AVRO\x10\x01\x32\x92\x03\n\x0eServingService\x12l\n\x13GetFeastServingInfo\x12).feast.serving.GetFeastServingInfoRequest\x1a*.feast.serving.GetFeastServingInfoResponse\x12\x66\n\x11GetOnlineFeatures\x12\'.feast.serving.GetOnlineFeaturesRequest\x1a(.feast.serving.GetOnlineFeaturesResponse\x12\x63\n\x10GetBatchFeatures\x12&.feast.serving.GetBatchFeaturesRequest\x1a\'.feast.serving.GetBatchFeaturesResponse\x12\x45\n\x06GetJob\x12\x1c.feast.serving.GetJobRequest\x1a\x1d.feast.serving.GetJobResponseBT\n\rfeast.servingB\x0fServingAPIProtoZ2github.com/gojek/feast/sdk/go/protos/feast/servingb\x06proto3') + serialized_options=b'\n\rfeast.servingB\017ServingAPIProtoZ2github.com/gojek/feast/sdk/go/protos/feast/serving', + serialized_pb=b'\n\"feast/serving/ServingService.proto\x12\rfeast.serving\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x17\x66\x65\x61st/types/Value.proto\"\x1c\n\x1aGetFeastServingInfoRequest\"{\n\x1bGetFeastServingInfoResponse\x12\x0f\n\x07version\x18\x01 \x01(\t\x12-\n\x04type\x18\x02 \x01(\x0e\x32\x1f.feast.serving.FeastServingType\x12\x1c\n\x14job_staging_location\x18\n \x01(\t\"u\n\x11\x46\x65\x61tureSetRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x05\x12\x15\n\rfeature_names\x18\x03 \x03(\t\x12*\n\x07max_age\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\"\x93\x03\n\x18GetOnlineFeaturesRequest\x12\x36\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32 .feast.serving.FeatureSetRequest\x12\x46\n\x0b\x65ntity_rows\x18\x02 \x03(\x0b\x32\x31.feast.serving.GetOnlineFeaturesRequest.EntityRow\x12!\n\x19omit_entities_in_response\x18\x03 \x01(\x08\x1a\xd3\x01\n\tEntityRow\x12\x34\n\x10\x65ntity_timestamp\x18\x01 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12M\n\x06\x66ields\x18\x02 \x03(\x0b\x32=.feast.serving.GetOnlineFeaturesRequest.EntityRow.FieldsEntry\x1a\x41\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.Value:\x02\x38\x01\"\x87\x01\n\x17GetBatchFeaturesRequest\x12\x36\n\x0c\x66\x65\x61ture_sets\x18\x01 \x03(\x0b\x32 .feast.serving.FeatureSetRequest\x12\x34\n\x0e\x64\x61taset_source\x18\x02 \x01(\x0b\x32\x1c.feast.serving.DatasetSource\"\x8c\x02\n\x19GetOnlineFeaturesResponse\x12J\n\x0c\x66ield_values\x18\x01 \x03(\x0b\x32\x34.feast.serving.GetOnlineFeaturesResponse.FieldValues\x1a\xa2\x01\n\x0b\x46ieldValues\x12P\n\x06\x66ields\x18\x01 \x03(\x0b\x32@.feast.serving.GetOnlineFeaturesResponse.FieldValues.FieldsEntry\x1a\x41\n\x0b\x46ieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.Value:\x02\x38\x01\";\n\x18GetBatchFeaturesResponse\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"0\n\rGetJobRequest\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"1\n\x0eGetJobResponse\x12\x1f\n\x03job\x18\x01 \x01(\x0b\x32\x12.feast.serving.Job\"\xb3\x01\n\x03Job\x12\n\n\x02id\x18\x01 \x01(\t\x12$\n\x04type\x18\x02 \x01(\x0e\x32\x16.feast.serving.JobType\x12(\n\x06status\x18\x03 \x01(\x0e\x32\x18.feast.serving.JobStatus\x12\r\n\x05\x65rror\x18\x04 \x01(\t\x12\x11\n\tfile_uris\x18\x05 \x03(\t\x12.\n\x0b\x64\x61ta_format\x18\x06 \x01(\x0e\x32\x19.feast.serving.DataFormat\"\xb2\x01\n\rDatasetSource\x12>\n\x0b\x66ile_source\x18\x01 \x01(\x0b\x32\'.feast.serving.DatasetSource.FileSourceH\x00\x1aO\n\nFileSource\x12\x11\n\tfile_uris\x18\x01 \x03(\t\x12.\n\x0b\x64\x61ta_format\x18\x02 \x01(\x0e\x32\x19.feast.serving.DataFormatB\x10\n\x0e\x64\x61taset_source*o\n\x10\x46\x65\x61stServingType\x12\x1e\n\x1a\x46\x45\x41ST_SERVING_TYPE_INVALID\x10\x00\x12\x1d\n\x19\x46\x45\x41ST_SERVING_TYPE_ONLINE\x10\x01\x12\x1c\n\x18\x46\x45\x41ST_SERVING_TYPE_BATCH\x10\x02*6\n\x07JobType\x12\x14\n\x10JOB_TYPE_INVALID\x10\x00\x12\x15\n\x11JOB_TYPE_DOWNLOAD\x10\x01*h\n\tJobStatus\x12\x16\n\x12JOB_STATUS_INVALID\x10\x00\x12\x16\n\x12JOB_STATUS_PENDING\x10\x01\x12\x16\n\x12JOB_STATUS_RUNNING\x10\x02\x12\x13\n\x0fJOB_STATUS_DONE\x10\x03*;\n\nDataFormat\x12\x17\n\x13\x44\x41TA_FORMAT_INVALID\x10\x00\x12\x14\n\x10\x44\x41TA_FORMAT_AVRO\x10\x01\x32\x92\x03\n\x0eServingService\x12l\n\x13GetFeastServingInfo\x12).feast.serving.GetFeastServingInfoRequest\x1a*.feast.serving.GetFeastServingInfoResponse\x12\x66\n\x11GetOnlineFeatures\x12\'.feast.serving.GetOnlineFeaturesRequest\x1a(.feast.serving.GetOnlineFeaturesResponse\x12\x63\n\x10GetBatchFeatures\x12&.feast.serving.GetBatchFeaturesRequest\x1a\'.feast.serving.GetBatchFeaturesResponse\x12\x45\n\x06GetJob\x12\x1c.feast.serving.GetJobRequest\x1a\x1d.feast.serving.GetJobResponseBT\n\rfeast.servingB\x0fServingAPIProtoZ2github.com/gojek/feast/sdk/go/protos/feast/servingb\x06proto3' , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,feast_dot_types_dot_Value__pb2.DESCRIPTOR,]) @@ -180,7 +178,7 @@ _descriptor.FieldDescriptor( name='version', full_name='feast.serving.GetFeastServingInfoResponse.version', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -194,7 +192,7 @@ _descriptor.FieldDescriptor( name='job_staging_location', full_name='feast.serving.GetFeastServingInfoResponse.job_staging_location', index=2, number=10, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -225,7 +223,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.serving.FeatureSetRequest.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -277,7 +275,7 @@ _descriptor.FieldDescriptor( name='key', full_name='feast.serving.GetOnlineFeaturesRequest.EntityRow.FieldsEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -294,7 +292,7 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], @@ -434,7 +432,7 @@ _descriptor.FieldDescriptor( name='key', full_name='feast.serving.GetOnlineFeaturesResponse.FieldValues.FieldsEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -451,7 +449,7 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], @@ -625,7 +623,7 @@ _descriptor.FieldDescriptor( name='id', full_name='feast.serving.Job.id', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -646,7 +644,7 @@ _descriptor.FieldDescriptor( name='error', full_name='feast.serving.Job.error', index=3, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/serving/ServingService_pb2.pyi b/sdk/python/feast/serving/ServingService_pb2.pyi index d03fa6568fa..09e6d29a458 100644 --- a/sdk/python/feast/serving/ServingService_pb2.pyi +++ b/sdk/python/feast/serving/ServingService_pb2.pyi @@ -34,6 +34,7 @@ from typing import ( Optional as typing___Optional, Text as typing___Text, Tuple as typing___Tuple, + Union as typing___Union, cast as typing___cast, ) @@ -42,115 +43,136 @@ from typing_extensions import ( ) -class FeastServingType(int): +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +builtin___str = str +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + +class FeastServingType(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> FeastServingType: ... + def Value(cls, name: builtin___str) -> 'FeastServingType': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[FeastServingType]: ... + def values(cls) -> typing___List['FeastServingType']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, FeastServingType]]: ... - FEAST_SERVING_TYPE_INVALID = typing___cast(FeastServingType, 0) - FEAST_SERVING_TYPE_ONLINE = typing___cast(FeastServingType, 1) - FEAST_SERVING_TYPE_BATCH = typing___cast(FeastServingType, 2) -FEAST_SERVING_TYPE_INVALID = typing___cast(FeastServingType, 0) -FEAST_SERVING_TYPE_ONLINE = typing___cast(FeastServingType, 1) -FEAST_SERVING_TYPE_BATCH = typing___cast(FeastServingType, 2) - -class JobType(int): + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'FeastServingType']]: ... + FEAST_SERVING_TYPE_INVALID = typing___cast('FeastServingType', 0) + FEAST_SERVING_TYPE_ONLINE = typing___cast('FeastServingType', 1) + FEAST_SERVING_TYPE_BATCH = typing___cast('FeastServingType', 2) +FEAST_SERVING_TYPE_INVALID = typing___cast('FeastServingType', 0) +FEAST_SERVING_TYPE_ONLINE = typing___cast('FeastServingType', 1) +FEAST_SERVING_TYPE_BATCH = typing___cast('FeastServingType', 2) +global___FeastServingType = FeastServingType + +class JobType(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> JobType: ... + def Value(cls, name: builtin___str) -> 'JobType': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[JobType]: ... + def values(cls) -> typing___List['JobType']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, JobType]]: ... - JOB_TYPE_INVALID = typing___cast(JobType, 0) - JOB_TYPE_DOWNLOAD = typing___cast(JobType, 1) -JOB_TYPE_INVALID = typing___cast(JobType, 0) -JOB_TYPE_DOWNLOAD = typing___cast(JobType, 1) - -class JobStatus(int): + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'JobType']]: ... + JOB_TYPE_INVALID = typing___cast('JobType', 0) + JOB_TYPE_DOWNLOAD = typing___cast('JobType', 1) +JOB_TYPE_INVALID = typing___cast('JobType', 0) +JOB_TYPE_DOWNLOAD = typing___cast('JobType', 1) +global___JobType = JobType + +class JobStatus(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> JobStatus: ... + def Value(cls, name: builtin___str) -> 'JobStatus': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[JobStatus]: ... + def values(cls) -> typing___List['JobStatus']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, JobStatus]]: ... - JOB_STATUS_INVALID = typing___cast(JobStatus, 0) - JOB_STATUS_PENDING = typing___cast(JobStatus, 1) - JOB_STATUS_RUNNING = typing___cast(JobStatus, 2) - JOB_STATUS_DONE = typing___cast(JobStatus, 3) -JOB_STATUS_INVALID = typing___cast(JobStatus, 0) -JOB_STATUS_PENDING = typing___cast(JobStatus, 1) -JOB_STATUS_RUNNING = typing___cast(JobStatus, 2) -JOB_STATUS_DONE = typing___cast(JobStatus, 3) - -class DataFormat(int): + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'JobStatus']]: ... + JOB_STATUS_INVALID = typing___cast('JobStatus', 0) + JOB_STATUS_PENDING = typing___cast('JobStatus', 1) + JOB_STATUS_RUNNING = typing___cast('JobStatus', 2) + JOB_STATUS_DONE = typing___cast('JobStatus', 3) +JOB_STATUS_INVALID = typing___cast('JobStatus', 0) +JOB_STATUS_PENDING = typing___cast('JobStatus', 1) +JOB_STATUS_RUNNING = typing___cast('JobStatus', 2) +JOB_STATUS_DONE = typing___cast('JobStatus', 3) +global___JobStatus = JobStatus + +class DataFormat(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> DataFormat: ... + def Value(cls, name: builtin___str) -> 'DataFormat': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[DataFormat]: ... + def values(cls) -> typing___List['DataFormat']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, DataFormat]]: ... - DATA_FORMAT_INVALID = typing___cast(DataFormat, 0) - DATA_FORMAT_AVRO = typing___cast(DataFormat, 1) -DATA_FORMAT_INVALID = typing___cast(DataFormat, 0) -DATA_FORMAT_AVRO = typing___cast(DataFormat, 1) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'DataFormat']]: ... + DATA_FORMAT_INVALID = typing___cast('DataFormat', 0) + DATA_FORMAT_AVRO = typing___cast('DataFormat', 1) +DATA_FORMAT_INVALID = typing___cast('DataFormat', 0) +DATA_FORMAT_AVRO = typing___cast('DataFormat', 1) +global___DataFormat = DataFormat class GetFeastServingInfoRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... def __init__(self, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeastServingInfoRequest: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeastServingInfoRequest: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeastServingInfoRequest: ... def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... +global___GetFeastServingInfoRequest = GetFeastServingInfoRequest class GetFeastServingInfoResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... version = ... # type: typing___Text - type = ... # type: FeastServingType + type = ... # type: global___FeastServingType job_staging_location = ... # type: typing___Text def __init__(self, *, version : typing___Optional[typing___Text] = None, - type : typing___Optional[FeastServingType] = None, + type : typing___Optional[global___FeastServingType] = None, job_staging_location : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetFeastServingInfoResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"job_staging_location",u"type",u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetFeastServingInfoResponse: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"job_staging_location",b"job_staging_location",u"type",b"type",u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetFeastServingInfoResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"job_staging_location",b"job_staging_location",u"type",b"type",u"version",b"version"]) -> None: ... +global___GetFeastServingInfoResponse = GetFeastServingInfoResponse class FeatureSetRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... name = ... # type: typing___Text - version = ... # type: int + version = ... # type: builtin___int feature_names = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[typing___Text] @property @@ -159,20 +181,21 @@ class FeatureSetRequest(google___protobuf___message___Message): def __init__(self, *, name : typing___Optional[typing___Text] = None, - version : typing___Optional[int] = None, + version : typing___Optional[builtin___int] = None, feature_names : typing___Optional[typing___Iterable[typing___Text]] = None, max_age : typing___Optional[google___protobuf___duration_pb2___Duration] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FeatureSetRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"max_age"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_names",u"max_age",u"name",u"version"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureSetRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"max_age",b"max_age"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"feature_names",b"feature_names",u"max_age",b"max_age",u"name",b"name",u"version",b"version"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureSetRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"max_age",b"max_age"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"feature_names",b"feature_names",u"max_age",b"max_age",u"name",b"name",u"version",b"version"]) -> None: ... +global___FeatureSetRequest = FeatureSetRequest class GetOnlineFeaturesRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -190,16 +213,17 @@ class GetOnlineFeaturesRequest(google___protobuf___message___Message): key : typing___Optional[typing___Text] = None, value : typing___Optional[feast___types___Value_pb2___Value] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesRequest.EntityRow.FieldsEntry: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"key",u"value"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesRequest.EntityRow.FieldsEntry: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesRequest.EntityRow.FieldsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___FieldsEntry = FieldsEntry @property @@ -213,64 +237,68 @@ class GetOnlineFeaturesRequest(google___protobuf___message___Message): entity_timestamp : typing___Optional[google___protobuf___timestamp_pb2___Timestamp] = None, fields : typing___Optional[typing___Mapping[typing___Text, feast___types___Value_pb2___Value]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesRequest.EntityRow: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"entity_timestamp"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"entity_timestamp",u"fields"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesRequest.EntityRow: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"entity_timestamp",b"entity_timestamp"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"entity_timestamp",b"entity_timestamp",u"fields",b"fields"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesRequest.EntityRow: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"entity_timestamp",b"entity_timestamp"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"entity_timestamp",b"entity_timestamp",u"fields",b"fields"]) -> None: ... + global___EntityRow = EntityRow - omit_entities_in_response = ... # type: bool + omit_entities_in_response = ... # type: builtin___bool @property - def feature_sets(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[FeatureSetRequest]: ... + def feature_sets(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___FeatureSetRequest]: ... @property - def entity_rows(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[GetOnlineFeaturesRequest.EntityRow]: ... + def entity_rows(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___GetOnlineFeaturesRequest.EntityRow]: ... def __init__(self, *, - feature_sets : typing___Optional[typing___Iterable[FeatureSetRequest]] = None, - entity_rows : typing___Optional[typing___Iterable[GetOnlineFeaturesRequest.EntityRow]] = None, - omit_entities_in_response : typing___Optional[bool] = None, + feature_sets : typing___Optional[typing___Iterable[global___FeatureSetRequest]] = None, + entity_rows : typing___Optional[typing___Iterable[global___GetOnlineFeaturesRequest.EntityRow]] = None, + omit_entities_in_response : typing___Optional[builtin___bool] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"entity_rows",u"feature_sets",u"omit_entities_in_response"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesRequest: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"entity_rows",b"entity_rows",u"feature_sets",b"feature_sets",u"omit_entities_in_response",b"omit_entities_in_response"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"entity_rows",b"entity_rows",u"feature_sets",b"feature_sets",u"omit_entities_in_response",b"omit_entities_in_response"]) -> None: ... +global___GetOnlineFeaturesRequest = GetOnlineFeaturesRequest class GetBatchFeaturesRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @property - def feature_sets(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[FeatureSetRequest]: ... + def feature_sets(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___FeatureSetRequest]: ... @property - def dataset_source(self) -> DatasetSource: ... + def dataset_source(self) -> global___DatasetSource: ... def __init__(self, *, - feature_sets : typing___Optional[typing___Iterable[FeatureSetRequest]] = None, - dataset_source : typing___Optional[DatasetSource] = None, + feature_sets : typing___Optional[typing___Iterable[global___FeatureSetRequest]] = None, + dataset_source : typing___Optional[global___DatasetSource] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetBatchFeaturesRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"dataset_source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",u"feature_sets"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetBatchFeaturesRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"feature_sets",b"feature_sets"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetBatchFeaturesRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"feature_sets",b"feature_sets"]) -> None: ... +global___GetBatchFeaturesRequest = GetBatchFeaturesRequest class GetOnlineFeaturesResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -288,16 +316,17 @@ class GetOnlineFeaturesResponse(google___protobuf___message___Message): key : typing___Optional[typing___Text] = None, value : typing___Optional[feast___types___Value_pb2___Value] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesResponse.FieldValues.FieldsEntry: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"key",u"value"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesResponse.FieldValues.FieldsEntry: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesResponse.FieldValues.FieldsEntry: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"key",b"key",u"value",b"value"]) -> None: ... + global___FieldsEntry = FieldsEntry @property @@ -307,159 +336,171 @@ class GetOnlineFeaturesResponse(google___protobuf___message___Message): *, fields : typing___Optional[typing___Mapping[typing___Text, feast___types___Value_pb2___Value]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesResponse.FieldValues: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"fields"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesResponse.FieldValues: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"fields",b"fields"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesResponse.FieldValues: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"fields",b"fields"]) -> None: ... + global___FieldValues = FieldValues @property - def field_values(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[GetOnlineFeaturesResponse.FieldValues]: ... + def field_values(self) -> google___protobuf___internal___containers___RepeatedCompositeFieldContainer[global___GetOnlineFeaturesResponse.FieldValues]: ... def __init__(self, *, - field_values : typing___Optional[typing___Iterable[GetOnlineFeaturesResponse.FieldValues]] = None, + field_values : typing___Optional[typing___Iterable[global___GetOnlineFeaturesResponse.FieldValues]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetOnlineFeaturesResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"field_values"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetOnlineFeaturesResponse: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"field_values",b"field_values"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetOnlineFeaturesResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"field_values",b"field_values"]) -> None: ... +global___GetOnlineFeaturesResponse = GetOnlineFeaturesResponse class GetBatchFeaturesResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @property - def job(self) -> Job: ... + def job(self) -> global___Job: ... def __init__(self, *, - job : typing___Optional[Job] = None, + job : typing___Optional[global___Job] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetBatchFeaturesResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetBatchFeaturesResponse: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetBatchFeaturesResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... +global___GetBatchFeaturesResponse = GetBatchFeaturesResponse class GetJobRequest(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @property - def job(self) -> Job: ... + def job(self) -> global___Job: ... def __init__(self, *, - job : typing___Optional[Job] = None, + job : typing___Optional[global___Job] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetJobRequest: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetJobRequest: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetJobRequest: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... +global___GetJobRequest = GetJobRequest class GetJobResponse(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @property - def job(self) -> Job: ... + def job(self) -> global___Job: ... def __init__(self, *, - job : typing___Optional[Job] = None, + job : typing___Optional[global___Job] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> GetJobResponse: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> GetJobResponse: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> GetJobResponse: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"job",b"job"]) -> None: ... +global___GetJobResponse = GetJobResponse class Job(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... id = ... # type: typing___Text - type = ... # type: JobType - status = ... # type: JobStatus + type = ... # type: global___JobType + status = ... # type: global___JobStatus error = ... # type: typing___Text file_uris = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[typing___Text] - data_format = ... # type: DataFormat + data_format = ... # type: global___DataFormat def __init__(self, *, id : typing___Optional[typing___Text] = None, - type : typing___Optional[JobType] = None, - status : typing___Optional[JobStatus] = None, + type : typing___Optional[global___JobType] = None, + status : typing___Optional[global___JobStatus] = None, error : typing___Optional[typing___Text] = None, file_uris : typing___Optional[typing___Iterable[typing___Text]] = None, - data_format : typing___Optional[DataFormat] = None, + data_format : typing___Optional[global___DataFormat] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Job: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"data_format",u"error",u"file_uris",u"id",u"status",u"type"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Job: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"data_format",b"data_format",u"error",b"error",u"file_uris",b"file_uris",u"id",b"id",u"status",b"status",u"type",b"type"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Job: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"data_format",b"data_format",u"error",b"error",u"file_uris",b"file_uris",u"id",b"id",u"status",b"status",u"type",b"type"]) -> None: ... +global___Job = Job class DatasetSource(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... class FileSource(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... file_uris = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[typing___Text] - data_format = ... # type: DataFormat + data_format = ... # type: global___DataFormat def __init__(self, *, file_uris : typing___Optional[typing___Iterable[typing___Text]] = None, - data_format : typing___Optional[DataFormat] = None, + data_format : typing___Optional[global___DataFormat] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> DatasetSource.FileSource: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"data_format",u"file_uris"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> DatasetSource.FileSource: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"data_format",b"data_format",u"file_uris",b"file_uris"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> DatasetSource.FileSource: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"data_format",b"data_format",u"file_uris",b"file_uris"]) -> None: ... + global___FileSource = FileSource @property - def file_source(self) -> DatasetSource.FileSource: ... + def file_source(self) -> global___DatasetSource.FileSource: ... def __init__(self, *, - file_source : typing___Optional[DatasetSource.FileSource] = None, + file_source : typing___Optional[global___DatasetSource.FileSource] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> DatasetSource: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"dataset_source",u"file_source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",u"file_source"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> DatasetSource: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"file_source",b"file_source"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"file_source",b"file_source"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> DatasetSource: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"file_source",b"file_source"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"dataset_source",b"dataset_source",u"file_source",b"file_source"]) -> None: ... def WhichOneof(self, oneof_group: typing_extensions___Literal[u"dataset_source",b"dataset_source"]) -> typing_extensions___Literal["file_source"]: ... +global___DatasetSource = DatasetSource diff --git a/sdk/python/feast/serving/ServingService_pb2_grpc.py b/sdk/python/feast/serving/ServingService_pb2_grpc.py index c73f9c744a6..1b83bd5c04d 100644 --- a/sdk/python/feast/serving/ServingService_pb2_grpc.py +++ b/sdk/python/feast/serving/ServingService_pb2_grpc.py @@ -5,100 +5,167 @@ class ServingServiceStub(object): - # missing associated documentation comment in .proto file - pass - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.GetFeastServingInfo = channel.unary_unary( - '/feast.serving.ServingService/GetFeastServingInfo', - request_serializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoRequest.SerializeToString, - response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoResponse.FromString, - ) - self.GetOnlineFeatures = channel.unary_unary( - '/feast.serving.ServingService/GetOnlineFeatures', - request_serializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesRequest.SerializeToString, - response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesResponse.FromString, - ) - self.GetBatchFeatures = channel.unary_unary( - '/feast.serving.ServingService/GetBatchFeatures', - request_serializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesRequest.SerializeToString, - response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesResponse.FromString, - ) - self.GetJob = channel.unary_unary( - '/feast.serving.ServingService/GetJob', - request_serializer=feast_dot_serving_dot_ServingService__pb2.GetJobRequest.SerializeToString, - response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetJobResponse.FromString, - ) + """Missing associated documentation comment in .proto file""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetFeastServingInfo = channel.unary_unary( + '/feast.serving.ServingService/GetFeastServingInfo', + request_serializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoRequest.SerializeToString, + response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoResponse.FromString, + ) + self.GetOnlineFeatures = channel.unary_unary( + '/feast.serving.ServingService/GetOnlineFeatures', + request_serializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesRequest.SerializeToString, + response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesResponse.FromString, + ) + self.GetBatchFeatures = channel.unary_unary( + '/feast.serving.ServingService/GetBatchFeatures', + request_serializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesRequest.SerializeToString, + response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesResponse.FromString, + ) + self.GetJob = channel.unary_unary( + '/feast.serving.ServingService/GetJob', + request_serializer=feast_dot_serving_dot_ServingService__pb2.GetJobRequest.SerializeToString, + response_deserializer=feast_dot_serving_dot_ServingService__pb2.GetJobResponse.FromString, + ) class ServingServiceServicer(object): - # missing associated documentation comment in .proto file - pass - - def GetFeastServingInfo(self, request, context): - """Get information about this Feast serving. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetOnlineFeatures(self, request, context): - """Get online features synchronously. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetBatchFeatures(self, request, context): - """Get batch features asynchronously. - - The client should check the status of the returned job periodically by - calling ReloadJob to determine if the job has completed successfully - or with an error. If the job completes successfully i.e. - status = JOB_STATUS_DONE with no error, then the client can check - the file_uris for the location to download feature values data. - The client is assumed to have access to these file URIs. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - def GetJob(self, request, context): - """Get the latest job status for batch feature retrieval. - """ - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') + """Missing associated documentation comment in .proto file""" + + def GetFeastServingInfo(self, request, context): + """Get information about this Feast serving. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetOnlineFeatures(self, request, context): + """Get online features synchronously. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetBatchFeatures(self, request, context): + """Get batch features asynchronously. + + The client should check the status of the returned job periodically by + calling ReloadJob to determine if the job has completed successfully + or with an error. If the job completes successfully i.e. + status = JOB_STATUS_DONE with no error, then the client can check + the file_uris for the location to download feature values data. + The client is assumed to have access to these file URIs. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetJob(self, request, context): + """Get the latest job status for batch feature retrieval. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') def add_ServingServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'GetFeastServingInfo': grpc.unary_unary_rpc_method_handler( - servicer.GetFeastServingInfo, - request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoRequest.FromString, - response_serializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoResponse.SerializeToString, - ), - 'GetOnlineFeatures': grpc.unary_unary_rpc_method_handler( - servicer.GetOnlineFeatures, - request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesRequest.FromString, - response_serializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesResponse.SerializeToString, - ), - 'GetBatchFeatures': grpc.unary_unary_rpc_method_handler( - servicer.GetBatchFeatures, - request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesRequest.FromString, - response_serializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesResponse.SerializeToString, - ), - 'GetJob': grpc.unary_unary_rpc_method_handler( - servicer.GetJob, - request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetJobRequest.FromString, - response_serializer=feast_dot_serving_dot_ServingService__pb2.GetJobResponse.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'feast.serving.ServingService', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) + rpc_method_handlers = { + 'GetFeastServingInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetFeastServingInfo, + request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoRequest.FromString, + response_serializer=feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoResponse.SerializeToString, + ), + 'GetOnlineFeatures': grpc.unary_unary_rpc_method_handler( + servicer.GetOnlineFeatures, + request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesRequest.FromString, + response_serializer=feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesResponse.SerializeToString, + ), + 'GetBatchFeatures': grpc.unary_unary_rpc_method_handler( + servicer.GetBatchFeatures, + request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesRequest.FromString, + response_serializer=feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesResponse.SerializeToString, + ), + 'GetJob': grpc.unary_unary_rpc_method_handler( + servicer.GetJob, + request_deserializer=feast_dot_serving_dot_ServingService__pb2.GetJobRequest.FromString, + response_serializer=feast_dot_serving_dot_ServingService__pb2.GetJobResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'feast.serving.ServingService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class ServingService(object): + """Missing associated documentation comment in .proto file""" + + @staticmethod + def GetFeastServingInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.serving.ServingService/GetFeastServingInfo', + feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoRequest.SerializeToString, + feast_dot_serving_dot_ServingService__pb2.GetFeastServingInfoResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetOnlineFeatures(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.serving.ServingService/GetOnlineFeatures', + feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesRequest.SerializeToString, + feast_dot_serving_dot_ServingService__pb2.GetOnlineFeaturesResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetBatchFeatures(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.serving.ServingService/GetBatchFeatures', + feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesRequest.SerializeToString, + feast_dot_serving_dot_ServingService__pb2.GetBatchFeaturesResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetJob(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/feast.serving.ServingService/GetJob', + feast_dot_serving_dot_ServingService__pb2.GetJobRequest.SerializeToString, + feast_dot_serving_dot_ServingService__pb2.GetJobResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/sdk/python/feast/storage/Redis_pb2.py b/sdk/python/feast/storage/Redis_pb2.py index 49b0b793781..2823225d749 100644 --- a/sdk/python/feast/storage/Redis_pb2.py +++ b/sdk/python/feast/storage/Redis_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/storage/Redis.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -20,8 +18,8 @@ name='feast/storage/Redis.proto', package='feast.storage', syntax='proto3', - serialized_options=_b('\n\rfeast.storageB\nRedisProtoZ2github.com/gojek/feast/sdk/go/protos/feast/storage'), - serialized_pb=_b('\n\x19\x66\x65\x61st/storage/Redis.proto\x12\rfeast.storage\x1a\x17\x66\x65\x61st/types/Field.proto\"E\n\x08RedisKey\x12\x13\n\x0b\x66\x65\x61ture_set\x18\x02 \x01(\t\x12$\n\x08\x65ntities\x18\x03 \x03(\x0b\x32\x12.feast.types.FieldBO\n\rfeast.storageB\nRedisProtoZ2github.com/gojek/feast/sdk/go/protos/feast/storageb\x06proto3') + serialized_options=b'\n\rfeast.storageB\nRedisProtoZ2github.com/gojek/feast/sdk/go/protos/feast/storage', + serialized_pb=b'\n\x19\x66\x65\x61st/storage/Redis.proto\x12\rfeast.storage\x1a\x17\x66\x65\x61st/types/Field.proto\"E\n\x08RedisKey\x12\x13\n\x0b\x66\x65\x61ture_set\x18\x02 \x01(\t\x12$\n\x08\x65ntities\x18\x03 \x03(\x0b\x32\x12.feast.types.FieldBO\n\rfeast.storageB\nRedisProtoZ2github.com/gojek/feast/sdk/go/protos/feast/storageb\x06proto3' , dependencies=[feast_dot_types_dot_Field__pb2.DESCRIPTOR,]) @@ -38,7 +36,7 @@ _descriptor.FieldDescriptor( name='feature_set', full_name='feast.storage.RedisKey.feature_set', index=0, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/storage/Redis_pb2.pyi b/sdk/python/feast/storage/Redis_pb2.pyi index 717aae79db2..4235978f55b 100644 --- a/sdk/python/feast/storage/Redis_pb2.pyi +++ b/sdk/python/feast/storage/Redis_pb2.pyi @@ -20,6 +20,7 @@ from typing import ( Iterable as typing___Iterable, Optional as typing___Optional, Text as typing___Text, + Union as typing___Union, ) from typing_extensions import ( @@ -27,6 +28,15 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class RedisKey(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... feature_set = ... # type: typing___Text @@ -39,11 +49,13 @@ class RedisKey(google___protobuf___message___Message): feature_set : typing___Optional[typing___Text] = None, entities : typing___Optional[typing___Iterable[feast___types___Field_pb2___Field]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> RedisKey: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"entities",u"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> RedisKey: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"entities",b"entities",u"feature_set",b"feature_set"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> RedisKey: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"entities",b"entities",u"feature_set",b"feature_set"]) -> None: ... +global___RedisKey = RedisKey diff --git a/sdk/python/feast/types/FeatureRowExtended_pb2.py b/sdk/python/feast/types/FeatureRowExtended_pb2.py index e7372958168..6634163339f 100644 --- a/sdk/python/feast/types/FeatureRowExtended_pb2.py +++ b/sdk/python/feast/types/FeatureRowExtended_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/types/FeatureRowExtended.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -21,8 +19,8 @@ name='feast/types/FeatureRowExtended.proto', package='feast.types', syntax='proto3', - serialized_options=_b('\n\013feast.typesB\027FeatureRowExtendedProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types'), - serialized_pb=_b('\n$feast/types/FeatureRowExtended.proto\x12\x0b\x66\x65\x61st.types\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1c\x66\x65\x61st/types/FeatureRow.proto\"O\n\x05\x45rror\x12\r\n\x05\x63\x61use\x18\x01 \x01(\t\x12\x11\n\ttransform\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x13\n\x0bstack_trace\x18\x04 \x01(\t\">\n\x07\x41ttempt\x12\x10\n\x08\x61ttempts\x18\x01 \x01(\x05\x12!\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x12.feast.types.Error\"\x96\x01\n\x12\x46\x65\x61tureRowExtended\x12$\n\x03row\x18\x01 \x01(\x0b\x32\x17.feast.types.FeatureRow\x12*\n\x0clast_attempt\x18\x02 \x01(\x0b\x32\x14.feast.types.Attempt\x12.\n\nfirst_seen\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampBX\n\x0b\x66\x65\x61st.typesB\x17\x46\x65\x61tureRowExtendedProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3') + serialized_options=b'\n\013feast.typesB\027FeatureRowExtendedProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types', + serialized_pb=b'\n$feast/types/FeatureRowExtended.proto\x12\x0b\x66\x65\x61st.types\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1c\x66\x65\x61st/types/FeatureRow.proto\"O\n\x05\x45rror\x12\r\n\x05\x63\x61use\x18\x01 \x01(\t\x12\x11\n\ttransform\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\x12\x13\n\x0bstack_trace\x18\x04 \x01(\t\">\n\x07\x41ttempt\x12\x10\n\x08\x61ttempts\x18\x01 \x01(\x05\x12!\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x12.feast.types.Error\"\x96\x01\n\x12\x46\x65\x61tureRowExtended\x12$\n\x03row\x18\x01 \x01(\x0b\x32\x17.feast.types.FeatureRow\x12*\n\x0clast_attempt\x18\x02 \x01(\x0b\x32\x14.feast.types.Attempt\x12.\n\nfirst_seen\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampBX\n\x0b\x66\x65\x61st.typesB\x17\x46\x65\x61tureRowExtendedProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3' , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,feast_dot_types_dot_FeatureRow__pb2.DESCRIPTOR,]) @@ -39,28 +37,28 @@ _descriptor.FieldDescriptor( name='cause', full_name='feast.types.Error.cause', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='transform', full_name='feast.types.Error.transform', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='message', full_name='feast.types.Error.message', index=2, number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='stack_trace', full_name='feast.types.Error.stack_trace', index=3, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/types/FeatureRowExtended_pb2.pyi b/sdk/python/feast/types/FeatureRowExtended_pb2.pyi index 4f3d02c8ee6..0e2599fa530 100644 --- a/sdk/python/feast/types/FeatureRowExtended_pb2.pyi +++ b/sdk/python/feast/types/FeatureRowExtended_pb2.pyi @@ -19,6 +19,7 @@ from google.protobuf.timestamp_pb2 import ( from typing import ( Optional as typing___Optional, Text as typing___Text, + Union as typing___Union, ) from typing_extensions import ( @@ -26,6 +27,15 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class Error(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... cause = ... # type: typing___Text @@ -40,37 +50,40 @@ class Error(google___protobuf___message___Message): message : typing___Optional[typing___Text] = None, stack_trace : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Error: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"cause",u"message",u"stack_trace",u"transform"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Error: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"cause",b"cause",u"message",b"message",u"stack_trace",b"stack_trace",u"transform",b"transform"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Error: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"cause",b"cause",u"message",b"message",u"stack_trace",b"stack_trace",u"transform",b"transform"]) -> None: ... +global___Error = Error class Attempt(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - attempts = ... # type: int + attempts = ... # type: builtin___int @property - def error(self) -> Error: ... + def error(self) -> global___Error: ... def __init__(self, *, - attempts : typing___Optional[int] = None, - error : typing___Optional[Error] = None, + attempts : typing___Optional[builtin___int] = None, + error : typing___Optional[global___Error] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Attempt: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"error"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"attempts",u"error"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Attempt: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"error",b"error"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"attempts",b"attempts",u"error",b"error"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Attempt: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"error",b"error"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"attempts",b"attempts",u"error",b"error"]) -> None: ... +global___Attempt = Attempt class FeatureRowExtended(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -79,7 +92,7 @@ class FeatureRowExtended(google___protobuf___message___Message): def row(self) -> feast___types___FeatureRow_pb2___FeatureRow: ... @property - def last_attempt(self) -> Attempt: ... + def last_attempt(self) -> global___Attempt: ... @property def first_seen(self) -> google___protobuf___timestamp_pb2___Timestamp: ... @@ -87,16 +100,17 @@ class FeatureRowExtended(google___protobuf___message___Message): def __init__(self, *, row : typing___Optional[feast___types___FeatureRow_pb2___FeatureRow] = None, - last_attempt : typing___Optional[Attempt] = None, + last_attempt : typing___Optional[global___Attempt] = None, first_seen : typing___Optional[google___protobuf___timestamp_pb2___Timestamp] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FeatureRowExtended: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"first_seen",u"last_attempt",u"row"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"first_seen",u"last_attempt",u"row"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureRowExtended: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"first_seen",b"first_seen",u"last_attempt",b"last_attempt",u"row",b"row"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"first_seen",b"first_seen",u"last_attempt",b"last_attempt",u"row",b"row"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureRowExtended: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"first_seen",b"first_seen",u"last_attempt",b"last_attempt",u"row",b"row"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"first_seen",b"first_seen",u"last_attempt",b"last_attempt",u"row",b"row"]) -> None: ... +global___FeatureRowExtended = FeatureRowExtended diff --git a/sdk/python/feast/types/FeatureRow_pb2.py b/sdk/python/feast/types/FeatureRow_pb2.py index 1b6c16910f2..ff5ac8a956d 100644 --- a/sdk/python/feast/types/FeatureRow_pb2.py +++ b/sdk/python/feast/types/FeatureRow_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/types/FeatureRow.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -21,8 +19,8 @@ name='feast/types/FeatureRow.proto', package='feast.types', syntax='proto3', - serialized_options=_b('\n\013feast.typesB\017FeatureRowProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types'), - serialized_pb=_b('\n\x1c\x66\x65\x61st/types/FeatureRow.proto\x12\x0b\x66\x65\x61st.types\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17\x66\x65\x61st/types/Field.proto\"z\n\nFeatureRow\x12\"\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x12.feast.types.Field\x12\x33\n\x0f\x65vent_timestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0b\x66\x65\x61ture_set\x18\x06 \x01(\tBP\n\x0b\x66\x65\x61st.typesB\x0f\x46\x65\x61tureRowProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3') + serialized_options=b'\n\013feast.typesB\017FeatureRowProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types', + serialized_pb=b'\n\x1c\x66\x65\x61st/types/FeatureRow.proto\x12\x0b\x66\x65\x61st.types\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17\x66\x65\x61st/types/Field.proto\"z\n\nFeatureRow\x12\"\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x12.feast.types.Field\x12\x33\n\x0f\x65vent_timestamp\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x13\n\x0b\x66\x65\x61ture_set\x18\x06 \x01(\tBP\n\x0b\x66\x65\x61st.typesB\x0f\x46\x65\x61tureRowProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3' , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,feast_dot_types_dot_Field__pb2.DESCRIPTOR,]) @@ -53,7 +51,7 @@ _descriptor.FieldDescriptor( name='feature_set', full_name='feast.types.FeatureRow.feature_set', index=2, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/types/FeatureRow_pb2.pyi b/sdk/python/feast/types/FeatureRow_pb2.pyi index 9bf745f9130..ca464c86d99 100644 --- a/sdk/python/feast/types/FeatureRow_pb2.pyi +++ b/sdk/python/feast/types/FeatureRow_pb2.pyi @@ -24,6 +24,7 @@ from typing import ( Iterable as typing___Iterable, Optional as typing___Optional, Text as typing___Text, + Union as typing___Union, ) from typing_extensions import ( @@ -31,6 +32,15 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class FeatureRow(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... feature_set = ... # type: typing___Text @@ -47,13 +57,14 @@ class FeatureRow(google___protobuf___message___Message): event_timestamp : typing___Optional[google___protobuf___timestamp_pb2___Timestamp] = None, feature_set : typing___Optional[typing___Text] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FeatureRow: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"event_timestamp"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"event_timestamp",u"feature_set",u"fields"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FeatureRow: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"event_timestamp",b"event_timestamp"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"event_timestamp",b"event_timestamp",u"feature_set",b"feature_set",u"fields",b"fields"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FeatureRow: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"event_timestamp",b"event_timestamp"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"event_timestamp",b"event_timestamp",u"feature_set",b"feature_set",u"fields",b"fields"]) -> None: ... +global___FeatureRow = FeatureRow diff --git a/sdk/python/feast/types/Field_pb2.py b/sdk/python/feast/types/Field_pb2.py index 95bcf38cf9d..67cee04f961 100644 --- a/sdk/python/feast/types/Field_pb2.py +++ b/sdk/python/feast/types/Field_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/types/Field.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -20,8 +18,8 @@ name='feast/types/Field.proto', package='feast.types', syntax='proto3', - serialized_options=_b('\n\013feast.typesB\nFieldProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types'), - serialized_pb=_b('\n\x17\x66\x65\x61st/types/Field.proto\x12\x0b\x66\x65\x61st.types\x1a\x17\x66\x65\x61st/types/Value.proto\"8\n\x05\x46ield\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.ValueBK\n\x0b\x66\x65\x61st.typesB\nFieldProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3') + serialized_options=b'\n\013feast.typesB\nFieldProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types', + serialized_pb=b'\n\x17\x66\x65\x61st/types/Field.proto\x12\x0b\x66\x65\x61st.types\x1a\x17\x66\x65\x61st/types/Value.proto\"8\n\x05\x46ield\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x05value\x18\x02 \x01(\x0b\x32\x12.feast.types.ValueBK\n\x0b\x66\x65\x61st.typesB\nFieldProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3' , dependencies=[feast_dot_types_dot_Value__pb2.DESCRIPTOR,]) @@ -38,7 +36,7 @@ _descriptor.FieldDescriptor( name='name', full_name='feast.types.Field.name', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/types/Field_pb2.pyi b/sdk/python/feast/types/Field_pb2.pyi index 1305503fab7..97239b00710 100644 --- a/sdk/python/feast/types/Field_pb2.pyi +++ b/sdk/python/feast/types/Field_pb2.pyi @@ -15,6 +15,7 @@ from google.protobuf.message import ( from typing import ( Optional as typing___Optional, Text as typing___Text, + Union as typing___Union, ) from typing_extensions import ( @@ -22,6 +23,15 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class Field(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... name = ... # type: typing___Text @@ -34,13 +44,14 @@ class Field(google___protobuf___message___Message): name : typing___Optional[typing___Text] = None, value : typing___Optional[feast___types___Value_pb2___Value] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Field: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"name",u"value"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Field: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"value",b"value"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Field: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"value",b"value"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"name",b"name",u"value",b"value"]) -> None: ... +global___Field = Field diff --git a/sdk/python/feast/types/Value_pb2.py b/sdk/python/feast/types/Value_pb2.py index fe2cd125ca5..7796c7e4161 100644 --- a/sdk/python/feast/types/Value_pb2.py +++ b/sdk/python/feast/types/Value_pb2.py @@ -2,8 +2,6 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # source: feast/types/Value.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -19,8 +17,8 @@ name='feast/types/Value.proto', package='feast.types', syntax='proto3', - serialized_options=_b('\n\013feast.typesB\nValueProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types'), - serialized_pb=_b('\n\x17\x66\x65\x61st/types/Value.proto\x12\x0b\x66\x65\x61st.types\"\xe0\x01\n\tValueType\"\xd2\x01\n\x04\x45num\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\n\n\x06STRING\x10\x02\x12\t\n\x05INT32\x10\x03\x12\t\n\x05INT64\x10\x04\x12\n\n\x06\x44OUBLE\x10\x05\x12\t\n\x05\x46LOAT\x10\x06\x12\x08\n\x04\x42OOL\x10\x07\x12\x0e\n\nBYTES_LIST\x10\x0b\x12\x0f\n\x0bSTRING_LIST\x10\x0c\x12\x0e\n\nINT32_LIST\x10\r\x12\x0e\n\nINT64_LIST\x10\x0e\x12\x0f\n\x0b\x44OUBLE_LIST\x10\x0f\x12\x0e\n\nFLOAT_LIST\x10\x10\x12\r\n\tBOOL_LIST\x10\x11\"\x82\x04\n\x05Value\x12\x13\n\tbytes_val\x18\x01 \x01(\x0cH\x00\x12\x14\n\nstring_val\x18\x02 \x01(\tH\x00\x12\x13\n\tint32_val\x18\x03 \x01(\x05H\x00\x12\x13\n\tint64_val\x18\x04 \x01(\x03H\x00\x12\x14\n\ndouble_val\x18\x05 \x01(\x01H\x00\x12\x13\n\tfloat_val\x18\x06 \x01(\x02H\x00\x12\x12\n\x08\x62ool_val\x18\x07 \x01(\x08H\x00\x12\x30\n\x0e\x62ytes_list_val\x18\x0b \x01(\x0b\x32\x16.feast.types.BytesListH\x00\x12\x32\n\x0fstring_list_val\x18\x0c \x01(\x0b\x32\x17.feast.types.StringListH\x00\x12\x30\n\x0eint32_list_val\x18\r \x01(\x0b\x32\x16.feast.types.Int32ListH\x00\x12\x30\n\x0eint64_list_val\x18\x0e \x01(\x0b\x32\x16.feast.types.Int64ListH\x00\x12\x32\n\x0f\x64ouble_list_val\x18\x0f \x01(\x0b\x32\x17.feast.types.DoubleListH\x00\x12\x30\n\x0e\x66loat_list_val\x18\x10 \x01(\x0b\x32\x16.feast.types.FloatListH\x00\x12.\n\rbool_list_val\x18\x11 \x01(\x0b\x32\x15.feast.types.BoolListH\x00\x42\x05\n\x03val\"\x18\n\tBytesList\x12\x0b\n\x03val\x18\x01 \x03(\x0c\"\x19\n\nStringList\x12\x0b\n\x03val\x18\x01 \x03(\t\"\x18\n\tInt32List\x12\x0b\n\x03val\x18\x01 \x03(\x05\"\x18\n\tInt64List\x12\x0b\n\x03val\x18\x01 \x03(\x03\"\x19\n\nDoubleList\x12\x0b\n\x03val\x18\x01 \x03(\x01\"\x18\n\tFloatList\x12\x0b\n\x03val\x18\x01 \x03(\x02\"\x17\n\x08\x42oolList\x12\x0b\n\x03val\x18\x01 \x03(\x08\x42K\n\x0b\x66\x65\x61st.typesB\nValueProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3') + serialized_options=b'\n\013feast.typesB\nValueProtoZ0github.com/gojek/feast/sdk/go/protos/feast/types', + serialized_pb=b'\n\x17\x66\x65\x61st/types/Value.proto\x12\x0b\x66\x65\x61st.types\"\xe0\x01\n\tValueType\"\xd2\x01\n\x04\x45num\x12\x0b\n\x07INVALID\x10\x00\x12\t\n\x05\x42YTES\x10\x01\x12\n\n\x06STRING\x10\x02\x12\t\n\x05INT32\x10\x03\x12\t\n\x05INT64\x10\x04\x12\n\n\x06\x44OUBLE\x10\x05\x12\t\n\x05\x46LOAT\x10\x06\x12\x08\n\x04\x42OOL\x10\x07\x12\x0e\n\nBYTES_LIST\x10\x0b\x12\x0f\n\x0bSTRING_LIST\x10\x0c\x12\x0e\n\nINT32_LIST\x10\r\x12\x0e\n\nINT64_LIST\x10\x0e\x12\x0f\n\x0b\x44OUBLE_LIST\x10\x0f\x12\x0e\n\nFLOAT_LIST\x10\x10\x12\r\n\tBOOL_LIST\x10\x11\"\x82\x04\n\x05Value\x12\x13\n\tbytes_val\x18\x01 \x01(\x0cH\x00\x12\x14\n\nstring_val\x18\x02 \x01(\tH\x00\x12\x13\n\tint32_val\x18\x03 \x01(\x05H\x00\x12\x13\n\tint64_val\x18\x04 \x01(\x03H\x00\x12\x14\n\ndouble_val\x18\x05 \x01(\x01H\x00\x12\x13\n\tfloat_val\x18\x06 \x01(\x02H\x00\x12\x12\n\x08\x62ool_val\x18\x07 \x01(\x08H\x00\x12\x30\n\x0e\x62ytes_list_val\x18\x0b \x01(\x0b\x32\x16.feast.types.BytesListH\x00\x12\x32\n\x0fstring_list_val\x18\x0c \x01(\x0b\x32\x17.feast.types.StringListH\x00\x12\x30\n\x0eint32_list_val\x18\r \x01(\x0b\x32\x16.feast.types.Int32ListH\x00\x12\x30\n\x0eint64_list_val\x18\x0e \x01(\x0b\x32\x16.feast.types.Int64ListH\x00\x12\x32\n\x0f\x64ouble_list_val\x18\x0f \x01(\x0b\x32\x17.feast.types.DoubleListH\x00\x12\x30\n\x0e\x66loat_list_val\x18\x10 \x01(\x0b\x32\x16.feast.types.FloatListH\x00\x12.\n\rbool_list_val\x18\x11 \x01(\x0b\x32\x15.feast.types.BoolListH\x00\x42\x05\n\x03val\"\x18\n\tBytesList\x12\x0b\n\x03val\x18\x01 \x03(\x0c\"\x19\n\nStringList\x12\x0b\n\x03val\x18\x01 \x03(\t\"\x18\n\tInt32List\x12\x0b\n\x03val\x18\x01 \x03(\x05\"\x18\n\tInt64List\x12\x0b\n\x03val\x18\x01 \x03(\x03\"\x19\n\nDoubleList\x12\x0b\n\x03val\x18\x01 \x03(\x01\"\x18\n\tFloatList\x12\x0b\n\x03val\x18\x01 \x03(\x02\"\x17\n\x08\x42oolList\x12\x0b\n\x03val\x18\x01 \x03(\x08\x42K\n\x0b\x66\x65\x61st.typesB\nValueProtoZ0github.com/gojek/feast/sdk/go/protos/feast/typesb\x06proto3' ) @@ -135,14 +133,14 @@ _descriptor.FieldDescriptor( name='bytes_val', full_name='feast.types.Value.bytes_val', index=0, number=1, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), + has_default_value=False, default_value=b"", message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='string_val', full_name='feast.types.Value.string_val', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), diff --git a/sdk/python/feast/types/Value_pb2.pyi b/sdk/python/feast/types/Value_pb2.pyi index d8b8a73dd36..9b8c450ca03 100644 --- a/sdk/python/feast/types/Value_pb2.pyi +++ b/sdk/python/feast/types/Value_pb2.pyi @@ -19,6 +19,7 @@ from typing import ( Optional as typing___Optional, Text as typing___Text, Tuple as typing___Tuple, + Union as typing___Union, cast as typing___cast, ) @@ -27,135 +28,154 @@ from typing_extensions import ( ) +builtin___bool = bool +builtin___bytes = bytes +builtin___float = float +builtin___int = int +builtin___str = str +if sys.version_info < (3,): + builtin___buffer = buffer + builtin___unicode = unicode + + class ValueType(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - class Enum(int): + class Enum(builtin___int): DESCRIPTOR: google___protobuf___descriptor___EnumDescriptor = ... @classmethod - def Name(cls, number: int) -> str: ... + def Name(cls, number: builtin___int) -> builtin___str: ... @classmethod - def Value(cls, name: str) -> ValueType.Enum: ... + def Value(cls, name: builtin___str) -> 'ValueType.Enum': ... @classmethod - def keys(cls) -> typing___List[str]: ... + def keys(cls) -> typing___List[builtin___str]: ... @classmethod - def values(cls) -> typing___List[ValueType.Enum]: ... + def values(cls) -> typing___List['ValueType.Enum']: ... @classmethod - def items(cls) -> typing___List[typing___Tuple[str, ValueType.Enum]]: ... - INVALID = typing___cast(ValueType.Enum, 0) - BYTES = typing___cast(ValueType.Enum, 1) - STRING = typing___cast(ValueType.Enum, 2) - INT32 = typing___cast(ValueType.Enum, 3) - INT64 = typing___cast(ValueType.Enum, 4) - DOUBLE = typing___cast(ValueType.Enum, 5) - FLOAT = typing___cast(ValueType.Enum, 6) - BOOL = typing___cast(ValueType.Enum, 7) - BYTES_LIST = typing___cast(ValueType.Enum, 11) - STRING_LIST = typing___cast(ValueType.Enum, 12) - INT32_LIST = typing___cast(ValueType.Enum, 13) - INT64_LIST = typing___cast(ValueType.Enum, 14) - DOUBLE_LIST = typing___cast(ValueType.Enum, 15) - FLOAT_LIST = typing___cast(ValueType.Enum, 16) - BOOL_LIST = typing___cast(ValueType.Enum, 17) - INVALID = typing___cast(ValueType.Enum, 0) - BYTES = typing___cast(ValueType.Enum, 1) - STRING = typing___cast(ValueType.Enum, 2) - INT32 = typing___cast(ValueType.Enum, 3) - INT64 = typing___cast(ValueType.Enum, 4) - DOUBLE = typing___cast(ValueType.Enum, 5) - FLOAT = typing___cast(ValueType.Enum, 6) - BOOL = typing___cast(ValueType.Enum, 7) - BYTES_LIST = typing___cast(ValueType.Enum, 11) - STRING_LIST = typing___cast(ValueType.Enum, 12) - INT32_LIST = typing___cast(ValueType.Enum, 13) - INT64_LIST = typing___cast(ValueType.Enum, 14) - DOUBLE_LIST = typing___cast(ValueType.Enum, 15) - FLOAT_LIST = typing___cast(ValueType.Enum, 16) - BOOL_LIST = typing___cast(ValueType.Enum, 17) + def items(cls) -> typing___List[typing___Tuple[builtin___str, 'ValueType.Enum']]: ... + INVALID = typing___cast('ValueType.Enum', 0) + BYTES = typing___cast('ValueType.Enum', 1) + STRING = typing___cast('ValueType.Enum', 2) + INT32 = typing___cast('ValueType.Enum', 3) + INT64 = typing___cast('ValueType.Enum', 4) + DOUBLE = typing___cast('ValueType.Enum', 5) + FLOAT = typing___cast('ValueType.Enum', 6) + BOOL = typing___cast('ValueType.Enum', 7) + BYTES_LIST = typing___cast('ValueType.Enum', 11) + STRING_LIST = typing___cast('ValueType.Enum', 12) + INT32_LIST = typing___cast('ValueType.Enum', 13) + INT64_LIST = typing___cast('ValueType.Enum', 14) + DOUBLE_LIST = typing___cast('ValueType.Enum', 15) + FLOAT_LIST = typing___cast('ValueType.Enum', 16) + BOOL_LIST = typing___cast('ValueType.Enum', 17) + INVALID = typing___cast('ValueType.Enum', 0) + BYTES = typing___cast('ValueType.Enum', 1) + STRING = typing___cast('ValueType.Enum', 2) + INT32 = typing___cast('ValueType.Enum', 3) + INT64 = typing___cast('ValueType.Enum', 4) + DOUBLE = typing___cast('ValueType.Enum', 5) + FLOAT = typing___cast('ValueType.Enum', 6) + BOOL = typing___cast('ValueType.Enum', 7) + BYTES_LIST = typing___cast('ValueType.Enum', 11) + STRING_LIST = typing___cast('ValueType.Enum', 12) + INT32_LIST = typing___cast('ValueType.Enum', 13) + INT64_LIST = typing___cast('ValueType.Enum', 14) + DOUBLE_LIST = typing___cast('ValueType.Enum', 15) + FLOAT_LIST = typing___cast('ValueType.Enum', 16) + BOOL_LIST = typing___cast('ValueType.Enum', 17) + global___Enum = Enum def __init__(self, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> ValueType: ... + if sys.version_info >= (3,): + @classmethod + def FromString(cls, s: builtin___bytes) -> ValueType: ... + else: + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> ValueType: ... def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... +global___ValueType = ValueType class Value(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - bytes_val = ... # type: bytes + bytes_val = ... # type: builtin___bytes string_val = ... # type: typing___Text - int32_val = ... # type: int - int64_val = ... # type: int - double_val = ... # type: float - float_val = ... # type: float - bool_val = ... # type: bool + int32_val = ... # type: builtin___int + int64_val = ... # type: builtin___int + double_val = ... # type: builtin___float + float_val = ... # type: builtin___float + bool_val = ... # type: builtin___bool @property - def bytes_list_val(self) -> BytesList: ... + def bytes_list_val(self) -> global___BytesList: ... @property - def string_list_val(self) -> StringList: ... + def string_list_val(self) -> global___StringList: ... @property - def int32_list_val(self) -> Int32List: ... + def int32_list_val(self) -> global___Int32List: ... @property - def int64_list_val(self) -> Int64List: ... + def int64_list_val(self) -> global___Int64List: ... @property - def double_list_val(self) -> DoubleList: ... + def double_list_val(self) -> global___DoubleList: ... @property - def float_list_val(self) -> FloatList: ... + def float_list_val(self) -> global___FloatList: ... @property - def bool_list_val(self) -> BoolList: ... + def bool_list_val(self) -> global___BoolList: ... def __init__(self, *, - bytes_val : typing___Optional[bytes] = None, + bytes_val : typing___Optional[builtin___bytes] = None, string_val : typing___Optional[typing___Text] = None, - int32_val : typing___Optional[int] = None, - int64_val : typing___Optional[int] = None, - double_val : typing___Optional[float] = None, - float_val : typing___Optional[float] = None, - bool_val : typing___Optional[bool] = None, - bytes_list_val : typing___Optional[BytesList] = None, - string_list_val : typing___Optional[StringList] = None, - int32_list_val : typing___Optional[Int32List] = None, - int64_list_val : typing___Optional[Int64List] = None, - double_list_val : typing___Optional[DoubleList] = None, - float_list_val : typing___Optional[FloatList] = None, - bool_list_val : typing___Optional[BoolList] = None, + int32_val : typing___Optional[builtin___int] = None, + int64_val : typing___Optional[builtin___int] = None, + double_val : typing___Optional[builtin___float] = None, + float_val : typing___Optional[builtin___float] = None, + bool_val : typing___Optional[builtin___bool] = None, + bytes_list_val : typing___Optional[global___BytesList] = None, + string_list_val : typing___Optional[global___StringList] = None, + int32_list_val : typing___Optional[global___Int32List] = None, + int64_list_val : typing___Optional[global___Int64List] = None, + double_list_val : typing___Optional[global___DoubleList] = None, + float_list_val : typing___Optional[global___FloatList] = None, + bool_list_val : typing___Optional[global___BoolList] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Value: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def HasField(self, field_name: typing_extensions___Literal[u"bool_list_val",u"bool_val",u"bytes_list_val",u"bytes_val",u"double_list_val",u"double_val",u"float_list_val",u"float_val",u"int32_list_val",u"int32_val",u"int64_list_val",u"int64_val",u"string_list_val",u"string_val",u"val"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"bool_list_val",u"bool_val",u"bytes_list_val",u"bytes_val",u"double_list_val",u"double_val",u"float_list_val",u"float_val",u"int32_list_val",u"int32_val",u"int64_list_val",u"int64_val",u"string_list_val",u"string_val",u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Value: ... else: - def HasField(self, field_name: typing_extensions___Literal[u"bool_list_val",b"bool_list_val",u"bool_val",b"bool_val",u"bytes_list_val",b"bytes_list_val",u"bytes_val",b"bytes_val",u"double_list_val",b"double_list_val",u"double_val",b"double_val",u"float_list_val",b"float_list_val",u"float_val",b"float_val",u"int32_list_val",b"int32_list_val",u"int32_val",b"int32_val",u"int64_list_val",b"int64_list_val",u"int64_val",b"int64_val",u"string_list_val",b"string_list_val",u"string_val",b"string_val",u"val",b"val"]) -> bool: ... - def ClearField(self, field_name: typing_extensions___Literal[u"bool_list_val",b"bool_list_val",u"bool_val",b"bool_val",u"bytes_list_val",b"bytes_list_val",u"bytes_val",b"bytes_val",u"double_list_val",b"double_list_val",u"double_val",b"double_val",u"float_list_val",b"float_list_val",u"float_val",b"float_val",u"int32_list_val",b"int32_list_val",u"int32_val",b"int32_val",u"int64_list_val",b"int64_list_val",u"int64_val",b"int64_val",u"string_list_val",b"string_list_val",u"string_val",b"string_val",u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Value: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def HasField(self, field_name: typing_extensions___Literal[u"bool_list_val",b"bool_list_val",u"bool_val",b"bool_val",u"bytes_list_val",b"bytes_list_val",u"bytes_val",b"bytes_val",u"double_list_val",b"double_list_val",u"double_val",b"double_val",u"float_list_val",b"float_list_val",u"float_val",b"float_val",u"int32_list_val",b"int32_list_val",u"int32_val",b"int32_val",u"int64_list_val",b"int64_list_val",u"int64_val",b"int64_val",u"string_list_val",b"string_list_val",u"string_val",b"string_val",u"val",b"val"]) -> builtin___bool: ... + def ClearField(self, field_name: typing_extensions___Literal[u"bool_list_val",b"bool_list_val",u"bool_val",b"bool_val",u"bytes_list_val",b"bytes_list_val",u"bytes_val",b"bytes_val",u"double_list_val",b"double_list_val",u"double_val",b"double_val",u"float_list_val",b"float_list_val",u"float_val",b"float_val",u"int32_list_val",b"int32_list_val",u"int32_val",b"int32_val",u"int64_list_val",b"int64_list_val",u"int64_val",b"int64_val",u"string_list_val",b"string_list_val",u"string_val",b"string_val",u"val",b"val"]) -> None: ... def WhichOneof(self, oneof_group: typing_extensions___Literal[u"val",b"val"]) -> typing_extensions___Literal["bytes_val","string_val","int32_val","int64_val","double_val","float_val","bool_val","bytes_list_val","string_list_val","int32_list_val","int64_list_val","double_list_val","float_list_val","bool_list_val"]: ... +global___Value = Value class BytesList(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[bytes] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___bytes] def __init__(self, *, - val : typing___Optional[typing___Iterable[bytes]] = None, + val : typing___Optional[typing___Iterable[builtin___bytes]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> BytesList: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> BytesList: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> BytesList: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___BytesList = BytesList class StringList(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... @@ -165,96 +185,108 @@ class StringList(google___protobuf___message___Message): *, val : typing___Optional[typing___Iterable[typing___Text]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> StringList: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> StringList: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> StringList: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___StringList = StringList class Int32List(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[int] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___int] def __init__(self, *, - val : typing___Optional[typing___Iterable[int]] = None, + val : typing___Optional[typing___Iterable[builtin___int]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Int32List: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Int32List: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Int32List: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___Int32List = Int32List class Int64List(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[int] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___int] def __init__(self, *, - val : typing___Optional[typing___Iterable[int]] = None, + val : typing___Optional[typing___Iterable[builtin___int]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> Int64List: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> Int64List: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Int64List: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___Int64List = Int64List class DoubleList(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[float] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___float] def __init__(self, *, - val : typing___Optional[typing___Iterable[float]] = None, + val : typing___Optional[typing___Iterable[builtin___float]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> DoubleList: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> DoubleList: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> DoubleList: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___DoubleList = DoubleList class FloatList(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[float] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___float] def __init__(self, *, - val : typing___Optional[typing___Iterable[float]] = None, + val : typing___Optional[typing___Iterable[builtin___float]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> FloatList: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> FloatList: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> FloatList: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___FloatList = FloatList class BoolList(google___protobuf___message___Message): DESCRIPTOR: google___protobuf___descriptor___Descriptor = ... - val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[bool] + val = ... # type: google___protobuf___internal___containers___RepeatedScalarFieldContainer[builtin___bool] def __init__(self, *, - val : typing___Optional[typing___Iterable[bool]] = None, + val : typing___Optional[typing___Iterable[builtin___bool]] = None, ) -> None: ... - @classmethod - def FromString(cls, s: bytes) -> BoolList: ... - def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... - def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... if sys.version_info >= (3,): - def ClearField(self, field_name: typing_extensions___Literal[u"val"]) -> None: ... + @classmethod + def FromString(cls, s: builtin___bytes) -> BoolList: ... else: - def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... + @classmethod + def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> BoolList: ... + def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ... + def ClearField(self, field_name: typing_extensions___Literal[u"val",b"val"]) -> None: ... +global___BoolList = BoolList diff --git a/sdk/python/tests/test_client.py b/sdk/python/tests/test_client.py index 9ef6e3d56fb..7826e78c691 100644 --- a/sdk/python/tests/test_client.py +++ b/sdk/python/tests/test_client.py @@ -357,7 +357,16 @@ def test_apply_feature_set_success(self, client): and feature_sets[0].name == "my-feature-set-1" and feature_sets[0].features[0].name == "fs1-my-feature-1" and feature_sets[0].features[0].dtype == ValueType.INT64 + and feature_sets[0].features[1].name == "fs1-my-feature-2" + and feature_sets[0].features[1].dtype == ValueType.STRING + and feature_sets[0].entities[0].name == "fs1-my-entity-1" + and feature_sets[0].entities[0].dtype == ValueType.INT64 + and feature_sets[1].features[0].name == "fs2-my-feature-1" + and feature_sets[1].features[0].dtype == ValueType.STRING_LIST + and feature_sets[1].features[1].name == "fs2-my-feature-2" and feature_sets[1].features[1].dtype == ValueType.BYTES_LIST + and feature_sets[1].entities[0].name == "fs2-my-entity-1" + and feature_sets[1].entities[0].dtype == ValueType.INT64 ) @pytest.mark.parametrize("dataframe", [dataframes.GOOD]) diff --git a/tests/e2e/basic-ingest-redis-serving.py b/tests/e2e/basic-ingest-redis-serving.py index 902b0985c14..c7d8c9da092 100644 --- a/tests/e2e/basic-ingest-redis-serving.py +++ b/tests/e2e/basic-ingest-redis-serving.py @@ -2,11 +2,14 @@ import math import random import time +import grpc from feast.entity import Entity from feast.serving.ServingService_pb2 import ( GetOnlineFeaturesRequest, GetOnlineFeaturesResponse, ) +from feast.core.CoreService_pb2_grpc import CoreServiceStub +from feast.core import CoreService_pb2 from feast.types.Value_pb2 import Value as Value from feast.client import Client from feast.feature_set import FeatureSet @@ -140,9 +143,9 @@ def test_basic_retrieve_online_success(client, basic_dataframe): basic_dataframe.iloc[0]["daily_transactions"]) if math.isclose( - sent_daily_transactions, - returned_daily_transactions, - abs_tol=FLOAT_TOLERANCE, + sent_daily_transactions, + returned_daily_transactions, + abs_tol=FLOAT_TOLERANCE, ): break @@ -299,7 +302,7 @@ def test_all_types_retrieve_online_success(client, all_types_dataframe): sent_float_list = all_types_dataframe.iloc[0]["float_list_feature"] if math.isclose( - returned_float_list[0], sent_float_list[0], abs_tol=FLOAT_TOLERANCE + returned_float_list[0], sent_float_list[0], abs_tol=FLOAT_TOLERANCE ): break @@ -394,9 +397,9 @@ def test_large_volume_retrieve_online_success(client, large_volume_dataframe): large_volume_dataframe.iloc[0]["daily_transactions"]) if math.isclose( - sent_daily_transactions, - returned_daily_transactions, - abs_tol=FLOAT_TOLERANCE, + sent_daily_transactions, + returned_daily_transactions, + abs_tol=FLOAT_TOLERANCE, ): break @@ -489,10 +492,86 @@ def test_all_types_parquet_register_feature_set_success(client): @pytest.mark.timeout(600) @pytest.mark.run(order=41) def test_all_types_infer_register_ingest_file_success(client, - all_types_parquet_file): + all_types_parquet_file): # Get feature set all_types_fs = client.get_feature_set(name="all_types_parquet") # Ingest user embedding data client.ingest(feature_set=all_types_fs, source=all_types_parquet_file, force_update=True) + + +# TODO: rewrite these using python SDK once the labels are implemented there +class TestsBasedOnGrpc: + LAST_VERSION = 0 + GRPC_CONNECTION_TIMEOUT = 3 + LABEL_KEY = "my" + LABEL_VALUE = "label" + + @pytest.fixture(scope="module") + def core_service_stub(self, core_url): + if core_url.endswith(":443"): + core_channel = grpc.secure_channel( + core_url, grpc.ssl_channel_credentials() + ) + else: + core_channel = grpc.insecure_channel(core_url) + + try: + grpc.channel_ready_future(core_channel).result(timeout=self.GRPC_CONNECTION_TIMEOUT) + except grpc.FutureTimeoutError: + raise ConnectionError( + f"Connection timed out while attempting to connect to Feast " + f"Core gRPC server {core_url} " + ) + core_service_stub = CoreServiceStub(core_channel) + return core_service_stub + + def apply_feature_set(self, core_service_stub, feature_set_proto): + try: + apply_fs_response = core_service_stub.ApplyFeatureSet( + CoreService_pb2.ApplyFeatureSetRequest(feature_set=feature_set_proto), + timeout=self.GRPC_CONNECTION_TIMEOUT, + ) # type: ApplyFeatureSetResponse + except grpc.RpcError as e: + raise grpc.RpcError(e.details()) + return apply_fs_response.feature_set + + def get_feature_set(self, core_service_stub, name): + try: + get_feature_set_response = core_service_stub.GetFeatureSet( + CoreService_pb2.GetFeatureSetRequest( + name=name.strip(), version=self.LAST_VERSION + ) + ) # type: GetFeatureSetResponse + except grpc.RpcError as e: + raise grpc.RpcError(e.details()) + return get_feature_set_response.feature_set + + @pytest.mark.timeout(45) + @pytest.mark.run(order=51) + def test_register_feature_set_with_labels(self, core_service_stub): + feature_set_name = "test_feature_set_labels" + feature_set_proto = FeatureSet(feature_set_name).to_proto() + feature_set_proto.labels[self.LABEL_KEY] = self.LABEL_VALUE + self.apply_feature_set(core_service_stub, feature_set_proto) + + retrieved_feature_set = self.get_feature_set(core_service_stub, feature_set_name) + + assert self.LABEL_KEY in retrieved_feature_set.labels + assert retrieved_feature_set.labels[self.LABEL_KEY] == self.LABEL_VALUE + + @pytest.mark.timeout(45) + @pytest.mark.run(order=52) + def test_register_feature_with_labels(self, core_service_stub): + feature_set_name = "test_feature_labels" + feature_set_proto = FeatureSet(feature_set_name, features=[Feature("rating", ValueType.INT64)]) \ + .to_proto() + feature_set_proto.features[0].labels[self.LABEL_KEY] = self.LABEL_VALUE + self.apply_feature_set(core_service_stub, feature_set_proto) + + retrieved_feature_set = self.get_feature_set(core_service_stub, feature_set_name) + retrieved_feature = retrieved_feature_set.features[0] + + assert self.LABEL_KEY in retrieved_feature.labels + assert retrieved_feature.labels[self.LABEL_KEY] == self.LABEL_VALUE From b5172251d5577df0f0b59df1f2da63fedde4d975 Mon Sep 17 00:00:00 2001 From: Willem Pienaar Date: Sun, 24 May 2020 02:27:12 +0000 Subject: [PATCH 5/6] GitBook: [v0.3-branch] 5 pages and 10 assets modified --- docs/.gitbook/assets/architecture.png | Bin 0 -> 24680 bytes .../assets/basic-architecture-diagram (2).svg | 1 + .../assets/basic-architecture-diagram (3).svg | 1 + docs/.gitbook/assets/blank-diagram-4.svg | 1 + .../feast-docs-overview-diagram-2 (2).svg | 1 + .../feast-docs-overview-diagram-2 (3).svg | 1 + docs/.gitbook/assets/image (1).png | Bin 0 -> 56975 bytes docs/.gitbook/assets/image (2).png | Bin 0 -> 149255 bytes docs/.gitbook/assets/image (3).png | Bin 0 -> 17434 bytes docs/.gitbook/assets/image.png | Bin 0 -> 13935 bytes docs/README.md | 2 +- docs/concepts.md | 2 +- docs/getting-started/installing-feast.md | 2 +- 13 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 docs/.gitbook/assets/architecture.png create mode 100644 docs/.gitbook/assets/basic-architecture-diagram (2).svg create mode 100644 docs/.gitbook/assets/basic-architecture-diagram (3).svg create mode 100644 docs/.gitbook/assets/blank-diagram-4.svg create mode 100644 docs/.gitbook/assets/feast-docs-overview-diagram-2 (2).svg create mode 100644 docs/.gitbook/assets/feast-docs-overview-diagram-2 (3).svg create mode 100644 docs/.gitbook/assets/image (1).png create mode 100644 docs/.gitbook/assets/image (2).png create mode 100644 docs/.gitbook/assets/image (3).png create mode 100644 docs/.gitbook/assets/image.png diff --git a/docs/.gitbook/assets/architecture.png b/docs/.gitbook/assets/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..bc655b60f327b7d7d508885666064e0c713522b5 GIT binary patch literal 24680 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 U{S>BsDu7N?9j;cUYWeKH07gwlNdN!< literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/basic-architecture-diagram (2).svg b/docs/.gitbook/assets/basic-architecture-diagram (2).svg new file mode 100644 index 00000000000..b707f490461 --- /dev/null +++ b/docs/.gitbook/assets/basic-architecture-diagram (2).svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/.gitbook/assets/basic-architecture-diagram (3).svg b/docs/.gitbook/assets/basic-architecture-diagram (3).svg new file mode 100644 index 00000000000..b707f490461 --- /dev/null +++ b/docs/.gitbook/assets/basic-architecture-diagram (3).svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/.gitbook/assets/blank-diagram-4.svg b/docs/.gitbook/assets/blank-diagram-4.svg new file mode 100644 index 00000000000..fb5e0659e55 --- /dev/null +++ b/docs/.gitbook/assets/blank-diagram-4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/.gitbook/assets/feast-docs-overview-diagram-2 (2).svg b/docs/.gitbook/assets/feast-docs-overview-diagram-2 (2).svg new file mode 100644 index 00000000000..7f30963ec78 --- /dev/null +++ b/docs/.gitbook/assets/feast-docs-overview-diagram-2 (2).svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/.gitbook/assets/feast-docs-overview-diagram-2 (3).svg b/docs/.gitbook/assets/feast-docs-overview-diagram-2 (3).svg new file mode 100644 index 00000000000..7f30963ec78 --- /dev/null +++ b/docs/.gitbook/assets/feast-docs-overview-diagram-2 (3).svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/.gitbook/assets/image (1).png b/docs/.gitbook/assets/image (1).png new file mode 100644 index 0000000000000000000000000000000000000000..090fdabf79221bb802f2d724874590b9e1e97ee4 GIT binary patch literal 56975 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
    HucQ~yybg_<9o2&s}4B+LU|xAG9O}*j1>WG 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/image (3).png b/docs/.gitbook/assets/image (3).png new file mode 100644 index 0000000000000000000000000000000000000000..2442410112fc9413bf4969dddf296cb06f201d3a GIT binary patch literal 17434 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 literal 0 HcmV?d00001 diff --git a/docs/.gitbook/assets/image.png b/docs/.gitbook/assets/image.png new file mode 100644 index 0000000000000000000000000000000000000000..273924d8cdbdcc1e0fd5993210d6e2bf1e0ea33f GIT binary patch literal 13935 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 MJG!@IkLQ*D0tJl&Q2+n{ literal 0 HcmV?d00001 diff --git a/docs/README.md b/docs/README.md index 76790929af1..ae9dbee8907 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ Feast aims to: * Provide consistent and point-in-time correct access to feature data. * Enable discovery, documentation, and insights into your features. -![](.gitbook/assets/feast-docs-overview-diagram-2.svg) +![](.gitbook/assets/feast-docs-overview-diagram-2%20%283%29.svg) **TL;DR:** Feast decouples feature engineering from feature usage. Features that are added to Feast become available immediately for training and serving. Models can retrieve the same features used in training from a low latency online store in production. diff --git a/docs/concepts.md b/docs/concepts.md index 5d15e28ba1f..ef7199080f4 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -2,7 +2,7 @@ ## Architecture -![Logical diagram of a typical Feast deployment](.gitbook/assets/basic-architecture-diagram.svg) +![Logical diagram of a typical Feast deployment](.gitbook/assets/basic-architecture-diagram%20%283%29.svg) The core components of a Feast deployment are diff --git a/docs/getting-started/installing-feast.md b/docs/getting-started/installing-feast.md index a88c3e547e9..92e061e7187 100644 --- a/docs/getting-started/installing-feast.md +++ b/docs/getting-started/installing-feast.md @@ -12,7 +12,7 @@ This installation guide will demonstrate three ways of installing Feast: ### Overview -A docker compose file is provided to quickly test Feast with the official docker images. There is no hard dependency on GCP, unless batch serving is required. +A docker compose file is provided to quickly test Feast with the official docker images. There is no hard dependency on GCP, unless batch serving is required. * Define and register feature set * Feature ingestion From 64852e26fd3d4cf342eb8c69b22724ea106cbabe Mon Sep 17 00:00:00 2001 From: Ches Martin Date: Wed, 10 Jun 2020 13:51:15 +0700 Subject: [PATCH 6/6] Release v0.3.8 --- CHANGELOG.md | 12 ++++++++++++ infra/charts/feast/Chart.yaml | 2 +- infra/charts/feast/README.md | 12 ++++++------ infra/charts/feast/charts/feast-core/Chart.yaml | 2 +- infra/charts/feast/charts/feast-serving/Chart.yaml | 2 +- infra/charts/feast/requirements.lock | 6 +++--- infra/charts/feast/requirements.yaml | 6 +++--- pom.xml | 2 +- 8 files changed, 28 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f936e6481..b4766d27753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [v0.3.8](https://github.com/feast-dev/feast/tree/v0.3.8) (2020-06-10) + +[Full Changelog](https://github.com/feast-dev/feast/compare/v0.3.7...v0.3.8) + +**Implemented enhancements:** + +- v0.3 backport: Add feature and feature set labels [\#737](https://github.com/feast-dev/feast/pull/737) ([ches](https://github.com/ches)) + +**Merged pull requests:** + +- v0.3 backport: Add Java coverage reporting [\#734](https://github.com/feast-dev/feast/pull/734) ([ches](https://github.com/ches)) + ## [v0.3.7](https://github.com/gojek/feast/tree/v0.3.7) (2020-05-01) [Full Changelog](https://github.com/gojek/feast/compare/v0.3.6...v0.3.7) diff --git a/infra/charts/feast/Chart.yaml b/infra/charts/feast/Chart.yaml index 80d17aeb6ba..49b6a590d85 100644 --- a/infra/charts/feast/Chart.yaml +++ b/infra/charts/feast/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 description: A Helm chart to install Feast on kubernetes name: feast -version: 0.3.2 +version: 0.3.8 diff --git a/infra/charts/feast/README.md b/infra/charts/feast/README.md index 0463a9a3f89..6e60202ef9a 100644 --- a/infra/charts/feast/README.md +++ b/infra/charts/feast/README.md @@ -39,7 +39,7 @@ helm repo update Install Feast release with minimal features, without batch serving and persistency: ```bash RELEASE_NAME=demo -helm install feast-charts/feast --name $RELEASE_NAME --version 0.3.2 -f values-demo.yaml +helm install feast-charts/feast --name $RELEASE_NAME --version 0.3.8 -f values-demo.yaml ``` Install Feast release for typical use cases, with batch and online serving: @@ -60,7 +60,7 @@ PROJECT_ID=google-cloud-project-id DATASET_ID=bigquery-dataset-id # Install the Helm release using default values.yaml -helm install feast-charts/feast --name feast --version 0.3.2 \ +helm install feast-charts/feast --name feast --version 0.3.8 \ --set feast-serving-batch."application\.yaml".feast.jobs.staging-location=$STAGING_LOCATION \ --set feast-serving-batch."store\.yaml".bigquery_config.project_id=$PROJECT_ID \ --set feast-serving-batch."store\.yaml".bigquery_config.dataset_id=$DATASET_ID @@ -83,7 +83,7 @@ The following table lists the configurable parameters of the Feast chart and the | `feast-core.kafka.topics[0].partitions` | No of partitions for the topic | `1` | `feast-core.replicaCount` | No of pods to create | `1` | `feast-core.image.repository` | Repository for Feast Core Docker image | `gcr.io/kf-feast/feast-core` -| `feast-core.image.tag` | Tag for Feast Core Docker image | `0.3.2` +| `feast-core.image.tag` | Tag for Feast Core Docker image | `0.3.8` | `feast-core.image.pullPolicy` | Image pull policy for Feast Core Docker image | `IfNotPresent` | `feast-core.application.yaml` | Configuration for Feast Core application | Refer to this [link](charts/feast-core/values.yaml) | `feast-core.springConfigMountPath` | Directory to mount application.yaml | `/etc/feast/feast-core` @@ -116,7 +116,7 @@ The following table lists the configurable parameters of the Feast chart and the | `feast-serving-online.core.enabled` | Flag for Feast Serving to use Feast Core in the same Helm release | `true` | `feast-serving-online.replicaCount` | No of pods to create | `1` | `feast-serving-online.image.repository` | Repository for Feast Serving Docker image | `gcr.io/kf-feast/feast-serving` -| `feast-serving-online.image.tag` | Tag for Feast Serving Docker image | `0.3.2` +| `feast-serving-online.image.tag` | Tag for Feast Serving Docker image | `0.3.8` | `feast-serving-online.image.pullPolicy` | Image pull policy for Feast Serving Docker image | `IfNotPresent` | `feast-serving-online.application.yaml` | Application configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) | `feast-serving-online.store.yaml` | Store configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) @@ -150,7 +150,7 @@ The following table lists the configurable parameters of the Feast chart and the | `feast-serving-batch.core.enabled` | Flag for Feast Serving to use Feast Core in the same Helm release | `true` | `feast-serving-batch.replicaCount` | No of pods to create | `1` | `feast-serving-batch.image.repository` | Repository for Feast Serving Docker image | `gcr.io/kf-feast/feast-serving` -| `feast-serving-batch.image.tag` | Tag for Feast Serving Docker image | `0.3.2` +| `feast-serving-batch.image.tag` | Tag for Feast Serving Docker image | `0.3.8` | `feast-serving-batch.image.pullPolicy` | Image pull policy for Feast Serving Docker image | `IfNotPresent` | `feast-serving-batch.application.yaml` | Application configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) | `feast-serving-batch.store.yaml` | Store configuration for Feast Serving | Refer to this [link](charts/feast-serving/values.yaml) @@ -176,4 +176,4 @@ The following table lists the configurable parameters of the Feast chart and the | `feast-serving-batch.http.targetPort` | Container port for HTTP request | `8080` | `feast-serving-batch.grpc.port` | Kubernetes Service port for GRPC request| `6566` | `feast-serving-batch.grpc.targetPort` | Container port for GRPC request| `6566` -| `feast-serving-batch.resources` | CPU and memory allocation for the pod | `{}` \ No newline at end of file +| `feast-serving-batch.resources` | CPU and memory allocation for the pod | `{}` diff --git a/infra/charts/feast/charts/feast-core/Chart.yaml b/infra/charts/feast/charts/feast-core/Chart.yaml index efda76d3026..a61e9a6f5cf 100644 --- a/infra/charts/feast/charts/feast-core/Chart.yaml +++ b/infra/charts/feast/charts/feast-core/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 description: A Helm chart for core component of Feast name: feast-core -version: 0.3.2 +version: 0.3.8 diff --git a/infra/charts/feast/charts/feast-serving/Chart.yaml b/infra/charts/feast/charts/feast-serving/Chart.yaml index 8486275d94f..af626473d93 100644 --- a/infra/charts/feast/charts/feast-serving/Chart.yaml +++ b/infra/charts/feast/charts/feast-serving/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v1 description: A Helm chart for serving component of Feast name: feast-serving -version: 0.3.2 +version: 0.3.8 diff --git a/infra/charts/feast/requirements.lock b/infra/charts/feast/requirements.lock index 8afd9521573..8f8bc96bfc8 100644 --- a/infra/charts/feast/requirements.lock +++ b/infra/charts/feast/requirements.lock @@ -1,12 +1,12 @@ dependencies: - name: feast-core repository: "" - version: 0.3.2 + version: 0.3.8 - name: feast-serving repository: "" - version: 0.3.2 + version: 0.3.8 - name: feast-serving repository: "" - version: 0.3.2 + version: 0.3.8 digest: sha256:7ee4cd271cbd4ace44817dd12ba65f490a8e3529adf199604a2c2bdad9c2fac3 generated: "2019-11-27T13:35:41.334054+08:00" diff --git a/infra/charts/feast/requirements.yaml b/infra/charts/feast/requirements.yaml index ed280d64b6e..d665dca5586 100644 --- a/infra/charts/feast/requirements.yaml +++ b/infra/charts/feast/requirements.yaml @@ -1,12 +1,12 @@ dependencies: - name: feast-core - version: 0.3.2 + version: 0.3.8 condition: feast-core.enabled - name: feast-serving alias: feast-serving-batch - version: 0.3.2 + version: 0.3.8 condition: feast-serving-batch.enabled - name: feast-serving alias: feast-serving-online - version: 0.3.2 + version: 0.3.8 condition: feast-serving-online.enabled diff --git a/pom.xml b/pom.xml index b5eaee0d281..f9e7ede68c1 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ - 0.3.8-SNAPSHOT + 0.3.8 https://github.com/gojek/feast UTF-8