diff --git a/Makefile.am b/Makefile.am
index 82ce190dec..e4dce6e5b2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -505,6 +505,7 @@ python_EXTRA_DIST= \
python/google/protobuf/internal/factory_test1.proto \
python/google/protobuf/internal/factory_test2.proto \
python/google/protobuf/internal/generator_test.py \
+ python/google/protobuf/internal/json_format_test.py \
python/google/protobuf/internal/message_factory_test.py \
python/google/protobuf/internal/message_listener.py \
python/google/protobuf/internal/message_set_extensions.proto \
@@ -560,6 +561,7 @@ python_EXTRA_DIST= \
python/google/protobuf/descriptor.py \
python/google/protobuf/descriptor_database.py \
python/google/protobuf/descriptor_pool.py \
+ python/google/protobuf/json_format.py \
python/google/protobuf/message.py \
python/google/protobuf/message_factory.py \
python/google/protobuf/proto_builder.py \
diff --git a/appveyor.yml b/appveyor.yml
index 3447602e31..c84ecae2f3 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,32 +1,32 @@
-# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can
-# test more combinations but AppVeyor just takes too long to finish (each
-# combination takes ~15mins).
-platform:
- - Win64
-
-configuration:
- - Debug
-
-environment:
- matrix:
- - language: cpp
- BUILD_DLL: ON
-
- - language: csharp
-
-install:
- - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip
- - 7z x gmock-1.7.0.zip
- - rename gmock-1.7.0 gmock
-
-before_build:
- - if %platform%==Win32 set generator=Visual Studio 12
- - if %platform%==Win64 set generator=Visual Studio 12 Win64
- - if %platform%==Win32 set vcplatform=Win32
- - if %platform%==Win64 set vcplatform=x64
-
-build_script:
- - CALL appveyor.bat
-
-skip_commits:
- message: /.*\[skip appveyor\].*/
+# Only test one combination: "Visual Studio 12 + Win64 + Debug + DLL". We can
+# test more combinations but AppVeyor just takes too long to finish (each
+# combination takes ~15mins).
+platform:
+ - Win64
+
+configuration:
+ - Debug
+
+environment:
+ matrix:
+ - language: cpp
+ BUILD_DLL: ON
+
+ - language: csharp
+
+install:
+ - ps: Start-FileDownload https://googlemock.googlecode.com/files/gmock-1.7.0.zip
+ - 7z x gmock-1.7.0.zip
+ - rename gmock-1.7.0 gmock
+
+before_build:
+ - if %platform%==Win32 set generator=Visual Studio 12
+ - if %platform%==Win64 set generator=Visual Studio 12 Win64
+ - if %platform%==Win32 set vcplatform=Win32
+ - if %platform%==Win64 set vcplatform=x64
+
+build_script:
+ - CALL appveyor.bat
+
+skip_commits:
+ message: /.*\[skip appveyor\].*/
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index a535b71833..4316efeef5 100644
--- a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -62,9 +62,8 @@ public abstract class GeneratedMessageLite<
private static final long serialVersionUID = 1L;
- /** For use by generated code only. */
- protected UnknownFieldSetLite unknownFields =
- UnknownFieldSetLite.getDefaultInstance();
+ /** For use by generated code only. Lazily initialized to reduce allocations. */
+ protected UnknownFieldSetLite unknownFields = null;
/** For use by generated code only. */
protected int memoizedSerializedSize = -1;
@@ -84,19 +83,56 @@ public abstract class GeneratedMessageLite<
return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER);
}
+ // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
+ // mutable during the parsing constructor and immutable after. This allows us to avoid
+ // any unnecessary intermediary allocations while reducing the generated code size.
+
+ /**
+ * Lazily initializes unknown fields.
+ */
+ private final void ensureUnknownFieldsInitialized() {
+ if (unknownFields == null) {
+ unknownFields = UnknownFieldSetLite.newInstance();
+ }
+ }
+
/**
- * Called by subclasses to parse an unknown field. For use by generated code
- * only.
+ * Called by subclasses to parse an unknown field. For use by generated code only.
+ *
* @return {@code true} unless the tag is an end-group tag.
*/
- protected static boolean parseUnknownField(
- CodedInputStream input,
- UnknownFieldSetLite.Builder unknownFields,
- ExtensionRegistryLite extensionRegistry,
- int tag) throws IOException {
+ protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
+ ensureUnknownFieldsInitialized();
return unknownFields.mergeFieldFrom(tag, input);
}
+ /**
+ * Called by subclasses to parse an unknown field. For use by generated code only.
+ */
+ protected void mergeVarintField(int tag, int value) {
+ ensureUnknownFieldsInitialized();
+ unknownFields.mergeVarintField(tag, value);
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field. For use by generated code only.
+ */
+ protected void mergeLengthDelimitedField(int fieldNumber, ByteString value) {
+ ensureUnknownFieldsInitialized();
+ unknownFields.mergeLengthDelimitedField(fieldNumber, value);
+ }
+
+ /**
+ * Called by subclasses to complete parsing. For use by generated code only.
+ */
+ protected void doneParsing() {
+ if (unknownFields == null) {
+ unknownFields = UnknownFieldSetLite.getDefaultInstance();
+ } else {
+ unknownFields.makeImmutable();
+ }
+ }
+
public final boolean isInitialized() {
return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null;
}
@@ -171,7 +207,7 @@ public abstract class GeneratedMessageLite<
*
For use by generated code only.
*/
protected final void mergeUnknownFields(UnknownFieldSetLite unknownFields) {
- this.unknownFields = UnknownFieldSetLite.concat(this.unknownFields, unknownFields);
+ this.unknownFields = UnknownFieldSetLite.mutableCopyOf(this.unknownFields, unknownFields);
}
@SuppressWarnings("unchecked")
@@ -225,7 +261,13 @@ public abstract class GeneratedMessageLite<
//@Override (Java 1.6 override semantics, but we must support 1.5)
public MessageType buildPartial() {
+ if (isBuilt) {
+ return instance;
+ }
+
instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
+ instance.unknownFields.makeImmutable();
+
isBuilt = true;
return instance;
}
@@ -249,18 +291,6 @@ public abstract class GeneratedMessageLite<
public MessageType getDefaultInstanceForType() {
return defaultInstance;
}
-
- /**
- * Called by subclasses to parse an unknown field.
- * @return {@code true} unless the tag is an end-group tag.
- */
- protected boolean parseUnknownField(
- CodedInputStream input,
- UnknownFieldSetLite.Builder unknownFields,
- ExtensionRegistryLite extensionRegistry,
- int tag) throws IOException {
- return unknownFields.mergeFieldFrom(tag, input);
- }
public BuilderType mergeFrom(
com.google.protobuf.CodedInputStream input,
@@ -334,6 +364,130 @@ public abstract class GeneratedMessageLite<
extensions.mergeFrom(((ExtendableMessage) other).extensions);
}
+ /**
+ * Parse an unknown field or an extension. For use by generated code only.
+ *
+ *
For use by generated code only.
+ *
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(
+ MessageType defaultInstance,
+ CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry,
+ int tag) throws IOException {
+ int wireType = WireFormat.getTagWireType(tag);
+ int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ // TODO(dweis): How much bytecode would be saved by not requiring the generated code to
+ // provide the default instance?
+ GeneratedExtension extension = extensionRegistry.findLiteExtensionByNumber(
+ defaultInstance, fieldNumber);
+
+ boolean unknown = false;
+ boolean packed = false;
+ if (extension == null) {
+ unknown = true; // Unknown field.
+ } else if (wireType == FieldSet.getWireFormatForFieldType(
+ extension.descriptor.getLiteType(),
+ false /* isPacked */)) {
+ packed = false; // Normal, unpacked value.
+ } else if (extension.descriptor.isRepeated &&
+ extension.descriptor.type.isPackable() &&
+ wireType == FieldSet.getWireFormatForFieldType(
+ extension.descriptor.getLiteType(),
+ true /* isPacked */)) {
+ packed = true; // Packed value.
+ } else {
+ unknown = true; // Wrong wire type.
+ }
+
+ if (unknown) { // Unknown field or wrong wire type. Skip.
+ return parseUnknownField(tag, input);
+ }
+
+ if (packed) {
+ int length = input.readRawVarint32();
+ int limit = input.pushLimit(length);
+ if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ int rawValue = input.readEnum();
+ Object value =
+ extension.descriptor.getEnumType().findValueByNumber(rawValue);
+ if (value == null) {
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
+ return true;
+ }
+ extensions.addRepeatedField(extension.descriptor,
+ extension.singularToFieldSetType(value));
+ }
+ } else {
+ while (input.getBytesUntilLimit() > 0) {
+ Object value =
+ FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType(),
+ /*checkUtf8=*/ false);
+ extensions.addRepeatedField(extension.descriptor, value);
+ }
+ }
+ input.popLimit(limit);
+ } else {
+ Object value;
+ switch (extension.descriptor.getLiteJavaType()) {
+ case MESSAGE: {
+ MessageLite.Builder subBuilder = null;
+ if (!extension.descriptor.isRepeated()) {
+ MessageLite existingValue =
+ (MessageLite) extensions.getField(extension.descriptor);
+ if (existingValue != null) {
+ subBuilder = existingValue.toBuilder();
+ }
+ }
+ if (subBuilder == null) {
+ subBuilder = extension.getMessageDefaultInstance()
+ .newBuilderForType();
+ }
+ if (extension.descriptor.getLiteType() ==
+ WireFormat.FieldType.GROUP) {
+ input.readGroup(extension.getNumber(),
+ subBuilder, extensionRegistry);
+ } else {
+ input.readMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.build();
+ break;
+ }
+ case ENUM:
+ int rawValue = input.readEnum();
+ value = extension.descriptor.getEnumType()
+ .findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // write it to unknown fields object.
+ if (value == null) {
+ mergeVarintField(fieldNumber, rawValue);
+ return true;
+ }
+ break;
+ default:
+ value = FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType(),
+ /*checkUtf8=*/ false);
+ break;
+ }
+
+ if (extension.descriptor.isRepeated()) {
+ extensions.addRepeatedField(extension.descriptor,
+ extension.singularToFieldSetType(value));
+ } else {
+ extensions.setField(extension.descriptor,
+ extension.singularToFieldSetType(value));
+ }
+ }
+
+ return true;
+ }
+
private void verifyExtensionContainingType(
final GeneratedExtension extension) {
if (extension.getContainingTypeDefaultInstance() !=
@@ -404,11 +558,10 @@ public abstract class GeneratedMessageLite<
}
- /**
- * Used by parsing constructors in generated classes.
- */
- protected static void makeExtensionsImmutable(
- FieldSet extensions) {
+ @Override
+ protected final void doneParsing() {
+ super.doneParsing();
+
extensions.makeImmutable();
}
@@ -619,131 +772,6 @@ public abstract class GeneratedMessageLite<
}
}
- //-----------------------------------------------------------------
-
- /**
- * Parse an unknown field or an extension. For use by generated code only.
- * @return {@code true} unless the tag is an end-group tag.
- */
- protected static
- boolean parseUnknownField(
- FieldSet extensions,
- MessageType defaultInstance,
- CodedInputStream input,
- UnknownFieldSetLite.Builder unknownFields,
- ExtensionRegistryLite extensionRegistry,
- int tag) throws IOException {
- int wireType = WireFormat.getTagWireType(tag);
- int fieldNumber = WireFormat.getTagFieldNumber(tag);
-
- GeneratedExtension extension =
- extensionRegistry.findLiteExtensionByNumber(
- defaultInstance, fieldNumber);
-
- boolean unknown = false;
- boolean packed = false;
- if (extension == null) {
- unknown = true; // Unknown field.
- } else if (wireType == FieldSet.getWireFormatForFieldType(
- extension.descriptor.getLiteType(),
- false /* isPacked */)) {
- packed = false; // Normal, unpacked value.
- } else if (extension.descriptor.isRepeated &&
- extension.descriptor.type.isPackable() &&
- wireType == FieldSet.getWireFormatForFieldType(
- extension.descriptor.getLiteType(),
- true /* isPacked */)) {
- packed = true; // Packed value.
- } else {
- unknown = true; // Wrong wire type.
- }
-
- if (unknown) { // Unknown field or wrong wire type. Skip.
- return unknownFields.mergeFieldFrom(tag, input);
- }
-
- if (packed) {
- int length = input.readRawVarint32();
- int limit = input.pushLimit(length);
- if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
- while (input.getBytesUntilLimit() > 0) {
- int rawValue = input.readEnum();
- Object value =
- extension.descriptor.getEnumType().findValueByNumber(rawValue);
- if (value == null) {
- // If the number isn't recognized as a valid value for this
- // enum, drop it (don't even add it to unknownFields).
- return true;
- }
- extensions.addRepeatedField(extension.descriptor,
- extension.singularToFieldSetType(value));
- }
- } else {
- while (input.getBytesUntilLimit() > 0) {
- Object value =
- FieldSet.readPrimitiveField(input,
- extension.descriptor.getLiteType(),
- /*checkUtf8=*/ false);
- extensions.addRepeatedField(extension.descriptor, value);
- }
- }
- input.popLimit(limit);
- } else {
- Object value;
- switch (extension.descriptor.getLiteJavaType()) {
- case MESSAGE: {
- MessageLite.Builder subBuilder = null;
- if (!extension.descriptor.isRepeated()) {
- MessageLite existingValue =
- (MessageLite) extensions.getField(extension.descriptor);
- if (existingValue != null) {
- subBuilder = existingValue.toBuilder();
- }
- }
- if (subBuilder == null) {
- subBuilder = extension.getMessageDefaultInstance()
- .newBuilderForType();
- }
- if (extension.descriptor.getLiteType() ==
- WireFormat.FieldType.GROUP) {
- input.readGroup(extension.getNumber(),
- subBuilder, extensionRegistry);
- } else {
- input.readMessage(subBuilder, extensionRegistry);
- }
- value = subBuilder.build();
- break;
- }
- case ENUM:
- int rawValue = input.readEnum();
- value = extension.descriptor.getEnumType()
- .findValueByNumber(rawValue);
- // If the number isn't recognized as a valid value for this enum,
- // write it to unknown fields object.
- if (value == null) {
- unknownFields.mergeVarintField(fieldNumber, rawValue);
- return true;
- }
- break;
- default:
- value = FieldSet.readPrimitiveField(input,
- extension.descriptor.getLiteType(),
- /*checkUtf8=*/ false);
- break;
- }
-
- if (extension.descriptor.isRepeated()) {
- extensions.addRepeatedField(extension.descriptor,
- extension.singularToFieldSetType(value));
- } else {
- extensions.setField(extension.descriptor,
- extension.singularToFieldSetType(value));
- }
- }
-
- return true;
- }
-
// -----------------------------------------------------------------
/** For use by generated code only. */
@@ -893,7 +921,7 @@ public abstract class GeneratedMessageLite<
extends ExtensionLite {
/**
- * Create a new isntance with the given parameters.
+ * Create a new instance with the given parameters.
*
* The last parameter {@code singularType} is only needed for enum types.
* We store integer values for enum types in a {@link ExtendableMessage}
@@ -905,7 +933,7 @@ public abstract class GeneratedMessageLite<
final Type defaultValue,
final MessageLite messageDefaultInstance,
final ExtensionDescriptor descriptor,
- Class singularType) {
+ final Class singularType) {
// Defensive checks to verify the correct initialization order of
// GeneratedExtensions and their related GeneratedMessages.
if (containingTypeDefaultInstance == null) {
@@ -921,24 +949,12 @@ public abstract class GeneratedMessageLite<
this.defaultValue = defaultValue;
this.messageDefaultInstance = messageDefaultInstance;
this.descriptor = descriptor;
-
- // Use Java reflection to invoke the static method {@code valueOf} of
- // enum types in order to convert integers to concrete enum objects.
- this.singularType = singularType;
- if (Internal.EnumLite.class.isAssignableFrom(singularType)) {
- this.enumValueOf = getMethodOrDie(
- singularType, "valueOf", int.class);
- } else {
- this.enumValueOf = null;
- }
}
final ContainingType containingTypeDefaultInstance;
final Type defaultValue;
final MessageLite messageDefaultInstance;
final ExtensionDescriptor descriptor;
- final Class singularType;
- final Method enumValueOf;
/**
* Default instance of the type being extended, used to identify that type.
@@ -980,7 +996,7 @@ public abstract class GeneratedMessageLite<
Object singularFromFieldSetType(final Object value) {
if (descriptor.getLiteJavaType() == WireFormat.JavaType.ENUM) {
- return invokeOrDie(enumValueOf, null, (Integer) value);
+ return descriptor.enumTypeMap.findValueByNumber((Integer) value);
} else {
return value;
}
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
index b4f4ce78b1..44d036c1cd 100644
--- a/java/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -118,6 +118,21 @@ public final class TextFormat {
}
}
+ /**
+ * Generates a human readable form of the field, useful for debugging
+ * and other purposes, with no newline characters.
+ */
+ public static String shortDebugString(final FieldDescriptor field,
+ final Object value) {
+ try {
+ final StringBuilder sb = new StringBuilder();
+ SINGLE_LINE_PRINTER.printField(field, value, new TextGenerator(sb));
+ return sb.toString().trim();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
/**
* Generates a human readable form of the unknown fields, useful for debugging
* and other purposes, with no newline characters.
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
index 45d5fc357f..435ad4d42a 100644
--- a/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
+++ b/java/src/main/java/com/google/protobuf/UnknownFieldSetLite.java
@@ -45,12 +45,13 @@ import java.util.Arrays;
* @author dweis@google.com (Daniel Weis)
*/
public final class UnknownFieldSetLite {
-
- private static final int[] EMPTY_INT_ARRAY = new int[0];
- private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+ // Arbitrarily chosen.
+ // TODO(dweis): Tune this number?
+ private static final int MIN_CAPACITY = 8;
private static final UnknownFieldSetLite DEFAULT_INSTANCE =
- new UnknownFieldSetLite(0, EMPTY_INT_ARRAY, EMPTY_OBJECT_ARRAY);
+ new UnknownFieldSetLite(0, new int[0], new Object[0], false /* isMutable */);
/**
* Get an empty {@code UnknownFieldSetLite}.
@@ -62,25 +63,32 @@ public final class UnknownFieldSetLite {
}
/**
- * Create a new {@link Builder}.
+ * Returns an empty {@code UnknownFieldSetLite.Builder}.
*
* For use by generated code only.
*/
public static Builder newBuilder() {
return new Builder();
}
+
+ /**
+ * Returns a new mutable instance.
+ */
+ static UnknownFieldSetLite newInstance() {
+ return new UnknownFieldSetLite();
+ }
/**
- * Returns an {@code UnknownFieldSetLite} that is the composite of {@code first} and
+ * Returns a mutable {@code UnknownFieldSetLite} that is the composite of {@code first} and
* {@code second}.
*/
- static UnknownFieldSetLite concat(UnknownFieldSetLite first, UnknownFieldSetLite second) {
+ static UnknownFieldSetLite mutableCopyOf(UnknownFieldSetLite first, UnknownFieldSetLite second) {
int count = first.count + second.count;
int[] tags = Arrays.copyOf(first.tags, count);
System.arraycopy(second.tags, 0, tags, first.count, second.count);
Object[] objects = Arrays.copyOf(first.objects, count);
System.arraycopy(second.objects, 0, objects, first.count, second.count);
- return new UnknownFieldSetLite(count, tags, objects);
+ return new UnknownFieldSetLite(count, tags, objects, true /* isMutable */);
}
/**
@@ -102,14 +110,45 @@ public final class UnknownFieldSetLite {
* The lazily computed serialized size of the set.
*/
private int memoizedSerializedSize = -1;
+
+ /**
+ * Indicates that this object is mutable.
+ */
+ private boolean isMutable;
+ /**
+ * Constructs a mutable {@code UnknownFieldSetLite}.
+ */
+ private UnknownFieldSetLite() {
+ this(0, new int[MIN_CAPACITY], new Object[MIN_CAPACITY], true /* isMutable */);
+ }
+
/**
* Constructs the {@code UnknownFieldSetLite}.
*/
- private UnknownFieldSetLite(int count, int[] tags, Object[] objects) {
+ private UnknownFieldSetLite(int count, int[] tags, Object[] objects, boolean isMutable) {
this.count = count;
this.tags = tags;
this.objects = objects;
+ this.isMutable = isMutable;
+ }
+
+ /**
+ * Marks this object as immutable.
+ *
+ *
Future calls to methods that attempt to modify this object will throw.
+ */
+ public void makeImmutable() {
+ this.isMutable = false;
+ }
+
+ /**
+ * Throws an {@link UnsupportedOperationException} if immutable.
+ */
+ void checkMutable() {
+ if (!isMutable) {
+ throw new UnsupportedOperationException();
+ }
}
/**
@@ -223,6 +262,114 @@ public final class UnknownFieldSetLite {
return hashCode;
}
+ private void storeField(int tag, Object value) {
+ ensureCapacity();
+
+ tags[count] = tag;
+ objects[count] = value;
+ count++;
+ }
+
+ /**
+ * Ensures that our arrays are long enough to store more metadata.
+ */
+ private void ensureCapacity() {
+ if (count == tags.length) {
+ int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
+ int newLength = count + increment;
+
+ tags = Arrays.copyOf(tags, newLength);
+ objects = Arrays.copyOf(objects, newLength);
+ }
+ }
+
+ /**
+ * Parse a single field from {@code input} and merge it into this set.
+ *
+ *
For use by generated code only.
+ *
+ * @param tag The field's tag number, which was already parsed.
+ * @return {@code false} if the tag is an end group tag.
+ */
+ boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
+ checkMutable();
+ final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ storeField(tag, input.readInt64());
+ return true;
+ case WireFormat.WIRETYPE_FIXED32:
+ storeField(tag, input.readFixed32());
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ storeField(tag, input.readFixed64());
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ storeField(tag, input.readBytes());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ final UnknownFieldSetLite subFieldSet = new UnknownFieldSetLite();
+ subFieldSet.mergeFrom(input);
+ input.checkLastTagWas(
+ WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ storeField(tag, subFieldSet);
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Convenience method for merging a new field containing a single varint
+ * value. This is used in particular when an unknown enum value is
+ * encountered.
+ *
+ *
For use by generated code only.
+ */
+ UnknownFieldSetLite mergeVarintField(int fieldNumber, int value) {
+ checkMutable();
+ if (fieldNumber == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+
+ storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
+
+ return this;
+ }
+
+ /**
+ * Convenience method for merging a length-delimited field.
+ *
+ *
For use by generated code only.
+ */
+ UnknownFieldSetLite mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
+ checkMutable();
+ if (fieldNumber == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+
+ storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
+
+ return this;
+ }
+
+ /**
+ * Parse an entire message from {@code input} and merge its fields into
+ * this set.
+ */
+ private UnknownFieldSetLite mergeFrom(final CodedInputStream input) throws IOException {
+ // Ensures initialization in mergeFieldFrom.
+ while (true) {
+ final int tag = input.readTag();
+ if (tag == 0 || !mergeFieldFrom(tag, input)) {
+ break;
+ }
+ }
+ return this;
+ }
+
/**
* Builder for {@link UnknownFieldSetLite}s.
*
@@ -230,53 +377,26 @@ public final class UnknownFieldSetLite {
*
*
For use by generated code only.
*/
+ // TODO(dweis): Update the mutable API to no longer need this builder and delete.
public static final class Builder {
-
- // Arbitrarily chosen.
- // TODO(dweis): Tune this number?
- private static final int MIN_CAPACITY = 8;
-
- private int count = 0;
- private int[] tags = EMPTY_INT_ARRAY;
- private Object[] objects = EMPTY_OBJECT_ARRAY;
- private boolean built;
-
- /**
- * Constructs a {@code Builder}.
- */
- private Builder() {}
+ private UnknownFieldSetLite set;
+
+ private Builder() {
+ this.set = null;
+ }
/**
* Ensures internal state is initialized for use.
*/
private void ensureNotBuilt() {
- if (built) {
- throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
+ if (set == null) {
+ set = new UnknownFieldSetLite();
}
- }
-
- private void storeField(int tag, Object value) {
- ensureCapacity();
- tags[count] = tag;
- objects[count] = value;
- count++;
+ set.checkMutable();
}
- /**
- * Ensures that our arrays are long enough to store more metadata.
- */
- private void ensureCapacity() {
- if (count == tags.length) {
- int increment = count < (MIN_CAPACITY / 2) ? MIN_CAPACITY : count >> 1;
- int newLength = count + increment;
-
- tags = Arrays.copyOf(tags, newLength);
- objects = Arrays.copyOf(objects, newLength);
- }
- }
-
/**
* Parse a single field from {@code input} and merge it into this set.
*
@@ -285,36 +405,9 @@ public final class UnknownFieldSetLite {
* @param tag The field's tag number, which was already parsed.
* @return {@code false} if the tag is an end group tag.
*/
- public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
- throws IOException {
+ boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException {
ensureNotBuilt();
-
- final int fieldNumber = WireFormat.getTagFieldNumber(tag);
- switch (WireFormat.getTagWireType(tag)) {
- case WireFormat.WIRETYPE_VARINT:
- storeField(tag, input.readInt64());
- return true;
- case WireFormat.WIRETYPE_FIXED32:
- storeField(tag, input.readFixed32());
- return true;
- case WireFormat.WIRETYPE_FIXED64:
- storeField(tag, input.readFixed64());
- return true;
- case WireFormat.WIRETYPE_LENGTH_DELIMITED:
- storeField(tag, input.readBytes());
- return true;
- case WireFormat.WIRETYPE_START_GROUP:
- final Builder subBuilder = newBuilder();
- subBuilder.mergeFrom(input);
- input.checkLastTagWas(
- WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
- storeField(tag, subBuilder.build());
- return true;
- case WireFormat.WIRETYPE_END_GROUP:
- return false;
- default:
- throw InvalidProtocolBufferException.invalidWireType();
- }
+ return set.mergeFieldFrom(tag, input);
}
/**
@@ -324,71 +417,42 @@ public final class UnknownFieldSetLite {
*
*
For use by generated code only.
*/
- public Builder mergeVarintField(int fieldNumber, int value) {
- if (fieldNumber == 0) {
- throw new IllegalArgumentException("Zero is not a valid field number.");
- }
+ Builder mergeVarintField(int fieldNumber, int value) {
ensureNotBuilt();
-
- storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_VARINT), (long) value);
-
+ set.mergeVarintField(fieldNumber, value);
return this;
}
-
+
/**
* Convenience method for merging a length-delimited field.
*
*
For use by generated code only.
*/
- public Builder mergeLengthDelimitedField(
- final int fieldNumber, final ByteString value) {
- if (fieldNumber == 0) {
- throw new IllegalArgumentException("Zero is not a valid field number.");
- }
- ensureNotBuilt();
-
- storeField(WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED), value);
-
+ public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) {
+ ensureNotBuilt();
+ set.mergeLengthDelimitedField(fieldNumber, value);
return this;
}
- /**
- * Parse an entire message from {@code input} and merge its fields into
- * this set.
- */
- private Builder mergeFrom(final CodedInputStream input) throws IOException {
- // Ensures initialization in mergeFieldFrom.
- while (true) {
- final int tag = input.readTag();
- if (tag == 0 || !mergeFieldFrom(tag, input)) {
- break;
- }
- }
- return this;
- }
-
/**
* Build the {@link UnknownFieldSetLite} and return it.
*
*
Once {@code build()} has been called, the {@code Builder} will no
* longer be usable. Calling any method after {@code build()} will result
- * in undefined behavior and can cause a {@code IllegalStateException} to be
- * thrown.
+ * in undefined behavior and can cause an
+ * {@code UnsupportedOperationException} to be thrown.
*
*
For use by generated code only.
*/
public UnknownFieldSetLite build() {
- if (built) {
- throw new IllegalStateException("Do not reuse UnknownFieldSetLite Builders.");
- }
-
- built = true;
-
- if (count == 0) {
+ if (set == null) {
return DEFAULT_INSTANCE;
}
+
+ set.checkMutable();
+ set.makeImmutable();
- return new UnknownFieldSetLite(count, tags, objects);
+ return set;
}
}
}
diff --git a/java/src/main/java/com/google/protobuf/Utf8.java b/java/src/main/java/com/google/protobuf/Utf8.java
index 0699778f73..48c7e9e62d 100644
--- a/java/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/src/main/java/com/google/protobuf/Utf8.java
@@ -360,8 +360,8 @@ final class Utf8 {
static class UnpairedSurrogateException extends IllegalArgumentException {
- private UnpairedSurrogateException(int index) {
- super("Unpaired surrogate at index " + index);
+ private UnpairedSurrogateException(int index, int length) {
+ super("Unpaired surrogate at index " + index + " of " + length);
}
}
@@ -417,7 +417,7 @@ final class Utf8 {
// Check that we have a well-formed surrogate pair.
int cp = Character.codePointAt(sequence, i);
if (cp < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
- throw new UnpairedSurrogateException(i);
+ throw new UnpairedSurrogateException(i, utf16Length);
}
i++;
}
@@ -457,7 +457,7 @@ final class Utf8 {
final char low;
if (i + 1 == sequence.length()
|| !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) {
- throw new UnpairedSurrogateException((i - 1));
+ throw new UnpairedSurrogateException((i - 1), utf16Length);
}
int codePoint = Character.toCodePoint(c, low);
bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18));
@@ -470,7 +470,7 @@ final class Utf8 {
if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE)
&& (i + 1 == sequence.length()
|| !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) {
- throw new UnpairedSurrogateException(i);
+ throw new UnpairedSurrogateException(i, utf16Length);
}
throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j);
}
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
index edd7fc4625..30da248706 100644
--- a/java/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -46,6 +46,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import com.google.protobuf.test.UnittestImport;
import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
import protobuf_unittest.TestCustomOptions;
import protobuf_unittest.UnittestCustomOptions;
import protobuf_unittest.UnittestProto;
@@ -115,7 +116,8 @@ public class DescriptorsTest extends TestCase {
assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
assertNull(file.findEnumTypeByName("NoSuchType"));
assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
- assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
+ assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
+ ImportEnumForMap.getDescriptor()),
UnittestImport.getDescriptor().getEnumTypes());
for (int i = 0; i < file.getEnumTypes().size(); i++) {
assertEquals(i, file.getEnumTypes().get(i).getIndex());
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
index 8294b8655d..1df4fad778 100644
--- a/java/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -830,6 +830,22 @@ public class TextFormatTest extends TestCase {
.build()));
}
+ public void testShortDebugString_field() {
+ final FieldDescriptor dataField =
+ OneString.getDescriptor().findFieldByName("data");
+ assertEquals(
+ "data: \"test data\"",
+ TextFormat.shortDebugString(dataField, "test data"));
+
+ final FieldDescriptor optionalField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+ final Object value = NestedMessage.newBuilder().setBb(42).build();
+
+ assertEquals(
+ "optional_nested_message { bb: 42 }",
+ TextFormat.shortDebugString(optionalField, value));
+ }
+
public void testShortDebugString_unknown() {
assertEquals("5: 1 5: 0x00000002 5: 0x0000000000000003 5: \"4\" 5 { 10: 5 }"
+ " 8: 1 8: 2 8: 3 15: 12379813812177893520 15: 0xabcd1234 15:"
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
index e76b4a6752..dc987379fc 100644
--- a/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java
@@ -30,6 +30,8 @@
package com.google.protobuf;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar;
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
@@ -52,7 +54,40 @@ public class UnknownFieldSetLiteTest extends TestCase {
UnknownFieldSetLite.newBuilder()
.build());
}
+
+ public void testBuilderReuse() throws IOException {
+ UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+ builder.mergeVarintField(10, 2);
+ builder.build();
+
+ try {
+ builder.build();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // Expected.
+ }
+
+ try {
+ builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // Expected.
+ }
+
+ try {
+ builder.mergeVarintField(5, 1);
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // Expected.
+ }
+ }
+ public void testBuilderReuse_empty() {
+ UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+ builder.build();
+ builder.build();
+ }
+
public void testDefaultInstance() {
UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
@@ -67,10 +102,10 @@ public class UnknownFieldSetLiteTest extends TestCase {
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.mergeFieldFrom(input.readTag(), input);
+ UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+ instance.mergeFieldFrom(input.readTag(), input);
- assertEquals(foo.toByteString(), toByteString(builder.build()));
+ assertEquals(foo.toByteString(), toByteString(instance));
}
public void testSerializedSize() throws IOException {
@@ -80,18 +115,18 @@ public class UnknownFieldSetLiteTest extends TestCase {
CodedInputStream input = CodedInputStream.newInstance(foo.toByteArray());
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.mergeFieldFrom(input.readTag(), input);
+ UnknownFieldSetLite instance = UnknownFieldSetLite.newInstance();
+ instance.mergeFieldFrom(input.readTag(), input);
- assertEquals(foo.toByteString().size(), builder.build().getSerializedSize());
+ assertEquals(foo.toByteString().size(), instance.getSerializedSize());
}
public void testMergeVarintField() throws IOException {
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.mergeVarintField(10, 2);
+ UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+ unknownFields.mergeVarintField(10, 2);
CodedInputStream input =
- CodedInputStream.newInstance(toByteString(builder.build()).toByteArray());
+ CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
int tag = input.readTag();
assertEquals(10, WireFormat.getTagFieldNumber(tag));
@@ -101,11 +136,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
}
public void testMergeVarintField_negative() throws IOException {
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
+ UnknownFieldSetLite builder = UnknownFieldSetLite.newInstance();
builder.mergeVarintField(10, -6);
CodedInputStream input =
- CodedInputStream.newInstance(toByteString(builder.build()).toByteArray());
+ CodedInputStream.newInstance(toByteString(builder).toByteArray());
int tag = input.readTag();
assertEquals(10, WireFormat.getTagFieldNumber(tag));
@@ -115,13 +150,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
}
public void testEqualsAndHashCode() {
- UnknownFieldSetLite.Builder builder1 = UnknownFieldSetLite.newBuilder();
- builder1.mergeVarintField(10, 2);
- UnknownFieldSetLite unknownFields1 = builder1.build();
+ UnknownFieldSetLite unknownFields1 = UnknownFieldSetLite.newInstance();
+ unknownFields1.mergeVarintField(10, 2);
- UnknownFieldSetLite.Builder builder2 = UnknownFieldSetLite.newBuilder();
- builder2.mergeVarintField(10, 2);
- UnknownFieldSetLite unknownFields2 = builder2.build();
+ UnknownFieldSetLite unknownFields2 = UnknownFieldSetLite.newInstance();
+ unknownFields2.mergeVarintField(10, 2);
assertEquals(unknownFields1, unknownFields2);
assertEquals(unknownFields1.hashCode(), unknownFields2.hashCode());
@@ -129,12 +162,11 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertFalse(unknownFields1.hashCode() == UnknownFieldSetLite.getDefaultInstance().hashCode());
}
- public void testConcat() throws IOException {
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.mergeVarintField(10, 2);
- UnknownFieldSetLite unknownFields = builder.build();
-
- unknownFields = UnknownFieldSetLite.concat(unknownFields, unknownFields);
+ public void testMutableCopyOf() throws IOException {
+ UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+ unknownFields.mergeVarintField(10, 2);
+ unknownFields = UnknownFieldSetLite.mutableCopyOf(unknownFields, unknownFields);
+ unknownFields.checkMutable();
CodedInputStream input =
CodedInputStream.newInstance(toByteString(unknownFields).toByteArray());
@@ -151,53 +183,15 @@ public class UnknownFieldSetLiteTest extends TestCase {
assertTrue(input.isAtEnd());
}
- public void testConcat_empty() {
- UnknownFieldSetLite unknownFields = UnknownFieldSetLite.concat(
+ public void testMutableCopyOf_empty() {
+ UnknownFieldSetLite unknownFields = UnknownFieldSetLite.mutableCopyOf(
UnknownFieldSetLite.getDefaultInstance(), UnknownFieldSetLite.getDefaultInstance());
+ unknownFields.checkMutable();
assertEquals(0, unknownFields.getSerializedSize());
assertEquals(ByteString.EMPTY, toByteString(unknownFields));
}
- public void testBuilderReuse() throws IOException {
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.mergeVarintField(10, 2);
- builder.build();
-
- try {
- builder.build();
- fail();
- } catch (IllegalStateException e) {
- // Expected.
- }
-
- try {
- builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0]));
- fail();
- } catch (IllegalStateException e) {
- // Expected.
- }
-
- try {
- builder.mergeVarintField(5, 1);
- fail();
- } catch (IllegalStateException e) {
- // Expected.
- }
- }
-
- public void testBuilderReuse_empty() {
- UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder();
- builder.build();
-
- try {
- builder.build();
- fail();
- } catch (IllegalStateException e) {
- // Expected.
- }
- }
-
public void testRoundTrips() throws InvalidProtocolBufferException {
Foo foo = Foo.newBuilder()
.setValue(1)
@@ -301,6 +295,64 @@ public class UnknownFieldSetLiteTest extends TestCase {
// Expected.
}
}
+
+ public void testMakeImmutable() throws Exception {
+ UnknownFieldSetLite unknownFields = UnknownFieldSetLite.newInstance();
+ unknownFields.makeImmutable();
+
+ try {
+ unknownFields.mergeVarintField(1, 1);
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ try {
+ unknownFields.mergeLengthDelimitedField(2, ByteString.copyFromUtf8("hello"));
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ try {
+ unknownFields.mergeFieldFrom(1, CodedInputStream.newInstance(new byte[0]));
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+ }
+
+ public void testEndToEnd() throws Exception {
+ TestAllTypesLite testAllTypes = TestAllTypesLite.getDefaultInstance();
+ try {
+ testAllTypes.unknownFields.checkMutable();
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ testAllTypes = TestAllTypesLite.parseFrom(new byte[0]);
+ try {
+ testAllTypes.unknownFields.checkMutable();
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ testAllTypes = TestAllTypesLite.newBuilder().build();
+ try {
+ testAllTypes.unknownFields.checkMutable();
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ testAllTypes = TestAllTypesLite.newBuilder()
+ .setDefaultBool(true)
+ .build();
+ try {
+ testAllTypes.unknownFields.checkMutable();
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ TestAllExtensionsLite testAllExtensions = TestAllExtensionsLite.newBuilder()
+ .mergeFrom(TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 2)
+ .build().toByteArray())
+ .build();
+ try {
+ testAllExtensions.unknownFields.checkMutable();
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+ }
private ByteString toByteString(UnknownFieldSetLite unknownFields) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
diff --git a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
index dc082615e1..8c37c03caf 100644
--- a/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
+++ b/java/src/test/java/com/google/protobuf/test_bad_identifiers.proto
@@ -140,11 +140,11 @@ message TestConflictingFieldNames {
optional bytes bytes_field_count = 14;
optional TestMessage message_field_count = 15;
- repeated int32 Int32Field = 21;
- repeated TestEnum EnumField = 22;
- repeated string StringField = 23;
- repeated bytes BytesField = 24;
- repeated TestMessage MessageField = 25;
+ repeated int32 Int32Field = 21; // NO_PROTO3
+ repeated TestEnum EnumField = 22; // NO_PROTO3
+ repeated string StringField = 23; // NO_PROTO3
+ repeated bytes BytesField = 24; // NO_PROTO3
+ repeated TestMessage MessageField = 25; // NO_PROTO3
// This field conflicts with "int32_field" as they both generate
// the method getInt32FieldList().
diff --git a/java/util/pom.xml b/java/util/pom.xml
index 44a5662d74..9416f380d3 100644
--- a/java/util/pom.xml
+++ b/java/util/pom.xml
@@ -10,7 +10,7 @@
com.google.protobuf
protobuf-java-util
- 3.0.0-beta-1
+ 3.0.0-alpha-4-pre
bundle
Protocol Buffer Java API
@@ -36,7 +36,7 @@
com.google.protobuf
protobuf-java
- 3.0.0-beta-1
+ 3.0.0-alpha-4-pre
compile
@@ -123,7 +123,7 @@
https://developers.google.com/protocol-buffers/
com.google.protobuf.util
- com.google.protobuf.util;version=3.0.0-beta-1
+ com.google.protobuf.util;version=3.0.0-alpha-3
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 95b703fceb..2bf3653270 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2007 Google Inc. All Rights Reserved.
-
"""Descriptors essentially contain exactly the information found in a .proto
file, in types that make this information accessible in Python.
"""
@@ -40,7 +38,6 @@ import six
from google.protobuf.internal import api_implementation
-
_USE_C_DESCRIPTORS = False
if api_implementation.Type() == 'cpp':
# Used by MakeDescriptor in cpp mode
@@ -221,6 +218,9 @@ class Descriptor(_NestedDescriptorBase):
fields_by_name: (dict str -> FieldDescriptor) Same FieldDescriptor
objects as in |fields|, but indexed by "name" attribute in each
FieldDescriptor.
+ fields_by_camelcase_name: (dict str -> FieldDescriptor) Same
+ FieldDescriptor objects as in |fields|, but indexed by
+ "camelcase_name" attribute in each FieldDescriptor.
nested_types: (list of Descriptors) Descriptor references
for all protocol message types nested within this one.
@@ -292,6 +292,7 @@ class Descriptor(_NestedDescriptorBase):
field.containing_type = self
self.fields_by_number = dict((f.number, f) for f in fields)
self.fields_by_name = dict((f.name, f) for f in fields)
+ self._fields_by_camelcase_name = None
self.nested_types = nested_types
for nested_type in nested_types:
@@ -317,6 +318,13 @@ class Descriptor(_NestedDescriptorBase):
oneof.containing_type = self
self.syntax = syntax or "proto2"
+ @property
+ def fields_by_camelcase_name(self):
+ if self._fields_by_camelcase_name is None:
+ self._fields_by_camelcase_name = dict(
+ (f.camelcase_name, f) for f in self.fields)
+ return self._fields_by_camelcase_name
+
def EnumValueName(self, enum, value):
"""Returns the string name of an enum value.
@@ -365,6 +373,7 @@ class FieldDescriptor(DescriptorBase):
name: (str) Name of this field, exactly as it appears in .proto.
full_name: (str) Name of this field, including containing scope. This is
particularly relevant for extensions.
+ camelcase_name: (str) Camelcase name of this field.
index: (int) Dense, 0-indexed index giving the order that this
field textually appears within its message in the .proto file.
number: (int) Tag number declared for this field in the .proto file.
@@ -509,6 +518,7 @@ class FieldDescriptor(DescriptorBase):
super(FieldDescriptor, self).__init__(options, 'FieldOptions')
self.name = name
self.full_name = full_name
+ self._camelcase_name = None
self.index = index
self.number = number
self.type = type
@@ -530,6 +540,12 @@ class FieldDescriptor(DescriptorBase):
else:
self._cdescriptor = None
+ @property
+ def camelcase_name(self):
+ if self._camelcase_name is None:
+ self._camelcase_name = _ToCamelCase(self.name)
+ return self._camelcase_name
+
@staticmethod
def ProtoTypeToCppProtoType(proto_type):
"""Converts from a Python proto type to a C++ Proto Type.
@@ -822,6 +838,27 @@ def _ParseOptions(message, string):
return message
+def _ToCamelCase(name):
+ """Converts name to camel-case and returns it."""
+ capitalize_next = False
+ result = []
+
+ for c in name:
+ if c == '_':
+ if result:
+ capitalize_next = True
+ elif capitalize_next:
+ result.append(c.upper())
+ capitalize_next = False
+ else:
+ result += c
+
+ # Lower-case the first letter.
+ if result and result[0].isupper():
+ result[0] = result[0].lower()
+ return ''.join(result)
+
+
def MakeDescriptor(desc_proto, package='', build_file_if_cpp=True,
syntax=None):
"""Make a protobuf Descriptor given a DescriptorProto protobuf.
diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py
index 4fd7a86493..31869e4575 100755
--- a/python/google/protobuf/internal/decoder.py
+++ b/python/google/protobuf/internal/decoder.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2009 Google Inc. All Rights Reserved.
-
"""Code for decoding protocol buffer primitives.
This code is very similar to encoder.py -- read the docs for that module first.
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
index 1baff7d1d1..3241cb7281 100644
--- a/python/google/protobuf/internal/descriptor_database_test.py
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -34,10 +34,7 @@
__author__ = 'matthewtoia@google.com (Matt Toia)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import descriptor_pb2
from google.protobuf.internal import factory_test2_pb2
from google.protobuf import descriptor_database
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 2a482fbabc..6bbc8233b4 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -35,11 +35,8 @@
__author__ = 'matthewtoia@google.com (Matt Toia)'
import os
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2
from google.protobuf.internal import api_implementation
@@ -47,6 +44,7 @@ from google.protobuf.internal import descriptor_pool_test1_pb2
from google.protobuf.internal import descriptor_pool_test2_pb2
from google.protobuf.internal import factory_test1_pb2
from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import test_util
from google.protobuf import descriptor
from google.protobuf import descriptor_database
from google.protobuf import descriptor_pool
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index 34843a6140..f94f9f14ec 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -1,4 +1,4 @@
-#! /usr/bin/python
+#! /usr/bin/env python
#
# Protocol Buffers - Google's data interchange format
# Copyright 2008 Google Inc. All rights reserved.
@@ -36,20 +36,17 @@ __author__ = 'robinson@google.com (Will Robinson)'
import sys
+import unittest
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2
from google.protobuf.internal import api_implementation
+from google.protobuf.internal import test_util
from google.protobuf import descriptor
from google.protobuf import symbol_database
from google.protobuf import text_format
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
-
TEST_EMPTY_MESSAGE_DESCRIPTOR_ASCII = """
name: 'TestEmptyMessage'
@@ -394,7 +391,7 @@ class DescriptorTest(unittest.TestCase):
self.assertEqual(self.my_file.name, 'some/filename/some.proto')
self.assertEqual(self.my_file.package, 'protobuf_unittest')
- @unittest.skipIf(
+ @test_util.skipIf(
api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
'Immutability of descriptors is only enforced in v2 implementation')
def testImmutableCppDescriptor(self):
@@ -425,10 +422,12 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.CheckDescriptorSequence(message_descriptor.fields)
self.CheckDescriptorMapping(message_descriptor.fields_by_name)
self.CheckDescriptorMapping(message_descriptor.fields_by_number)
+ self.CheckDescriptorMapping(message_descriptor.fields_by_camelcase_name)
def CheckFieldDescriptor(self, field_descriptor):
# Basic properties
self.assertEqual(field_descriptor.name, 'optional_int32')
+ self.assertEqual(field_descriptor.camelcase_name, 'optionalInt32')
self.assertEqual(field_descriptor.full_name,
'protobuf_unittest.TestAllTypes.optional_int32')
self.assertEqual(field_descriptor.containing_type.name, 'TestAllTypes')
@@ -437,6 +436,10 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.assertEqual(
field_descriptor.containing_type.fields_by_name['optional_int32'],
field_descriptor)
+ self.assertEqual(
+ field_descriptor.containing_type.fields_by_camelcase_name[
+ 'optionalInt32'],
+ field_descriptor)
self.assertIn(field_descriptor, [field_descriptor])
self.assertIn(field_descriptor, {field_descriptor: None})
@@ -481,6 +484,9 @@ class GeneratedDescriptorTest(unittest.TestCase):
self.CheckMessageDescriptor(message_descriptor)
field_descriptor = message_descriptor.fields_by_name['optional_int32']
self.CheckFieldDescriptor(field_descriptor)
+ field_descriptor = message_descriptor.fields_by_camelcase_name[
+ 'optionalInt32']
+ self.CheckFieldDescriptor(field_descriptor)
def testCppDescriptorContainer(self):
# Check that the collection is still valid even if the parent disappeared.
@@ -779,5 +785,20 @@ class MakeDescriptorTest(unittest.TestCase):
self.assertEqual(101,
options.Extensions[unittest_custom_options_pb2.msgopt].i)
+ def testCamelcaseName(self):
+ descriptor_proto = descriptor_pb2.DescriptorProto()
+ descriptor_proto.name = 'Bar'
+ names = ['foo_foo', 'FooBar', 'fooBaz', 'fooFoo', 'foobar']
+ camelcase_names = ['fooFoo', 'fooBar', 'fooBaz', 'fooFoo', 'foobar']
+ for index in range(len(names)):
+ field = descriptor_proto.field.add()
+ field.number = index + 1
+ field.name = names[index]
+ result = descriptor.MakeDescriptor(descriptor_proto)
+ for index in range(len(camelcase_names)):
+ self.assertEqual(result.fields[index].camelcase_name,
+ camelcase_names[index])
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index d72cd29d03..48ef2df31c 100755
--- a/python/google/protobuf/internal/encoder.py
+++ b/python/google/protobuf/internal/encoder.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2009 Google Inc. All Rights Reserved.
-
"""Code for encoding protocol message primitives.
Contains the logic for encoding every logical protocol field type
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
index 9956da59b4..7fcb137793 100755
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -41,10 +41,7 @@ further ensures that we can use Python protocol message objects as we expect.
__author__ = 'robinson@google.com (Will Robinson)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf.internal import test_bad_identifiers_pb2
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_import_pb2
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
new file mode 100644
index 0000000000..6d0071be33
--- /dev/null
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -0,0 +1,522 @@
+#! /usr/bin/env python
+#
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc. All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Test for google.protobuf.json_format."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import json
+import math
+import sys
+
+import unittest
+from google.protobuf import json_format
+from google.protobuf.util import json_format_proto3_pb2
+
+
+class JsonFormatBase(unittest.TestCase):
+
+ def FillAllFields(self, message):
+ message.int32_value = 20
+ message.int64_value = -20
+ message.uint32_value = 3120987654
+ message.uint64_value = 12345678900
+ message.float_value = float('-inf')
+ message.double_value = 3.1415
+ message.bool_value = True
+ message.string_value = 'foo'
+ message.bytes_value = b'bar'
+ message.message_value.value = 10
+ message.enum_value = json_format_proto3_pb2.BAR
+ # Repeated
+ message.repeated_int32_value.append(0x7FFFFFFF)
+ message.repeated_int32_value.append(-2147483648)
+ message.repeated_int64_value.append(9007199254740992)
+ message.repeated_int64_value.append(-9007199254740992)
+ message.repeated_uint32_value.append(0xFFFFFFF)
+ message.repeated_uint32_value.append(0x7FFFFFF)
+ message.repeated_uint64_value.append(9007199254740992)
+ message.repeated_uint64_value.append(9007199254740991)
+ message.repeated_float_value.append(0)
+
+ message.repeated_double_value.append(1E-15)
+ message.repeated_double_value.append(float('inf'))
+ message.repeated_bool_value.append(True)
+ message.repeated_bool_value.append(False)
+ message.repeated_string_value.append('Few symbols!#$,;')
+ message.repeated_string_value.append('bar')
+ message.repeated_bytes_value.append(b'foo')
+ message.repeated_bytes_value.append(b'bar')
+ message.repeated_message_value.add().value = 10
+ message.repeated_message_value.add().value = 11
+ message.repeated_enum_value.append(json_format_proto3_pb2.FOO)
+ message.repeated_enum_value.append(json_format_proto3_pb2.BAR)
+ self.message = message
+
+ def CheckParseBack(self, message, parsed_message):
+ json_format.Parse(json_format.MessageToJson(message),
+ parsed_message)
+ self.assertEqual(message, parsed_message)
+
+ def CheckError(self, text, error_message):
+ message = json_format_proto3_pb2.TestMessage()
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ error_message,
+ json_format.Parse, text, message)
+
+
+class JsonFormatTest(JsonFormatBase):
+
+ def testEmptyMessageToJson(self):
+ message = json_format_proto3_pb2.TestMessage()
+ self.assertEqual(json_format.MessageToJson(message),
+ '{}')
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ self.CheckParseBack(message, parsed_message)
+
+ def testPartialMessageToJson(self):
+ message = json_format_proto3_pb2.TestMessage(
+ string_value='test',
+ repeated_int32_value=[89, 4])
+ self.assertEqual(json.loads(json_format.MessageToJson(message)),
+ json.loads('{"stringValue": "test", '
+ '"repeatedInt32Value": [89, 4]}'))
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ self.CheckParseBack(message, parsed_message)
+
+ def testAllFieldsToJson(self):
+ message = json_format_proto3_pb2.TestMessage()
+ text = ('{"int32Value": 20, '
+ '"int64Value": "-20", '
+ '"uint32Value": 3120987654,'
+ '"uint64Value": "12345678900",'
+ '"floatValue": "-Infinity",'
+ '"doubleValue": 3.1415,'
+ '"boolValue": true,'
+ '"stringValue": "foo",'
+ '"bytesValue": "YmFy",'
+ '"messageValue": {"value": 10},'
+ '"enumValue": "BAR",'
+ '"repeatedInt32Value": [2147483647, -2147483648],'
+ '"repeatedInt64Value": ["9007199254740992", "-9007199254740992"],'
+ '"repeatedUint32Value": [268435455, 134217727],'
+ '"repeatedUint64Value": ["9007199254740992", "9007199254740991"],'
+ '"repeatedFloatValue": [0],'
+ '"repeatedDoubleValue": [1e-15, "Infinity"],'
+ '"repeatedBoolValue": [true, false],'
+ '"repeatedStringValue": ["Few symbols!#$,;", "bar"],'
+ '"repeatedBytesValue": ["Zm9v", "YmFy"],'
+ '"repeatedMessageValue": [{"value": 10}, {"value": 11}],'
+ '"repeatedEnumValue": ["FOO", "BAR"]'
+ '}')
+ self.FillAllFields(message)
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message)),
+ json.loads(text))
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ json_format.Parse(text, parsed_message)
+ self.assertEqual(message, parsed_message)
+
+ def testJsonEscapeString(self):
+ message = json_format_proto3_pb2.TestMessage()
+ if sys.version_info[0] < 3:
+ message.string_value = '&\n<\"\r>\b\t\f\\\001/\xe2\x80\xa8\xe2\x80\xa9'
+ else:
+ message.string_value = '&\n<\"\r>\b\t\f\\\001/'
+ message.string_value += (b'\xe2\x80\xa8\xe2\x80\xa9').decode('utf-8')
+ self.assertEqual(
+ json_format.MessageToJson(message),
+ '{\n "stringValue": '
+ '"&\\n<\\\"\\r>\\b\\t\\f\\\\\\u0001/\\u2028\\u2029"\n}')
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ self.CheckParseBack(message, parsed_message)
+ text = u'{"int32Value": "\u0031"}'
+ json_format.Parse(text, message)
+ self.assertEqual(message.int32_value, 1)
+
+ def testAlwaysSeriliaze(self):
+ message = json_format_proto3_pb2.TestMessage(
+ string_value='foo')
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads('{'
+ '"repeatedStringValue": [],'
+ '"stringValue": "foo",'
+ '"repeatedBoolValue": [],'
+ '"repeatedUint32Value": [],'
+ '"repeatedInt32Value": [],'
+ '"enumValue": "FOO",'
+ '"int32Value": 0,'
+ '"floatValue": 0,'
+ '"int64Value": "0",'
+ '"uint32Value": 0,'
+ '"repeatedBytesValue": [],'
+ '"repeatedUint64Value": [],'
+ '"repeatedDoubleValue": [],'
+ '"bytesValue": "",'
+ '"boolValue": false,'
+ '"repeatedEnumValue": [],'
+ '"uint64Value": "0",'
+ '"doubleValue": 0,'
+ '"repeatedFloatValue": [],'
+ '"repeatedInt64Value": [],'
+ '"repeatedMessageValue": []}'))
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ self.CheckParseBack(message, parsed_message)
+
+ def testMapFields(self):
+ message = json_format_proto3_pb2.TestMap()
+ message.bool_map[True] = 1
+ message.bool_map[False] = 2
+ message.int32_map[1] = 2
+ message.int32_map[2] = 3
+ message.int64_map[1] = 2
+ message.int64_map[2] = 3
+ message.uint32_map[1] = 2
+ message.uint32_map[2] = 3
+ message.uint64_map[1] = 2
+ message.uint64_map[2] = 3
+ message.string_map['1'] = 2
+ message.string_map['null'] = 3
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads('{'
+ '"boolMap": {"false": 2, "true": 1},'
+ '"int32Map": {"1": 2, "2": 3},'
+ '"int64Map": {"1": 2, "2": 3},'
+ '"uint32Map": {"1": 2, "2": 3},'
+ '"uint64Map": {"1": 2, "2": 3},'
+ '"stringMap": {"1": 2, "null": 3}'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestMap()
+ self.CheckParseBack(message, parsed_message)
+
+ def testOneofFields(self):
+ message = json_format_proto3_pb2.TestOneof()
+ # Always print does not affect oneof fields.
+ self.assertEqual(
+ json_format.MessageToJson(message, True),
+ '{}')
+ message.oneof_int32_value = 0
+ self.assertEqual(
+ json_format.MessageToJson(message, True),
+ '{\n'
+ ' "oneofInt32Value": 0\n'
+ '}')
+ parsed_message = json_format_proto3_pb2.TestOneof()
+ self.CheckParseBack(message, parsed_message)
+
+ def testTimestampMessage(self):
+ message = json_format_proto3_pb2.TestTimestamp()
+ message.value.seconds = 0
+ message.value.nanos = 0
+ message.repeated_value.add().seconds = 20
+ message.repeated_value[0].nanos = 1
+ message.repeated_value.add().seconds = 0
+ message.repeated_value[1].nanos = 10000
+ message.repeated_value.add().seconds = 100000000
+ message.repeated_value[2].nanos = 0
+ # Maximum time
+ message.repeated_value.add().seconds = 253402300799
+ message.repeated_value[3].nanos = 999999999
+ # Minimum time
+ message.repeated_value.add().seconds = -62135596800
+ message.repeated_value[4].nanos = 0
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads('{'
+ '"value": "1970-01-01T00:00:00Z",'
+ '"repeatedValue": ['
+ ' "1970-01-01T00:00:20.000000001Z",'
+ ' "1970-01-01T00:00:00.000010Z",'
+ ' "1973-03-03T09:46:40Z",'
+ ' "9999-12-31T23:59:59.999999999Z",'
+ ' "0001-01-01T00:00:00Z"'
+ ']'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestTimestamp()
+ self.CheckParseBack(message, parsed_message)
+ text = (r'{"value": "1972-01-01T01:00:00.01+08:00",'
+ r'"repeatedValue":['
+ r' "1972-01-01T01:00:00.01+08:30",'
+ r' "1972-01-01T01:00:00.01-01:23"]}')
+ json_format.Parse(text, parsed_message)
+ self.assertEqual(parsed_message.value.seconds, 63104400)
+ self.assertEqual(parsed_message.value.nanos, 10000000)
+ self.assertEqual(parsed_message.repeated_value[0].seconds, 63106200)
+ self.assertEqual(parsed_message.repeated_value[1].seconds, 63070620)
+
+ def testDurationMessage(self):
+ message = json_format_proto3_pb2.TestDuration()
+ message.value.seconds = 1
+ message.repeated_value.add().seconds = 0
+ message.repeated_value[0].nanos = 10
+ message.repeated_value.add().seconds = -1
+ message.repeated_value[1].nanos = -1000
+ message.repeated_value.add().seconds = 10
+ message.repeated_value[2].nanos = 11000000
+ message.repeated_value.add().seconds = -315576000000
+ message.repeated_value.add().seconds = 315576000000
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads('{'
+ '"value": "1s",'
+ '"repeatedValue": ['
+ ' "0.000000010s",'
+ ' "-1.000001s",'
+ ' "10.011s",'
+ ' "-315576000000s",'
+ ' "315576000000s"'
+ ']'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestDuration()
+ self.CheckParseBack(message, parsed_message)
+
+ def testFieldMaskMessage(self):
+ message = json_format_proto3_pb2.TestFieldMask()
+ message.value.paths.append('foo.bar')
+ message.value.paths.append('bar')
+ self.assertEqual(
+ json_format.MessageToJson(message, True),
+ '{\n'
+ ' "value": "foo.bar,bar"\n'
+ '}')
+ parsed_message = json_format_proto3_pb2.TestFieldMask()
+ self.CheckParseBack(message, parsed_message)
+
+ def testWrapperMessage(self):
+ message = json_format_proto3_pb2.TestWrapper()
+ message.bool_value.value = False
+ message.int32_value.value = 0
+ message.string_value.value = ''
+ message.bytes_value.value = b''
+ message.repeated_bool_value.add().value = True
+ message.repeated_bool_value.add().value = False
+ self.assertEqual(
+ json.loads(json_format.MessageToJson(message, True)),
+ json.loads('{\n'
+ ' "int32Value": 0,'
+ ' "boolValue": false,'
+ ' "stringValue": "",'
+ ' "bytesValue": "",'
+ ' "repeatedBoolValue": [true, false],'
+ ' "repeatedInt32Value": [],'
+ ' "repeatedUint32Value": [],'
+ ' "repeatedFloatValue": [],'
+ ' "repeatedDoubleValue": [],'
+ ' "repeatedBytesValue": [],'
+ ' "repeatedInt64Value": [],'
+ ' "repeatedUint64Value": [],'
+ ' "repeatedStringValue": []'
+ '}'))
+ parsed_message = json_format_proto3_pb2.TestWrapper()
+ self.CheckParseBack(message, parsed_message)
+
+ def testParseNull(self):
+ message = json_format_proto3_pb2.TestMessage()
+ message.repeated_int32_value.append(1)
+ message.repeated_int32_value.append(2)
+ message.repeated_int32_value.append(3)
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ self.FillAllFields(parsed_message)
+ json_format.Parse('{"int32Value": null, '
+ '"int64Value": null, '
+ '"uint32Value": null,'
+ '"uint64Value": null,'
+ '"floatValue": null,'
+ '"doubleValue": null,'
+ '"boolValue": null,'
+ '"stringValue": null,'
+ '"bytesValue": null,'
+ '"messageValue": null,'
+ '"enumValue": null,'
+ '"repeatedInt32Value": [1, 2, null, 3],'
+ '"repeatedInt64Value": null,'
+ '"repeatedUint32Value": null,'
+ '"repeatedUint64Value": null,'
+ '"repeatedFloatValue": null,'
+ '"repeatedDoubleValue": null,'
+ '"repeatedBoolValue": null,'
+ '"repeatedStringValue": null,'
+ '"repeatedBytesValue": null,'
+ '"repeatedMessageValue": null,'
+ '"repeatedEnumValue": null'
+ '}',
+ parsed_message)
+ self.assertEqual(message, parsed_message)
+
+ def testNanFloat(self):
+ message = json_format_proto3_pb2.TestMessage()
+ message.float_value = float('nan')
+ text = '{\n "floatValue": "NaN"\n}'
+ self.assertEqual(json_format.MessageToJson(message), text)
+ parsed_message = json_format_proto3_pb2.TestMessage()
+ json_format.Parse(text, parsed_message)
+ self.assertTrue(math.isnan(parsed_message.float_value))
+
+ def testParseEmptyText(self):
+ self.CheckError('',
+ r'Failed to load JSON: (Expecting value)|(No JSON)')
+
+ def testParseBadEnumValue(self):
+ self.CheckError(
+ '{"enumValue": 1}',
+ 'Enum value must be a string literal with double quotes. '
+ 'Type "proto3.EnumType" has no value named 1.')
+ self.CheckError(
+ '{"enumValue": "baz"}',
+ 'Enum value must be a string literal with double quotes. '
+ 'Type "proto3.EnumType" has no value named baz.')
+
+ def testParseBadIdentifer(self):
+ self.CheckError('{int32Value: 1}',
+ (r'Failed to load JSON: Expecting property name enclosed '
+ r'in double quotes: line 1'))
+ self.CheckError('{"unknownName": 1}',
+ 'Message type "proto3.TestMessage" has no field named '
+ '"unknownName".')
+
+ def testDuplicateField(self):
+ self.CheckError('{"int32Value": 1,\n"int32Value":2}',
+ 'Failed to load JSON: duplicate key int32Value')
+
+ def testInvalidBoolValue(self):
+ self.CheckError('{"boolValue": 1}',
+ 'Failed to parse boolValue field: '
+ 'Expected true or false without quotes.')
+ self.CheckError('{"boolValue": "true"}',
+ 'Failed to parse boolValue field: '
+ 'Expected true or false without quotes.')
+
+ def testInvalidIntegerValue(self):
+ message = json_format_proto3_pb2.TestMessage()
+ text = '{"int32Value": 0x12345}'
+ self.assertRaises(json_format.ParseError,
+ json_format.Parse, text, message)
+ self.CheckError('{"int32Value": 012345}',
+ (r'Failed to load JSON: Expecting \',\' delimiter: '
+ r'line 1'))
+ self.CheckError('{"int32Value": 1.0}',
+ 'Failed to parse int32Value field: '
+ 'Couldn\'t parse integer: 1.0')
+ self.CheckError('{"int32Value": " 1 "}',
+ 'Failed to parse int32Value field: '
+ 'Couldn\'t parse integer: " 1 "')
+ self.CheckError('{"int32Value": 12345678901234567890}',
+ 'Failed to parse int32Value field: Value out of range: '
+ '12345678901234567890')
+ self.CheckError('{"int32Value": 1e5}',
+ 'Failed to parse int32Value field: '
+ 'Couldn\'t parse integer: 100000.0')
+ self.CheckError('{"uint32Value": -1}',
+ 'Failed to parse uint32Value field: Value out of range: -1')
+
+ def testInvalidFloatValue(self):
+ self.CheckError('{"floatValue": "nan"}',
+ 'Failed to parse floatValue field: Couldn\'t '
+ 'parse float "nan", use "NaN" instead')
+
+ def testInvalidBytesValue(self):
+ self.CheckError('{"bytesValue": "AQI"}',
+ 'Failed to parse bytesValue field: Incorrect padding')
+ self.CheckError('{"bytesValue": "AQI*"}',
+ 'Failed to parse bytesValue field: Incorrect padding')
+
+ def testInvalidMap(self):
+ message = json_format_proto3_pb2.TestMap()
+ text = '{"int32Map": {"null": 2, "2": 3}}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse int32Map field: Couldn\'t parse integer: "null"',
+ json_format.Parse, text, message)
+ text = '{"int32Map": {1: 2, "2": 3}}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ (r'Failed to load JSON: Expecting property name enclosed '
+ r'in double quotes: line 1'),
+ json_format.Parse, text, message)
+ text = r'{"stringMap": {"a": 3, "\u0061": 2}}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to load JSON: duplicate key a',
+ json_format.Parse, text, message)
+ text = '{"boolMap": {"null": 1}}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse boolMap field: Expect "true" or "false", not null.',
+ json_format.Parse, text, message)
+
+ def testInvalidTimestamp(self):
+ message = json_format_proto3_pb2.TestTimestamp()
+ text = '{"value": "10000-01-01T00:00:00.00Z"}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'time data \'10000-01-01T00:00:00\' does not match'
+ ' format \'%Y-%m-%dT%H:%M:%S\'',
+ json_format.Parse, text, message)
+ text = '{"value": "1970-01-01T00:00:00.0123456789012Z"}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse value field: Failed to parse Timestamp: '
+ 'nanos 0123456789012 more than 9 fractional digits.',
+ json_format.Parse, text, message)
+ text = '{"value": "1972-01-01T01:00:00.01+08"}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ (r'Failed to parse value field: Invalid timezone offset value: \+08'),
+ json_format.Parse, text, message)
+ # Time smaller than minimum time.
+ text = '{"value": "0000-01-01T00:00:00Z"}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Failed to parse value field: year is out of range',
+ json_format.Parse, text, message)
+ # Time bigger than maxinum time.
+ message.value.seconds = 253402300800
+ self.assertRaisesRegexp(
+ json_format.SerializeToJsonError,
+ 'Failed to serialize value field: year is out of range',
+ json_format.MessageToJson, message)
+
+ def testInvalidOneof(self):
+ message = json_format_proto3_pb2.TestOneof()
+ text = '{"oneofInt32Value": 1, "oneofStringValue": "2"}'
+ self.assertRaisesRegexp(
+ json_format.ParseError,
+ 'Message type "proto3.TestOneof"'
+ ' should not have multiple "oneof_value" oneof fields.',
+ json_format.Parse, text, message)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py
index 0d880a75ea..9ec54fff53 100644
--- a/python/google/protobuf/internal/message_factory_test.py
+++ b/python/google/protobuf/internal/message_factory_test.py
@@ -34,10 +34,7 @@
__author__ = 'matthewtoia@google.com (Matt Toia)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import descriptor_pb2
from google.protobuf.internal import factory_test1_pb2
from google.protobuf.internal import factory_test2_pb2
@@ -45,7 +42,6 @@ from google.protobuf import descriptor_database
from google.protobuf import descriptor_pool
from google.protobuf import message_factory
-
class MessageFactoryTest(unittest.TestCase):
def setUp(self):
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index d99b89be61..604c426a88 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -43,22 +43,16 @@ abstract interface.
__author__ = 'gps@google.com (Gregory P. Smith)'
+
import collections
import copy
import math
import operator
import pickle
-import sys
-
import six
+import sys
-if six.PY3:
- long = int
-
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf.internal import _parameterized
from google.protobuf import map_unittest_pb2
from google.protobuf import unittest_pb2
@@ -68,6 +62,9 @@ from google.protobuf.internal import packed_field_test_pb2
from google.protobuf.internal import test_util
from google.protobuf import message
+if six.PY3:
+ long = int
+
# Python pre-2.6 does not have isinf() or isnan() functions, so we have
# to provide our own.
def isnan(val):
@@ -442,7 +439,7 @@ class MessageTest(unittest.TestCase):
message.repeated_nested_message.add().bb = 24
message.repeated_nested_message.add().bb = 10
message.repeated_nested_message.sort(key=lambda z: z.bb // 10)
- self.assertEquals(
+ self.assertEqual(
[13, 11, 10, 21, 20, 24, 33],
[n.bb for n in message.repeated_nested_message])
@@ -451,7 +448,7 @@ class MessageTest(unittest.TestCase):
pb = message.SerializeToString()
message.Clear()
message.MergeFromString(pb)
- self.assertEquals(
+ self.assertEqual(
[13, 11, 10, 21, 20, 24, 33],
[n.bb for n in message.repeated_nested_message])
@@ -914,7 +911,6 @@ class MessageTest(unittest.TestCase):
with self.assertRaises(pickle.PickleError) as _:
pickle.dumps(m.repeated_int32, pickle.HIGHEST_PROTOCOL)
-
def testSortEmptyRepeatedCompositeContainer(self, message_module):
"""Exercise a scenario that has led to segfaults in the past.
"""
diff --git a/python/google/protobuf/internal/missing_enum_values.proto b/python/google/protobuf/internal/missing_enum_values.proto
index 161fc5e14f..1850be5bb7 100644
--- a/python/google/protobuf/internal/missing_enum_values.proto
+++ b/python/google/protobuf/internal/missing_enum_values.proto
@@ -50,3 +50,7 @@ message TestMissingEnumValues {
repeated NestedEnum repeated_nested_enum = 2;
repeated NestedEnum packed_nested_enum = 3 [packed = true];
}
+
+message JustString {
+ required string dummy = 1;
+}
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
index 1eda10fbb9..e0467251aa 100644
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -34,14 +34,10 @@
try:
from collections import OrderedDict
-except ImportError:
- from ordereddict import OrderedDict #PY26
-
-try:
- import unittest2 as unittest #PY26
except ImportError:
- import unittest
-
+ from ordereddict import OrderedDict #PY26
+import collections
+import unittest
from google.protobuf import descriptor_pb2
from google.protobuf import descriptor_pool
from google.protobuf import proto_builder
diff --git a/python/google/protobuf/internal/python_message.py b/python/google/protobuf/internal/python_message.py
index 4e5032a7ed..2b87f7045c 100755
--- a/python/google/protobuf/internal/python_message.py
+++ b/python/google/protobuf/internal/python_message.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2007 Google Inc. All Rights Reserved.
-#
# This code is meant to work on Python 2.4 and above only.
#
# TODO(robinson): Helpers for verbose, common checks like seeing if a
diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py
index 266113533b..6815c238c6 100755
--- a/python/google/protobuf/internal/reflection_test.py
+++ b/python/google/protobuf/internal/reflection_test.py
@@ -38,14 +38,10 @@ pure-Python protocol compiler.
import copy
import gc
import operator
-import struct
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
-
import six
+import struct
+import unittest
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
@@ -1627,7 +1623,7 @@ class ReflectionTest(unittest.TestCase):
self.assertFalse(proto.IsInitialized(errors))
self.assertEqual(errors, ['a', 'b', 'c'])
- @unittest.skipIf(
+ @test_util.skipIf(
api_implementation.Type() != 'cpp' or api_implementation.Version() != 2,
'Errors are only available from the most recent C++ implementation.')
def testFileDescriptorErrors(self):
@@ -1799,7 +1795,6 @@ class ReflectionTest(unittest.TestCase):
# Just check the default value.
self.assertEqual(57, msg.inner.value)
-
# Since we had so many tests for protocol buffer equality, we broke these out
# into separate TestCase classes.
@@ -2827,7 +2822,7 @@ class OptionsTest(unittest.TestCase):
class ClassAPITest(unittest.TestCase):
- @unittest.skipIf(
+ @test_util.skipIf(
api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
'C++ implementation requires a call to MakeDescriptor()')
def testMakeClassWithNestedDescriptor(self):
diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py
index 98614b77f6..564e2d1a39 100755
--- a/python/google/protobuf/internal/service_reflection_test.py
+++ b/python/google/protobuf/internal/service_reflection_test.py
@@ -34,10 +34,7 @@
__author__ = 'petar@google.com (Petar Petrov)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import unittest_pb2
from google.protobuf import service_reflection
from google.protobuf import service
diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py
index 9744226296..7fb4b56d62 100644
--- a/python/google/protobuf/internal/symbol_database_test.py
+++ b/python/google/protobuf/internal/symbol_database_test.py
@@ -32,27 +32,29 @@
"""Tests for google.protobuf.symbol_database."""
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import unittest_pb2
+from google.protobuf import descriptor
from google.protobuf import symbol_database
-
class SymbolDatabaseTest(unittest.TestCase):
def _Database(self):
- db = symbol_database.SymbolDatabase()
- # Register representative types from unittest_pb2.
- db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
- db.RegisterMessage(unittest_pb2.TestAllTypes)
- db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
- db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
- db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
- db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
- db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
- return db
+ # TODO(b/17734095): Remove this difference when the C++ implementation
+ # supports multiple databases.
+ if descriptor._USE_C_DESCRIPTORS:
+ return symbol_database.Default()
+ else:
+ db = symbol_database.SymbolDatabase()
+ # Register representative types from unittest_pb2.
+ db.RegisterFileDescriptor(unittest_pb2.DESCRIPTOR)
+ db.RegisterMessage(unittest_pb2.TestAllTypes)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.NestedMessage)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.OptionalGroup)
+ db.RegisterMessage(unittest_pb2.TestAllTypes.RepeatedGroup)
+ db.RegisterEnumDescriptor(unittest_pb2.ForeignEnum.DESCRIPTOR)
+ db.RegisterEnumDescriptor(unittest_pb2.TestAllTypes.NestedEnum.DESCRIPTOR)
+ return db
def testGetPrototype(self):
instance = self._Database().GetPrototype(
diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py
index ac88fa81d8..539236b4cd 100755
--- a/python/google/protobuf/internal/test_util.py
+++ b/python/google/protobuf/internal/test_util.py
@@ -38,6 +38,13 @@ __author__ = 'robinson@google.com (Will Robinson)'
import os.path
+import sys
+# PY2.6 compatible skipIf
+if sys.version_info < (2, 7):
+ from unittest2 import skipIf
+else:
+ from unittest import skipIf
+
from google.protobuf import unittest_import_pb2
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2
diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py
index 338a287b1b..9e7b9ce433 100755
--- a/python/google/protobuf/internal/text_encoding_test.py
+++ b/python/google/protobuf/internal/text_encoding_test.py
@@ -32,10 +32,7 @@
"""Tests for google.protobuf.text_encoding."""
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import text_encoding
TEST_VALUES = [
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index d332b77dbc..fb4addeb25 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -34,14 +34,12 @@
__author__ = 'kenton@google.com (Kenton Varda)'
+
import re
import six
import string
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf.internal import _parameterized
from google.protobuf import map_unittest_pb2
@@ -389,7 +387,7 @@ class TextFormatTest(TextFormatBase):
# Ideally the schemas would be made more similar so these tests could pass.
class OnlyWorksWithProto2RightNowTests(TextFormatBase):
- def testPrintAllFieldsPointy(self, message_module):
+ def testPrintAllFieldsPointy(self):
message = unittest_pb2.TestAllTypes()
test_util.SetAllFields(message)
self.CompareToGoldenFile(
diff --git a/python/google/protobuf/internal/type_checkers.py b/python/google/protobuf/internal/type_checkers.py
index 8fa3d8c835..f30ca6a80e 100755
--- a/python/google/protobuf/internal/type_checkers.py
+++ b/python/google/protobuf/internal/type_checkers.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2008 Google Inc. All Rights Reserved.
-
"""Provides type checking routines.
This module defines type checking utilities in the forms of dictionaries:
@@ -52,6 +50,7 @@ import six
if six.PY3:
long = int
+from google.protobuf.internal import api_implementation
from google.protobuf.internal import decoder
from google.protobuf.internal import encoder
from google.protobuf.internal import wire_format
diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py
index 011d3b55da..25b447e18b 100755
--- a/python/google/protobuf/internal/unknown_fields_test.py
+++ b/python/google/protobuf/internal/unknown_fields_test.py
@@ -35,11 +35,7 @@
__author__ = 'bohdank@google.com (Bohdan Koval)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
-
+import unittest
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_pb2
from google.protobuf import unittest_proto3_arena_pb2
@@ -52,7 +48,7 @@ from google.protobuf.internal import type_checkers
def SkipIfCppImplementation(func):
- return unittest.skipIf(
+ return test_util.skipIf(
api_implementation.Type() == 'cpp' and api_implementation.Version() == 2,
'C++ implementation does not expose unknown fields to Python')(func)
@@ -262,6 +258,19 @@ class UnknownEnumValuesTest(unittest.TestCase):
decoder(value, 0, len(value), self.message, result_dict)
return result_dict[field_descriptor]
+ def testUnknownParseMismatchEnumValue(self):
+ just_string = missing_enum_values_pb2.JustString()
+ just_string.dummy = 'blah'
+
+ missing = missing_enum_values_pb2.TestEnumValues()
+ # The parse is invalid, storing the string proto into the set of
+ # unknown fields.
+ missing.ParseFromString(just_string.SerializeToString())
+
+ # Fetching the enum field shouldn't crash, instead returning the
+ # default value.
+ self.assertEqual(missing.optional_nested_enum, 0)
+
@SkipIfCppImplementation
def testUnknownEnumValue(self):
self.assertFalse(self.missing_message.HasField('optional_nested_enum'))
diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py
index f659d18e42..78dc11670f 100755
--- a/python/google/protobuf/internal/wire_format_test.py
+++ b/python/google/protobuf/internal/wire_format_test.py
@@ -34,10 +34,7 @@
__author__ = 'robinson@google.com (Will Robinson)'
-try:
- import unittest2 as unittest
-except ImportError:
- import unittest
+import unittest
from google.protobuf import message
from google.protobuf.internal import wire_format
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
new file mode 100644
index 0000000000..09110e04dd
--- /dev/null
+++ b/python/google/protobuf/json_format.py
@@ -0,0 +1,601 @@
+# Protocol Buffers - Google's data interchange format
+# Copyright 2008 Google Inc. All rights reserved.
+# https://developers.google.com/protocol-buffers/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Contains routines for printing protocol messages in JSON format."""
+
+__author__ = 'jieluo@google.com (Jie Luo)'
+
+import base64
+from datetime import datetime
+import json
+import math
+import re
+
+from google.protobuf import descriptor
+
+_TIMESTAMPFOMAT = '%Y-%m-%dT%H:%M:%S'
+_NUMBER = re.compile(u'[0-9+-][0-9e.+-]*')
+_INTEGER = re.compile(u'[0-9+-]')
+_INT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT32,
+ descriptor.FieldDescriptor.CPPTYPE_UINT32,
+ descriptor.FieldDescriptor.CPPTYPE_INT64,
+ descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_INT64_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_INT64,
+ descriptor.FieldDescriptor.CPPTYPE_UINT64])
+_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
+ descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
+if str is bytes:
+ _UNICODETYPE = unicode
+else:
+ _UNICODETYPE = str
+
+
+class SerializeToJsonError(Exception):
+ """Thrown if serialization to JSON fails."""
+
+
+class ParseError(Exception):
+ """Thrown in case of parsing error."""
+
+
+def MessageToJson(message, including_default_value_fields=False):
+ """Converts protobuf message to JSON format.
+
+ Args:
+ message: The protocol buffers message instance to serialize.
+ including_default_value_fields: If True, singular primitive fields,
+ repeated fields, and map fields will always be serialized. If
+ False, only serialize non-empty fields. Singular message fields
+ and oneof fields are not affected by this option.
+
+ Returns:
+ A string containing the JSON formatted protocol buffer message.
+ """
+ js = _MessageToJsonObject(message, including_default_value_fields)
+ return json.dumps(js, indent=2)
+
+
+def _MessageToJsonObject(message, including_default_value_fields):
+ """Converts message to an object according to Proto3 JSON Specification."""
+ message_descriptor = message.DESCRIPTOR
+ if _IsTimestampMessage(message_descriptor):
+ return _TimestampMessageToJsonObject(message)
+ if _IsDurationMessage(message_descriptor):
+ return _DurationMessageToJsonObject(message)
+ if _IsFieldMaskMessage(message_descriptor):
+ return _FieldMaskMessageToJsonObject(message)
+ if _IsWrapperMessage(message_descriptor):
+ return _WrapperMessageToJsonObject(message)
+ return _RegularMessageToJsonObject(message, including_default_value_fields)
+
+
+def _IsMapEntry(field):
+ return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and
+ field.message_type.has_options and
+ field.message_type.GetOptions().map_entry)
+
+
+def _RegularMessageToJsonObject(message, including_default_value_fields):
+ """Converts normal message according to Proto3 JSON Specification."""
+ js = {}
+ fields = message.ListFields()
+
+ try:
+ for field, value in fields:
+ name = field.camelcase_name
+ if _IsMapEntry(field):
+ # Convert a map field.
+ js_map = {}
+ for key in value:
+ js_map[key] = _ConvertFieldToJsonObject(
+ field.message_type.fields_by_name['value'],
+ value[key], including_default_value_fields)
+ js[name] = js_map
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ # Convert a repeated field.
+ repeated = []
+ for element in value:
+ repeated.append(_ConvertFieldToJsonObject(
+ field, element, including_default_value_fields))
+ js[name] = repeated
+ else:
+ js[name] = _ConvertFieldToJsonObject(
+ field, value, including_default_value_fields)
+
+ # Serialize default value if including_default_value_fields is True.
+ if including_default_value_fields:
+ message_descriptor = message.DESCRIPTOR
+ for field in message_descriptor.fields:
+ # Singular message fields and oneof fields will not be affected.
+ if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
+ field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
+ field.containing_oneof):
+ continue
+ name = field.camelcase_name
+ if name in js:
+ # Skip the field which has been serailized already.
+ continue
+ if _IsMapEntry(field):
+ js[name] = {}
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ js[name] = []
+ else:
+ js[name] = _ConvertFieldToJsonObject(field, field.default_value)
+
+ except ValueError as e:
+ raise SerializeToJsonError(
+ 'Failed to serialize {0} field: {1}'.format(field.name, e))
+
+ return js
+
+
+def _ConvertFieldToJsonObject(
+ field, value, including_default_value_fields=False):
+ """Converts field value according to Proto3 JSON Specification."""
+ if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ return _MessageToJsonObject(value, including_default_value_fields)
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+ enum_value = field.enum_type.values_by_number.get(value, None)
+ if enum_value is not None:
+ return enum_value.name
+ else:
+ raise SerializeToJsonError('Enum field contains an integer value '
+ 'which can not mapped to an enum value.')
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+ if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+ # Use base64 Data encoding for bytes
+ return base64.b64encode(value).decode('utf-8')
+ else:
+ return value
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+ if value:
+ return True
+ else:
+ return False
+ elif field.cpp_type in _INT64_TYPES:
+ return str(value)
+ elif field.cpp_type in _FLOAT_TYPES:
+ if math.isinf(value):
+ if value < 0.0:
+ return '-Infinity'
+ else:
+ return 'Infinity'
+ if math.isnan(value):
+ return 'NaN'
+ return value
+
+
+def _IsTimestampMessage(message_descriptor):
+ return (message_descriptor.name == 'Timestamp' and
+ message_descriptor.file.name == 'google/protobuf/timestamp.proto')
+
+
+def _TimestampMessageToJsonObject(message):
+ """Converts Timestamp message according to Proto3 JSON Specification."""
+ nanos = message.nanos % 1e9
+ dt = datetime.utcfromtimestamp(
+ message.seconds + (message.nanos - nanos) / 1e9)
+ result = dt.isoformat()
+ if (nanos % 1e9) == 0:
+ # If there are 0 fractional digits, the fractional
+ # point '.' should be omitted when serializing.
+ return result + 'Z'
+ if (nanos % 1e6) == 0:
+ # Serialize 3 fractional digits.
+ return result + '.%03dZ' % (nanos / 1e6)
+ if (nanos % 1e3) == 0:
+ # Serialize 6 fractional digits.
+ return result + '.%06dZ' % (nanos / 1e3)
+ # Serialize 9 fractional digits.
+ return result + '.%09dZ' % nanos
+
+
+def _IsDurationMessage(message_descriptor):
+ return (message_descriptor.name == 'Duration' and
+ message_descriptor.file.name == 'google/protobuf/duration.proto')
+
+
+def _DurationMessageToJsonObject(message):
+ """Converts Duration message according to Proto3 JSON Specification."""
+ if message.seconds < 0 or message.nanos < 0:
+ result = '-'
+ seconds = - message.seconds + int((0 - message.nanos) / 1e9)
+ nanos = (0 - message.nanos) % 1e9
+ else:
+ result = ''
+ seconds = message.seconds + int(message.nanos / 1e9)
+ nanos = message.nanos % 1e9
+ result += '%d' % seconds
+ if (nanos % 1e9) == 0:
+ # If there are 0 fractional digits, the fractional
+ # point '.' should be omitted when serializing.
+ return result + 's'
+ if (nanos % 1e6) == 0:
+ # Serialize 3 fractional digits.
+ return result + '.%03ds' % (nanos / 1e6)
+ if (nanos % 1e3) == 0:
+ # Serialize 6 fractional digits.
+ return result + '.%06ds' % (nanos / 1e3)
+ # Serialize 9 fractional digits.
+ return result + '.%09ds' % nanos
+
+
+def _IsFieldMaskMessage(message_descriptor):
+ return (message_descriptor.name == 'FieldMask' and
+ message_descriptor.file.name == 'google/protobuf/field_mask.proto')
+
+
+def _FieldMaskMessageToJsonObject(message):
+ """Converts FieldMask message according to Proto3 JSON Specification."""
+ result = ''
+ first = True
+ for path in message.paths:
+ if not first:
+ result += ','
+ result += path
+ first = False
+ return result
+
+
+def _IsWrapperMessage(message_descriptor):
+ return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
+
+
+def _WrapperMessageToJsonObject(message):
+ return _ConvertFieldToJsonObject(
+ message.DESCRIPTOR.fields_by_name['value'], message.value)
+
+
+def _DuplicateChecker(js):
+ result = {}
+ for name, value in js:
+ if name in result:
+ raise ParseError('Failed to load JSON: duplicate key ' + name)
+ result[name] = value
+ return result
+
+
+def Parse(text, message):
+ """Parses a JSON representation of a protocol message into a message.
+
+ Args:
+ text: Message JSON representation.
+ message: A protocol beffer message to merge into.
+
+ Returns:
+ The same message passed as argument.
+
+ Raises::
+ ParseError: On JSON parsing problems.
+ """
+ if not isinstance(text, _UNICODETYPE): text = text.decode('utf-8')
+ try:
+ js = json.loads(text, object_pairs_hook=_DuplicateChecker)
+ except ValueError as e:
+ raise ParseError('Failed to load JSON: ' + str(e))
+ _ConvertFieldValuePair(js, message)
+ return message
+
+
+def _ConvertFieldValuePair(js, message):
+ """Convert field value pairs into regular message.
+
+ Args:
+ js: A JSON object to convert the field value pairs.
+ message: A regular protocol message to record the data.
+
+ Raises:
+ ParseError: In case of problems converting.
+ """
+ names = []
+ message_descriptor = message.DESCRIPTOR
+ for name in js:
+ try:
+ field = message_descriptor.fields_by_camelcase_name.get(name, None)
+ if not field:
+ raise ParseError(
+ 'Message type "{0}" has no field named "{1}".'.format(
+ message_descriptor.full_name, name))
+ if name in names:
+ raise ParseError(
+ 'Message type "{0}" should not have multiple "{1}" fields.'.format(
+ message.DESCRIPTOR.full_name, name))
+ names.append(name)
+ # Check no other oneof field is parsed.
+ if field.containing_oneof is not None:
+ oneof_name = field.containing_oneof.name
+ if oneof_name in names:
+ raise ParseError('Message type "{0}" should not have multiple "{1}" '
+ 'oneof fields.'.format(
+ message.DESCRIPTOR.full_name, oneof_name))
+ names.append(oneof_name)
+
+ value = js[name]
+ if value is None:
+ message.ClearField(field.name)
+ continue
+
+ # Parse field value.
+ if _IsMapEntry(field):
+ message.ClearField(field.name)
+ _ConvertMapFieldValue(value, message, field)
+ elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+ message.ClearField(field.name)
+ if not isinstance(value, list):
+ raise ParseError('repeated field {0} must be in [] which is '
+ '{1}'.format(name, value))
+ for item in value:
+ if item is None:
+ continue
+ if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ sub_message = getattr(message, field.name).add()
+ _ConvertMessage(item, sub_message)
+ else:
+ getattr(message, field.name).append(
+ _ConvertScalarFieldValue(item, field))
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ sub_message = getattr(message, field.name)
+ _ConvertMessage(value, sub_message)
+ else:
+ setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+ except ParseError as e:
+ if field and field.containing_oneof is None:
+ raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+ else:
+ raise ParseError(str(e))
+ except ValueError as e:
+ raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+ except TypeError as e:
+ raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+
+
+def _ConvertMessage(value, message):
+ """Convert a JSON object into a message.
+
+ Args:
+ value: A JSON object.
+ message: A WKT or regular protocol message to record the data.
+
+ Raises:
+ ParseError: In case of convert problems.
+ """
+ message_descriptor = message.DESCRIPTOR
+ if _IsTimestampMessage(message_descriptor):
+ _ConvertTimestampMessage(value, message)
+ elif _IsDurationMessage(message_descriptor):
+ _ConvertDurationMessage(value, message)
+ elif _IsFieldMaskMessage(message_descriptor):
+ _ConvertFieldMaskMessage(value, message)
+ elif _IsWrapperMessage(message_descriptor):
+ _ConvertWrapperMessage(value, message)
+ else:
+ _ConvertFieldValuePair(value, message)
+
+
+def _ConvertTimestampMessage(value, message):
+ """Convert a JSON representation into Timestamp message."""
+ timezone_offset = value.find('Z')
+ if timezone_offset == -1:
+ timezone_offset = value.find('+')
+ if timezone_offset == -1:
+ timezone_offset = value.rfind('-')
+ if timezone_offset == -1:
+ raise ParseError(
+ 'Failed to parse timestamp: missing valid timezone offset.')
+ time_value = value[0:timezone_offset]
+ # Parse datetime and nanos
+ point_position = time_value.find('.')
+ if point_position == -1:
+ second_value = time_value
+ nano_value = ''
+ else:
+ second_value = time_value[:point_position]
+ nano_value = time_value[point_position + 1:]
+ date_object = datetime.strptime(second_value, _TIMESTAMPFOMAT)
+ seconds = (date_object - datetime(1970, 1, 1)).total_seconds()
+ if len(nano_value) > 9:
+ raise ParseError(
+ 'Failed to parse Timestamp: nanos {0} more than '
+ '9 fractional digits.'.format(nano_value))
+ if nano_value:
+ nanos = round(float('0.' + nano_value) * 1e9)
+ else:
+ nanos = 0
+ # Parse timezone offsets
+ if value[timezone_offset] == 'Z':
+ if len(value) != timezone_offset + 1:
+ raise ParseError(
+ 'Failed to parse timestamp: invalid trailing data {0}.'.format(value))
+ else:
+ timezone = value[timezone_offset:]
+ pos = timezone.find(':')
+ if pos == -1:
+ raise ParseError(
+ 'Invalid timezone offset value: ' + timezone)
+ if timezone[0] == '+':
+ seconds += (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+ else:
+ seconds -= (int(timezone[1:pos])*60+int(timezone[pos+1:]))*60
+ # Set seconds and nanos
+ message.seconds = int(seconds)
+ message.nanos = int(nanos)
+
+
+def _ConvertDurationMessage(value, message):
+ """Convert a JSON representation into Duration message."""
+ if value[-1] != 's':
+ raise ParseError(
+ 'Duration must end with letter "s": ' + value)
+ try:
+ duration = float(value[:-1])
+ except ValueError:
+ raise ParseError(
+ 'Couldn\'t parse duration: ' + value)
+ message.seconds = int(duration)
+ message.nanos = int(round((duration - message.seconds) * 1e9))
+
+
+def _ConvertFieldMaskMessage(value, message):
+ """Convert a JSON representation into FieldMask message."""
+ for path in value.split(','):
+ message.paths.append(path)
+
+
+def _ConvertWrapperMessage(value, message):
+ """Convert a JSON representation into Wrapper message."""
+ field = message.DESCRIPTOR.fields_by_name['value']
+ setattr(message, 'value', _ConvertScalarFieldValue(value, field))
+
+
+def _ConvertMapFieldValue(value, message, field):
+ """Convert map field value for a message map field.
+
+ Args:
+ value: A JSON object to convert the map field value.
+ message: A protocol message to record the converted data.
+ field: The descriptor of the map field to be converted.
+
+ Raises:
+ ParseError: In case of convert problems.
+ """
+ if not isinstance(value, dict):
+ raise ParseError(
+ 'Map fieled {0} must be in {} which is {1}.'.format(field.name, value))
+ key_field = field.message_type.fields_by_name['key']
+ value_field = field.message_type.fields_by_name['value']
+ for key in value:
+ key_value = _ConvertScalarFieldValue(key, key_field, True)
+ if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+ _ConvertMessage(value[key], getattr(message, field.name)[key_value])
+ else:
+ getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+ value[key], value_field)
+
+
+def _ConvertScalarFieldValue(value, field, require_quote=False):
+ """Convert a single scalar field value.
+
+ Args:
+ value: A scalar value to convert the scalar field value.
+ field: The descriptor of the field to convert.
+ require_quote: If True, '"' is required for the field value.
+
+ Returns:
+ The converted scalar field value
+
+ Raises:
+ ParseError: In case of convert problems.
+ """
+ if field.cpp_type in _INT_TYPES:
+ return _ConvertInteger(value)
+ elif field.cpp_type in _FLOAT_TYPES:
+ return _ConvertFloat(value)
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+ return _ConvertBool(value, require_quote)
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+ if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+ return base64.b64decode(value)
+ else:
+ return value
+ elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+ # Convert an enum value.
+ enum_value = field.enum_type.values_by_name.get(value, None)
+ if enum_value is None:
+ raise ParseError(
+ 'Enum value must be a string literal with double quotes. '
+ 'Type "{0}" has no value named {1}.'.format(
+ field.enum_type.full_name, value))
+ return enum_value.number
+
+
+def _ConvertInteger(value):
+ """Convert an integer.
+
+ Args:
+ value: A scalar value to convert.
+
+ Returns:
+ The integer value.
+
+ Raises:
+ ParseError: If an integer couldn't be consumed.
+ """
+ if isinstance(value, float):
+ raise ParseError('Couldn\'t parse integer: {0}'.format(value))
+
+ if isinstance(value, _UNICODETYPE) and not _INTEGER.match(value):
+ raise ParseError('Couldn\'t parse integer: "{0}"'.format(value))
+
+ return int(value)
+
+
+def _ConvertFloat(value):
+ """Convert an floating point number."""
+ if value == 'nan':
+ raise ParseError('Couldn\'t parse float "nan", use "NaN" instead')
+ try:
+ # Assume Python compatible syntax.
+ return float(value)
+ except ValueError:
+ # Check alternative spellings.
+ if value == '-Infinity':
+ return float('-inf')
+ elif value == 'Infinity':
+ return float('inf')
+ elif value == 'NaN':
+ return float('nan')
+ else:
+ raise ParseError('Couldn\'t parse float: {0}'.format(value))
+
+
+def _ConvertBool(value, require_quote):
+ """Convert a boolean value.
+
+ Args:
+ value: A scalar value to convert.
+ require_quote: If True, '"' is required for the boolean value.
+
+ Returns:
+ The bool parsed.
+
+ Raises:
+ ParseError: If a boolean value couldn't be consumed.
+ """
+ if require_quote:
+ if value == 'true':
+ return True
+ elif value == 'false':
+ return False
+ else:
+ raise ParseError('Expect "true" or "false", not {0}.'.format(value))
+
+ if not isinstance(value, bool):
+ raise ParseError('Expected true or false without quotes.')
+ return value
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
index 36062a5693..9cd9c2a810 100644
--- a/python/google/protobuf/message_factory.py
+++ b/python/google/protobuf/message_factory.py
@@ -28,8 +28,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2012 Google Inc. All Rights Reserved.
-
"""Provides a factory class for generating dynamic messages.
The easiest way to use this class is if you have access to the FileDescriptor
diff --git a/python/google/protobuf/proto_builder.py b/python/google/protobuf/proto_builder.py
index 700e3c25e5..736caed385 100644
--- a/python/google/protobuf/proto_builder.py
+++ b/python/google/protobuf/proto_builder.py
@@ -48,7 +48,7 @@ def _GetMessageFromFactory(factory, full_name):
factory: a MessageFactory instance.
full_name: str, the fully qualified name of the proto type.
Returns:
- a class, for the type identified by full_name.
+ A class, for the type identified by full_name.
Raises:
KeyError, if the proto is not found in the factory's descriptor pool.
"""
@@ -57,7 +57,7 @@ def _GetMessageFromFactory(factory, full_name):
return proto_cls
-def MakeSimpleProtoClass(fields, full_name, pool=None):
+def MakeSimpleProtoClass(fields, full_name=None, pool=None):
"""Create a Protobuf class whose fields are basic types.
Note: this doesn't validate field names!
@@ -66,18 +66,20 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
fields: dict of {name: field_type} mappings for each field in the proto. If
this is an OrderedDict the order will be maintained, otherwise the
fields will be sorted by name.
- full_name: str, the fully-qualified name of the proto type.
+ full_name: optional str, the fully-qualified name of the proto type.
pool: optional DescriptorPool instance.
Returns:
a class, the new protobuf class with a FileDescriptor.
"""
factory = message_factory.MessageFactory(pool=pool)
- try:
- proto_cls = _GetMessageFromFactory(factory, full_name)
- return proto_cls
- except KeyError:
- # The factory's DescriptorPool doesn't know about this class yet.
- pass
+
+ if full_name is not None:
+ try:
+ proto_cls = _GetMessageFromFactory(factory, full_name)
+ return proto_cls
+ except KeyError:
+ # The factory's DescriptorPool doesn't know about this class yet.
+ pass
# Get a list of (name, field_type) tuples from the fields dict. If fields was
# an OrderedDict we keep the order, but otherwise we sort the field to ensure
@@ -94,6 +96,25 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
fields_hash.update(str(f_type).encode('utf-8'))
proto_file_name = fields_hash.hexdigest() + '.proto'
+ # If the proto is anonymous, use the same hash to name it.
+ if full_name is None:
+ full_name = ('net.proto2.python.public.proto_builder.AnonymousProto_' +
+ fields_hash.hexdigest())
+ try:
+ proto_cls = _GetMessageFromFactory(factory, full_name)
+ return proto_cls
+ except KeyError:
+ # The factory's DescriptorPool doesn't know about this class yet.
+ pass
+
+ # This is the first time we see this proto: add a new descriptor to the pool.
+ factory.pool.Add(
+ _MakeFileDescriptorProto(proto_file_name, full_name, field_items))
+ return _GetMessageFromFactory(factory, full_name)
+
+
+def _MakeFileDescriptorProto(proto_file_name, full_name, field_items):
+ """Populate FileDescriptorProto for MessageFactory's DescriptorPool."""
package, name = full_name.rsplit('.', 1)
file_proto = descriptor_pb2.FileDescriptorProto()
file_proto.name = os.path.join(package.replace('.', '/'), proto_file_name)
@@ -106,6 +127,4 @@ def MakeSimpleProtoClass(fields, full_name, pool=None):
field_proto.number = f_number
field_proto.label = descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL
field_proto.type = f_type
-
- factory.pool.Add(file_proto)
- return _GetMessageFromFactory(factory, full_name)
+ return file_proto
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 3806643f11..b238fd0272 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -223,8 +223,7 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) {
options.SerializeToString(&serialized);
io::CodedInputStream input(
reinterpret_cast(serialized.c_str()), serialized.size());
- input.SetExtensionRegistry(pool->pool,
- GetDescriptorPool()->message_factory);
+ input.SetExtensionRegistry(pool->pool, pool->message_factory);
bool success = cmsg->message->MergePartialFromCodedStream(&input);
if (!success) {
PyErr_Format(PyExc_ValueError, "Error parsing Options message");
@@ -414,8 +413,14 @@ static PyObject* GetFile(PyBaseDescriptor *self, void *closure) {
}
static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) {
+ // Retuns the canonical class for the given descriptor.
+ // This is the class that was registered with the primary descriptor pool
+ // which contains this descriptor.
+ // This might not be the one you expect! For example the returned object does
+ // not know about extensions defined in a custom pool.
PyObject* concrete_class(cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), _GetDescriptor(self)));
+ GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()),
+ _GetDescriptor(self)));
Py_XINCREF(concrete_class);
return concrete_class;
}
@@ -424,6 +429,11 @@ static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) {
return NewMessageFieldsByName(_GetDescriptor(self));
}
+static PyObject* GetFieldsByCamelcaseName(PyBaseDescriptor* self,
+ void *closure) {
+ return NewMessageFieldsByCamelcaseName(_GetDescriptor(self));
+}
+
static PyObject* GetFieldsByNumber(PyBaseDescriptor* self, void *closure) {
return NewMessageFieldsByNumber(_GetDescriptor(self));
}
@@ -564,6 +574,8 @@ static PyGetSetDef Getters[] = {
{ "fields", (getter)GetFieldsSeq, NULL, "Fields sequence"},
{ "fields_by_name", (getter)GetFieldsByName, NULL, "Fields by name"},
+ { "fields_by_camelcase_name", (getter)GetFieldsByCamelcaseName, NULL,
+ "Fields by camelCase name"},
{ "fields_by_number", (getter)GetFieldsByNumber, NULL, "Fields by number"},
{ "nested_types", (getter)GetNestedTypesSeq, NULL, "Nested types sequence"},
{ "nested_types_by_name", (getter)GetNestedTypesByName, NULL,
@@ -662,6 +674,10 @@ static PyObject* GetName(PyBaseDescriptor *self, void *closure) {
return PyString_FromCppString(_GetDescriptor(self)->name());
}
+static PyObject* GetCamelcaseName(PyBaseDescriptor* self, void *closure) {
+ return PyString_FromCppString(_GetDescriptor(self)->camelcase_name());
+}
+
static PyObject* GetType(PyBaseDescriptor *self, void *closure) {
return PyInt_FromLong(_GetDescriptor(self)->type());
}
@@ -850,6 +866,7 @@ static int SetOptions(PyBaseDescriptor *self, PyObject *value,
static PyGetSetDef Getters[] = {
{ "full_name", (getter)GetFullName, NULL, "Full name"},
{ "name", (getter)GetName, NULL, "Unqualified name"},
+ { "camelcase_name", (getter)GetCamelcaseName, NULL, "Camelcase name"},
{ "type", (getter)GetType, NULL, "C++ Type"},
{ "cpp_type", (getter)GetCppType, NULL, "C++ Type"},
{ "label", (getter)GetLabel, NULL, "Label"},
@@ -1070,6 +1087,15 @@ PyObject* PyEnumDescriptor_FromDescriptor(
&PyEnumDescriptor_Type, enum_descriptor, NULL);
}
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj) {
+ if (!PyObject_TypeCheck(obj, &PyEnumDescriptor_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not an EnumDescriptor");
+ return NULL;
+ }
+ return reinterpret_cast(
+ reinterpret_cast(obj)->descriptor);
+}
+
namespace enumvalue_descriptor {
// Unchecked accessor to the C++ pointer.
@@ -1359,6 +1385,15 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
return py_descriptor;
}
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj) {
+ if (!PyObject_TypeCheck(obj, &PyFileDescriptor_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Not a FileDescriptor");
+ return NULL;
+ }
+ return reinterpret_cast(
+ reinterpret_cast(obj)->descriptor);
+}
+
namespace oneof_descriptor {
// Unchecked accessor to the C++ pointer.
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index b2550406c3..eb99df182e 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -72,6 +72,8 @@ PyObject* PyFileDescriptor_FromDescriptorWithSerializedPb(
// exception set.
const Descriptor* PyMessageDescriptor_AsDescriptor(PyObject* obj);
const FieldDescriptor* PyFieldDescriptor_AsDescriptor(PyObject* obj);
+const EnumDescriptor* PyEnumDescriptor_AsDescriptor(PyObject* obj);
+const FileDescriptor* PyFileDescriptor_AsDescriptor(PyObject* obj);
// Returns the raw C++ pointer.
const void* PyDescriptor_AsVoidPtr(PyObject* obj);
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index 92e11e3122..b20f5e4ffe 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -79,9 +79,12 @@ struct PyContainer;
typedef int (*CountMethod)(PyContainer* self);
typedef const void* (*GetByIndexMethod)(PyContainer* self, int index);
typedef const void* (*GetByNameMethod)(PyContainer* self, const string& name);
+typedef const void* (*GetByCamelcaseNameMethod)(PyContainer* self,
+ const string& name);
typedef const void* (*GetByNumberMethod)(PyContainer* self, int index);
typedef PyObject* (*NewObjectFromItemMethod)(const void* descriptor);
typedef const string& (*GetItemNameMethod)(const void* descriptor);
+typedef const string& (*GetItemCamelcaseNameMethod)(const void* descriptor);
typedef int (*GetItemNumberMethod)(const void* descriptor);
typedef int (*GetItemIndexMethod)(const void* descriptor);
@@ -95,6 +98,9 @@ struct DescriptorContainerDef {
// Retrieve item by name (usually a call to some 'FindByName' method).
// Used by "by_name" mappings.
GetByNameMethod get_by_name_fn;
+ // Retrieve item by camelcase name (usually a call to some
+ // 'FindByCamelcaseName' method). Used by "by_camelcase_name" mappings.
+ GetByCamelcaseNameMethod get_by_camelcase_name_fn;
// Retrieve item by declared number (field tag, or enum value).
// Used by "by_number" mappings.
GetByNumberMethod get_by_number_fn;
@@ -102,6 +108,9 @@ struct DescriptorContainerDef {
NewObjectFromItemMethod new_object_from_item_fn;
// Retrieve the name of an item. Used by iterators on "by_name" mappings.
GetItemNameMethod get_item_name_fn;
+ // Retrieve the camelcase name of an item. Used by iterators on
+ // "by_camelcase_name" mappings.
+ GetItemCamelcaseNameMethod get_item_camelcase_name_fn;
// Retrieve the number of an item. Used by iterators on "by_number" mappings.
GetItemNumberMethod get_item_number_fn;
// Retrieve the index of an item for the container type.
@@ -125,6 +134,7 @@ struct PyContainer {
enum ContainerKind {
KIND_SEQUENCE,
KIND_BYNAME,
+ KIND_BYCAMELCASENAME,
KIND_BYNUMBER,
} kind;
};
@@ -172,6 +182,23 @@ static bool _GetItemByKey(PyContainer* self, PyObject* key, const void** item) {
self, string(name, name_size));
return true;
}
+ case PyContainer::KIND_BYCAMELCASENAME:
+ {
+ char* camelcase_name;
+ Py_ssize_t name_size;
+ if (PyString_AsStringAndSize(key, &camelcase_name, &name_size) < 0) {
+ if (PyErr_ExceptionMatches(PyExc_TypeError)) {
+ // Not a string, cannot be in the container.
+ PyErr_Clear();
+ *item = NULL;
+ return true;
+ }
+ return false;
+ }
+ *item = self->container_def->get_by_camelcase_name_fn(
+ self, string(camelcase_name, name_size));
+ return true;
+ }
case PyContainer::KIND_BYNUMBER:
{
Py_ssize_t number = PyNumber_AsSsize_t(key, NULL);
@@ -203,6 +230,12 @@ static PyObject* _NewKey_ByIndex(PyContainer* self, Py_ssize_t index) {
const string& name(self->container_def->get_item_name_fn(item));
return PyString_FromStringAndSize(name.c_str(), name.size());
}
+ case PyContainer::KIND_BYCAMELCASENAME:
+ {
+ const string& name(
+ self->container_def->get_item_camelcase_name_fn(item));
+ return PyString_FromStringAndSize(name.c_str(), name.size());
+ }
case PyContainer::KIND_BYNUMBER:
{
int value = self->container_def->get_item_number_fn(item);
@@ -276,6 +309,9 @@ static PyObject* ContainerRepr(PyContainer* self) {
case PyContainer::KIND_BYNAME:
kind = "mapping by name";
break;
+ case PyContainer::KIND_BYCAMELCASENAME:
+ kind = "mapping by camelCase name";
+ break;
case PyContainer::KIND_BYNUMBER:
kind = "mapping by number";
break;
@@ -731,6 +767,18 @@ static PyObject* NewMappingByName(
return reinterpret_cast(self);
}
+static PyObject* NewMappingByCamelcaseName(
+ DescriptorContainerDef* container_def, const void* descriptor) {
+ PyContainer* self = PyObject_New(PyContainer, &DescriptorMapping_Type);
+ if (self == NULL) {
+ return NULL;
+ }
+ self->descriptor = descriptor;
+ self->container_def = container_def;
+ self->kind = PyContainer::KIND_BYCAMELCASENAME;
+ return reinterpret_cast(self);
+}
+
static PyObject* NewMappingByNumber(
DescriptorContainerDef* container_def, const void* descriptor) {
if (container_def->get_by_number_fn == NULL ||
@@ -889,6 +937,11 @@ static ItemDescriptor GetByName(PyContainer* self, const string& name) {
return GetDescriptor(self)->FindFieldByName(name);
}
+static ItemDescriptor GetByCamelcaseName(PyContainer* self,
+ const string& name) {
+ return GetDescriptor(self)->FindFieldByCamelcaseName(name);
+}
+
static ItemDescriptor GetByNumber(PyContainer* self, int number) {
return GetDescriptor(self)->FindFieldByNumber(number);
}
@@ -905,6 +958,10 @@ static const string& GetItemName(ItemDescriptor item) {
return item->name();
}
+static const string& GetItemCamelcaseName(ItemDescriptor item) {
+ return item->camelcase_name();
+}
+
static int GetItemNumber(ItemDescriptor item) {
return item->number();
}
@@ -918,9 +975,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)GetByCamelcaseName,
(GetByNumberMethod)GetByNumber,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)GetItemCamelcaseName,
(GetItemNumberMethod)GetItemNumber,
(GetItemIndexMethod)GetItemIndex,
};
@@ -931,6 +990,11 @@ PyObject* NewMessageFieldsByName(ParentDescriptor descriptor) {
return descriptor::NewMappingByName(&fields::ContainerDef, descriptor);
}
+PyObject* NewMessageFieldsByCamelcaseName(ParentDescriptor descriptor) {
+ return descriptor::NewMappingByCamelcaseName(&fields::ContainerDef,
+ descriptor);
+}
+
PyObject* NewMessageFieldsByNumber(ParentDescriptor descriptor) {
return descriptor::NewMappingByNumber(&fields::ContainerDef, descriptor);
}
@@ -972,9 +1036,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1022,9 +1088,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1094,9 +1162,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL,
};
@@ -1140,9 +1210,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1190,9 +1262,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1258,9 +1332,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)GetByNumber,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)GetItemNumber,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1314,9 +1390,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1370,9 +1448,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1416,9 +1496,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1462,9 +1544,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)GetByName,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)GetItemName,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)GetItemIndex,
};
@@ -1496,9 +1580,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL,
};
@@ -1530,9 +1616,11 @@ static DescriptorContainerDef ContainerDef = {
(CountMethod)Count,
(GetByIndexMethod)GetByIndex,
(GetByNameMethod)NULL,
+ (GetByCamelcaseNameMethod)NULL,
(GetByNumberMethod)NULL,
(NewObjectFromItemMethod)NewObjectFromItem,
(GetItemNameMethod)NULL,
+ (GetItemCamelcaseNameMethod)NULL,
(GetItemNumberMethod)NULL,
(GetItemIndexMethod)NULL,
};
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index 8fbdaff9d3..ce40747d57 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -54,6 +54,7 @@ bool InitDescriptorMappingTypes();
namespace message_descriptor {
PyObject* NewMessageFieldsByName(const Descriptor* descriptor);
+PyObject* NewMessageFieldsByCamelcaseName(const Descriptor* descriptor);
PyObject* NewMessageFieldsByNumber(const Descriptor* descriptor);
PyObject* NewMessageFieldsSeq(const Descriptor* descriptor);
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index 7aed651d3f..6443a7d5c9 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -108,6 +108,7 @@ static void Dealloc(PyDescriptorPool* self) {
Py_DECREF(it->second);
}
delete self->descriptor_options;
+ delete self->pool;
delete self->message_factory;
Py_TYPE(self)->tp_free(reinterpret_cast(self));
}
@@ -131,22 +132,9 @@ PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) {
}
// Add a message class to our database.
-const Descriptor* RegisterMessageClass(
- PyDescriptorPool* self, PyObject *message_class, PyObject* descriptor) {
- ScopedPyObjectPtr full_message_name(
- PyObject_GetAttrString(descriptor, "full_name"));
- Py_ssize_t name_size;
- char* name;
- if (PyString_AsStringAndSize(full_message_name, &name, &name_size) < 0) {
- return NULL;
- }
- const Descriptor *message_descriptor =
- self->pool->FindMessageTypeByName(string(name, name_size));
- if (!message_descriptor) {
- PyErr_Format(PyExc_TypeError, "Could not find C++ descriptor for '%s'",
- name);
- return NULL;
- }
+int RegisterMessageClass(PyDescriptorPool* self,
+ const Descriptor *message_descriptor,
+ PyObject *message_class) {
Py_INCREF(message_class);
typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator;
std::pair ret = self->classes_by_descriptor->insert(
@@ -156,7 +144,7 @@ const Descriptor* RegisterMessageClass(
Py_DECREF(ret.first->second);
ret.first->second = message_class;
}
- return message_descriptor;
+ return 0;
}
// Retrieve the message class added to our database.
@@ -260,6 +248,80 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg) {
return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
}
+PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
+ Py_ssize_t name_size;
+ char* name;
+ if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+ return NULL;
+ }
+
+ const FileDescriptor* file_descriptor =
+ self->pool->FindFileContainingSymbol(string(name, name_size));
+ if (file_descriptor == NULL) {
+ PyErr_Format(PyExc_KeyError, "Couldn't find symbol %.200s", name);
+ return NULL;
+ }
+
+ return PyFileDescriptor_FromDescriptor(file_descriptor);
+}
+
+// These functions should not exist -- the only valid way to create
+// descriptors is to call Add() or AddSerializedFile().
+// But these AddDescriptor() functions were created in Python and some people
+// call them, so we support them for now for compatibility.
+// However we do check that the existing descriptor already exists in the pool,
+// which appears to always be true for existing calls -- but then why do people
+// call a function that will just be a no-op?
+// TODO(amauryfa): Need to investigate further.
+
+PyObject* AddFileDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+ const FileDescriptor* file_descriptor =
+ PyFileDescriptor_AsDescriptor(descriptor);
+ if (!file_descriptor) {
+ return NULL;
+ }
+ if (file_descriptor !=
+ self->pool->FindFileByName(file_descriptor->name())) {
+ PyErr_Format(PyExc_ValueError,
+ "The file descriptor %s does not belong to this pool",
+ file_descriptor->name().c_str());
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject* AddDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+ const Descriptor* message_descriptor =
+ PyMessageDescriptor_AsDescriptor(descriptor);
+ if (!message_descriptor) {
+ return NULL;
+ }
+ if (message_descriptor !=
+ self->pool->FindMessageTypeByName(message_descriptor->full_name())) {
+ PyErr_Format(PyExc_ValueError,
+ "The message descriptor %s does not belong to this pool",
+ message_descriptor->full_name().c_str());
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject* AddEnumDescriptor(PyDescriptorPool* self, PyObject* descriptor) {
+ const EnumDescriptor* enum_descriptor =
+ PyEnumDescriptor_AsDescriptor(descriptor);
+ if (!enum_descriptor) {
+ return NULL;
+ }
+ if (enum_descriptor !=
+ self->pool->FindEnumTypeByName(enum_descriptor->full_name())) {
+ PyErr_Format(PyExc_ValueError,
+ "The enum descriptor %s does not belong to this pool",
+ enum_descriptor->full_name().c_str());
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
// The code below loads new Descriptors from a serialized FileDescriptorProto.
@@ -341,6 +403,15 @@ static PyMethodDef Methods[] = {
{ "AddSerializedFile", (PyCFunction)AddSerializedFile, METH_O,
"Adds a serialized FileDescriptorProto to this pool." },
+ // TODO(amauryfa): Understand why the Python implementation differs from
+ // this one, ask users to use another API and deprecate these functions.
+ { "AddFileDescriptor", (PyCFunction)AddFileDescriptor, METH_O,
+ "No-op. Add() must have been called before." },
+ { "AddDescriptor", (PyCFunction)AddDescriptor, METH_O,
+ "No-op. Add() must have been called before." },
+ { "AddEnumDescriptor", (PyCFunction)AddEnumDescriptor, METH_O,
+ "No-op. Add() must have been called before." },
+
{ "FindFileByName", (PyCFunction)FindFileByName, METH_O,
"Searches for a file descriptor by its .proto name." },
{ "FindMessageTypeByName", (PyCFunction)FindMessageByName, METH_O,
@@ -353,6 +424,9 @@ static PyMethodDef Methods[] = {
"Searches for enum type descriptor by full name." },
{ "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
"Searches for oneof descriptor by full name." },
+
+ { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
+ "Gets the FileDescriptor containing the specified symbol." },
{NULL}
};
@@ -420,7 +494,7 @@ bool InitDescriptorPool() {
return true;
}
-PyDescriptorPool* GetDescriptorPool() {
+PyDescriptorPool* GetDefaultDescriptorPool() {
return python_generated_pool;
}
@@ -432,7 +506,7 @@ PyDescriptorPool* GetDescriptorPool_FromPool(const DescriptorPool* pool) {
}
hash_map::iterator it =
descriptor_pool_map.find(pool);
- if (it != descriptor_pool_map.end()) {
+ if (it == descriptor_pool_map.end()) {
PyErr_SetString(PyExc_KeyError, "Unknown descriptor pool");
return NULL;
}
diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h
index 541d920bc8..eda73d385e 100644
--- a/python/google/protobuf/pyext/descriptor_pool.h
+++ b/python/google/protobuf/pyext/descriptor_pool.h
@@ -89,12 +89,10 @@ const Descriptor* FindMessageTypeByName(PyDescriptorPool* self,
const string& name);
// Registers a new Python class for the given message descriptor.
-// Returns the message Descriptor.
-// On error, returns NULL with a Python exception set.
-const Descriptor* RegisterMessageClass(
- PyDescriptorPool* self, PyObject* message_class, PyObject* descriptor);
-
-// The function below are also exposed as methods of the DescriptorPool type.
+// On error, returns -1 with a Python exception set.
+int RegisterMessageClass(PyDescriptorPool* self,
+ const Descriptor* message_descriptor,
+ PyObject* message_class);
// Retrieves the Python class registered with the given message descriptor.
//
@@ -103,6 +101,8 @@ const Descriptor* RegisterMessageClass(
PyObject* GetMessageClass(PyDescriptorPool* self,
const Descriptor* message_descriptor);
+// The functions below are also exposed as methods of the DescriptorPool type.
+
// Looks up a message by name. Returns a PyMessageDescriptor corresponding to
// the field on success, or NULL on failure.
//
@@ -136,8 +136,9 @@ PyObject* FindOneofByName(PyDescriptorPool* self, PyObject* arg);
} // namespace cdescriptor_pool
// Retrieve the global descriptor pool owned by the _message module.
+// This is the one used by pb2.py generated modules.
// Returns a *borrowed* reference.
-PyDescriptorPool* GetDescriptorPool();
+PyDescriptorPool* GetDefaultDescriptorPool();
// Retrieve the python descriptor pool owning a C++ descriptor pool.
// Returns a *borrowed* reference.
diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc
index 8ebbb27c46..9c9b417822 100644
--- a/python/google/protobuf/pyext/extension_dict.cc
+++ b/python/google/protobuf/pyext/extension_dict.cc
@@ -123,7 +123,8 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) {
if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) {
if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject *message_class = cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), descriptor->message_type());
+ cmessage::GetDescriptorPoolForMessage(self->parent),
+ descriptor->message_type());
if (message_class == NULL) {
return NULL;
}
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 62c7c478f5..63d531364b 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -107,8 +108,18 @@ struct PyMessageMeta {
// C++ descriptor of this message.
const Descriptor* message_descriptor;
+
// Owned reference, used to keep the pointer above alive.
PyObject* py_message_descriptor;
+
+ // The Python DescriptorPool used to create the class. It is needed to resolve
+ // fields descriptors, including extensions fields; its C++ MessageFactory is
+ // used to instantiate submessages.
+ // This can be different from DESCRIPTOR.file.pool, in the case of a custom
+ // DescriptorPool which defines new extensions.
+ // We own the reference, because it's important to keep the descriptors and
+ // factory alive.
+ PyDescriptorPool* py_descriptor_pool;
};
namespace message_meta {
@@ -139,18 +150,10 @@ static bool AddFieldNumberToClass(
// Finalize the creation of the Message class.
-// Called from its metaclass: GeneratedProtocolMessageType.__init__().
-static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
- const Descriptor* message_descriptor =
- cdescriptor_pool::RegisterMessageClass(
- GetDescriptorPool(), cls, descriptor);
- if (message_descriptor == NULL) {
- return -1;
- }
-
+static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) {
// If there are extension_ranges, the message is "extendable", and extension
// classes will register themselves in this class.
- if (message_descriptor->extension_range_count() > 0) {
+ if (descriptor->extension_range_count() > 0) {
ScopedPyObjectPtr by_name(PyDict_New());
if (PyObject_SetAttr(cls, k_extensions_by_name, by_name) < 0) {
return -1;
@@ -162,8 +165,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
}
// For each field set: cls._FIELD_NUMBER =
- for (int i = 0; i < message_descriptor->field_count(); ++i) {
- if (!AddFieldNumberToClass(cls, message_descriptor->field(i))) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ if (!AddFieldNumberToClass(cls, descriptor->field(i))) {
return -1;
}
}
@@ -173,8 +176,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
// The enum descriptor we get from
// .enum_types_by_name[name]
// which was built previously.
- for (int i = 0; i < message_descriptor->enum_type_count(); ++i) {
- const EnumDescriptor* enum_descriptor = message_descriptor->enum_type(i);
+ for (int i = 0; i < descriptor->enum_type_count(); ++i) {
+ const EnumDescriptor* enum_descriptor = descriptor->enum_type(i);
ScopedPyObjectPtr enum_type(
PyEnumDescriptor_FromDescriptor(enum_descriptor));
if (enum_type == NULL) {
@@ -212,8 +215,8 @@ static int AddDescriptors(PyObject* cls, PyObject* descriptor) {
// Extension descriptors come from
// .extensions_by_name[name]
// which was defined previously.
- for (int i = 0; i < message_descriptor->extension_count(); ++i) {
- const google::protobuf::FieldDescriptor* field = message_descriptor->extension(i);
+ for (int i = 0; i < descriptor->extension_count(); ++i) {
+ const google::protobuf::FieldDescriptor* field = descriptor->extension(i);
ScopedPyObjectPtr extension_field(PyFieldDescriptor_FromDescriptor(field));
if (extension_field == NULL) {
return -1;
@@ -258,14 +261,14 @@ static PyObject* New(PyTypeObject* type,
}
// Check dict['DESCRIPTOR']
- PyObject* descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
- if (descriptor == NULL) {
+ PyObject* py_descriptor = PyDict_GetItem(dict, kDESCRIPTOR);
+ if (py_descriptor == NULL) {
PyErr_SetString(PyExc_TypeError, "Message class has no DESCRIPTOR");
return NULL;
}
- if (!PyObject_TypeCheck(descriptor, &PyMessageDescriptor_Type)) {
+ if (!PyObject_TypeCheck(py_descriptor, &PyMessageDescriptor_Type)) {
PyErr_Format(PyExc_TypeError, "Expected a message Descriptor, got %s",
- descriptor->ob_type->tp_name);
+ py_descriptor->ob_type->tp_name);
return NULL;
}
@@ -291,14 +294,28 @@ static PyObject* New(PyTypeObject* type,
}
// Cache the descriptor, both as Python object and as C++ pointer.
- const Descriptor* message_descriptor =
- PyMessageDescriptor_AsDescriptor(descriptor);
- if (message_descriptor == NULL) {
+ const Descriptor* descriptor =
+ PyMessageDescriptor_AsDescriptor(py_descriptor);
+ if (descriptor == NULL) {
+ return NULL;
+ }
+ Py_INCREF(py_descriptor);
+ newtype->py_message_descriptor = py_descriptor;
+ newtype->message_descriptor = descriptor;
+ // TODO(amauryfa): Don't always use the canonical pool of the descriptor,
+ // use the MessageFactory optionally passed in the class dict.
+ newtype->py_descriptor_pool = GetDescriptorPool_FromPool(
+ descriptor->file()->pool());
+ if (newtype->py_descriptor_pool == NULL) {
+ return NULL;
+ }
+ Py_INCREF(newtype->py_descriptor_pool);
+
+ // Add the message to the DescriptorPool.
+ if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool,
+ descriptor, result) < 0) {
return NULL;
}
- Py_INCREF(descriptor);
- newtype->py_message_descriptor = descriptor;
- newtype->message_descriptor = message_descriptor;
// Continue with type initialization: add other descriptors, enum values...
if (AddDescriptors(result, descriptor) < 0) {
@@ -309,6 +326,7 @@ static PyObject* New(PyTypeObject* type,
static void Dealloc(PyMessageMeta *self) {
Py_DECREF(self->py_message_descriptor);
+ Py_DECREF(self->py_descriptor_pool);
Py_TYPE(self)->tp_free(reinterpret_cast(self));
}
@@ -381,12 +399,20 @@ PyTypeObject PyMessageMeta_Type = {
message_meta::New, // tp_new
};
-static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+static PyMessageMeta* CheckMessageClass(PyTypeObject* cls) {
if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) {
PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name);
return NULL;
}
- return reinterpret_cast(cls)->message_descriptor;
+ return reinterpret_cast(cls);
+}
+
+static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) {
+ PyMessageMeta* type = CheckMessageClass(cls);
+ if (type == NULL) {
+ return NULL;
+ }
+ return type->message_descriptor;
}
// Forward declarations
@@ -723,6 +749,17 @@ bool CheckFieldBelongsToMessage(const FieldDescriptor* field_descriptor,
namespace cmessage {
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) {
+ // No need to check the type: the type of instances of CMessage is always
+ // an instance of PyMessageMeta. Let's prove it with a debug-only check.
+ GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type));
+ return reinterpret_cast(Py_TYPE(message))->py_descriptor_pool;
+}
+
+MessageFactory* GetFactoryForMessage(CMessage* message) {
+ return GetDescriptorPoolForMessage(message)->message_factory;
+}
+
static int MaybeReleaseOverlappingOneofField(
CMessage* cmessage,
const FieldDescriptor* field) {
@@ -773,7 +810,7 @@ static Message* GetMutableMessage(
return NULL;
}
return reflection->MutableMessage(
- parent_message, parent_field, GetDescriptorPool()->message_factory);
+ parent_message, parent_field, GetFactoryForMessage(parent));
}
struct FixupMessageReference : public ChildVisitor {
@@ -814,10 +851,7 @@ int AssureWritable(CMessage* self) {
// If parent is NULL but we are trying to modify a read-only message, this
// is a reference to a constant default instance that needs to be replaced
// with a mutable top-level message.
- const Message* prototype =
- GetDescriptorPool()->message_factory->GetPrototype(
- self->message->GetDescriptor());
- self->message = prototype->New();
+ self->message = self->message->New();
self->owner.reset(self->message);
// Cascade the new owner to eventual children: even if this message is
// empty, some submessages or repeated containers might exist already.
@@ -1190,15 +1224,19 @@ CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) {
// The __new__ method of Message classes.
// Creates a new C++ message and takes ownership.
-static PyObject* New(PyTypeObject* type,
+static PyObject* New(PyTypeObject* cls,
PyObject* unused_args, PyObject* unused_kwargs) {
+ PyMessageMeta* type = CheckMessageClass(cls);
+ if (type == NULL) {
+ return NULL;
+ }
// Retrieve the message descriptor and the default instance (=prototype).
- const Descriptor* message_descriptor = GetMessageDescriptor(type);
+ const Descriptor* message_descriptor = type->message_descriptor;
if (message_descriptor == NULL) {
return NULL;
}
- const Message* default_message =
- GetDescriptorPool()->message_factory->GetPrototype(message_descriptor);
+ const Message* default_message = type->py_descriptor_pool->message_factory
+ ->GetPrototype(message_descriptor);
if (default_message == NULL) {
PyErr_SetString(PyExc_TypeError, message_descriptor->full_name().c_str());
return NULL;
@@ -1528,7 +1566,7 @@ int SetOwner(CMessage* self, const shared_ptr& new_owner) {
Message* ReleaseMessage(CMessage* self,
const Descriptor* descriptor,
const FieldDescriptor* field_descriptor) {
- MessageFactory* message_factory = GetDescriptorPool()->message_factory;
+ MessageFactory* message_factory = GetFactoryForMessage(self);
Message* released_message = self->message->GetReflection()->ReleaseMessage(
self->message, field_descriptor, message_factory);
// ReleaseMessage will return NULL which differs from
@@ -1883,8 +1921,8 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) {
AssureWritable(self);
io::CodedInputStream input(
reinterpret_cast(data), data_length);
- input.SetExtensionRegistry(GetDescriptorPool()->pool,
- GetDescriptorPool()->message_factory);
+ PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
+ input.SetExtensionRegistry(pool->pool, pool->message_factory);
bool success = self->message->MergePartialFromCodedStream(&input);
if (success) {
return PyInt_FromLong(input.CurrentPosition());
@@ -1907,11 +1945,6 @@ static PyObject* ByteSize(CMessage* self, PyObject* args) {
static PyObject* RegisterExtension(PyObject* cls,
PyObject* extension_handle) {
- ScopedPyObjectPtr message_descriptor(PyObject_GetAttr(cls, kDESCRIPTOR));
- if (message_descriptor == NULL) {
- return NULL;
- }
-
const FieldDescriptor* descriptor =
GetExtensionDescriptor(extension_handle);
if (descriptor == NULL) {
@@ -1920,13 +1953,6 @@ static PyObject* RegisterExtension(PyObject* cls,
const Descriptor* cmessage_descriptor = GetMessageDescriptor(
reinterpret_cast(cls));
- if (cmessage_descriptor != descriptor->containing_type()) {
- if (PyObject_SetAttrString(extension_handle, "containing_type",
- message_descriptor) < 0) {
- return NULL;
- }
- }
-
ScopedPyObjectPtr extensions_by_name(
PyObject_GetAttr(cls, k_extensions_by_name));
if (extensions_by_name == NULL) {
@@ -2050,7 +2076,8 @@ static PyObject* ListFields(CMessage* self) {
// TODO(amauryfa): consider building the class on the fly!
if (fields[i]->message_type() != NULL &&
cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), fields[i]->message_type()) == NULL) {
+ GetDescriptorPoolForMessage(self),
+ fields[i]->message_type()) == NULL) {
PyErr_Clear();
continue;
}
@@ -2207,7 +2234,9 @@ PyObject* InternalGetScalar(const Message* message,
message->GetReflection()->GetUnknownFields(*message);
for (int i = 0; i < unknown_field_set.field_count(); ++i) {
if (unknown_field_set.field(i).number() ==
- field_descriptor->number()) {
+ field_descriptor->number() &&
+ unknown_field_set.field(i).type() ==
+ google::protobuf::UnknownField::TYPE_VARINT) {
result = PyInt_FromLong(unknown_field_set.field(i).varint());
break;
}
@@ -2233,11 +2262,12 @@ PyObject* InternalGetScalar(const Message* message,
PyObject* InternalGetSubMessage(
CMessage* self, const FieldDescriptor* field_descriptor) {
const Reflection* reflection = self->message->GetReflection();
+ PyDescriptorPool* pool = GetDescriptorPoolForMessage(self);
const Message& sub_message = reflection->GetMessage(
- *self->message, field_descriptor, GetDescriptorPool()->message_factory);
+ *self->message, field_descriptor, pool->message_factory);
PyObject *message_class = cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), field_descriptor->message_type());
+ pool, field_descriptor->message_type());
if (message_class == NULL) {
return NULL;
}
@@ -2560,7 +2590,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
const FieldDescriptor* value_type = entry_type->FindFieldByName("value");
if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject* value_class = cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), value_type->message_type());
+ GetDescriptorPoolForMessage(self), value_type->message_type());
if (value_class == NULL) {
return NULL;
}
@@ -2583,7 +2613,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) {
PyObject* py_container = NULL;
if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
PyObject *message_class = cdescriptor_pool::GetMessageClass(
- GetDescriptorPool(), field_descriptor->message_type());
+ GetDescriptorPoolForMessage(self), field_descriptor->message_type());
if (message_class == NULL) {
return NULL;
}
@@ -2908,9 +2938,10 @@ bool InitProto2MessageModule(PyObject *m) {
// Expose the DescriptorPool used to hold all descriptors added from generated
// pb2.py files.
- Py_INCREF(GetDescriptorPool()); // PyModule_AddObject steals a reference.
- PyModule_AddObject(
- m, "default_pool", reinterpret_cast(GetDescriptorPool()));
+ // PyModule_AddObject steals a reference.
+ Py_INCREF(GetDefaultDescriptorPool());
+ PyModule_AddObject(m, "default_pool",
+ reinterpret_cast(GetDefaultDescriptorPool()));
// This implementation provides full Descriptor types, we advertise it so that
// descriptor.py can use them in replacement of the Python classes.
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index f147d433ef..1ff82e2f64 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -49,12 +49,15 @@ class Message;
class Reflection;
class FieldDescriptor;
class Descriptor;
+class DescriptorPool;
+class MessageFactory;
using internal::shared_ptr;
namespace python {
struct ExtensionDict;
+struct PyDescriptorPool;
typedef struct CMessage {
PyObject_HEAD;
@@ -220,6 +223,16 @@ PyObject* FindInitializationErrors(CMessage* self);
int SetOwner(CMessage* self, const shared_ptr& new_owner);
int AssureWritable(CMessage* self);
+
+// Returns the "best" DescriptorPool for the given message.
+// This is often equivalent to message.DESCRIPTOR.pool, but not always, when
+// the message class was created from a MessageFactory using a custom pool which
+// uses the generated pool as an underlay.
+//
+// The returned pool is suitable for finding fields and building submessages,
+// even in the case of extensions.
+PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
+
} // namespace cmessage
diff --git a/python/google/protobuf/symbol_database.py b/python/google/protobuf/symbol_database.py
index 4c70b3938d..b81ef4d78c 100644
--- a/python/google/protobuf/symbol_database.py
+++ b/python/google/protobuf/symbol_database.py
@@ -60,6 +60,7 @@ Example usage:
"""
+from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool
@@ -72,6 +73,31 @@ class SymbolDatabase(object):
buffer types used within a program.
"""
+ # pylint: disable=protected-access
+ if _descriptor._USE_C_DESCRIPTORS:
+
+ def __new__(cls):
+ raise TypeError("Instances of SymbolDatabase cannot be created")
+
+ @classmethod
+ def _CreateDefaultDatabase(cls):
+ self = object.__new__(cls) # Bypass the __new__ above.
+ # Don't call __init__() and initialize here.
+ self._symbols = {}
+ self._symbols_by_file = {}
+ # As of today all descriptors are registered and retrieved from
+ # _message.default_pool (see FileDescriptor.__new__), so it's not
+ # necessary to use another pool.
+ self.pool = _descriptor._message.default_pool
+ return self
+ # pylint: enable=protected-access
+
+ else:
+
+ @classmethod
+ def _CreateDefaultDatabase(cls):
+ return cls()
+
def __init__(self):
"""Constructor."""
@@ -177,7 +203,7 @@ class SymbolDatabase(object):
result.update(self._symbols_by_file[f])
return result
-_DEFAULT = SymbolDatabase()
+_DEFAULT = SymbolDatabase._CreateDefaultDatabase()
def Default():
diff --git a/python/google/protobuf/text_encoding.py b/python/google/protobuf/text_encoding.py
index a0728e3ca8..9899563825 100644
--- a/python/google/protobuf/text_encoding.py
+++ b/python/google/protobuf/text_encoding.py
@@ -27,6 +27,7 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
"""Encoding related utilities."""
import re
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 1399223fbf..e4fadf09e8 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -28,9 +28,17 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-# Copyright 2007 Google Inc. All Rights Reserved.
+"""Contains routines for printing protocol messages in text format.
-"""Contains routines for printing protocol messages in text format."""
+Simple usage example:
+
+ # Create a proto object and serialize it to a text proto string.
+ message = my_proto_pb2.MyMessage(foo='bar')
+ text_proto = text_format.MessageToString(message)
+
+ # Parse a text proto string.
+ message = text_format.Parse(text_proto, my_proto_pb2.MyMessage())
+"""
__author__ = 'kenton@google.com (Kenton Varda)'
diff --git a/python/google/protobuf/util/__init__.py b/python/google/protobuf/util/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/python/setup.py b/python/setup.py
index 8269c4a5f4..a7bc6cd6b2 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -88,6 +88,15 @@ def GenerateUnittestProtos():
generate_proto("../src/google/protobuf/unittest_mset_wire_format.proto", False)
generate_proto("../src/google/protobuf/unittest_no_generic_services.proto", False)
generate_proto("../src/google/protobuf/unittest_proto3_arena.proto", False)
+ # Move the well-known-types proto to required when they are no longer only
+ # required by json format tests.
+ generate_proto("../src/google/protobuf/timestamp.proto", False)
+ generate_proto("../src/google/protobuf/duration.proto", False)
+ generate_proto("../src/google/protobuf/wrappers.proto", False)
+ generate_proto("../src/google/protobuf/struct.proto", False)
+ generate_proto("../src/google/protobuf/any.proto", False)
+ generate_proto("../src/google/protobuf/field_mask.proto", False)
+ generate_proto("../src/google/protobuf/util/json_format_proto3.proto", False)
generate_proto("google/protobuf/internal/descriptor_pool_test1.proto", False)
generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
generate_proto("google/protobuf/internal/factory_test1.proto", False)
diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc
index c6ed37ae38..7351d3773b 100644
--- a/src/google/protobuf/any.cc
+++ b/src/google/protobuf/any.cc
@@ -43,6 +43,7 @@ string GetTypeUrl(const Descriptor* message) {
const char kAnyFullTypeName[] = "google.protobuf.Any";
const char kTypeGoogleApisComPrefix[] = "type.googleapis.com/";
+const char kTypeGoogleProdComPrefix[] = "type.googleprod.com/";
AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value)
: type_url_(type_url), value_(value) {
@@ -70,11 +71,17 @@ bool AnyMetadata::InternalIs(const Descriptor* descriptor) const {
}
bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) {
- const int prefix_len = strlen(kTypeGoogleApisComPrefix);
- if (strncmp(type_url.c_str(), kTypeGoogleApisComPrefix, prefix_len) == 0) {
- full_type_name->assign(type_url.data() + prefix_len,
- type_url.size() - prefix_len);
- return true;
+ static const char* prefix[] = {
+ kTypeGoogleApisComPrefix,
+ kTypeGoogleProdComPrefix
+ };
+ for (int i = 0; i < 2; i++) {
+ const int prefix_len = strlen(prefix[i]);
+ if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) {
+ full_type_name->assign(type_url.data() + prefix_len,
+ type_url.size() - prefix_len);
+ return true;
+ }
}
return false;
}
diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h
index 7eeb6b707a..f760ad5d24 100644
--- a/src/google/protobuf/any.h
+++ b/src/google/protobuf/any.h
@@ -70,6 +70,7 @@ class LIBPROTOBUF_EXPORT AnyMetadata {
extern const char kAnyFullTypeName[]; // "google.protobuf.Any".
extern const char kTypeGoogleApisComPrefix[]; // "type.googleapis.com/".
+extern const char kTypeGoogleProdComPrefix[]; // "type.googleprod.com/".
// Get the proto type name from Any::type_url value. For example, passing
// "type.googleapis.com/rpc.QueryOrigin" will return "rpc.QueryOrigin" in
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 907a6a20c5..74b0965520 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -38,17 +38,17 @@ namespace google {
namespace protobuf {
google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
-Arena::ThreadCache& Arena::thread_cache() {
- static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
- return thread_cache_;
-}
-#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
Arena::ThreadCache& Arena::thread_cache() {
static internal::ThreadLocalStorage* thread_cache_ =
new internal::ThreadLocalStorage();
return *thread_cache_->Get();
}
+#elif defined(PROTOBUF_USE_DLLS)
+Arena::ThreadCache& Arena::thread_cache() {
+ static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
+ return thread_cache_;
+}
#else
GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
#endif
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index 074a9e5411..16e0d50edb 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -38,7 +38,16 @@
#if __cplusplus >= 201103L
#include
#endif
+#if defined(_MSC_VER) && !_HAS_EXCEPTIONS
+// Work around bugs in MSVC header when _HAS_EXCEPTIONS=0.
+#include
#include
+namespace std {
+using type_info = ::type_info;
+}
+#else
+#include
+#endif
#include
#include
@@ -533,15 +542,15 @@ class LIBPROTOBUF_EXPORT Arena {
static const size_t kHeaderSize = sizeof(Block);
static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
-#ifdef PROTOBUF_USE_DLLS
- // Thread local variables cannot be exposed through DLL interface but we can
- // wrap them in static functions.
- static ThreadCache& thread_cache();
-#elif defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
+#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
// Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
// local storage class we implemented.
// iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
static ThreadCache& thread_cache();
+#elif defined(PROTOBUF_USE_DLLS)
+ // Thread local variables cannot be exposed through DLL interface but we can
+ // wrap them in static functions.
+ static ThreadCache& thread_cache();
#else
static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
static ThreadCache& thread_cache() { return thread_cache_; }
@@ -581,11 +590,13 @@ class LIBPROTOBUF_EXPORT Arena {
template
static double DestructorSkippable(...);
+ // The raw_skippable_value const bool variable is separated from the typedef
+ // line below as a work-around of an NVCC 7.0 (and earlier) compiler bug.
+ static const bool raw_skippable_value =
+ sizeof(DestructorSkippable(static_cast(0))) ==
+ sizeof(char) || google::protobuf::internal::has_trivial_destructor::value == true;
// This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
- typedef google::protobuf::internal::integral_constant(static_cast(0))) ==
- sizeof(char) || google::protobuf::internal::has_trivial_destructor::value == true>
- type;
+ typedef google::protobuf::internal::integral_constant type;
static const type value;
};
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index c9ca1fd18d..6b67f446fd 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -362,7 +362,7 @@ TEST(ArenaTest, ReleaseMessage) {
Arena arena;
TestAllTypes* arena_message = Arena::CreateMessage(&arena);
arena_message->mutable_optional_nested_message()->set_bb(118);
- scoped_ptr nested(
+ google::protobuf::scoped_ptr nested(
arena_message->release_optional_nested_message());
EXPECT_EQ(118, nested->bb());
@@ -383,7 +383,7 @@ TEST(ArenaTest, ReleaseString) {
Arena arena;
TestAllTypes* arena_message = Arena::CreateMessage(&arena);
arena_message->set_optional_string("hello");
- scoped_ptr released_str(
+ google::protobuf::scoped_ptr released_str(
arena_message->release_optional_string());
EXPECT_EQ("hello", *released_str);
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index 9560d0e0b4..46ea5c4e42 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -63,13 +63,13 @@
#include
#include
-namespace google {
-namespace protobuf {
-namespace compiler {
// Disable the whole test when we use tcmalloc for "draconian" heap checks, in
// which case tcmalloc will print warnings that fail the plugin tests.
#if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
+namespace google {
+namespace protobuf {
+namespace compiler {
#if defined(_WIN32)
#ifndef STDIN_FILENO
@@ -1800,8 +1800,8 @@ TEST_F(EncodeDecodeTest, ProtoParseError) {
} // anonymous namespace
-#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
-
} // namespace compiler
} // namespace protobuf
+
+#endif // !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN
} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index 25acc61bed..e5e2f07dd4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -66,7 +66,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["wrapper"] = "EntryWrapper";
break;
case FieldDescriptor::CPPTYPE_ENUM:
- (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
+ (*variables)["val_cpp"] = ClassName(val->enum_type(), true);
(*variables)["wrapper"] = "EnumEntryWrapper";
break;
default:
@@ -200,7 +200,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
case FieldDescriptor::CPPTYPE_ENUM:
printer->Print(variables_,
"(*mutable_$name$())[entry->key()] =\n"
- " static_cast<$val_cpp$>(*entry->mutable_value());\n");
+ " static_cast< $val_cpp$ >(*entry->mutable_value());\n");
break;
default:
printer->Print(variables_,
@@ -215,7 +215,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" DO_(entry->ParseFromString(data));\n"
" if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
" (*mutable_$name$())[entry->key()] =\n"
- " static_cast<$val_cpp$>(*entry->mutable_value());\n"
+ " static_cast< $val_cpp$ >(*entry->mutable_value());\n"
" } else {\n");
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index fc1ce962ab..8cc8c7bae2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -350,7 +350,7 @@ void CollectMapInfo(const Descriptor* descriptor,
(*variables)["val"] = FieldMessageTypeName(val);
break;
case FieldDescriptor::CPPTYPE_ENUM:
- (*variables)["val"] = ClassName(val->enum_type(), false);
+ (*variables)["val"] = ClassName(val->enum_type(), true);
break;
default:
(*variables)["val"] = PrimitiveTypeName(val->cpp_type());
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index 2c3608c290..e8bf15d0d5 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -299,7 +299,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
- " unknownFields.mergeVarintField($number$, rawValue);\n");
+ " super.mergeVarintField($number$, rawValue);\n");
}
printer->Print(variables_,
"} else {\n"
@@ -492,7 +492,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
- " unknownFields.mergeVarintField($number$, rawValue);\n");
+ " super.mergeVarintField($number$, rawValue);\n");
}
printer->Print(variables_,
"} else {\n"
@@ -850,7 +850,7 @@ GenerateParsingCode(io::Printer* printer) const {
"if (value == null) {\n");
if (PreserveUnknownFields(descriptor_->containing_type())) {
printer->Print(variables_,
- " unknownFields.mergeVarintField($number$, rawValue);\n");
+ " super.mergeVarintField($number$, rawValue);\n");
}
printer->Print(variables_,
"} else {\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index 4fe656d3bb..d2039403e9 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -405,7 +405,7 @@ GenerateParsingCode(io::Printer* printer) const {
printer->Print(
variables_,
"if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
- " unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
+ " super.mergeLengthDelimitedField($number$, bytes);\n"
"} else {\n"
" $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
"}\n");
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index 8b6c75b8ba..94ed2c396a 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -1029,12 +1029,6 @@ GenerateParsingConstructor(io::Printer* printer) {
"bit_field_name", GetBitFieldName(i));
}
- if (PreserveUnknownFields(descriptor_)) {
- printer->Print(
- "com.google.protobuf.UnknownFieldSetLite.Builder unknownFields =\n"
- " com.google.protobuf.UnknownFieldSetLite.newBuilder();\n");
- }
-
printer->Print(
"try {\n");
printer->Indent();
@@ -1056,13 +1050,10 @@ GenerateParsingConstructor(io::Printer* printer) {
if (PreserveUnknownFields(descriptor_)) {
if (descriptor_->extension_range_count() > 0) {
- // Lite runtime directly invokes parseUnknownField to reduce method
- // counts.
printer->Print(
"default: {\n"
- " if (!parseUnknownField(extensions, getDefaultInstanceForType(),\n"
- " input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
+ " if (!parseUnknownField(getDefaultInstanceForType(),\n"
+ " input, extensionRegistry, tag)) {\n"
" done = true;\n" // it's an endgroup tag
" }\n"
" break;\n"
@@ -1070,8 +1061,7 @@ GenerateParsingConstructor(io::Printer* printer) {
} else {
printer->Print(
"default: {\n"
- " if (!parseUnknownField(input, unknownFields,\n"
- " extensionRegistry, tag)) {\n"
+ " if (!parseUnknownField(tag, input)) {\n"
" done = true;\n" // it's an endgroup tag
" }\n"
" break;\n"
@@ -1146,16 +1136,8 @@ GenerateParsingConstructor(io::Printer* printer) {
field_generators_.get(field).GenerateParsingDoneCode(printer);
}
- if (PreserveUnknownFields(descriptor_)) {
- // Make unknown fields immutable.
- printer->Print("this.unknownFields = unknownFields.build();\n");
- }
-
- if (descriptor_->extension_range_count() > 0) {
- // Make extensions immutable.
- printer->Print(
- "makeExtensionsImmutable(extensions);\n");
- }
+ printer->Print(
+ "doneParsing();\n");
printer->Outdent();
printer->Outdent();
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 4d0184252b..a389a4fcee 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -993,6 +993,9 @@ bool Parser::ParseFieldOptions(FieldDescriptorProto* field,
// We intentionally pass field_location rather than location here, since
// the default value is not actually an option.
DO(ParseDefaultAssignment(field, field_location, containing_file));
+ } else if (LookingAt("json_name")) {
+ // Like default value, this "json_name" is not an actual option.
+ DO(ParseJsonName(field, field_location, containing_file));
} else {
DO(ParseOption(field->mutable_options(), location,
containing_file, OPTION_ASSIGNMENT));
@@ -1140,6 +1143,28 @@ bool Parser::ParseDefaultAssignment(
return true;
}
+bool Parser::ParseJsonName(
+ FieldDescriptorProto* field,
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file) {
+ if (field->has_json_name()) {
+ AddError("Already set option \"json_name\".");
+ field->clear_json_name();
+ }
+
+ DO(Consume("json_name"));
+ DO(Consume("="));
+
+ LocationRecorder location(field_location,
+ FieldDescriptorProto::kJsonNameFieldNumber);
+ location.RecordLegacyLocation(
+ field, DescriptorPool::ErrorCollector::OPTION_VALUE);
+ DO(ConsumeString(field->mutable_json_name(),
+ "Expected string for JSON name."));
+ return true;
+}
+
+
bool Parser::ParseOptionNamePart(UninterpretedOption* uninterpreted_option,
const LocationRecorder& part_location,
const FileDescriptorProto* containing_file) {
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index 007b001c35..3ba1e17077 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -439,6 +439,10 @@ class LIBPROTOBUF_EXPORT Parser {
const LocationRecorder& field_location,
const FileDescriptorProto* containing_file);
+ bool ParseJsonName(FieldDescriptorProto* field,
+ const LocationRecorder& field_location,
+ const FileDescriptorProto* containing_file);
+
enum OptionStyle {
OPTION_ASSIGNMENT, // just "name = value"
OPTION_STATEMENT // "option name = value;"
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index cc6f1efb21..0d729e0b99 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -452,6 +452,20 @@ TEST_F(ParseMessageTest, FieldDefaults) {
#undef ETC
}
+TEST_F(ParseMessageTest, FieldJsonName) {
+ ExpectParsesTo(
+ "message TestMessage {\n"
+ " optional string foo = 1 [json_name = \"@type\"];\n"
+ "}\n",
+ "message_type {"
+ " name: \"TestMessage\""
+ " field {\n"
+ " name: \"foo\" label: LABEL_OPTIONAL type: TYPE_STRING number: 1"
+ " json_name: \"@type\"\n"
+ " }\n"
+ "}\n");
+}
+
TEST_F(ParseMessageTest, FieldOptions) {
ExpectParsesTo(
"message TestMessage {\n"
@@ -1126,6 +1140,22 @@ TEST_F(ParseErrorTest, DefaultValueTooLarge) {
"6:36: Integer out of range.\n");
}
+TEST_F(ParseErrorTest, JsonNameNotString) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional string foo = 1 [json_name=1];\n"
+ "}\n",
+ "1:37: Expected string for JSON name.\n");
+}
+
+TEST_F(ParseErrorTest, DuplicateJsonName) {
+ ExpectHasErrors(
+ "message TestMessage {\n"
+ " optional uint32 foo = 1 [json_name=\"a\",json_name=\"b\"];\n"
+ "}\n",
+ "1:41: Already set option \"json_name\".\n");
+}
+
TEST_F(ParseErrorTest, EnumValueOutOfRange) {
ExpectHasErrors(
"enum TestEnum {\n"
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index e81af7009d..4d500f90e9 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -28,6 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#PY25 compatible generated code for GAE.
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: robinson@google.com (Will Robinson)
//
@@ -166,6 +167,7 @@ void PrintTopBoilerplate(
printer->Print(
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"# source: $filename$\n"
+ "\nimport sys\n_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))" //##PY25
"\n",
"filename", file->name());
if (HasTopLevelEnums(file)) {
@@ -257,9 +259,12 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_ENUM:
return SimpleItoa(field.default_value_enum()->number());
case FieldDescriptor::CPPTYPE_STRING:
- return "b\"" + CEscape(field.default_value_string()) +
- (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
- "\".decode('utf-8')");
+//##!PY25 return "b\"" + CEscape(field.default_value_string()) +
+//##!PY25 (field.type() != FieldDescriptor::TYPE_STRING ? "\"" :
+//##!PY25 "\".decode('utf-8')");
+ return "_b(\"" + CEscape(field.default_value_string()) + //##PY25
+ (field.type() != FieldDescriptor::TYPE_STRING ? "\")" : //##PY25
+ "\").decode('utf-8')"); //##PY25
case FieldDescriptor::CPPTYPE_MESSAGE:
return "None";
}
@@ -385,7 +390,8 @@ void Generator::PrintFileDescriptor() const {
printer_->Print(m, file_descriptor_template);
printer_->Indent();
printer_->Print(
- "serialized_pb=b'$value$'\n",
+//##!PY25 "serialized_pb=b'$value$'\n",
+ "serialized_pb=_b('$value$')\n", //##PY25
"value", strings::CHexEscape(file_descriptor_serialized_));
if (file_->dependency_count() != 0) {
printer_->Print(",\ndependencies=[");
@@ -1029,8 +1035,10 @@ string Generator::OptionsValue(
return "None";
} else {
string full_class_name = "descriptor_pb2." + class_name;
- return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
- + CEscape(serialized_options)+ "')";
+//##!PY25 return "_descriptor._ParseOptions(" + full_class_name + "(), b'"
+//##!PY25 + CEscape(serialized_options)+ "')";
+ return "_descriptor._ParseOptions(" + full_class_name + "(), _b('" //##PY25
+ + CEscape(serialized_options)+ "'))"; //##PY25
}
}
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 5256b83c44..b40fe95a91 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -34,6 +34,10 @@
#include
#include