~osomon/pyexiv2/pyexiv2-0.3

« back to all changes in this revision

Viewing changes to src/pyexiv2.py

  • Committer: Olivier Tilloy
  • Date: 2009-07-30 07:47:09 UTC
  • Revision ID: olivier@tilloy.net-20090730074709-jjvy5h300n3u6095
Renamed xtype attributes to type.

Show diffs side-by-side

added added

removed removed

Lines of Context:
199
199
 
200
200
    """
201
201
    A class representing a rational number.
202
 
 
203
 
    Its numerator and denominator are read-only properties.
204
202
    """
205
203
 
206
204
    _format_re = re.compile(r'(?P<numerator>-?\d+)/(?P<denominator>\d+)')
219
217
        if denominator == 0:
220
218
            msg = 'Denominator of a rational number cannot be zero.'
221
219
            raise ZeroDivisionError(msg)
222
 
        self._numerator = long(numerator)
223
 
        self._denominator = long(denominator)
224
 
 
225
 
    @property
226
 
    def numerator(self):
227
 
        return self._numerator
228
 
 
229
 
    @property
230
 
    def denominator(self):
231
 
        return self._denominator
 
220
        self.numerator = long(numerator)
 
221
        self.denominator = long(denominator)
232
222
 
233
223
    @staticmethod
234
224
    def from_string(string):
255
245
        @return: a floating point number approximation of the value
256
246
        @rtype:  C{float}
257
247
        """
258
 
        return float(self._numerator) / self._denominator
 
248
        return float(self.numerator) / self.denominator
259
249
 
260
250
    def __eq__(self, other):
261
251
        """
269
259
        @return: C{True} if equal, C{False} otherwise
270
260
        @rtype:  C{bool}
271
261
        """
272
 
        return (self._numerator * other._denominator) == \
273
 
               (other._numerator * self._denominator)
 
262
        return (self.numerator * other.denominator) == \
 
263
               (other.numerator * self.denominator)
274
264
 
275
265
    def __str__(self):
276
266
        """
277
267
        Return a string representation of the rational number.
278
268
        """
279
 
        return '%d/%d' % (self._numerator, self._denominator)
 
269
        return '%d/%d' % (self.numerator, self.denominator)
280
270
 
281
271
 
282
272
class ListenerInterface(object):
439
429
 
440
430
        @rtype: C{str}
441
431
        """
442
 
        return '<%s [%s] = %s>' % (self.key, self.type, str(self.raw_value))
 
432
        r = 'Key = ' + self.key + os.linesep + \
 
433
            'Name = ' + self.name + os.linesep + \
 
434
            'Label = ' + self.label + os.linesep + \
 
435
            'Description = ' + self.description + os.linesep + \
 
436
            'Type = ' + self.type + os.linesep + \
 
437
            'Raw value = ' + str(self.raw_value)
 
438
        return r
443
439
 
444
440
 
445
441
class ExifValueError(ValueError):
462
458
               (self.type, self.value)
463
459
 
464
460
 
465
 
class ExifTag(MetadataTag, ListenerInterface):
 
461
class ExifTag(MetadataTag):
466
462
 
