<commit_before># micromodels

A simple library for building read-only model classes based on dictionaries of data.

Perfect for wrapping Python objects around JSON data returned from web-based APIs.

## Really simple example

    import micromodels

    class Author(micromodels.Model):
        first_name = micromodels.CharField()
        last_name = micromodels.CharField()
        date_of_birth = micromodels.DateField(format="%Y-%m-%d")

        @property
        def full_name(self):
            return "%s %s" % (self.first_name, self.last_name)


    douglas_data = {
        "first_name": "Douglas",
        "last_name": "Adams",
        "date_of_birth": "1952-03-11",
    }

    douglas = Author(douglas_data)
    print "%s was born in %s" % (douglas.full_name, douglas.date_of_birth.strftime("%Y"))

## Slightly more complex example

    import json
    from urllib2 import urlopen

    import micromodels

    class TwitterUser(micromodels.Model):
        id = micromodels.IntegerField()
        screen_name = micromodels.CharField()
        name = micromodels.CharField()
        description = micromodels.CharField()

        def get_profile_url(self):
            return 'http://twitter.com/%s' % self.screen_name


    class Tweet(micromodels.Model):
        id = micromodels.IntegerField()
        text = micromodels.CharField()
        created_at = micromodels.DateTimeField(format="%a %b %d %H:%M:%S +0000 %Y")
        user = micromodels.ModelField(TwitterUser)


    json_data = urlopen('http://api.twitter.com/1/statuses/show/20.json')
    tweet = Tweet(json.load(json_data))

    print "Tweet was posted by %s (%s) on a %s" % (
        tweet.user.name,
        tweet.user.get_profile_url(),
        tweet.created_at.strftime("%A")
    )


## Field reference

### Field options

The following optional argument is available for all field types.

#### `source`

By default, a model class will look for a key in its source data with the same name as each of its fields. For example:

    class ExampleModel(micromodels.Model):
        myfield = micromodels.CharField()

    >>> e = ExampleModel({'myfield': 'Some Value'})
    >>> e.myfield
    u'Some Value'

If you wish to change this, you can pass the 'source' argument to each field instance:

    class ExampleModel(micromodels.Model):
        myfield = micromodels.CharField()
        anotherfield = micromodels.CharField(source='some_other_field')

    >>> e = ExampleModel({'myfield': 'Some Value', 'some_other_field': 'Another Value'})
    >>> e.anotherfield
    u'Another Value'

### Field types

#### PassField

The simplest type of field - this simply passes through whatever is in the data dictionary without changing it at all.

#### CharField

A field for string data. **Will attempt to convert its supplied data to Unicode.**

#### IntegerField

Attempts to convert its supplied data to an integer.

#### BooleanField

Attempts to convert its supplied data to a boolean. If the data is a string, `"true"` (case insensitive) will be converted to `True` and all other strings will be converted to `False`. If the supplied data is an integer, positive numbers will become `True` and negative numbers or zero will become `False`.

#### DateTimeField

