How to assign values to an optional message field in protobuf? - python

I have below proto file
syntax = "proto3";
package my_proto;
message ID
{
optional uint64 id_upper = 1;
optional uint64 id_lower = 2;
}
message mymessage
{
optional ID id = 1;
}
And I tried assigning value to ID field using below python script
import my_proto_pb2
message = my_proto_pb2.mymessage()
id = message.id()
id.id_upper = 10
id.id_lower = 20
But I got below error:
Traceback (most recent call last):
File "create_message.py", line 4, in <module>
id = message.id()
TypeError: 'ID' object is not callable
May I know why it is throwing this error? Also, how can I assign value to an 'optional' message field?

Try removing parenthesis here:
id = message.id() to id = message.id
another way to do this:
thisid = ID()
thisid.id_upper = 10
thisid.id_lower = 20
message = mymessage()
message.id = thisid

Related

TypeError: 'NoneType' object is not subscriptable in a int object

Here is a function to check the data and update it
div , update are my mongodb collection object
def data_updater(user1_id,code):
device_id = dvi.find_one({"user_id":user1_id},{"_id":0,"user_id":0})["device_id"]
prv_data = update.find_one({"device_id":device_id},{"_id":0,"device_id":0})
prv_date = prv_data["date"]
msg = prv_data["message"]
if prv_date < current_date and msg != code:
x = update.find_one_and_update({"device_id":id,},{"$set":message":code,"date":current_date}})
print(x.acknowledged)
and when I am calling the function it is giving TypeError data_updater(95626,972681)
the error
Traceback (most recent call last):
File line 170, in <module>
data_updater(95626,972681)
File line 71, in data_updater
device_id = dvi.find_one({"user_id":int(user1_id)},{"_id":0,"user_id":0})["device_id"]
TypeError: 'NoneType' object is not subscriptable
I am not able to find any mistake please help
Your context isn't very clear, however, from the error trace as generated it seems that your find_one() function returns None with the arguments as passed and you are trying to access the value for the key device_id. I recommend you refactor your find_one() function or make use of the following code to resolve the issue at hand:
def data_updater(user1_id,code):
try:
device_id = dvi.find_one({"user_id":user1_id},{"_id":0,"user_id":0})["device_id"]
prv_data = update.find_one({"device_id":device_id},{"_id":0,"device_id":0})
prv_date = prv_data["date"]
msg = prv_data["message"]
if prv_date < current_date and msg != code:
x = update.find_one_and_update({"device_id":id,},{"message":code,"date":current_date}})
print(x.acknowledged)
except TypeError:
print('No value found for specified parameters :/')
PS: I also didn't understand the use of $ in your code, so I removed it thinking of it as a mistake. Hope this helps! 😊

How to set a protobuf Timestamp field in python?

I am exploring the use of protocol buffers and would like to use the new Timestamp data type which is in protobuf3. Here is my .proto file:
syntax = "proto3";
package shoppingbasket;
import "google/protobuf/timestamp.proto";
message TransactionItem {
optional string product = 1;
optional int32 quantity = 2;
optional double price = 3;
optional double discount = 4;
}
message Basket {
optional string basket = 1;
optional google.protobuf.Timestamp tstamp = 2;
optional string customer = 3;
optional string store = 4;
optional string channel = 5;
repeated TransactionItem transactionItems = 6;
}
message Baskets {
repeated Basket baskets = 1;
}
After generating python classes from this .proto file I'm attempting to create some objects using the generated classes. Here's the code:
import shoppingbasket_pb2
from google.protobuf.timestamp_pb2 import Timestamp
baskets = shoppingbasket_pb2.Baskets()
basket1 = baskets.baskets.add()
basket1.basket = "001"
basket1.tstamp = Timestamp().GetCurrentTime()
which fails with error:
AttributeError: Assignment not allowed to composite field "tstamp" in protocol message object.
Can anyone explain to me why this isn't working as I am nonplussed.
See Timestamp.
I think you want:
basket1.tstamp.GetCurrentTime()
You could also parse it:
Timestamp().FromJsonString("2022-03-26T22:23:34Z")
I found this highly confusing, as it differs from how other values was assigned in my demo, so I'd like to add this method using .FromDatetime():
.proto:
message User {
int64 id = 1;
string first_name = 2;
...
string phone_number = 7;
google.protobuf.Timestamp created_on = 8; # <-- NB
}
The response, UserMsgs.User(), is here a class generated from the above protofile, and is aware of what type each field has.
def GetUser(self, request, context):
response = UserMsgs.User()
if request.id is not None and request.id > 0:
usr = User.get_by_id(request.id)
response.id = usr.id
response.first_name = usr.first_name
...
response.phone_number = str(usr.phone_number)
response.created_on.FromDatetime(usr.created_on) # <-- NB
return response
So instead of assigning response.created_on with = as the others, we can use the built in function .FromDatetime as mentioned here.
NB: Notice the lowercase t in Datetime
usr.created_on in my example is a python datetime, and is assigned to a google.protobuf.Timestamp field.

Calling Solidity Function using Python Web3.py

I have written a smart contract function using solidity consisting of different parameters given below
function addDevice(address _address, string _deviceType, string _deviceName, string _minerID, string _deviceID) public
{
DeviceData storage device = devices[_address];
device.deviceType = _deviceType;
device.deviceName = _deviceName;
device.minerID = _minerID;
device.deviceID = _deviceID;
devicesAddresses.push(_address) -1;
}
I am using web3.py to call this function with the given commands as
D_Address = input("Device Address ").encode()
D_Type = input("Device Type ")
D_Name = input("Device Name ")
M_ID = input("Miner ID ")
D_ID = input("Device ID ")
tx_hash = contract_instance.functions.addDevice(D_Address,D_Type,D_Name,M_ID,D_ID).transact()
tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)
In REMIX, this smart contract is working fine, but when I run the file, it shows the following error
Found 1 function(s) with the name addDevice: ['addDevice(address,string,string,string,string)']
Function invocation failed due to no matching argument types.
Delete .encode(), because you should pass in a string for the address field.
Let me know if it still doesn't work!

