BeanieODM / beanie

Asynchronous Python ODM for MongoDB
http://beanie-odm.dev/
Apache License 2.0
2.01k stars 212 forks source link

No support for Regex elements #983

Closed lothesven-clauger closed 3 weeks ago

lothesven-clauger commented 1 month ago

Hello,

In the process to migrate from odmantics to beanie, I need to process a List of Regex elements:

from odmantic import Model, Field
from odmantic.bson import Regex
class MyClass(Model):
    myField: Optional[List[Regex]] = None

I haven't figured out how to do it properly with beanie. What I managed so far is to declare myField as List[Any] to read the Regex elements in my database and convert then to strings on the go when reading. But this solution can't store Regex, only strings.

def transform_to_str(input_data: List) -> List[Regex]:
    regex_list = []
    for element in input_data:
        if isinstance(element, str):
            regex_list.append(element)
        if isinstance(element, Regex):
            regex_list.append(element.pattern)
    return regex_list

class MyClass(Document):

    myField: Optional[List[Any]] = Field(default=None)

    @field_validator(
        'myField'
    )
    def convert_bson_regex(cls, value):
        return transform_to_str(value)

This solution seems to work but it feels a bit clunky. Am i missing something ?

Originally posted by @lothesven-clauger in https://github.com/BeanieODM/beanie/discussions/977

07pepa commented 1 month ago

i am fairly shure that using re.Pattern will work

lothesven-clauger commented 1 month ago

Thanks for your reply. I couldn't make it work. How should I implement it with re.Pattern ?

07pepa commented 1 month ago

my theory is that beanie supports re.Pattern and translate it internaly to/from bson one see here

https://github.com/BeanieODM/beanie/blob/54e0f2d5b2f3e9c83f37393fdd8bde4bf38fde81/beanie/odm/utils/encoder.py#L47

theoreticaly should work

import re
class MyClass(Model):
    myField: Optional[List[re.Pattern]] = None

should work that also mean that you would have to translate from odmantic.bson import Regex to re.Pattern

can you provide code what you tried ?

lothesven-clauger commented 1 month ago
import asyncio
import re
from typing import Optional
from beanie import Document
from bson import Regex

from motor.motor_asyncio import AsyncIOMotorClient
from beanie import init_beanie

class MyReg(Document):
    myfield: Optional[Regex] = None

    class Config():
        arbitrary_types_allowed = True

class MyPat(Document):
    myfield: Optional[re.Pattern] = None

    class Config():
        arbitrary_types_allowed = True

async def init_db():

    client = AsyncIOMotorClient(
        "mongodb://localhost:27017",
        uuidRepresentation="standard",
        tz_aware=True
    )

    await init_beanie(
        database=client.DataMap,
        document_models=[
            MyReg,
            MyPat
        ]
    )

if __name__ == "__main__":

    asyncio.run(init_db())

    content1 = Regex(".*")
    myreg = MyReg(myfield=content1)
    try:
        asyncio.run(myreg.save())
    except Exception as e:
        print(e)

    content2 = re.compile(".*")
    mypat = MyPat(myfield=content2)
    try:
        asyncio.run(mypat.save())
    except Exception as e:
        print(e)

Here is the code I just tried, I get a "Cannot encode Regex".

07pepa commented 1 month ago

this is a bug.... i am working on PR to fix this

07pepa commented 1 month ago

@lothesven-clauger my PR is allowing bson.regex and new semicustom type miroring pattern. but keep in minde there are diferences between mongo native bson.regex (PCRE) and python re.pattern (non pcre) ... (bigest diferences are flags) I recomend to use bson.regex

lothesven-clauger commented 1 month ago

Thanks a lot for this. Bson.regex is exactly what i used before with odmantics so this is great :)

07pepa commented 3 weeks ago

@lothesven-clauger support added will be probably in next release.

lothesven-clauger commented 3 weeks ago

@lothesven-clauger support added will be probably in next release.

Thanks a lot for the follow up and job done on this :) Have you any rough idea of when this release could be expected ?