467
463
    """
468
464
    An EXIF metadata tag.
480
476
                         '%Y-%m-%d %H:%M:%S',
481
477
                         '%Y-%m-%dT%H:%M:%SZ')
482
478
 
483
 
    _date_formats = ('%Y:%m:%d',)
484
 
 
485
479
    def __init__(self, key, name, label, description, type, value, fvalue):
486
480
        super(ExifTag, self).__init__(key, name, label,
487
481
                                      description, type, value)
488
482
        self.fvalue = fvalue
489
 
        self._init_values()
490
 
 
491
 
    def _init_values(self):
492
 
        # Initial conversion of the raw values to their corresponding python
493
 
        # types.
494
 
        if self.type in ('Short', 'Long', 'SLong', 'Rational', 'SRational'):
 
483
        if type in ('Short', 'Long', 'SLong', 'Rational', 'SRational'):
495
484
            # May contain multiple values
496
 
            values = self.raw_value.split()
 
485
            values = value.split()
497
486
            if len(values) > 1:
498
 
                # Make values a notifying list
499
 
                values = map(self._convert_to_python, values)
500
 
                self._value = NotifyingList(values)
501
 
                self._value.register_listener(self)
 
487
                self._value = \
 
488
                    map(lambda x: ExifTag._convert_to_python(x, type, fvalue), values)
502
489
                return
503
 
        self._value = self._convert_to_python(self.raw_value)
 
490
        self._value = ExifTag._convert_to_python(value, type, fvalue)
504
491
 
505
492
    def _get_value(self):
506
493
        return self._value
507
494
 
508
495
    def _set_value(self, new_value):
509
496
        if self.metadata is not None:
510
 
            if isinstance(new_value, (list, tuple)):
511
 
                raw_values = map(self._convert_to_string, new_value)
512
 
                raw_value = ' '.join(raw_values)
513
 
            else:
514
 
                raw_value = self._convert_to_string(new_value)
 
497
            raw_value = ExifTag._convert_to_string(new_value, self.type)
515
498
            self.metadata._set_exif_tag_value(self.key, raw_value)
516
 
 
517
 
        if isinstance(self._value, NotifyingList):
518
 
            self._value.unregister_listener(self)
519
 
 
520
 
        if isinstance(new_value, NotifyingList):
521
 
            # Already a notifying list
522
 
            self._value = new_value
523
 
            self._value.register_listener(self)
524
 
        elif isinstance(new_value, (list, tuple)):
525
 
            # Make the values a notifying list 
526
 
            self._value = NotifyingList(new_value)
527
 
            self._value.register_listener(self)
528
 
        else:
529
 
            # Single value
530
 
            self._value = new_value
 
499
        self._value = new_value
531
500
 
532
501
    def _del_value(self):
533
502
        if self.metadata is not None:
534
503
            self.metadata._delete_exif_tag(self.key)
535
 
 
536
 
        if isinstance(self._value, NotifyingList):
537
 
            self._value.unregister_listener(self)
538
 
 
539
504
        del self._value
540
505
 
541
506
    """the value of the tag converted to its corresponding python type"""
542
507
    value = property(fget=_get_value, fset=_set_value, fdel=_del_value,
543
508
                     doc=None)
544
509
 
545
 
    def contents_changed(self):
546
 
        """
547
 
        Implementation of the L{ListenerInterface}.
548
 
        React on changes to the list of values of the tag.
549
 
        """
550
 
        # self._value is a list of value and its contents changed.
551
 
        self._set_value(self._value)
552
 
 
553
 
    def _convert_to_python(self, value):
554
 
        """
555
 
        Convert one raw value to its corresponding python type.
 
510
    @staticmethod
 
511
    def _convert_to_python(value, xtype, fvalue):
 
512
        """
 
513
        Convert a raw value to its corresponding python type.
556
514
 
557
515
        @param value:  the raw value to be converted
558
516
        @type value:   C{str}
 
517
        @param xtype:  the EXIF type of the value
 
518
        @type xtype:   C{str}
 
519
        @param fvalue: the value formatted as a human-readable string by exiv2
 
520
        @type fvalue:  C{str}
559
521
 
560
522
        @return: the value converted to its corresponding python type
561
 
        @rtype:  depends on C{self.type} (DOCME)
 
523
        @rtype:  depends on xtype (DOCME)
562
524
 
563
525
        @raise ExifValueError: if the conversion fails
564
526
        """
565
 
        if self.type == 'Ascii':
 
527
        if xtype == 'Ascii':
566
528
            # The value may contain a Datetime
567
 
            for format in self._datetime_formats:
 
529
            for format in ExifTag._datetime_formats:
568
530
                try:
569
531
                    t = time.strptime(value, format)
570
532
                except ValueError:
571
533
                    continue
572
534
                else:
573
535
                    return datetime.datetime(*t[:6])
574
 
            # Or a Date (e.g. Exif.GPSInfo.GPSDateStamp)
575
 
            for format in self._date_formats:
576
 
                try:
577
 
                    t = time.strptime(value, format)
578
 
                except ValueError:
579
 
                    continue
