-
-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bindings(python): better message type #586
Comments
Hey @AzideCupric! Thank you so much for your work (and the congratulations)! I'll try to take a look as soon as possible! I'm very happy about your contribution, but need to find a slot when to give this the attention it deserves :-) Unfortunately, I'm not the most experienced Python developer... But: Very happy to learn from you! Maybe Henning can also chime in. |
Thanks again for your work, but also for creating this issue, @AzideCupric, I still had moving your suggestions into a new issue on my list but unfortunately didn't get round to it yet. I'm really sorry for keeping you waiting this long. I think a better type interface on the Python side is definitely a topic we should persue further and your approach looks reasonable. I'm currently not sure how this impacts the maintainability of I'm still catching up with other projects at the moment, but otherwise I'm happy to support on this. Hopefully, I'll find the time to take a good look at your suggestions over the weekend. |
Thanks for the patient responses from both of you. I am here awaiting good news. |
@AzideCupric Thanks again for you patience! I now finally found some time to take a deeper look at this. I really like the work you have done here! As I could not find an example on how to construct one of the types, I played around with it myself and result looks pretty neat (maybe except for the type paths but I did not want to pollute the local namespace too much): # imap_codec_model/models/__init__.py
from . import fetch, sequence
# tests/test_validate.py
from imap_codec_model import models
def test_construct_command():
remaining, decoded = type_codec_decode(
CommandCodec, b"ABCD UID FETCH 1,2:* (BODY.PEEK[1.2.3.4.MIME]<42.1337>)\r\n"
)
assert remaining == b""
ref = models.Command(
tag="ABCD",
body=models.command.Fetch(
sequence_set=[
models.sequence.Single(models.sequence.Value(1)),
models.sequence.Range((models.sequence.Value(2), "Asterisk")),
],
macro_or_item_names=models.fetch.MessageDataItemNames(
[
models.fetch.NameBodyExt(
section=models.fetch.Mime([1, 2, 3, 4]),
partial=(42, 1337),
peek=True,
)
]
),
uid=True,
),
)
assert decoded == ref There is actually not much for me to add, as I think working on your IMAP extension for NoneBot will probably guide you to implementing a better API than any theoretical stuff we would come up with will. I would probably prefer wrapper types instead of re-export the types from However, I think the question on how to continue with this is more of organizational than of technical nature. As mentioned above, I'm a still bit hesitant about extending Off hand, I see two paths for this:
@AzideCupric, @duesee What are your thoughts on this? |
Thanks so much for your kind words! Regarding your question:
As you might have noticed in {
"Unseen": 12
} to a format more like: {
"tag": "Unseen",
"data": 12
} This would help avoid unnecessary performance costs and potential errors when adjusting the structure after generation. Additionally, I'm concerned that testing each IMAP lines one by one might be too extensive and time-consuming. I'm wondering if there's a more efficient way to validate the alignment between the Python models and
Between the two options, I lean more towards the first one. As a user, it’s always more convenient to have just one dependency rather than two. Moreover, needing to install two different packages from separate authors for a single feature might feel a bit odd or even unsettling. |
This can be configured through |
@AzideCupric To give you a heads-up on this: @duesee and I will move the Python bindings code into their own repository over the next days. Afterwards, it would be awesome if you can provide a PR with the first set of changes, as we really would like to see the great work you did merged into the project, so others can benefit from it. Meanwhile, I will look into the mapping thing and see, how I can change it to the internally tagged representation. It would indeed be nice, if we could get rid of the conversions. |
Thank you for the update! It's an honor to contribute to the project, I'm excited for the changes ahead and to see how we can improve things further together. |
@AzideCupric Thanks again for your patience! After we have now separated the repositories (see https://github.com/duesee/imap-codec-python), I took a shot at the enum representation. The This means, that You should be able to compile/install the package directly from my development branch: The corresponding branches/changes can be found here:
I'm curious if this makes things work better in combination with |
Sorry for the delay in my response, and thank you so much for the work you've done on the
If "adjacently tagged" is the only option, as mentioned in my initial post, it forces all structures into the second format. For example, in the case of: #[derive(Serialize, Deserialize, Debug)]
enum Status {
Untagged(StatusBody),
// ...
}
#[derive(Serialize, Deserialize, Debug)]
struct StatusBody {
kind: StatusKind,
code: Option<Code>,
text: String,
} We would have to write it as: # now
class Untagged(TaggedBase):
codec_data: StatusBody
class StatusBody(TaggedBase):
kind: StatusKind
code: Code | None
text: str
res = Untagged(StatusBody(kind="Ok", code=None, text="..."))
# before
class Untagged(TaggedBase):
kind: StatusKind
code: Code | None
text: str
res = Untagged(kind="Ok", code=None, text="...") Compared to the previous approach, this adds an additional import of If possible, perhaps a custom
Additionally, I think the Finally, I noticed that the current Python bindings repository could benefit from adding static type checking and formatting tools like |
Just a small update: We havn't forgotten about you :-) It's just that we don't have funding currently and too busy with our day-to-day jobs... But: Your work will not get old, don't worry! We'll surely come back to this eventually! |
I'm in the same boat, and I also except this new feature can be implemented soon! |
Congratulations on the release of the first version of the Python bindings! 🎉
As I mentioned in issue #559 and in the
bindings/python
documentation:To address this, I attempted to implement a library that facilitates the conversion between
dict
and Python classes usingmsgspec
. You can check it out here.Initially, I adjusted the original
dict
structure:Currently, enum variant names are used as keys. These can be used as a tag field in tagged unions, so I placed them as the value of
codec_model
:Specifically, if the value isn't an object or if it represents a Rust enum variant object, the value is placed in a
codec_data
field (as implemented inutils.py
):Next, I created some
msgspec
structs in themodels
directory to build upon this structure:Unlike Rust enums, Python enums do not support Algebraic Data Types (ADT), so I used
Union
to simulate them:And so on...
In my repository, I referred to
imap-types
to define all the structures that will be used in the Python bindings. I also defined some functions invalidate.py
for use:You can find some tests in the
tests
directory, which can be run usingpytest
.I haven’t tested all the structures yet, so there might be some structural mistakes. The main goal of this issue is to propose a potential solution to improve the typing experience on the Python side as I understand it. Additionally, I’m interested in exploring any effective methods to test the consistency of the structure between
imap-types
andimap-codec-model
(it does seem a bit overwhelming).If it's feasible, perhaps this could be integrated into the Python bindings library. I’d be happy to contribute further!
The text was updated successfully, but these errors were encountered: