zeep.exceptions.Fault - Invalid Enum Value | Python Zeep Enum Attribute Error - python

def generate_waybill(shipper, consignee, services, profile):
success = True
request = {
"Shipper": shipper,
"Consignee": consignee,
"Services": services
}
client = Client(url)
res = client.service.GenerateWayBill(Request=request, Profile=profile)
print("RESPONSE GENERATE WAYBILL: \n\n", res, res.json())
if not res:
success = False
return res, success
While calling the generate_waybill function i get an execption from zeep >>> 'Invalid enum value 'ProductType.Dutiables'
In the services object it has a key named as ProductType and its Data Type ProductType [Enumerator] and the allowed values for this fields are ProductType.Docs, ProductType.Dutiables.
The services object
services = {
"ProductCode": shipping_options['bluedart']['product_code'],
"ProductType": shipping_options['bluedart']['product_type'],
"PieceCount": return_request_line_items.all().count(),
"ActualWeight": weight,
"CreditReferenceNo": reference_id,
"PickupDate": timezone.now() + timezone.timedelta(days=2),
"PickupTime": '1052',
"RegisterPickup": True,
"IsReversePickup": True
}
In the "ProductType": field I have passed hard coded string value as 'ProductType.Dutiables'
I have also tried creating a calss with Enum type like
from enum import Enum
class ProductType(Enum):
Dutiables = "Dutiables"
and used this as ProductType.Dutiables in the 'ProductType' field.
But nothing seems to work for me. Please help!
zeep.exceptions.Fault: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:Request. The InnerException message was 'Invalid enum value 'ProductType.Dutiables' cannot be deserialized into type 'SAPI.Entities.Enums.AWBGeneration.ProductType'. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.'. Please see InnerException for more details.

Related

with Pydantic, how can i create my own ValidationError reason

it seems impossible to set a regex constraint with a __root__ field like this one:
class Cars(BaseModel):
__root__: Dict[str, CarData]
so, i've resorted to doing it at the endpoint:
#app.post("/cars")
async def get_cars(cars: Cars = Body(...)):
x = cars.json()
y = json.loads(x)
keys = list(y.keys())
try:
if any([re.search(r'^\d+$', i) is None for i in keys]):
raise ValidationError
except ValidationError as ex:
return 'wrong type'
return 'works'
this works well in that i get wrong type returned if i dont use a digit in the request body.
but i'd like to return something similar to what pydantic returns but with a custom message:
{
"detail": [
{
"loc": [
"body",
"__root__",
],
"msg": "hey there, you can only use digits!",
"type": "type_error.???"
}
]
}
You can pass your own error string by using raise ValidationError("Wrong data type").
Hope it helps.
if it helps anyone, here is how i validated a dynamic field:
class Cars(BaseModel):
__root__: Dict[str, CarData]
#pydantic.root_validator(pre=True)
#classmethod
def car_id_is_digit(cls, fields):
car_ids = list(list(fields.values())[0].keys())
print(car_ids)
if any([bool(re.search(r'^\d+$', car_id)) == False for car_id in car_ids]):
raise ValueError("car_id must be a string that is a digit.")
else:
return fields
since a regular field validator requires a field name as an argument, i used the root_validator which validates all fields - and does not require that argument.
all this, because __root__ cannot be referenced in the regular field validator, it seems.
however, this means you can only have __root__ fields - and they will all be under the same validation rules...not sure how to added more fields with this.

is it possible to search null objects in mongoengine?

I'm trying to search null object with python NoneType but got the below error message:
raise ValidationError(message, errors=errors, field_name=field_name) mongoengine.errors.ValidationError: 'null' is not a valid ObjectId, it must be a 12-byte input or a 24-character hex string
Code for reproducing this issue:
class User(mongoengine.Document):
meta = {
"db_alias": 'core',
"collection": 'so_users_details'
}
user_name = mongoengine.StringField(required=True)
tag_details = mongoengine.ObjectIdField(null=True)
User(user_name='Sam').save() # This will create a new user with null value in tag_details
User.objects().filter(tag_details=None) # Getting the above error
I will recommend you to change the default value of tag_details to :
tag_details = mongoengine.ObjectIdField(blank=True)
so you can search for null objects like this:
User.objects(Q(tag_details__exists=False))

Python: Printing all Protocol Buffer field options

I have proto message that I need to attach a string containing information about the data (units, scaling factor etc).
I am using custom options as per the proto2 guide. I also have attempted to follow a previous question where they printed custom options for 1 message here. I would like to print out all fields from the message along side the string. I have been struggling to find a solution, so far what i have tried is:
In my .proto file: The Service message contains fields that are themselves messages such as My_Message.
import "google/protobuf/descriptor.proto";
extend google.protobuf.FieldOptions {
optional string formatting_stuff = 50000;
}
message My_Message
{
optional uint32 base_frequency_hz = 1 [(formatting_stuff) = "test"];
optional float trigger_frequency_hz = 2 [(formatting_stuff) = "test2"];
...
}
message Service
{
optional My_Message x = 13;
...
}
Then in the python file,how would iterate over each field in Service and the nested message My_Message to retrieve both its value and also then extract the 'formatting_stuff'.
This is my attempt, but I can not get the field options to print the custom options:
messanger.py
...
rsp = self.proto.Service().FromString(self.data)
desc = protobuf_file.Service.My_Message.DESCRIPTOR
for rsp_field in response.DESCRIPTOR.fields:
print("Response Field name: ", rsp_field.name)
print("Response Field value: ", getattr(rsp, rsp_field.name))
options = desc.GetOptions()
formatting = options.Extensions[protobuf_file.formatting_stuff]
print("Response Field formatting: ", formatting)
The terminal output is:
Response Field name: base_frequency_hz
Response Field value: 720000
Response Field formatting:
Response Field name: trigger_frequency_hz
Response Field value: 3000.0
Response Field formatting:
As you can see, my custom fields are not being printed. Please could you assist me with printing out the custom options.
Kind regards