580
 
                else:
581
 
                    return datetime.date(*t[:3])
582
536
            # Default to string
583
537
            try:
584
538
                return unicode(value, 'utf-8')
585
539
            except TypeError:
586
 
                raise ExifValueError(value, self.type)
 
540
                raise ExifValueError(value, xtype)
587
541
 
588
 
        elif self.type == 'Byte':
 
542
        elif xtype == 'Byte':
589
543
            return value
590
544
 
591
 
        elif self.type == 'Short':
 
545
        elif xtype == 'Short':
592
546
            try:
593
547
                return int(value)
594
548
            except ValueError:
595
 
                raise ExifValueError(value, self.type)
 
549
                raise ExifValueError(value, xtype)
596
550
 
597
 
        elif self.type in ('Long', 'SLong'):
 
551
        elif xtype in ('Long', 'SLong'):
598
552
            try:
599
553
                return long(value)
600
554
            except ValueError:
601
 
                raise ExifValueError(value, self.type)
 
555
                raise ExifValueError(value, xtype)
602
556
 
603
 
        elif self.type in ('Rational', 'SRational'):
 
557
        elif xtype in ('Rational', 'SRational'):
604
558
            try:
605
559
                r = Rational.from_string(value)
606
560
            except (ValueError, ZeroDivisionError):
607
 
                raise ExifValueError(value, self.type)
 
561
                raise ExifValueError(value, xtype)
608
562
            else:
609
 
                if self.type == 'Rational' and r.numerator < 0:
610
 
                    raise ExifValueError(value, self.type)
 
563
                if xtype == 'Rational' and r.numerator < 0:
 
564
                    raise ExifValueError(value, xtype)
611
565
                return r
612
566
 
613
 
        elif self.type == 'Undefined':
 
567
        elif xtype == 'Undefined':
614
568
            try:
615
 
                return unicode(self.fvalue, 'utf-8')
 
569
                return unicode(fvalue, 'utf-8')
616
570
            except TypeError:
617
 
                raise ExifValueError(self.fvalue, self.type)
618
 
 
619
 
        raise ExifValueError(value, self.type)
620
 
 
621
 
    def _convert_to_string(self, value):
 
571
                raise ExifValueError(fvalue, xtype)
 
572
 
 
573
        raise ExifValueError(value, xtype)
 
574
 
 
575
    @staticmethod
 
576
    def _convert_to_string(value, xtype):
622
577
        """
623
 
        Convert one value to its corresponding string representation, suitable
624
 
        to pass to libexiv2.
 
578
        Convert a value to its corresponding string representation, suitable to
 
579
        pass to libexiv2.
625
580
 
626
581
        @param value: the value to be converted
627
 
        @type value:  depends on C{self.type} (DOCME)
 
582
        @type value:  depends on xtype (DOCME)
 
583
        @param xtype: the EXIF type of the value
 
584
        @type xtype:  C{str}
628
585
 
629
586
        @return: the value converted to its corresponding string representation
630
587
        @rtype:  C{str}
631
588
 
632
589
        @raise ExifValueError: if the conversion fails
633
590
        """
634
 
        if self.type == 'Ascii':
 
591
        if xtype == 'Ascii':
635
592
            if type(value) is datetime.datetime:
636
 
                return value.strftime(self._datetime_formats[0])
 
593
                return value.strftime('%Y:%m:%d %H:%M:%S')
637
594
            elif type(value) is datetime.date:
638
 
                if self.key == 'Exif.GPSInfo.GPSDateStamp':
639
 
                    # Special case
640
 
                    return value.strftime(self._date_formats[0])
641
 
                else:
642
 
                    return value.strftime('%s 00:00:00' % self._date_formats[0])
 
595
                return value.strftime('%Y:%m:%d 00:00:00')
643
596
            elif type(value) is unicode:
644
597
                try:
645
598
                    return value.encode('utf-8')
646
599
                except UnicodeEncodeError:
647
 
                    raise ExifValueError(value, self.type)
 
600
                    raise ExifValueError(value, xtype)
648
601
            elif type(value) is str:
649
602
                return value
650
603
            else:
