/usr/lib/python2.7/dist-packages/metadataserver/fields.py is in python-django-maas 1.5.4+bzr2294-0ubuntu1.2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | # Copyright 2012 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Custom field types for the metadata server."""
from __future__ import (
absolute_import,
print_function,
unicode_literals,
)
str = None
__metaclass__ = type
__all__ = [
'BinaryField',
]
from base64 import (
b64decode,
b64encode,
)
from django.db import connection
from django.db.models import (
Field,
SubfieldBase,
)
from south.modelsinspector import add_introspection_rules
class Bin(bytes):
"""Wrapper class to convince django that a string is really binary.
This is really just a "bytes," but gets around an idiosyncracy of Django
custom field conversions: they must be able to tell on the fly whether a
value was retrieved from the database (and needs to be converted to a
python-side value), or whether it's already a python-side object (which
can stay as it is). The line between bytes and unicode is dangerously
thin.
So, to store a value in a BinaryField, wrap it in a Bin:
my_model_object.binary_data = Bin(b"\x01\x02\x03")
"""
def __init__(self, initializer):
"""Wrap a bytes.
:param initializer: Binary string of data for this Bin. This must
be a bytes. Anything else is almost certainly a mistake, so e.g.
this constructor will refuse to render None as b'None'.
:type initializer: bytes
"""
if not isinstance(initializer, bytes):
raise AssertionError(
"Not a binary string: '%s'" % repr(initializer))
super(Bin, self).__init__(initializer)
def __emittable__(self):
"""Emit base-64 encoded bytes.
Exists as a hook for Piston's JSON encoder.
"""
return b64encode(self)
# The BinaryField does not introduce any new parameters compared to its
# parent's constructor so South will handle it just fine.
# See http://south.aeracode.org/docs/customfields.html#extending-introspection
# for details.
add_introspection_rules([], ["^metadataserver\.fields\.BinaryField"])
class BinaryField(Field):
"""A field that stores binary data.
The data is base64-encoded internally, so this is not very efficient.
Do not use this for large blobs.
We do not have direct support for binary data in django at the moment.
It's possible to create a django model Field based by a postgres BYTEA,
but:
1. Any data you save gets mis-interpreted as encoded text. This won't
be obvious until you test with data that can't be decoded.
2. Any data you retrieve gets truncated at the first zero byte.
"""
__metaclass__ = SubfieldBase
def to_python(self, value):
"""Django overridable: convert database value to python-side value."""
if isinstance(value, unicode):
# Encoded binary data from the database. Convert.
return Bin(b64decode(value))
elif value is None or isinstance(value, Bin):
# Already in python-side form.
return value
else:
raise AssertionError(
"Invalid BinaryField value (expected unicode): '%s'"
% repr(value))
def get_db_prep_value(self, value, connection=None, prepared=False):
"""Django overridable: convert python-side value to database value."""
if value is None:
# Equivalent of a NULL.
return None
elif isinstance(value, Bin):
# Python-side form. Convert to database form.
return b64encode(value)
elif isinstance(value, bytes):
# Binary string. Require a Bin to make intent explicit.
raise AssertionError(
"Converting a binary string to BinaryField: "
"either conversion is going the wrong way, or the value "
"needs to be wrapped in a Bin.")
elif isinstance(value, unicode):
# Unicode here is almost certainly a sign of a mistake.
raise AssertionError(
"A unicode string is being mistaken for binary data.")
else:
raise AssertionError(
"Invalid BinaryField value (expected Bin): '%s'"
% repr(value))
def get_internal_type(self):
return 'TextField'
def _get_default(self):
"""Cargo-cult of Django's `Field.get_default`.
Django is totally smoking crack on this one. It forces a
unicode string out of the default which is demonstrably not
unicode. This corrects that behaviour.
"""
if self.has_default():
if callable(self.default):
return self.default()
return self.default
if not self.empty_strings_allowed:
return None
if self.null:
if not connection.features.interprets_empty_strings_as_nulls:
return None
return b""
def get_default(self):
"""Override Django's crack-smoking ``Field.get_default``."""
default = self._get_default()
return None if default is None else Bin(default)
|