Alexander
Thank you for reporting! We were able to reproduce it
Anonymous
:)
Roman
Anonymous
Thanks!
Xavier
Hi , I have a doubt definig models, there is a way to define a datetime with timezone?
Alexander
Hi, at this moment Pony you can only use datetime without timezone
Xavier
Thank you i will try to bypass this
Lucky
Alexander
In bytecode or in our progress on that?
Alexander
Hi Guys! We've fixed decompiler errors on Python 3.7. Now all expressions should be translated correclty.
The official release will be published in few days
@vitalium, can you check that your queries are working correctly now?
Lucky
Alexey
Roberto
Anzor
Hi all! Something similar was asked before, but still...
Why not handle some after_load hook for clarity?
Alexander
Hi! Can you explain in more details, when this hook should be called?
Alexander
In Pony, object may be in a partially loaded state. For example, when someone do something like
with db_session:
s = Student[123]
g = s.group
print(g.id)
for c in s.courses:
print(c.id)
In the first line Pony loads Student object s with all non-lazy columns into memory. This Student instance contains group_id attribute. At this moment, a Group instance is created in memory as well, but this Group instance contains only id attribute received from the Student's group_id attribute. So, g object exists in a partially loaded state.
If later program will try to get value of some other attribute of g object, say, g.major, then all non-lazy attributes of g object will be loaded from the database. Until that, Pony makes no attempt to load g attributes, but you still can keep g object in a variable, because its id attribute value is already known.
In the next line you can see for c in s.courses loop. At this moment all courses associated with this specific students are created in memory. But in order to know the list of such courses it is not necessary to load them from the course table. Many-to-many relationship is supported using intermediary course_student table which keeps pairs (student_id, course_id). So, when Pony loads s.courses collection, it loads only course_id value from intermediary course_student table and creates partially loaded Course object for each course_id. Other fields will be loaded if you try to access any field in Course beside course_id
So it is not entirely clear at which moment proposed after_load hook should be triggered. If it is called on initial creation of partially loaded object, it may immediately access some other fields and provoke unnecessary load of entire object into memory. Maybe it should be called after the actual load of all non-lazy attributes. But it may be surprising for some users.
I think in you case you can have some machine_state property which initializes state from json field on first access. I'm not sure it should be tied to some after_load hook
Anzor
In Pony, object may be in a partially loaded state. For example, when someone do something like
with db_session:
s = Student[123]
g = s.group
print(g.id)
for c in s.courses:
print(c.id)
In the first line Pony loads Student object s with all non-lazy columns into memory. This Student instance contains group_id attribute. At this moment, a Group instance is created in memory as well, but this Group instance contains only id attribute received from the Student's group_id attribute. So, g object exists in a partially loaded state.
If later program will try to get value of some other attribute of g object, say, g.major, then all non-lazy attributes of g object will be loaded from the database. Until that, Pony makes no attempt to load g attributes, but you still can keep g object in a variable, because its id attribute value is already known.
In the next line you can see for c in s.courses loop. At this moment all courses associated with this specific students are created in memory. But in order to know the list of such courses it is not necessary to load them from the course table. Many-to-many relationship is supported using intermediary course_student table which keeps pairs (student_id, course_id). So, when Pony loads s.courses collection, it loads only course_id value from intermediary course_student table and creates partially loaded Course object for each course_id. Other fields will be loaded if you try to access any field in Course beside course_id
So it is not entirely clear at which moment proposed after_load hook should be triggered. If it is called on initial creation of partially loaded object, it may immediately access some other fields and provoke unnecessary load of entire object into memory. Maybe it should be called after the actual load of all non-lazy attributes. But it may be surprising for some users.
I think in you case you can have some machine_state property which initializes state from json field on first access. I'm not sure it should be tied to some after_load hook
Great explanation, thanx!
Now need for some custom initializer looks obvious
Lucky
In my case though I only store the current state in the database, and not the state machine itself.
Mine lies in python code.
Anzor
Lucky
pm
for the benefit of everyone interested I'll share some takeaways though
Lucky
I use https://github.com/pytransitions/transitions
Lucky
Hey, I’m getting pony.orm.dbapiprovider.OperationalError: unable to open database file with
db_params = dict(provider="sqlite", filename="/data/states.db", create_db=True)
db.bind(**db_params)
Matthew
have you checked the file permissions?
Lucky
Like of the folder?
Alexander
yes, maybe you can't create file in that folder
Matthew
of the file. Can you open the file in python as that user? open('/data/states.db' ,'w')
Lucky
Matthew
the above code will attempt to create it, but yeah it would be folder permissions
Matthew
are you sure you want /data/ instead of data/ ?
Lucky
Yeah, /data/ is correct as it is a docker container. I’ll check on folder permissions.
To clarify: it also says unable to open database file if it cannot create a file?
So it doesn’t say failure in creating file specifically?
Alexander
This message is from sqlite and potentially can depend on sqlite version
Lucky
So, /data/ is 755.
>>> import os
>>> os.stat(„/data/“)
os.stat_result(st_mode=16877, st_ino=38012780, st_dev=2306, st_nlink=2, st_uid=0, st_gid=0, st_size=4096, st_atime=1554309461, st_mtime=1554306536, st_ctime=1554309458)
>>> st_mode=16877
>>> oct(st_mode)
0o40755
Alexander
"755 means full permissions for the owner and read and execute permission for others"
If I'm not mistaken, this directory is read-only if you aren't the owner
Lucky
open(„/data/test.db“)
PermissionError: [Errno 13] Permission denied: '/data/test.db'
Yeah seems to be a access issue.
Lucky
Yeah, switched from root to a fixed uid, and had to chown the folder. Thanks.
However, now I get the following error:
Lucky
pony.orm.dbapiprovider.OperationalError: no such table: AlbumPost_Post
Lucky
pony.orm.dbapiprovider.OperationalError: no such table: AlbumPost_Post
r2tg_1 | File "./r2tg/reddit.py", line 11, in <module>
r2tg_1 | from . import database # so migrations can run, etc.
r2tg_1 | File "./r2tg/database.py", line 101, in <module>
r2tg_1 | db.generate_mapping()
r2tg_1 | File "<string>", line 2, in generate_mapping
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 78, in cut_traceback
r2tg_1 | reraise(exc_type, exc, full_tb)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 95, in reraise
r2tg_1 | try: raise exc.with_traceback(tb)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 61, in cut_traceback
r2tg_1 | try: return func(*args, **kwargs)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/orm/core.py", line 1130, in generate_mapping
r2tg_1 | elif check_tables: database.check_tables()
r2tg_1 | File "<string>", line 2, in check_tables
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 78, in cut_traceback
r2tg_1 | reraise(exc_type, exc, full_tb)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 95, in reraise
r2tg_1 | try: raise exc.with_traceback(tb)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/utils/utils.py", line 61, in cut_traceback
r2tg_1 | try: return func(*args, **kwargs)
r2tg_1 | File "<string>", line 2, in check_tables
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/orm/core.py", line 528, in new_func
r2tg_1 | result = func(*args, **kwargs)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/orm/core.py", line 1203, in check_tables
r2tg_1 | database.schema.check_tables(database.provider, connection)
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/orm/dbschema.py", line 78, in check_tables
r2tg_1 | provider.execute(cursor, sql)
r2tg_1 | File "<string>", line 2, in execute
r2tg_1 | File "/usr/local/lib/python3.6/site-packages/pony/orm/dbapiprovider.py", line 61, in wrap_dbapi_exceptions
r2tg_1 | raise OperationalError(e)
r2tg_1 | pony.orm.dbapiprovider.OperationalError: no such table: AlbumPost_Post
Lucky
It seems db.generate_mapping() is failing.
Lucky
I don’t know why it is not creating the AlbumPost_Post table, but later expecting it.
Alexander
did you specify create_tables=True in generate_mapping?
Lucky
Oh. I already had create_db = True, thought it would be not needed.
Lucky
Is there any reason why it shouldn’t be set to True?
Matthew
if you want iit to fail if the database doesn't exist
Lucky
Sorry, create_tables.
Lucky
I feel like True should be the default there.
Alexander
If a user wants to connect to some pre-existed database which was not created with Pony and mistype tanle name (for example, write it using incorrect case) it may be confusing if Pony will try to create some tables. So create_tables option is turned off by default
I agree that with create_db=True it make sense to create tables as well, but changing default value may be not obvious. Probably we can improve error message so it starts suggesting setting create_tables=True if create_db=True
Lucky
class State(db.Entity, self.State):
user_id = orm.Required(int)
chat_id = orm.Required(int)
state = orm.Required(str)
data = orm.Optional(orm.Json) # can be None
orm.PrimaryKey(user_id, chat_id)
# end class
Now I’m getting:
ValueError: Attribute State.data cannot be set to None
Am I missing something?
Alexander
optional Json means it can be empty (that is, {}). If you want it to be None, specify nullable=True as well
Vitaliy
Hm, that should be documented. In my app I set default={} for all JSON-fields 🙂
Alexander
I agree, we should document it #todo
Vitaliy
Alexander, I have updated pony from github, but did not tested it yet with python 3.7. I've rewrote all my expressions app wide to X and Y and ... not Z pattern 🙂
Alexander
Ok, I think it works correctly now. Hope we can do release really soon
Lucky
Jacob
I see the blog post on migrations. Does that mean v0.8 is about to be released?
Alexander
Not yet, migrations still require some work
Alexander
but wouldn't null be valid json?
I don't remember all the details right now. In theory it is possible to have Json whicj consists of a single null, but note that it is different from database NULL, and follows completely different rules in comparison operations. It may be confusing to user to see Json null as a top-level value of JSON document, especialy when intermixed with database NULLs
Lucky
Currently I can't really use PonyORM inside a library
Lucky
It's possible, just very cumbersome
Jacob
blueprints?
Lucky
blueprints?
Concept similar to Flask blueprints:
You define your database extending from
blueprint.Entity
instead of
db.Entity
This allows you to later register it with your database:
Jacob
Ooh! Is that in the works?
I've only seen using the factory function to build the models.
Lucky
Jacob
It's also not possible to build a model programmatically right now because of the implementation of PrimaryKey, composite_key, and composite_index.
Lucky
In fact, migrations were the smaller problem as you could already do those yourself if you aren't afraid of writing a bit of SQL.
For example the pony_up package at https://GitHub.com/luckydonald/pony_up can already help you with that.
Couldn't get anything similar to blueprints working though.
Lucky
Anonymous
@luckydonald Happy birthday, btw! What's the downside of using blueprint functions?
def blueprint(db):
class Car(db.Entity):
...
return db
Jacob
Is there a way to build a custom field type? Ie, I want to use the field as a Boolean, but I'm stuck with an irritating DB that implemented the column with CHAR(1) where the value is "Y" or "N".
Lucky
Lucky
I think I had a full example in the related GitHub issue
Lucky
But am in the supermarket right now, so can't look it up
Lucky
Jacob
My wife says "supreme! Always supreme!" Re what Pizza to get...