flask sqlalchemy query with keyword as function argument

I am stuck with a query in a function. here is my code:
def action(changePin, action):
pins = Pins.query.all()
changePin = int(changePin)
deviceName = Pins.query.filter_by(pin=changePin, name)
if action == "on":
GPIO.output(changePin, GPIO.HIGH)
print("turned ", deviceName , " on")
if action =="off":
GPIO.output(changePin, GPIO.LOW)
print("turned ", deviceName , " off")
for pin in pins:
db.session.commit()
The error for this is
File "<stdin>", line 4
SyntaxError: positional argument follows keyword argument
In line 4 I want to find the name of the pin relating to the pin "changePin", this is adapted code from a tutorial, here is the origional code where a dictionary holds the pin information not a database, code:
deviceName = pins[changePin]['name']
I have tried numerous different ways but none work, here is a list of the different versions of line 4:
deviceName = Pins.query.filter_by(changePin=pin).name
deviceName = Pins.query.filter_by(changePin, name=name)
deviceName = Pins.query.filter_by(Pins.pin=changePin, Pins.Name)
deviceName = Pins.query(Pins.pin=changePin, Pins.Name)
deviceName = Pins.query(**changePin, Pins.name)
deviceName = Pins.query(**changePin)
deviceName = db.session.filter_by(Pins.changePin)
deviceName = db.session(Pins).filter_by(pin=changePin)
and many other variations, I have read the sqlalchemy docs and the flask docs, but I have not seen any comparisons, I have looked at and tried this; flask sqlalchemy query with keyword as variable
but got this;
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in action
TypeError: BaseQuery object argument after ** must be a mapping, not int
this is my models.py code;
class Pins(db.Model):
id = db.Column(db.Integer, primary_key=True)
pin = db.Column(db.Integer, index=True, unique=True)
name = db.Column(db.String(64))
upDown = db.Column(db.String(4))
state = db.Column(db.String(9))
def __repr__(self):
return '<Valves {}>'.format(self.pin)
Querying with function on Flask-SQLAlchemy model gives BaseQuery object is not callable error
Dear Menno
Thank you for comming back to me I have followed your advice and it works!!!
rows = Pins.query.filter_by(pin=changePin).all()
deviceName = rows[0].name
I don't understand how the "rows[0].name" part works but it does,
thank you thank you
help
regards
Paul
A filter_by expression selects rows, not fields. From the documentation: "apply the given filtering criterion to a copy of this Query, using keyword expressions.". Name is not a keyword expression, just a name.
Also, after building the query, you have to run it. You do that by calling all() on it:
deviceName = Pins.query.filter_by(pin=changePin).all()
LetÅ› also change the name of the outcome:
rows = Pins.query.filter_by(pin=changePin).all()
Calling that returns a list with zero or more rows, hence the name. rows[0] (the first row) is what you want. After you have a row, a field becomes an attribute of the row: rows[0].name. You can also use one() to get a unique row.
If you still need that: To limit the columns that are returned use load only cols

in protobuf python api how to add element to nested message repeated property?

message items {
message require {
optional bool require_sex = 1; //
repeated int32 fate = 2 [packed = true];
}
optional int32 sub_type = 1;
repeated int32 levels = 2 [packed = true];
}
I tried
raw.require.require_sex = 1
raw.require.fate.append(1)
raw.require.fate.extend([2,3])
got an error
AttributeError: 'property' object has no attribute 'append'
but the first level repeated field works fine:
raw = down_pb2.items()
raw.levels.append(4)
is this kind of definition not supported?
You need to create a field using that require type and then access that field in the code.
message items {
message require {
optional bool require_sex = 1; //
repeated int32 fate = 2 [packed = true];
}
optional int32 sub_type = 1;
repeated int32 levels = 2 [packed = true];
required require sub = 3;
}
then
raw.sub.fate.append(1)

Categories