Converts its supplied data to a Python `datetime.datetime` object using the format given in the required `format` argument. See [the Python documentation](http://docs.python.org/library/datetime.html#strftime-strptime-behavior) for details of the format string. For example:

    class MyModel(micromodels.Model):
        created_at = micromodels.DateTimeField(format="%a %b %d %H:%M:%S +0000 %Y")

#### DateField

Converts its supplied data to a Python `datetime.date` object using the format given in the required `format` argument (see `DateTimeField` for details).

#### TimeField

Converts its supplied data to a Python `datetime.time` object using the format given in the required `format` argument (see `DateTimeField` for details).

#### ModelField

Use this field when you wish to nest one object inside another. For example, given the following dictionary:

    some_data = {
        'first_item': 'Some value',
        'second_item': {
            'nested_item': 'Some nested value',
        },
    }

You could build the following classes (note that you have to define the inner nested models first):

    class MyNestedModel(micromodels.Model):
        nested_item = micromodels.CharField()

    class MyMainModel(micromodels.Model):
        first_item = micromodels.CharField()
        second_item = micromodels.ModelField(MyNestedModel) # pass the class of the nested model

Then you can access the data as follows:

    >>> m = MyMainModel(some_data)
    >>> m.first_item
    u'Some value'
    >>> m.second_item.__class__.__name__
    'MyNestedModel'
    >>> m.second_item.nested_item
    u'Some nested value'

#### ModelCollectionField

Use this field when your source data dictionary contains a list of dictionaries. For example:

    some_data = {
        'list': [
            {'value': 'First value'},
            {'value': 'Second value'},
            {'value': 'Third value'},
        ]
    }

    class MyNestedModel(micromodels.Model):
        value = micromodels.CharField()


    class MyMainModel(micromodels.Model):
        list = micromodels.ModelCollectionField(MyNestedModel)

    >>> m = MyMainModel(some_data)
    >>> len(m.list)
    3
    >>> m.list[0].__class__.__name__
    'MyNestedModel'
    >>> m.list[0].value
    u'First value'
    >>> [item.value for item in m.list]
    [u'First value', u'Second value', u'Third value']

#### FieldCollectionField

Use this field when your source data dictionary contains a list of items of the same type. For example:

    some_data = {
        'first_list': [0, 34, 42],
        'second_list': ['first_item', 'second_item', 'third_item'],
    }

    class MyModel(micromodels.Model):
        first_list = micromodels.FieldCollectionField(micromodels.IntegerField)
        second_list = micromodels.FieldCollectionField(micromodels.CharField)

    >>> m = MyModel(some_data)
    >>> len(m.first_list), len(m.second_list)<commit_msg>Extra blank line not really needed here<commit_after># micromodels

A simple library for building read-only model classes based on dictionaries of data.

Perfect for wrapping Python objects around JSON data returned from web-based APIs.

## Really simple example

    import micromodels

    class Author(micromodels.Model):
        first_name = micromodels.CharField()
        last_name = micromodels.CharField()
        date_of_birth = micromodels.DateField(format="%Y-%m-%d")

        @property
        def full_name(self):
            return "%s %s" % (self.first_name, self.last_name)


    douglas_data = {
        "first_name": "Douglas",
        "last_name": "Adams",
        "date_of_birth": "1952-03-11",
    }

    douglas = Author(douglas_data)
    print "%s was born in %s" % (douglas.full_name, douglas.date_of_birth.strftime("%Y"))

## Slightly more complex example

    import json
    from urllib2 import urlopen

    import micromodels

    class TwitterUser(micromodels.Model):
        id = micromodels.IntegerField()
        screen_name = micromodels.CharField()
        name = micromodels.CharField()
        description = micromodels.CharField()

        def get_profile_url(self):
            return 'http://twitter.com/%s' % self.screen_name


    class Tweet(micromodels.Model):
        id = micromodels.IntegerField()
        text = micromodels.CharField()
        created_at = micromodels.DateTimeField(format="%a %b %d %H:%M:%S +0000 %Y")
        user = micromodels.ModelField(TwitterUser)


    json_data = urlopen('http://api.twitter.com/1/statuses/show/20.json')
    tweet = Tweet(json.load(json_data))

    print "Tweet was posted by %s (%s) on a %s" % (
        tweet.user.name,
        tweet.user.get_profile_url(),
        tweet.created_at.strftime("%A")
    )


## Field reference

### Field options

The following optional argument is available for all field types.

#### `source`

By default, a model class will look for a key in its source data with the same name as each of its fields. For example:

    class ExampleModel(micromodels.Model):
        myfield = micromodels.CharField()

    >>> e = ExampleModel({'myfield': 'Some Value'})
    >>> e.myfield
    u'Some Value'

If you wish to change this, you can pass the 'source' argument to each field instance:

    class ExampleModel(micromodels.Model):
        myfield = micromodels.CharField()
        anotherfield = micromodels.CharField(source='some_other_field')

    >>> e = ExampleModel({'myfield': 'Some Value', 'some_other_field': 'Another Value'})
    >>> e.anotherfield
    u'Another Value'

### Field types

#### PassField

The simplest type of field - this simply passes through whatever is in the data dictionary without changing it at all.

#### CharField

A field for string data. **Will attempt to convert its supplied data to Unicode.**

#### IntegerField

Attempts to convert its supplied data to an integer.

#### BooleanField

Attempts to convert its supplied data to a boolean. If the data is a string, `"true"` (case insensitive) will be converted to `True` and all other strings will be converted to `False`. If the supplied data is an integer, positive numbers will become `True` and negative numbers or zero will become `False`.

#### DateTimeField

Converts its supplied data to a Python `datetime.datetime` object using the format given in the required `format` argument. See [the Python documentation](http://docs.python.org/library/datetime.html#strftime-strptime-behavior) for details of the format string. For example:

    class MyModel(micromodels.Model):
        created_at = micromodels.DateTimeField(format="%a %b %d %H:%M:%S +0000 %Y")

#### DateField

Converts its supplied data to a Python `datetime.date` object using the format given in the required `format` argument (see `DateTimeField` for details).

#### TimeField

Converts its supplied data to a Python `datetime.time` object using the format given in the required `format` argument (see `DateTimeField` for details).

#### ModelField

Use this field when you wish to nest one object inside another. For example, given the following dictionary:

    some_data = {
        'first_item': 'Some value',
        'second_item': {
            'nested_item': 'Some nested value',
        },
    }

You could build the following classes (note that you have to define the inner nested models first):

    class MyNestedModel(micromodels.Model):
        nested_item = micromodels.CharField()

    class MyMainModel(micromodels.Model):
        first_item = micromodels.CharField()
        second_item = micromodels.ModelField(MyNestedModel) # pass the class of the nested model

Then you can access the data as follows:

    >>> m = MyMainModel(some_data)
    >>> m.first_item
    u'Some value'
    >>> m.second_item.__class__.__name__
    'MyNestedModel'
    >>> m.second_item.nested_item
    u'Some nested value'

#### ModelCollectionField

Use this field when your source data dictionary contains a list of dictionaries. For example:

    some_data = {
        'list': [
            {'value': 'First value'},
            {'value': 'Second value'},
            {'value': 'Third value'},
        ]
    }

    class MyNestedModel(micromodels.Model):
        value = micromodels.CharField()

    class MyMainModel(micromodels.Model):
        list = micromodels.ModelCollectionField(MyNestedModel)

    >>> m = MyMainModel(some_data)
    >>> len(m.list)
    3
    >>> m.list[0].__class__.__name__
    'MyNestedModel'
    >>> m.list[0].value
    u'First value'
    >>> [item.value for item in m.list]
    [u'First value', u'Second value', u'Third value']

#### FieldCollectionField

Use this field when your source data dictionary contains a list of items of the same type. For example:

    some_data = {
        'first_list': [0, 34, 42],
        'second_list': ['first_item', 'second_item', 'third_item'],
    }

    class MyModel(micromodels.Model):
        first_list = micromodels.FieldCollectionField(micromodels.IntegerField)
        second_list = micromodels.FieldCollectionField(micromodels.CharField)

    >>> m = MyModel(some_data)
    >>> len(m.first_list), len(m.second_list)
{'fraction_non_alphanumeric': 0.10662332385209264, 'fraction_numerical': 0.004550995530272247, 'mean_word_length': 3.314866760168303, 'pattern_counts': {'":': 6, '<': 3, '<?xml version=': 0, '>': 93, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '159298', 'n_tokens_mistral': 3752, 'n_tokens_neox': 3537, 'n_words': 1143}