keleshev / schema

Schema validation just got Pythonic
MIT License
2.88k stars 215 forks source link

[Question] How to validate/convert into a list of str? #232

Closed cuteufo closed 4 years ago

cuteufo commented 4 years ago

I would allow following types of inputs, and want to use Schema(...).validate() to validate the input and convert them into a list of str, as commented:

      ["123", "456"],      # ["123", "456"]
      [123, 456],          # ["123", "456"]
      [date(2020, 2, 2)],  # ["2020-02-02"]
      123,                 # ["123"]
      [],                  # None
      None,                # None

Tried a bunch of Schema() settings, but didn't get any luck. The challenge is how to convert 123 into a str and then into a list of str.

Any advice will be much appreciated.

skorokithakis commented 4 years ago

[Use(str)]?

cuteufo commented 4 years ago

Finally, I tried this one to resolve my problem:

schema = Schema(
  Or(                                     # 0
    None, 
    And(
      Or(int, datetime),                  # 1
      Use(lambda x: [str(x)])
    ), 
    And(
      list, 
      Use(lambda x: [str(y) for y in x] if len(x)>0 else None)    # 2
    )
  )
).validate(datetime(2020, 2, 2))

The overall syntax in building Schema object is to use Or() (# 0) to allow each scenario I will be handling. Here I listed three scenarios to filter out and then process them.

The first scenario is None. Just validate and let it be.

The second one is to use And(cond1, cond2) to filter out one scenario like cond1, then use cond2 to do the conversion. In this case, cond1 is Or(int, datetime), which filters out the scenarios when the input is an int or datetime object. Cond2 is Use() to call a lambda to convert the int or datetime object into a single-element list of str object.

The third scenario is of same syntax of scenario 2 but dealing with list objects. If the list object is empty, it will be changed into a None object. Otherwise, the elements in the list object will be str()-ed.

This syntax framework just works like you can imagine, comparing to C, Or() like switch(), each cond1 in And() like the conditions after case, and cond2 like the codes within case and break.

As for the overall syntax, I myself can hardly figure out a better solution, but if you have one, please share and it is greatly appreciated.

However, although the above syntax can solve my problem for now, but what if: 1) in # 1, if I need to handle objects other than int or datetime, what can I do besides enumerate them in the Or() syntax? 2) in # 2, what if the object in the list doesn't have a proper str()? And

Thanks.

skorokithakis commented 4 years ago

You can just write a custom function that will take an object and return a string that represents it, and use that in the Use. That way you don't need to enumerate at all.

cuteufo commented 4 years ago

You can just write a custom function that will take an object and return a string that represents it, and use that in the Use. That way you don't need to enumerate at all.

Very much appreciated!