Giter VIP home page Giter VIP logo

trafaret's Introduction

Trafaret

Build status @ Circle CI Gitter Chat Latest release BSD license

Ultimate transformation library that supports validation, contexts and aiohttp.

Trafaret is rigid and powerful lib to work with foreign data, configs etc. It provides simple way to check anything, and convert it accordingly to your needs.

It has shortcut syntax and ability to express anything that you can code:

>>> from trafaret.constructor import construct
>>> validator = construct({'a': int, 'b': [str]})
>>> validator({'a': 5, 'b': ['lorem', 'ipsum']})
{'a': 5, 'b': ['lorem', 'ipsum']}

>>> validator({'a': 5, 'b': ['gorky', 9]})
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/mkrivushin/w/trafaret/trafaret/__init__.py", line 204, in __call__
    return self.check(val)
  File "/Users/mkrivushin/w/trafaret/trafaret/__init__.py", line 144, in check
    return self._convert(self.check_and_return(value))
  File "/Users/mkrivushin/w/trafaret/trafaret/__init__.py", line 1105, in check_and_return
    raise DataError(error=errors, trafaret=self)
trafaret.DataError: {'b': DataError({1: DataError(value is not a string)})}

Read The Docs hosted documentation http://trafaret.readthedocs.org/en/latest/ or look to the docs/intro.rst for start.

Trafaret can even generate Trafarets instances to build transformators from json, like in json schema implementation Trafaret Schema

New

2.0.2

  • construct for int and float will use ToInt and ToFloat

2.0.0

  • WithRepr – use it to return custom representation, like <Email>
  • Strip a lot from dict, like keys()
  • Trafarets are not mutable
  • DataError has new code attribute, self.failure has code argument
  • OnError has code argument too
  • New DataError.to_struct method that returns errors in more consistent way
  • String, AnyString, Bytes, FromBytes(encoding=utf-8)
  • Int, ToInt, Float, ToFloat
  • ToDecimal
  • Iterable that acts like a List, but works with any iterable
  • New Date, ToDate and DateTime, ToDateTime trafarets
  • StrBool trafaret renamed to ToBool
  • Visitor trafaret was deleted
  • Test coverage

1.x.x

  • converters and convert=False are deleted in favor of And and &
  • String parameter regex deleted in favor of Regexp and RegexpRaw usage
  • new OnError to customize error message
  • context=something argument for __call__ and check Trafaret methods. Supported by Or, And, Forward etc.
  • new customizable method transform like change_and_return but takes context= arg
  • new trafaret_instance.async_check method that works with await

Doc

For simple example what can be done:

import datetime
import trafaret as t

date = t.Dict(year=t.Int, month=t.Int, day=t.Int) >> (lambda d: datetime.datetime(**d))
assert date.check({'year': 2012, 'month': 1, 'day': 12}) == datetime.datetime(2012, 1, 12)

Work with regex:

>>> c = t.RegexpRaw(r'^name=(\w+)$') >> (lambda m: m.group(1))
>>> c.check('name=Jeff')
'Jeff'

Rename dict keys:

>>> c = t.Dict({(t.Key('uNJ') >> 'user_name'): t.String})
>>> c.check({'uNJ': 'Adam'})
{'user_name': 'Adam'}

Arrow date checking:

import arrow

def check_datetime(str):
    try:
        return arrow.get(str).naive
    except arrow.parser.ParserError:
        return t.DataError('value is not in proper date/time format')

Yes, you can write trafarets that simple.

Related projects

Trafaret Config

Trafaret Validator

trafaret's People

Contributors

arfey avatar asvetlov avatar axik avatar barbuza avatar deepwalker avatar dreamsorcerer avatar errno avatar froosty avatar hellysmile avatar holdbar avatar ilyachch avatar jona-sassenhagen avatar kleschenko avatar knholovan avatar kserhii avatar litwisha avatar marcinkuzminski avatar mklymyshyn avatar nimnull avatar oohlaf avatar pcinkh avatar piranha avatar popravich avatar shonny-ua avatar smagafurov avatar sonerayberk avatar tailhook avatar tyulpan avatar vovanbo avatar webknjaz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

trafaret's Issues

How to work with tuples in general?

Hello. Here the case.

Maintainers of aiozmq library recommend to use trafaret for type checking.
But also aiozmq's internals convert all lists to tuples while passing messages for RPC.

Trafaret's tuples take implicit types as parameter, but I'm not able just to receive tuple instead of list using trafaret.

For example:

