Skip to content

Commit

Permalink
Merge pull request #106 from alfred82santa/feature/0.11.0
Browse files Browse the repository at this point in the history
Feature/0.11.0
  • Loading branch information
alfred82santa committed Nov 19, 2017
2 parents 990bf0f + 698bd19 commit 7fec81f
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 14 deletions.
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,22 @@ run-tests:

publish:
@echo "Publishing new version on Pypi..."
python setup.py sdist upload
python setup.py bdist_wheel upload

clean:
@echo "Cleaning compiled files..."
find . | grep -E "(__pycache__|\.pyc|\.pyo)$ " | xargs rm -rf
@echo "Cleaning distribution files..."
rm -rf dist
@echo "Cleaning build files..."
rm -rf build
@echo "Cleaning egg info files..."
rm -rf ${PACKAGE_NAME}.egg-info
@echo "Cleaning coverage files..."
rm -f .coverage

build:
python3 setup.py bdist_wheel

flake:
@echo "Running flake8 tests..."
Expand Down
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ Features
Changelog
---------


Version 0.11.0
--------------

- New field type :class:`~dirty_models.fields.BytesField`.

- String to integer casting could use any format allowed by Python: HEX (`0x23`), OCT (`0o43`) or
no-meaning underscores (`1_232_232`, only since Python 3.6).

Version 0.10.1
--------------

Expand Down
2 changes: 1 addition & 1 deletion dirty_models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
from .fields import *
from .utils import *

__version__ = '0.10.1'
__version__ = '0.11.0'
55 changes: 53 additions & 2 deletions dirty_models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,15 +170,24 @@ class IntegerField(BaseField):

@convert_enum
def convert_value(self, value):
if isinstance(value, str):
return int(value, 0)
return int(value)

def check_value(self, value):
return isinstance(value, int)

@can_use_enum
def can_use_value(self, value):
return isinstance(value, float) \
or (isinstance(value, str) and value.isdigit())
if isinstance(value, float):
return True
elif isinstance(value, str):
try:
int(value, 0)
return True
except ValueError:
pass
return False


class FloatField(BaseField):
Expand Down Expand Up @@ -923,3 +932,45 @@ def can_use_value(self, value):
pass

return value in self.enum_class.__members__.keys()


class BytesField(BaseField):
"""
It allows to use a bytes as value in a field.
**Automatic cast from:**
* :class:`str`
* :class:`int`
* :class:`bytearray`
* :class:`list` of :class:`int` in range(0, 256)
* :class:`~enum.Enum` if value of enum can be cast.
"""

@convert_enum
def convert_value(self, value):
if isinstance(value, str):
return value.encode()
elif isinstance(value, (list, ListModel, bytearray, int)):
if isinstance(value, int):
value = bytes([value, ])
elif isinstance(value, ListModel):
value = value.export_data()
try:
return bytes(value)
except TypeError:
pass

return None

def check_value(self, value):
return isinstance(value, bytes)

@can_use_enum
def can_use_value(self, value):
return isinstance(value, (int, str, list, ListModel, bytearray))
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
python-dateutil
python-dateutil
wheel
84 changes: 75 additions & 9 deletions tests/dirty_models/tests_fields.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
from datetime import time, date, datetime, timezone, timedelta
from enum import Enum
from datetime import date, datetime, time, timedelta, timezone
from unittest import TestCase

import iso8601
import sys
from dateutil import tz
from enum import Enum

from dirty_models.fields import (IntegerField, StringField, BooleanField,
FloatField, ModelField, TimeField, DateField,
DateTimeField, ArrayField, StringIdField, HashMapField, MultiTypeField, TimedeltaField,
EnumField)
from dirty_models.fields import ArrayField, BooleanField, BytesField, DateField, DateTimeField, EnumField, FloatField, \
HashMapField, IntegerField, ModelField, MultiTypeField, StringField, StringIdField, TimeField, TimedeltaField
from dirty_models.model_types import ListModel
from dirty_models.models import BaseModel, HashMapModel