651
 
                raise ExifValueError(value, self.type) 
 
604
                raise ExifValueError(value, xtype) 
652
605
 
653
 
        elif self.type == 'Byte':
 
606
        elif xtype == 'Byte':
654
607
            if type(value) is unicode:
655
608
                try:
656
609
                    return value.encode('utf-8')
657
610
                except UnicodeEncodeError:
658
 
                    raise ExifValueError(value, self.type)
 
611
                    raise ExifValueError(value, xtype)
659
612
            elif type(value) is str:
660
613
                return value
661
614
            else:
662
 
                raise ExifValueError(value, self.type)
 
615
                raise ExifValueError(value, xtype)
663
616
 
664
 
        elif self.type == 'Short':
 
617
        elif xtype == 'Short':
665
618
            if type(value) is int and value >= 0:
666
619
                return str(value)
667
620
            else:
668
 
                raise ExifValueError(value, self.type)
 
621
                raise ExifValueError(value, xtype)
669
622
 
670
 
        elif self.type == 'Long':
 
623
        elif xtype == 'Long':
671
624
            if type(value) in (int, long) and value >= 0:
672
625
                return str(value)
673
626
            else:
674
 
                raise ExifValueError(value, self.type)
 
627
                raise ExifValueError(value, xtype)
675
628
 
676
 
        elif self.type == 'SLong':
 
629
        elif xtype == 'SLong':
677
630
            if type(value) in (int, long):
678
631
                return str(value)
679
632
            else:
680
 
                raise ExifValueError(value, self.type)
 
633
                raise ExifValueError(value, xtype)
681
634
 
682
 
        elif self.type == 'Rational':
 
635
        elif xtype == 'Rational':
683
636
            if type(value) is Rational and value.numerator >= 0:
684
637
                return str(value)
685
638
            else:
686
 
                raise ExifValueError(value, self.type)
 
639
                raise ExifValueError(value, xtype)
687
640
 
688
 
        elif self.type == 'SRational':
 
641
        elif xtype == 'SRational':
689
642
            if type(value) is Rational:
690
643
                return str(value)
691
644
            else:
692
 
                raise ExifValueError(value, self.type)
 
645
                raise ExifValueError(value, xtype)
693
646
 
694
 
        elif self.type == 'Undefined':
 
647
        elif xtype == 'Undefined':
695
648
            if type(value) is unicode:
696
649
                try:
697
650
                    return value.encode('utf-8')
698
651
                except UnicodeEncodeError:
699
 
                    raise ExifValueError(value, self.type)
 
652
                    raise ExifValueError(value, xtype)
700
653
            elif type(value) is str:
701
654
                return value
702
655
            else:
703
 
                raise ExifValueError(value, self.type)
 
656
                raise ExifValueError(value, xtype)
704
657
 
705
 
        raise ExifValueError(value, self.type)
 
658
        raise ExifValueError(value, xtype)
706
659
 
707
660
    def to_string(self):
708
661
        """
711
664
 
712
665
        @rtype: C{str}
713
666
        """
714
 
        return self._convert_to_string(self.value)
 
667
        return ExifTag._convert_to_string(self.value, self.type)
715
668
 
716
669
    def __str__(self):
717
670
        """
719
672
 
720
673
        @rtype: C{str}
721
674
        """
722
 
        left = '%s [%s]' % (self.key, self.type)
723
 
        if self.type == 'Undefined' and len(self._value) > 100:
724
 
            right = '(Binary value suppressed)'
725
 
        else:
726
 
            right = self.fvalue
727
 
        return '<%s = %s>' % (left, right)
 
675
        r = 'Key = ' + self.key + os.linesep + \
 
676
            'Name = ' + self.name + os.linesep + \
 
677
            'Label = ' + self.label + os.linesep + \
 
678
            'Description = ' + self.description + os.linesep + \
 
679
            'Type = ' + self.type + os.linesep + \
 
680
            'Value = ' + str(self.value) + os.linesep + \
 
681
            'Formatted value = ' + self.fvalue
 
682
        return r
728
683
 
729
684
 
730
685
class IptcValueError(ValueError):