import trafaret

recieved_msg = (1,2,3,4,5)

trafaret.Tuple(trafaret.Int).check(recieved_msg)

raises an error DataError: {0: DataError(value must contain 1 items)}

I'm not able to use trafaret.List too. It checks isinstance(obj, list).

Can you suggest some workaround?

Using function to validate username

I couldn't find an example of this in the documentation, so is this the expected way to run a function to validate a value?

    def check_if_user_exists(username):
        if username == "reserved":
            raise t.DataError("Username already exists")
        return username
    signup_form = t.Dict({
        "username": t.String() & check_if_user_exists,
        "password": t.String()
    })

As an extension to that, is it possible to support async functions in some way? So, that code might end up looking like:

    async def check_if_user_exists(username):
        with db.connect() as conn:
            result = await conn.scalar(users.count().where(users.username == username))
        if result is not None:
            raise t.DataError("Username already exists")
        return username
    signup_form = t.Dict({
        "username": t.String() & t.Await(check_if_user_exists),
        "password": t.String()
    })

Add to documentation way to set range validation in numerical data types

In version2 (branch) u need to add a part that describe set range validation in numerical data types. I think that it can be just documentation with Int checker but in brackets u need to say that it is avalivle to all numerical checkers.

For that u can use tests which connected with current part or source code.

    >>> Int[1:]
    <Int(gte=1)>
    >>> Int[1:10]
    <Int(gte=1, lte=10)>
    >>> Int[:10]
    <Int(lte=10)>
    >>> Float[1:]
    <Float(gte=1)>
    >>> Int > 3
    <Int(gt=3)>
    >>> 1 < (Float < 10)
    <Float(gt=1, lt=10)>
    >>> (Int > 5).check(10)
    10

As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Hex and URLSafe validators

Would be nice to have a couple more String validators that validated the string as e.g. hex or url safe. Matching for example, the output you'd get from secrets.token_hex() and secrets.token_urlsafe().

Trafaret object to pass value as is

Hello and thank you for your work fiirst of all.

I have a small suggestion to use trafaret in more uniform way. I have some data with assigned trafaret and some without constraints. So I have to do something like this:
if data.trafaret:
val = data.trafaret.check_and_return(rawval)
else:
val = rawval

If you'll kindly add an object something like "NoCheck" which will pass arguments out without any check it will be possible to always do:
val = data.trafaret.check_and_return(rawval)

while data without constraints will be initialized as:
data.trafaret = trafaret.NoCheck()

Add documentation about int, ToInt

In version2 (branch) u need to add to introduction part documentation about int and ToInt .

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Add documentation about float, ToFloat

In version2 (branch) u need to add to introduction part documentation about float and ToFloat.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Add documentation about Enum

In version2 (branch) u need to add to introduction part documentation about Enum.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

In this task i recommend to add some example of usage and some reach description.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

SyntaxError on python 3.5

Upgraded to 0.11 and seeing a SyntaxError:

File "/home/foo/.virtualenvs/bar/lib/python3.5/site-packages/trafaret_config/__init__.py", line 3, in <module>
    from .simple import read_and_validate, parse_and_validate
  File "/home/foo/.virtualenvs/bar/lib/python3.5/site-packages/trafaret_config/simple.py", line 4, in <module>
    import trafaret as _trafaret
  File "/home/foo/.virtualenvs/bar/lib/python3.5/site-packages/trafaret/__init__.py", line 1, in <module>
    from .base import (
  File "/home/foo/.virtualenvs/bar/lib/python3.5/site-packages/trafaret/base.py", line 20, in <module>
    from .async import (
  File "/home/foo/.virtualenvs/bar/lib/python3.5/site-packages/trafaret/async.py", line 176
    yield (
    ^
SyntaxError: 'yield' inside async function

docs: Add more useful example for KeysSubset

Piece of code to think:

def mapping_region(order: Order) -> Dict[str, Any]:
    region = {
        'id': order.get('region_id'),
        'name': order.get('region_name')
    }

    return {'region': region}


KeysSubset('region_id', 'region_name'): mapping_region,

DeprecationWarning on import of abstract classes from collections

In python 3.7 I'm getting the following deprecation warning:

DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

collections.abc is available starting from python 3.3.

Are there any plans on fixing it? (I guess you want to retain python2 support yet)

Also I don't mind to create PR to fix this. If you agree, do you have any preferred way this to be done?

Way to redefine error messages

I have a scheme of t.Dict with several fields. I want when required field is absent to replace default error string. What is the best way to do it? without kostyls...

Getting data error for a valid string in Python 2.7.17 & trafaret v2.0.2

>>> import trafaret as t
>>> t.String().check("test")
Traceback (most recent call last):
File "", line 1, in
File "/Users/user/miniconda/envs/tools/lib/python2.7/site-packages/trafaret/base.py", line 115, in check
return self.check_and_return(value)
File "/Users/user/miniconda/envs/tools/lib/python2.7/site-packages/trafaret/base.py", line 469, in check_and_return
self._failure(self.TYPE_ERROR_MESSAGE, value=value, code=self.TYPE_ERROR_CODE)
File "/Users/user/miniconda/envs/tools/lib/python2.7/site-packages/trafaret/base.py", line 130, in _failure
raise DataError(error=error, value=value, trafaret=self, code=code)
trafaret.dataerror.DataError: value is not a string
>>> t.String().check(u"test")
u'test'
>>>

No FromString/ToBytes?

There is a FromBytes object to convert to string. It would be nice to have the inverse to convert to bytes.

Add documentation about Iterable

In version2 (branch) u need to add to introduction part documentation about Iterable.

For that u can use tests which connected with current part. As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Valid url do not fit trafaret.URL

Hi @Deepwalker . I found the next validation error for working url 'https://www.dior.com/fr_fr/maquillage/adoptez-le-look-du-defile-croisiere\xa02020'
Is it expected behavior? What do you think?

(3_7_2) MacBook-Pro-2:test fedir$ python -c "import trafaret as t; t.URL.check('https://www.dior.com/fr_fr/maquillage/adoptez-le-look-du-defile-croisiere\xa02020')"
Traceback (most recent call last):
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 166, in transform
    return self.trafaret(value, context=context)
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 156, in __call__
    return self.check(val, context=context)
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 118, in check
    return self.transform(value, context=context)
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 286, in transform
    raise DataError(dict(enumerate(errors)), trafaret=self)
trafaret.dataerror.DataError: {0: DataError(does not match pattern ^(?:http|ftp)s?://(?:\S+(?::\S*)?@)?(?:(?:[A-Z0-9](?:[A-Z0-9-_]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?(?:/?|[/?]\S+)$), 1: DataError(does not match pattern ^(?:http|ftp)s?://(?:\S+(?::\S*)?@)?(?:(?:[A-Z0-9](?:[A-Z0-9-_]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?(?:/?|[/?]\S+)$)}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 118, in check
    return self.transform(value, context=context)
  File "/Users/fedir/env/3_7_2/lib/python3.7/site-packages/trafaret/base.py", line 168, in transform
    raise DataError(self.message, value=value)
trafaret.dataerror.DataError: value is not URL

Add documentation about Any

In version2 (branch) u need to add to introduction part documentation about Any.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

In this task i recommend to add some example of usage and some reach description.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Missing class init for `KeysSubset`

If init method without calling super:

  File "/opt/python3.4/trafaret/__init__.py", line 1129, in merge
    set(key.get_name() for key in self.keys)
  File "/opt/python3.4/trafaret/__init__.py", line 1129, in <genexpr>
    set(key.get_name() for key in self.keys)
  File "/opt/python3.4/trafaret/__init__.py", line 940, in get_name
    return self.to_name or self.name
AttributeError: to_name

Add documentation about bool, StrBool

In version2 (branch) u need to add to introduction part documentation about bool and StrBool.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

JSON parsing

It would be nice to have a way to automatically transform a JSON string before it is validated.

As an example:

token = t.Dict({
    "token": t.Dict({"access_token": t.String()}, json=True),
})

Where input might be something like:

token = {"token": "{\"access_token\": \"TOKEN\"}"}

Perhaps adding a json argument to the base trafaret would be useful, so any trafaret can be used with a JSON string.

Add documentation about Null

In version2 (branch) u need to add to introduction part documentation about Null.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

In this task i recommend to add some example of usage and some reach description.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Allow extra keys ignored after dict merge

Let me start with code,

In [1]: import trafaret as t

In [2]: td = t.Dict({'key': t.String()}).allow_extra('extra_key')

In [3]: td.merge(t.Dict({'other_key': t.String()})).check({'key': '1', 'extra_key': '2', 'other_key': '3'})
---------------------------------------------------------------------------
DataError                                 Traceback (most recent call last)
<ipython-input-3-84cf57110770> in <module>()
----> 1 td.merge(t.Dict({'other_key': t.String()})).check({'key': '1', 'extra_key': '2', 'other_key': '3'})

/usr/local/lib/python3.6/dist-packages/trafaret/base.py in check(self, value, context)
    116         """
    117         if hasattr(self, 'transform'):
--> 118             return self.transform(value, context=context)
    119         elif hasattr(self, 'check_value'):
    120             self.check_value(value)

/usr/local/lib/python3.6/dist-packages/trafaret/base.py in transform(self, value, context)
    990                         errors[key] = de
    991         if errors:
--> 992             raise DataError(error=errors, trafaret=self)
    993         return collect
    994 

DataError: {'extra_key': DataError(extra_key is not allowed key)}

From my point of view DataError is unexpected, but am I right it is raised due to logic reasons, that on merge you ignore all extra t.Dict rules to avoid errors on startup? E.g., when I'll try to merge some dict with key from .allow_extra?

If no and this is not intentional, I'd say it is a bug.

Casting one element to a list

Sorry for disturbing again.

I wonder is it possible to convet individually supplied value to a list.

I want to do something like:
t = trafaret.List(trafaret.String())
t(['a','b'])

['a','b']
t('a')
['a']

It will be amazingly cosily to pass FieldStorage.getvalue() directly to trafaret.

URL_RE explain

URL_REGEXP = re.compile(
    r'^(?:http|ftp)s?://'  # http:// or https://
    r'(?:\S+(?::\S*)?@)?'  # user and password
    r'(?:(?:[A-Z0-9](?:[A-Z0-9-_]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'  # domain...
    r'localhost|'  # localhost...
    r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
    r'(?::\d+)?'  # optional port
    r'(?:/?|[/?]\S+)$',
    re.IGNORECASE,
)
  1. r'(?:\S+(?::\S*)?@)?' # user and password
    (?::\S*)? уже и так ловится \S+
    Ещё здесь уместней нежадный квантификатор +?: \S+?@, потому что мы же не ожидаем ещё одного @ в этой подстроке?
  2. r'(?:(?:A-Z0-9?.)+(?:[A-Z]{2,6}.?|[A-Z0-9-]{2,}.?)|' # domain...
    Эта сложность оправдана? По каким кейсам не подходит (?:\w[\w-]+.)+[\w-]+\w.?
    Минус должен быть в конце группы, я не знаю, что получится из [A-Z0-9-_]

validator stopped working with 0.12.3

It doesn't work anymore, here is the code and small test suite:

import pytest
import trafaret as t


def strong_password(string):
    """Check that ``string`` is strong enough password"""
    if (any(char.isdigit() for char in string)
            and any(char.islower() for char in string)
            and any(char.isupper() for char in string)
            and any(char in punctuation for char in string)):
        return string
    else:
        raise t.DataError('Password is not strong enough')


account_new_validate = t.Dict(
    username=t.String(min_length=1, max_length=255) & t.Regexp(r'^[\w-]+$'),
    password=t.String(t.String(min_length=10, max_length=255) & strong_password),
    validation=t.String(),
    bio=t.String(allow_blank=True, max_length=1024),
)

def test_account_new_validate_empty():
    data = dict()
    with pytest.raises(t.DataError):
        assert account_new_validate(data)

def test_account_new_validate_valid():
    data = dict(
        username="amirouche",
        password="FooBar!42",
        validation="FooBar!42",
        bio="energy hacker",
    )
    assert account_new_validate(data)

def test_account_new_validate_invalid_password():
    data = dict(
        username="peon",
        password="toosimple",
        validation="toosimple",
        bio="much wow",
    )
    assert account_new_validate(data)

Is it still possible to compose validators using &?

Add documentation about ToDecemal

In version2 (branch) u need to add to introduction part documentation about ToDecemal.

For that u can use tests which connected with current part. As example u can use this PR.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

incompatibility of versions 0.10.0 and 0.12.0

In version 0.10.0 I can wrote or following code

In [1]: import trafaret as t
In [3]: Ok = t.Regexp(r'^[oO][kK]$') >> unicode.upper
In [5]: Ok(u'ok')
Out[5]: u'OK'

Or like this

In [1]: import trafaret as t
In [2]: from toolz.curried import flip
In [4]: a = t.Regexp(r'^[^,]+(\s*,\s*[^,]+)*$') >> flip(unicode.split, ',')
In [5]: a(u'1,2,3,4')
Out[5]: [u'1', u'2', u'3', u'4']

In trafaret 0.12.0 I can pass only functions:

In [2]: Ok = t.Regexp(r'^[oO][kK]$') >> unicode.upper
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-71fe3186d2fa> in <module>()
----> 1 Ok = t.Regexp(r'^[oO][kK]$') >> unicode.upper

/home/mikhail/venvs/test/local/lib/python2.7/site-packages/trafaret/base.pyc in __rshift__(self, other)
    151 
    152     def __rshift__(self, other):
--> 153         return And(self, other)
    154 
    155     def __call__(self, val, context=None):

/home/mikhail/venvs/test/local/lib/python2.7/site-packages/trafaret/base.pyc in __init__(self, trafaret, other)
    301     def __init__(self, trafaret, other):
    302         self.trafaret = ensure_trafaret(trafaret)
--> 303         self.other = ensure_trafaret(other)
    304 
    305     def transform(self, value, context=None):

/home/mikhail/venvs/test/local/lib/python2.7/site-packages/trafaret/base.pyc in ensure_trafaret(trafaret)
    177         return trafaret
    178     elif inspect.isroutine(trafaret):
--> 179         if 'context' in getargspec(trafaret).args:
    180             return trafaret
    181         else:

/usr/lib/python2.7/inspect.pyc in getargspec(func)
    814         func = func.im_func
    815     if not isfunction(func):
--> 816         raise TypeError('{!r} is not a Python function'.format(func))
    817     args, varargs, varkw = getargs(func.func_code)
    818     return ArgSpec(args, varargs, varkw, func.func_defaults)

TypeError: <method 'upper' of 'unicode' objects> is not a Python function

For what purpose was added restriction for methods and callable objects? Can it be changed backwards or I stuck with version 0.10.0 ?

Inconsistent internet trafarets after upgrade to 0.11

Long story short: After upgrade to 0.11 there is no t.Email() or t.URL() call available due to TypeError.


In 0.10 we're validating URLs & Emails as,

    on_finish_url = t.URL()
def email(*, allow_blank: bool=False, nullable: bool=True) >> t.Trafaret:
     trafaret = t.Email(allow_blank=allow_blank)
     if nullable:
        trafaret = trafaret | t.Null()
     return trafaret >> validate_email

But after upgrade to 0.11 there is no t.URL() or t.Email() call due to,

    on_finish_url = t.URL()
E   TypeError: __call__() missing 1 required positional argument: 'val'

or,

    trafaret = t.Email(allow_blank=allow_blank)
TypeError: __call__() got an unexpected keyword argument 'allow_blank'

Yes, I've updated t.URL() call to t.URL and temporarily stripped ability to supply blank strings to emails, but I'm not sure what lead to those changes and why it's required now to remember which base trafarets are bound, and which are unbound.

Or is this a new-style to use t.String / t.Int by default, but not t.String() / t.Int()?

`construct(dict)` doesn't convert types

I'm not sure if it's the intended behavior, but in 0.12 it worked without wrapping into t.Dict:

>>> rule, raw = {"foo": int}, {"foo": "1"}
>>> construct(rule)(raw)
{'foo': '1'}
>>> construct(t.Dict(rule))(raw)
{'foo': 1}

constructors '?' behavior

If key has ‘?’ at the and it will be optional and ‘?’ will be removed

Maybe also allow blank strings in this case?

Why Dict.make_optional is deprecated?

I'm probably missing something out, but I'm wondering why was the Dict.make_optional method deprecated:
c0d4e6d#diff-a50b492e07b76174479082312cde9bd4R980

Suppose I have a large (I mean really large) dict where I need all keys to be optional. I personally find the currently-deprecated way of achieving this with .make_optional('*') [A] much more appealing than using explicit Key(..., optional=True) for each key [B]. Or maybe there already is a third non-deprecated method which is less cumbersome than [B] which I'm missing?

[A]:

mydict = t.Dict(
    a=t.Int,
    b=t.Int,
    ...
).make_optional('*')

[B]:

mydict = t.Dict({
    t.Key('a', optional=True): t.Int,
    t.Key('b', optional=True): t.Int,
    ...
})

Error classification

I'd like to start a discussion about everything that comes with errors.
At the moment we have only one type of error - DataError, which is when something is invalid.
The problem I see here is when you want to give any extra details about what gone wrong, you can't.

In my application I've come up across this issue and the only way I could deal with it is something like this:

from enum import Enum


class ErrorCode(Enum):
    required = 'required'
    too_big = 'too_big'
    too_short = 'too_short'
    invalid = 'invalid'

def make_code(text: str) -> ErrorCode:
    if text == 'is required':
        return ErrorCode.required

    if any(phrase in text for phrase in ('long', 'is greater', 'should be less', 'too many')):
        return ErrorCode.too_big

    if any(phrase in text for phrase in ('short', 'is less', 'should be greater')):
        return ErrorCode.too_short

    return ErrorCode.invalid

error: trafaret.DataError
# some logic to get an error
error_code = make_code(error.error)

This is ugly and absolutely not reliable. Trafarets tend to have different messages describing such cases, and next time I'm gonna add a trafaret I'm not using just yet, I can't be sure it works like expected. Not speaking about custom extensions...

In my opinion there should be internal error classification and all the trafarets we have so far should stick to it. And honestly, I think we need to drop error messages too because really they're out of scope of this library, it is simply too much specific context that generally lives on app level.
Such system also has to be extendable for specific cases when trafaret's basics aren't enough. I mean you should be able to easily make your own error types and use them inside library ecosystem, not around it.

First approach I'd like to consider is introduce some classes like generic InvalidError along with more specific RequiredError, TooBigError and so on, which all subclass DataError. Also it would be handy to add some shortcuts for Trafaret class as well. And maybe deal with OnError trafaret in some way to go along with the changes?

I'm willing to make a pull request with those improvements, but of course we have to come to terms first about how it should be done.
What do you think?

Add documentation about Callable

In version2 (branch) u need to add to introduction part documentation about Callable.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

In this task i recommend to add some example of usage and some reach description.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Add documentation about Call

In version2 (branch) u need to add to introduction part documentation about Call.

For that u can use old documentation and also tests which connected with current part. As example u can use this PR.

In this task i recommend to add some example of usage and some reach description.

Please don't forget:

  • your MR u need to do to the version2 (branch)
  • add screenshot with your part of documentation
  • write below that u want to take it to work

Discuss about improve documentation #contributeit

Hello everyone 🤚.

We want to improve the documentation for trafaret. To do this, we need to know what, in your opinion, is not good described in the documentation and how to do it better.

If you have any advice or want to help write documentation, feel free to write under this issue 👇.

Valid emails do not fit trafaret.Email

trafaret.Email('contaс[email protected]')

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in __call__(self, val, context)
    154
    155     def __call__(self, val, context=None):
--> 156         return self.check(val, context=context)
    157
    158

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in check(self, value, context)
    116         """
    117         if hasattr(self, 'transform'):
--> 118             return self.transform(value, context=context)
    119         elif hasattr(self, 'check_value'):
    120             self.check_value(value)

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in transform(self, value, context)
    304         if isinstance(res, DataError):
    305             raise DataError
--> 306         res = self.other(res, context=context)
    307         if isinstance(res, DataError):
    308             raise res

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in __call__(self, val, context)
    154
    155     def __call__(self, val, context=None):
--> 156         return self.check(val, context=context)
    157
    158

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in check(self, value, context)
    116         """
    117         if hasattr(self, 'transform'):
--> 118             return self.transform(value, context=context)
    119         elif hasattr(self, 'check_value'):
    120             self.check_value(value)

~/py/ocean/ocean_ai/env/lib/python3.6/site-packages/trafaret/base.py in transform(self, value, context)
    166             return self.trafaret(value, context=context)
    167         except DataError:
--> 168             raise DataError(self.message, value=value)
    169
    170

DataError: value is not a valid email address

Changelog missed

Hi,

Recently you updated trafaret to 1.0 and there are completely no docs on what changed between 0.12.0 and 1.0.0 release.

Did you consider put this to CHANGES.txt or at least at GitHub releases page?

ps. There is kind of changelog in docs, but it completely out-of-sync
pps. And yes, documentation for trafaret at RTFD still rendered for 0.10.4 version.


Keep a Changelog provides more information about how to make good Changelog for your users.

As usual thanks for trafaret, but let it be more developer friendly.

Too old to be a <1.0.0 release version

I'd like to rely on this software for important world changing projects, but it's still in 0.X version which means minor version bumps include breaking changes which is not good.

Are there any plans to bump to 1.X so I can pin to trafaret>=1,<2? I'd like some sort of agreement of stability before I include start using this to change the world.

`extras.py` is still present on version 2.0.0

Steps to reproduce: install latest version from pypi

image

There is no extras.py in source code anymore but it is still present after installation. This creates certain confusion as two versions of KeysSubset are present (in keys.py and extras).
Moreover, documentation is still pointing to the extras, which is even more confusing

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.