How can I ignore unknown arguments passed as inputs to a mutation?

As per the GraphQL spec https://graphql.github.io/graphql-spec/draft/#sec-Input-Objects
the input object literal or unordered map must not contain any entries with names not defined by a field of this input object type, otherwise an error must be thrown.
Let's say I have a project which has a user called buyer, the schema for which is as follows
type Buyer {
id: ID!
name: String!
address: String!
email: String!
}
Now I can write a graphene schema for it
class BuyerType(DjangoObjectType):
class Meta:
model = Buyer
and make a mutation for this
class BuyerInput(graphene.InputObjectType):
name = graphene.String(required=False, default_value='')
address = graphene.String(required=False, default_value='')
email = graphene.String(required=False, default_value='')
class BuyerMutation(graphene.Mutation):
"""
API to create applicant
"""
class Arguments:
buyer_data = BuyerInput(required=True)
buyer = graphene.Field(BuyerType)
ok = graphene.Boolean()
def mutate(self, info, buyer_data=None):
buyer = Buyer(name=buyer.name, address=buyer.address, email=buyer.email)
buyer.save()
return BuyerMutation(buyer=buyer, ok=True)
and write the resolvers functions and query and mutation class. Pretty basic stuff so far.
And now to create a new buyer, I just call the mutation
mutation {
createBuyer(
name: "New Buyer"
address: "Earth"
email: "abc#example.com"
) {
ok
}
}
But if I pass an additional field called phone
mutation {
createBuyer(
name: "New Buyer"
address: "Earth"
email: "abc#example.com"
phone: 8541345474
) {
ok
}
}
an Unknown field 'phone' error comes up, which is understood.
But I want to make process for frontend devs easier. Rather than mentioning each field in the argument of mutation, they can just pass a dict which contains these three fields and also other arguments that might originate from a form submission, and then read the dict in the backend and only extract the fields that I need, much like it is done with REST APIs.
If this is possible, then how can I implement this?
We could get the class attributes of BuyerInput using the inspect module, and then assemble the arguments dictionary so that it ignores the keys which are not such an attribute. Say, we have the dict containing the parameters of createBuyer stored in the variable kwargs, this could look like the following:
import inspect
members = inspect.getmembers(BuyerInput, lambda a: not(inspect.isroutine(a)))
attributes = [
tup[0]
for tup in members
if not tup[0].startswith("_")
]
kwargs = {
key: value
for key, value in kwargs.items()
if key in attributes
}

Graphene: Enum argument doesn't seem to work

Im currently having hard time on mutation enum Argument.
Below are my code for Mutation:
class CreatePerson(graphene.Mutation):
foo = graphene.String()
def mutate(self, info, **kwargs):
return CreatePerson(foo='foo')
class Arguments:
enum_arg = graphene.Argument(graphene.Enum.from_enum(EnumArg))
Enum class:
from enum import Enum
class EnumArg(Enum):
Baz = 0
Bar = 1
Spam = 2
Egg = 3
Command using POSTMAN:
{
"query": "mutation": {createPerson(enumArg=1) { foo }}
}
But I end up this error message:
"message": "Argument \"enumArg\" has invalid value 1.
Expected type \"EnumArg\", found 1.",
I also tried giving enumArg=\"Bar\" on the createPerson mutation and the error still persists.
When defining an enum, we can assign an arbitrary value to each enum value in the enum. However, this value is only used internally by the GraphQL service itself. For example, if the type of a field's argument is the enum, this value will be passed to the field's resolver as the argument value. However, when composing a GraphQL document, the enum value must always be referred to by it's name, not it's value.
mutation {
createPerson(enumArg: Bar) {
foo
}
}
enum defined in backend is:
enum Gender {
MALE
FEMALE
}
I am using Vue for frontend so passing data to the mutation from Vue can be done like this.
I have defined gender as a string in my local state of the component as:
data(){
return {
gender: ''
}
}
The method from Vue is:
async handleEditProfile () {
const response = await this.$apollo.mutate({
query: EDIT_PROFILE,
variables: {
nameAsInPan: this.nameAsInPan,
gender: this.gender,
dateOfBirth: this.dateOfBirth
}
})
}
mutation used above EDIT_PROFILE:
gql`mutation editProfile($name: String!, $email: String!,$phone: String!, $gender: Gender!, $dateOfBirth: String!) {
editProfile (profileInput:{name: $name, email: $email, phone: $phone, gender: $gender, dateOfBirth: $dateOfBirth}){
id
email
phone
firstName
lastName
nameAsInPan
gender
dateOfBirth
}
}
`
use the enum variable name as defined in the mutation and send it to Graphql, like I have used gender As
$gender: Gender! in gql mutation. You don't have to worry about sending data as enum, just send it as String otherwise you will have to face JSON error, Graphql will take care of the value you send as a string (like 'MALE' or 'FEMALE') just don't forget to mention that gender is type of Gender(which is enum) in gql mutation as I did above.
Please read my answer on this link Link for reference

Categories

Resources