def test_exif(self): # datetime d = datetime.datetime(1899, 12, 31) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 00:00:00') d = datetime.datetime(1899, 12, 31, 23) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:00:00') d = datetime.datetime(1899, 12, 31, 23, 59) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:59:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:59:59') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:59:59') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:59:59') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset(hours=5)) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31 23:59:59') d = datetime.datetime(2011, 8, 8, 19, 3, 37) self.assertEqual(DateTimeFormatter.exif(d), '2011:08:08 19:03:37') # date d = datetime.date(1899, 12, 31) self.assertEqual(DateTimeFormatter.exif(d), '1899:12:31') d = datetime.date(2011, 8, 8) self.assertEqual(DateTimeFormatter.exif(d), '2011:08:08') # invalid type self.assertRaises(TypeError, DateTimeFormatter.exif, None) self.assertRaises(TypeError, DateTimeFormatter.exif, 3.14)
def test_iptc_date(self): # datetime d = datetime.datetime(1899, 12, 31) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59, 59) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset(hours=5)) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.datetime(2011, 8, 8, 19, 3, 37) self.assertEqual(DateTimeFormatter.iptc_date(d), '2011-08-08') # date d = datetime.date(1899, 12, 31) self.assertEqual(DateTimeFormatter.iptc_date(d), '1899-12-31') d = datetime.date(2011, 8, 8) self.assertEqual(DateTimeFormatter.iptc_date(d), '2011-08-08') # invalid type self.assertRaises(TypeError, DateTimeFormatter.iptc_date, None) self.assertRaises(TypeError, DateTimeFormatter.iptc_date, 3.14)
def _convert_to_string(self, value): """Convert one value to its corresponding string representation, suitable to pass to libexiv2. Args: value -- the value to be converted Return: the value converted to its corresponding string representation Raise IptcValueError: if the conversion fails """ if self.type == 'Short': if isinstance(value, int): return str(value) else: raise IptcValueError(value, self.type) elif self.type == 'String': if isinstance(value, str): try: return value.encode('utf-8') except UnicodeEncodeError: raise IptcValueError(value, self.type) elif isinstance(value, bytes): return value else: raise IptcValueError(value, self.type) elif self.type == 'Date': if isinstance(value, (datetime.date, datetime.datetime)): return DateTimeFormatter.iptc_date(value) else: raise IptcValueError(value, self.type) elif self.type == 'Time': if isinstance(value, (datetime.time, datetime.datetime)): return DateTimeFormatter.iptc_time(value) else: raise IptcValueError(value, self.type) elif self.type == 'Undefined': if isinstance(value, str): return value else: raise IptcValueError(value, self.type) raise IptcValueError(value, self.type)
def _convert_to_string(self, value): """ Convert one value to its corresponding string representation, suitable to pass to libexiv2. :param value: the value to be converted :return: the value converted to its corresponding string representation :rtype: string :raise IptcValueError: if the conversion fails """ if self.type == 'Short': if isinstance(value, int): return str(value) else: raise IptcValueError(value, self.type) elif self.type == 'String': if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise IptcValueError(value, self.type) elif isinstance(value, str): return value else: raise IptcValueError(value, self.type) elif self.type == 'Date': if isinstance(value, (datetime.date, datetime.datetime)): return DateTimeFormatter.iptc_date(value) else: raise IptcValueError(value, self.type) elif self.type == 'Time': if isinstance(value, (datetime.time, datetime.datetime)): return DateTimeFormatter.iptc_time(value) else: raise IptcValueError(value, self.type) elif self.type == 'Undefined': if isinstance(value, str): return value else: raise IptcValueError(value, self.type) raise IptcValueError(value, self.type)
def test_timedelta_to_offset(self): # positive deltas t = datetime.timedelta(hours=5) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '+05:00') t = datetime.timedelta(minutes=300) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '+05:00') t = datetime.timedelta(hours=5, minutes=12) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '+05:12') t = datetime.timedelta(seconds=10800) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '+03:00') # negative deltas t = datetime.timedelta(hours=-4) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '-04:00') t = datetime.timedelta(minutes=-258) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '-04:18') t = datetime.timedelta(hours=-2, minutes=-12) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '-02:12') t = datetime.timedelta(seconds=-10000) self.assertEqual(DateTimeFormatter.timedelta_to_offset(t), '-02:46')
def test_xmp(self): # datetime d = datetime.datetime(1899, 12, 31) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31') d = datetime.datetime(1899, 12, 31, 23, 59) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59Z') d = datetime.datetime(1899, 12, 31, 23, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59Z') d = datetime.datetime(1899, 12, 31, 23, 59, tzinfo=FixedOffset(hours=3)) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59+03:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59Z') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59Z') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset(hours=3)) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59+03:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59.999999Z') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59.999999Z') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999, tzinfo=FixedOffset(hours=3)) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31T23:59:59.999999+03:00') d = datetime.datetime(2011, 8, 11, 9, 23, 44) self.assertEqual(DateTimeFormatter.xmp(d), '2011-08-11T09:23:44Z') # date d = datetime.date(1899, 12, 31) self.assertEqual(DateTimeFormatter.xmp(d), '1899-12-31') d = datetime.date(2011, 8, 8) self.assertEqual(DateTimeFormatter.xmp(d), '2011-08-08') # invalid type self.assertRaises(TypeError, DateTimeFormatter.xmp, None) self.assertRaises(TypeError, DateTimeFormatter.xmp, 3.14)
def test_iptc_time(self): # datetime d = datetime.datetime(1899, 12, 31) self.assertEqual(DateTimeFormatter.iptc_time(d), '00:00:00+00:00') d = datetime.datetime(1899, 12, 31, 23) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:00:00+00:00') d = datetime.datetime(1899, 12, 31, 23, 59) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:00+00:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59, 999999) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.datetime(1899, 12, 31, 23, 59, 59, tzinfo=FixedOffset(hours=5)) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+05:00') d = datetime.datetime(2011, 8, 8, 19, 3, 37) self.assertEqual(DateTimeFormatter.iptc_time(d), '19:03:37+00:00') # time d = datetime.time(23) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:00:00+00:00') d = datetime.time(23, 59) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:00+00:00') d = datetime.time(23, 59, 59) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.time(23, 59, 59, 999999) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.time(23, 59, 59, tzinfo=FixedOffset()) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+00:00') d = datetime.time(23, 59, 59, tzinfo=FixedOffset(hours=5)) self.assertEqual(DateTimeFormatter.iptc_time(d), '23:59:59+05:00') d = datetime.time(19, 3, 37) self.assertEqual(DateTimeFormatter.iptc_time(d), '19:03:37+00:00') # invalid type self.assertRaises(TypeError, DateTimeFormatter.iptc_time, None) self.assertRaises(TypeError, DateTimeFormatter.iptc_time, 3.14)
def test_iptc_time_valid(formatted, ts): assert DateTimeFormatter.iptc_time(ts) == formatted
def test_iptc_time_invalid(bad_ts): with pytest.raises(TypeError): DateTimeFormatter.iptc_time(bad_ts)
def _convert_to_string(self, value): """ Convert one value to its corresponding string representation, suitable to pass to libexiv2. :param value: the value to be converted :return: the value converted to its corresponding string representation :rtype: string :raise ExifValueError: if the conversion fails """ if self.type == 'Ascii': if isinstance(value, datetime.datetime): return DateTimeFormatter.exif(value) elif isinstance(value, datetime.date): if self.key == 'Exif.GPSInfo.GPSDateStamp': # Special case return DateTimeFormatter.exif(value) else: return '%s 00:00:00' % DateTimeFormatter.exif(value) else: return value elif self.type in ('Byte', 'SByte'): if isinstance(value, str): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, bytes): return value else: raise ExifValueError(value, self.type) elif self.type == 'Comment': return self._convert_to_bytes(value) elif self.type == 'Short': if isinstance(value, int) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SShort': if isinstance(value, int): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Long': if isinstance(value, int) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SLong': if isinstance(value, int): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Rational': if is_fraction(value) and value.numerator >= 0: return fraction_to_string(value) else: raise ExifValueError(value, self.type) elif self.type == 'SRational': if is_fraction(value): return fraction_to_string(value) else: raise ExifValueError(value, self.type) elif self.type == 'Undefined': if isinstance(value, str): try: return string_to_undefined(value) except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, bytes): return string_to_undefined(value) else: raise ExifValueError(value, self.type) raise ExifValueError(value, self.type)
def test_xmp_valid(formatted, ts): assert DateTimeFormatter.xmp(ts) == formatted
def _convert_to_string(self, value, type_): """Convert a value to its corresponding string representation. Args: value -- the value to be converted type_ -- the simple type of the value Return: the value converted to its corresponding string representation Raise XmpValueError: if the conversion fails """ if type_ == 'Boolean': if isinstance(value, bool): return str(value) else: raise XmpValueError(value, type_) elif type_ == 'Date': if isinstance(value, (datetime.date, datetime.datetime)): return DateTimeFormatter.xmp(value) else: raise XmpValueError(value, type_) elif type_ == 'GPSCoordinate': if isinstance(value, GPSCoordinate): return str(value) else: raise XmpValueError(value, type_) elif type_ == 'Integer': if isinstance(value, int): return str(value) else: raise XmpValueError(value, type_) elif type_ == 'MIMEType': if isinstance(value, tuple) and len(value) == 2: return '/'.join(value) else: raise XmpValueError(value, type_) elif type_ in ('AgentName', 'ProperName', 'Text', 'URI', 'URL'): if isinstance(value, str): try: return value.encode('utf-8') except UnicodeEncodeError: raise XmpValueError(value, type_) elif isinstance(value, bytes): return value raise XmpValueError(value, type_) elif type_ == 'Rational': if is_fraction(value): return str(value) else: raise XmpValueError(value, type_) elif type_ == '': # Undefined type if isinstance(value, str): try: return value.encode('utf-8') except UnicodeEncodeError: raise XmpValueError(value, type_) elif isinstance(value, (datetime.date, datetime.datetime)): return DateTimeFormatter.xmp(value) raise NotImplementedError('XMP conversion for type [%s]' % type_)
def _convert_to_string(self, value, type): """ Convert a value to its corresponding string representation, suitable to pass to libexiv2. :param value: the value to be converted :param type: the simple type of the value :type type: string :return: the value converted to its corresponding string representation :rtype: string :raise XmpValueError: if the conversion fails """ if type == 'Boolean': if isinstance(value, bool): return str(value) else: raise XmpValueError(value, type) elif type == 'Date': if isinstance(value, (datetime.date, datetime.datetime)): return DateTimeFormatter.xmp(value) else: raise XmpValueError(value, type) elif type == 'GPSCoordinate': if isinstance(value, GPSCoordinate): return str(value) else: raise XmpValueError(value, type) elif type == 'Integer': if isinstance(value, (int, long)): return str(value) else: raise XmpValueError(value, type) elif type == 'MIMEType': if isinstance(value, tuple) and len(value) == 2: return '/'.join(value) else: raise XmpValueError(value, type) elif type in ('AgentName', 'ProperName', 'Text', 'URI', 'URL'): if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise XmpValueError(value, type) elif isinstance(value, str): return value else: raise XmpValueError(value, type) elif type == 'Rational': if is_fraction(value): return str(value) else: raise XmpValueError(value, type) elif type == '': # Unknown type, assume string if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise XmpValueError(value, type) elif isinstance(value, str): return value else: raise XmpValueError(value, type) raise NotImplementedError('XMP conversion for type [%s]' % type)
def test_exif_invalid(bad_ts): with pytest.raises(TypeError): DateTimeFormatter.exif(bad_ts)
def test_exif_valid(formatted, ts): assert DateTimeFormatter.exif(ts) == formatted
def test_timedelta_to_offset(offset, timedelta): assert DateTimeFormatter.timedelta_to_offset(TD(**timedelta)) == offset
def test_xmp_invalid(bad_ts): with pytest.raises(TypeError): DateTimeFormatter.xmp(bad_ts)
def _convert_to_string(self, value): """ Convert one value to its corresponding string representation, suitable to pass to libexiv2. :param value: the value to be converted :return: the value converted to its corresponding string representation :rtype: string :raise ExifValueError: if the conversion fails """ if self.type == 'Ascii': if isinstance(value, datetime.datetime): return DateTimeFormatter.exif(value) elif isinstance(value, datetime.date): if self.key == 'Exif.GPSInfo.GPSDateStamp': # Special case return DateTimeFormatter.exif(value) else: return '%s 00:00:00' % DateTimeFormatter.exif(value) elif isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: raise ExifValueError(value, self.type) elif self.type in ('Byte', 'SByte'): if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: try: return(str(value)) except: raise ExifValueError(value, self.type) elif self.type == 'Comment': if value is not None and self.raw_value is not None and \ self.raw_value.startswith('charset='): charset, val = self.raw_value.split(' ', 1) charset = charset.split('=')[1].strip('"') encoding = self._match_encoding(charset) try: val = value.encode(encoding) except UnicodeError: # Best effort, do not fail just because the original # encoding of the tag cannot encode the new value. pass else: return 'charset="%s" %s' % (charset, val) if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: raise ExifValueError(value, self.type) elif self.type == 'Short': if isinstance(value, int) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SShort': if isinstance(value, int): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Long': if isinstance(value, (int, long)) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SLong': if isinstance(value, (int, long)): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Rational': if is_fraction(value) and value.numerator >= 0: return fraction_to_string(value) else: try: return(str(value)) except: raise ExifValueError(value, self.type) elif self.type == 'SRational': if is_fraction(value): return fraction_to_string(value) else: try: return(str(value)) except: raise ExifValueError(value, self.type) elif self.type == 'Undefined': if isinstance(value, unicode): try: return string_to_undefined(value.encode('utf-8')) except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return string_to_undefined(value) else: raise ExifValueError(value, self.type) raise ExifValueError(value, self.type)
def _convert_to_string(self, value): """ Convert one value to its corresponding string representation, suitable to pass to libexiv2. :param value: the value to be converted :return: the value converted to its corresponding string representation :rtype: string :raise ExifValueError: if the conversion fails """ if self.type == 'Ascii': if isinstance(value, datetime.datetime): return DateTimeFormatter.exif(value) elif isinstance(value, datetime.date): if self.key == 'Exif.GPSInfo.GPSDateStamp': # Special case return DateTimeFormatter.exif(value) else: return '%s 00:00:00' % DateTimeFormatter.exif(value) elif isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: raise ExifValueError(value, self.type) elif self.type in ('Byte', 'SByte'): if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: raise ExifValueError(value, self.type) elif self.type == 'Comment': if value is not None and self.raw_value is not None and \ self.raw_value.startswith('charset='): charset, val = self.raw_value.split(' ', 1) charset = charset.split('=')[1].strip('"') encoding = self._match_encoding(charset) try: val = value.encode(encoding) except UnicodeError: # Best effort, do not fail just because the original # encoding of the tag cannot encode the new value. pass else: return 'charset="%s" %s' % (charset, val) if isinstance(value, unicode): try: return value.encode('utf-8') except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return value else: raise ExifValueError(value, self.type) elif self.type == 'Short': if isinstance(value, int) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SShort': if isinstance(value, int): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Long': if isinstance(value, (int, long)) and value >= 0: return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'SLong': if isinstance(value, (int, long)): return str(value) else: raise ExifValueError(value, self.type) elif self.type == 'Rational': if is_fraction(value) and value.numerator >= 0: return fraction_to_string(value) else: raise ExifValueError(value, self.type) elif self.type == 'SRational': if is_fraction(value): return fraction_to_string(value) else: raise ExifValueError(value, self.type) elif self.type == 'Undefined': if isinstance(value, unicode): try: return string_to_undefined(value.encode('utf-8')) except UnicodeEncodeError: raise ExifValueError(value, self.type) elif isinstance(value, str): return string_to_undefined(value) else: raise ExifValueError(value, self.type) raise ExifValueError(value, self.type)