Expand Down Expand Up @@ -174,6 +173,31 @@ class TestModel(BaseModel):
model.field_name = "3"
self.assertEqual(model.field_name, 3)

def test_int_field_on_class_using_str_hex(self):
class TestModel(BaseModel):
field_name = IntegerField()

model = TestModel()
model.field_name = "0x13"
self.assertEqual(model.field_name, 19)

def test_int_field_on_class_using_str_oct(self):
class TestModel(BaseModel):
field_name = IntegerField()

model = TestModel()
model.field_name = "0o13"
self.assertEqual(model.field_name, 11)

if sys.version_info >= (3, 6):
def test_int_field_on_class_using_str_undescore(self):
class TestModel(BaseModel):
field_name = IntegerField()

model = TestModel()
model.field_name = "1_345_232"
self.assertEqual(model.field_name, 1345232)

def test_int_field_on_class_using_dict(self):
class TestModel(BaseModel):
field_name = IntegerField()
Expand Down Expand Up @@ -1558,7 +1582,6 @@ class Model(BaseModel):
self.assertEqual(model.date_time_field.tzinfo, timezone.utc)

def test_export_definition(self):

field = DateTimeField(name='test_field', alias=[], default_timezone=timezone.utc, force_timezone=True)

self.assertEqual(field.export_definition(),
Expand Down Expand Up @@ -1611,7 +1634,6 @@ class Model(BaseModel):
self.assertEqual(model.time_field.tzinfo, tz.gettz('Europe/Amsterdam'))

def test_export_definition(self):

field = TimeField(name='test_field', alias=[], default_timezone=timezone.utc)

self.assertEqual(field.export_definition(),
Expand All @@ -1625,7 +1647,6 @@ def test_export_definition(self):
class EnumFieldTests(TestCase):

class TestEnum(Enum):

value_1 = 'value1'
value_2 = 2

Expand Down Expand Up @@ -1668,3 +1689,48 @@ def test_export_definition(self):
'enum_class': self.TestEnum,
'name': 'test_field', 'read_only': False},
self.field.export_definition())


class BytesFieldTests(TestCase):

def setUp(self):
self.field = BytesField(name='test_field', alias=[])

def test_check_value(self):
self.assertTrue(self.field.check_value(b'2332345as'))

def test_check_value_fail(self):
self.assertFalse(self.field.check_value('2332345as'))
self.assertFalse(self.field.check_value(12))
self.assertFalse(self.field.check_value(12.3))
self.assertFalse(self.field.check_value(bytearray([12, 43, 52])))
self.assertFalse(self.field.check_value([12, 43, 52]))
self.assertFalse(self.field.check_value({'sasa': 'asasas'}))

def test_can_use_value_check_values(self):
self.assertTrue(self.field.can_use_value('2332345as'))
self.assertTrue(self.field.can_use_value(12))
self.assertTrue(self.field.can_use_value(bytearray([12, 43, 52])))
self.assertTrue(self.field.can_use_value([12, 43, 52]))
self.assertTrue(self.field.can_use_value(ListModel([12, 43, 52])))

def test_can_use_value_check_values_fail(self):
self.assertFalse(self.field.can_use_value(12.3))
self.assertFalse(self.field.can_use_value({'sasa': 'asasas'}))

def test_convert_value_from_values(self):
self.assertEqual(self.field.convert_value('2332345as'), b'2332345as')
self.assertEqual(self.field.convert_value(12), b'\x0c')
self.assertEqual(self.field.convert_value(bytearray([12, 43, 52])), b'\x0c+4')
self.assertEqual(self.field.convert_value([12, 43, 52]), b'\x0c+4')
self.assertEqual(self.field.convert_value(ListModel([12, 43, 52])), b'\x0c+4')

def test_convert_value_from_invalid_values(self):
self.assertIsNone(self.field.convert_value(ListModel([{'ass': 'as'}])))

def test_export_definition(self):
self.assertEqual(self.field.export_definition(),
{'alias': [],
'doc': 'BytesField field',
'name': 'test_field', 'read_only': False},
self.field.export_definition())

0 comments on commit 7fec81f

Please sign in to comment.