BeanieODM/beanie

No support for Regex elements

lothesven-clauger opened this issue · 9 comments

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 #977

i am fairly shure that using re.Pattern will work

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

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

re.Pattern: bson.Regex.from_native,

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 ?

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".

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

@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

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

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

@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 ?