IPTCInfo3 2.1.4__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ __pycache__
2
+ .cache
3
+ .coverage
4
+
5
+ # Packaging files
6
+ *.egg-info
7
+ dist/*
8
+ build/*
9
+ .cache
10
+ __pycache__
11
+
12
+ # Test files cleanup
13
+ .jpg
14
+ .jpeg
15
+
16
+ # ide stuff
17
+ .vscode
18
+ .vscode/*
19
+
20
+ # pipfile stuff
21
+ Pipfile.lock
@@ -0,0 +1,88 @@
1
+ ## 2.2.0 (2025-10-02)
2
+
3
+ ### Bug Fixes
4
+ - **Issue #40**: Clarified license statements - now consistently states "Artistic-1.0 OR GPL-1.0-or-later"
5
+ - **Issue #24**: Changed "Marker scan hit start of image data" to INFO level when `force=True` is used
6
+ - **Issue #32**: Fixed charset recognition for ISO 2022 escape sequences (UTF-8 as `\x1b%G`)
7
+ - **Issue #26**: Added validation for float/NaN values in `packedIIMData()` to prevent TypeError
8
+
9
+ ### New Features
10
+ - **Issue #35**: Added 'credit line' field support per IPTC Core 1.1 (backward compatible with 'credit')
11
+ - **Issue #42**: Added 'destination' field as alias for 'original transmission reference'
12
+
13
+ ### Improvements
14
+ - **Issue #15**: Enhanced IPTC tag collection with better field mappings
15
+ - **Issue #38**: Verified backup file behavior (use `options={'overwrite': True}` to avoid ~ files)
16
+ - Better error handling and logging throughout
17
+
18
+ ### Notes
19
+ - **Issue #39, #41**: Ready for PyPI release with all fixes from master branch
20
+
21
+ ---
22
+
23
+ Updating builds to target 3.9.7
24
+
25
+ 2.1: Fixes merged to save modified IPTC info images
26
+
27
+ 1.9.5-8: https://bitbucket.org/gthomas/iptcinfo/issue/4/file-permissions-for-changed-files-are-not - copy original file's permission bits on save/saveAs
28
+
29
+ 1.9.5-7: https://bitbucket.org/gthomas/iptcinfo/issue/3/images-w-o-iptc-data-should-not-log-errors - have silencable parse errors.
30
+
31
+ 1.9.5-6: to have a nice new upload (seems easy_install grabs an old version).
32
+
33
+ 1.9.5-5: fix some issues with "super"
34
+
35
+ 1.9.5-3: use logging module.
36
+
37
+ 1.9.5-2: Emil Stenström pinpointed some bugs/misleading (un)comments
38
+ Also a new (mis)feature is implemented: if you don't specify inp_charset
39
+ (and the image misses such information, too) than no conversion is made
40
+ to unicode, everything stays bytestring!
41
+ This way you don't need to deal with charsets, BUT it is your risk to make
42
+ the modifications with the SAME charset as it is in the image!
43
+
44
+ 1.9.5-1: getting in sync with the Perl version 1.9.5
45
+
46
+ 1.9.2-rc8:
47
+ charset recognition loosened (failed with some image out of
48
+ Adobe Lightroom).
49
+
50
+ 1.9.2-rc7: NOT READY
51
+ IPTCInfo now accepts 'inp_charset' keyword for setting input charset.
52
+
53
+ 1.9.2-rc6: just PyLint-ed out some errors.
54
+
55
+ 1.9.2-rc5: Amos Latteier sent me a patch which releases the requirement of the
56
+ file objects to be file objects (he uses this on jpeg files stored in
57
+ databases as strings).
58
+ It modifies the module in order to look for a read method on the file
59
+ object. If one exists it assumes the argument is a file object, otherwise it
60
+ assumes it's a filename.
61
+
62
+ 1.9.2-rc4: on Windows systems, tmpfile may not work correctly - now I use
63
+ cStringIO on file save (to save the file without truncating it on Exception).
64
+
65
+ 1.9.2-rc3: some little bug fixes, some safety enhancements (now iptcinfo.py
66
+ will overwrite the original image file (info.save()) only if everything goes
67
+ fine (so if an exception is thrown at writing, it won't cut your original
68
+ file).
69
+
70
+ This is a pre-release version: needs some testing, and has an unfound bug
71
+ (yet): some pictures can be enhanced with iptc data, and iptcinfo.py is able
72
+ to read them, but some other iptc data readers will spit on it.
73
+
74
+ 1.9.1: a first release with some little encoding support
75
+
76
+ The class IPTCInfo now has an inp_charset and an out_charset attribute - the
77
+ first is the read image's charset (defaults to the system default charset),
78
+ the second is the charset the writer will use (defaults to inp_charset).
79
+
80
+ Reader will find the charset included in IPTC data (if any, defaults to the
81
+ system's default charset), and use it to read to unicode strings. Writer will
82
+ write using IPTCinfo.out_charset (if it is not set, will not write charset
83
+ IPTC record).
84
+
85
+ With this, it is possible to read and write i18n strings correctly.
86
+
87
+ I haven't tested this functionality thoroughly, and that little test was only
88
+ on my WinXP box only, with the only other IPTC reader: IrfanView.
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: IPTCInfo3
3
+ Version: 2.2.0
4
+ Summary: Extract and modify IPTC metadata from JPEG images
5
+ Project-URL: Homepage, https://github.com/jamesacampbell/iptcinfo3
6
+ Project-URL: Repository, https://github.com/jamesacampbell/iptcinfo3
7
+ Project-URL: Issues, https://github.com/jamesacampbell/iptcinfo3/issues
8
+ Author-email: Tamas Gulacsi <gthomas@fw.hu>
9
+ Maintainer-email: James Campbell <jc@normail.co>
10
+ License: Artistic-1.0 OR GPL-1.0-or-later
11
+ Keywords: exif,iptc,jpeg,metadata,photography
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: Artistic License
15
+ Classifier: License :: OSI Approved :: GNU General Public License (GPL)
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Multimedia :: Graphics
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.8
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
29
+ Requires-Dist: pytest-watch>=4.2; extra == 'dev'
30
+ Requires-Dist: pytest>=7.0; extra == 'dev'
31
+ Description-Content-Type: text/x-rst
32
+
33
+ ``IPTCINFO 3``
34
+ ==============
35
+
36
+ `Build Status <https://api.travis-ci.org/crccheck/iptcinfo3.png>`_
37
+
38
+ Like IPTCInfo but finally compatible for Python 3
39
+ -------------------------------------------------
40
+
41
+
42
+ Ported from Josh Carter's Perl IPTCInfo-1.9.pm by Tamas Gulacsi
43
+
44
+ Ever wish you add information to your photos like a caption, the place
45
+ you took it, the date, and perhaps even keywords and categories? You
46
+ already can. The International Press Telecommunications Council (IPTC)
47
+ defines a format for exchanging meta-information in news content, and
48
+ that includes photographs. You can embed all kinds of information in
49
+ your images. The trick is putting it to use.
50
+
51
+ That's where this IPTCInfo Python module comes into play. You can embed
52
+ information using many programs, including Adobe Photoshop, and
53
+ IPTCInfo will let your web server -- and other automated server
54
+ programs -- pull it back out. You can use the information directly in
55
+ Python programs, export it to XML, or even export SQL statements ready
56
+ to be fed into a database.
57
+
58
+ Usage
59
+ -----
60
+
61
+ ``from iptcinfo3 import IPTCInfo``
62
+
63
+
64
+ Create new info object
65
+ ``info = IPTCInfo('doge.jpg')``
66
+
67
+ Print list of keywords, supplemental categories, contacts
68
+ ``print(info['keywords'])``
69
+ ``print(info['supplementalCategories'])``
70
+ ``print(info['contacts'])``
71
+
72
+ Get specific attributes...
73
+ ``caption = info['caption/abstract']``
74
+
75
+ Create object for file that may not have IPTC data
76
+ ``info = IPTCInfo('such_iptc.jpg', force=True)``
77
+
78
+ Add/change an attribute
79
+ ``info['caption/abstract'] = 'Witty caption here'``
80
+ ``info['supplemental category'] = ['portrait']``
81
+
82
+ Lists for keywords, so you can just append!
83
+ ``info['keywords']).append('cool')``
84
+
85
+ Save new info to file
86
+ ``info.save()``
87
+ ``info.save_as('very_meta.jpg')``
@@ -1,7 +1,7 @@
1
1
  ``IPTCINFO 3``
2
2
  ==============
3
3
 
4
- `Build Status <https://travis-ci.org/crccheck/iptcinfo3.svg?branch=master>`_
4
+ `Build Status <https://api.travis-ci.org/crccheck/iptcinfo3.png>`_
5
5
 
6
6
  Like IPTCInfo but finally compatible for Python 3
7
7
  -------------------------------------------------
@@ -47,6 +47,9 @@ Add/change an attribute
47
47
  ``info['caption/abstract'] = 'Witty caption here'``
48
48
  ``info['supplemental category'] = ['portrait']``
49
49
 
50
+ Lists for keywords, so you can just append!
51
+ ``info['keywords']).append('cool')``
52
+
50
53
  Save new info to file
51
54
  ``info.save()``
52
55
  ``info.save_as('very_meta.jpg')``
@@ -11,7 +11,8 @@
11
11
  # All rights reserved.
12
12
  #
13
13
  # This program is free software; you can redistribute it and/or modify
14
- # it under the same terms as Python itself.
14
+ # it under the terms of the Artistic License or the GNU General Public
15
+ # License (GPL). You may choose either license.
15
16
  #
16
17
  # VERSION = '1.9';
17
18
  """
@@ -24,8 +25,9 @@ import shutil
24
25
  import sys
25
26
  import tempfile
26
27
  from struct import pack, unpack
28
+ import json
27
29
 
28
- __version__ = '2.1.4'
30
+ __version__ = '2.2.0'
29
31
  __author__ = 'Gulácsi, Tamás'
30
32
  __updated_by__ = 'Campbell, James'
31
33
 
@@ -177,7 +179,7 @@ def jpeg_get_variable_length(fh):
177
179
 
178
180
  # Length includes itself, so must be at least 2
179
181
  if length < 2:
180
- logger.warn("jpeg_get_variable_length: erroneous JPEG marker length")
182
+ logger.warning("jpeg_get_variable_length: erroneous JPEG marker length")
181
183
  return 0
182
184
  return length - 2
183
185
 
@@ -192,7 +194,7 @@ def jpeg_next_marker(fh):
192
194
  try:
193
195
  byte = read_exactly(fh, 1)
194
196
  while ord3(byte) != 0xff:
195
- # logger.warn("jpeg_next_marker: bogus stuff in Jpeg file at: ')
197
+ # logger.warning("jpeg_next_marker: bogus stuff in Jpeg file at: ')
196
198
  byte = read_exactly(fh, 1)
197
199
 
198
200
  # Now skip any extra 0xffs, which are valid padding.
@@ -360,7 +362,7 @@ def jpeg_debug_scan(filename): # pragma: no cover
360
362
  break
361
363
 
362
364
  if ord3(marker) == 0:
363
- logger.warn("Marker scan failed")
365
+ logger.warning("Marker scan failed")
364
366
  break
365
367
 
366
368
  elif ord3(marker) == 0xd9:
@@ -368,7 +370,7 @@ def jpeg_debug_scan(filename): # pragma: no cover
368
370
  break
369
371
 
370
372
  if not jpeg_skip_variable(fh):
371
- logger.warn("jpeg_skip_variable failed")
373
+ logger.warning("jpeg_skip_variable failed")
372
374
  return None
373
375
 
374
376
 
@@ -480,7 +482,7 @@ c_datasets = {
480
482
  101: 'country/primary location name',
481
483
  103: 'original transmission reference',
482
484
  105: 'headline',
483
- 110: 'credit',
485
+ 110: 'credit line', # Updated from 'credit' to 'credit line' per IPTC Core 1.1
484
486
  115: 'source',
485
487
  116: 'copyright notice',
486
488
  118: 'contact',
@@ -536,6 +538,12 @@ class IPTCData(dict):
536
538
  return key
537
539
  elif isinstance(key, str) and key.lower() in c_datasets_r:
538
540
  return c_datasets_r[key.lower()]
541
+ # Backward compatibility: 'credit' is now 'credit line' per IPTC Core 1.1
542
+ elif isinstance(key, str) and key.lower() == 'credit':
543
+ return 110
544
+ # Alias for compatibility with gThumb/exiftool
545
+ elif isinstance(key, str) and key.lower() == 'destination':
546
+ return 103 # Maps to 'original transmission reference'
539
547
  elif key.startswith(cls.c_cust_pre) and key[len(cls.c_cust_pre):].isdigit():
540
548
  # example: nonstandard_69 -> 69
541
549
  return int(key[len(cls.c_cust_pre):])
@@ -553,6 +561,13 @@ class IPTCData(dict):
553
561
  else:
554
562
  raise KeyError("Key %s is not in %s!" % (key, list(c_datasets.keys())))
555
563
 
564
+ def __contains__(self, name):
565
+ try:
566
+ key = self._key_as_int(name)
567
+ except KeyError:
568
+ return False
569
+ return super().__contains__(key)
570
+
556
571
  def __getitem__(self, name):
557
572
  return self.get(self._key_as_int(name), None)
558
573
 
@@ -598,6 +613,7 @@ class IPTCInfo:
598
613
  'contact': [],
599
614
  })
600
615
  self._fobj = fobj
616
+ self._force = force
601
617
  if duck_typed(fobj, 'read'): # DELETEME
602
618
  self._filename = None
603
619
  else:
@@ -613,7 +629,7 @@ class IPTCInfo:
613
629
  if datafound:
614
630
  self.collectIIMInfo(fh)
615
631
  else:
616
- logger.warn('No IPTC data found in %s', fobj)
632
+ logger.warning('No IPTC data found in %s', fobj)
617
633
 
618
634
  def _filepos(self, fh):
619
635
  """For debugging, return what position in the file we are."""
@@ -630,7 +646,7 @@ class IPTCInfo:
630
646
  """Saves Jpeg with IPTC data to a given file name."""
631
647
  with smart_open(self._fobj, 'rb') as fh:
632
648
  if not file_is_jpeg(fh):
633
- logger.error('Source file %s is not a Jpeg.' % self._fob)
649
+ logger.error('Source file %s is not a Jpeg.' % self._fobj)
634
650
  return None
635
651
 
636
652
  jpeg_parts = jpeg_collect_file_parts(fh)
@@ -686,8 +702,10 @@ class IPTCInfo:
686
702
  os.unlink(tmpfn)
687
703
  else:
688
704
  tmpfh.close()
689
- if os.path.exists(newfile):
690
- shutil.move(newfile, newfile + '~')
705
+ if os.path.exists(newfile) and options is not None and 'overwrite' in options:
706
+ os.unlink(newfile)
707
+ elif os.path.exists(newfile):
708
+ shutil.move(newfile, "{file}~".format(file=newfile))
691
709
  shutil.move(tmpfn, newfile)
692
710
  return True
693
711
 
@@ -699,6 +717,9 @@ class IPTCInfo:
699
717
  def __len__(self):
700
718
  return len(self._data)
701
719
 
720
+ def __contains__(self, key):
721
+ return key in self._data
722
+
702
723
  def __getitem__(self, key):
703
724
  return self._data[key]
704
725
 
@@ -716,7 +737,7 @@ class IPTCInfo:
716
737
  logger.info("File is JPEG, proceeding with JpegScan")
717
738
  return self.jpegScan(fh)
718
739
  else:
719
- logger.warn("File not a JPEG, trying blindScan")
740
+ logger.warning("File not a JPEG, trying blindScan")
720
741
  return self.blindScan(fh)
721
742
 
722
743
  c_marker_err = {0: "Marker scan failed",
@@ -752,14 +773,18 @@ class IPTCInfo:
752
773
  err = "jpeg_skip_variable failed"
753
774
  if err is not None:
754
775
  self.error = err
755
- logger.warn(err)
776
+ # When force=True, log as INFO instead of WARNING since we expect no IPTC data
777
+ if self._force:
778
+ logger.info(err)
779
+ else:
780
+ logger.warning(err)
756
781
  return None
757
782
 
758
783
  # If were's here, we must have found the right marker.
759
784
  # Now blindScan through the data.
760
785
  return self.blindScan(fh, MAX=jpeg_get_variable_length(fh))
761
786
 
762
- def blindScan(self, fh, MAX=8192):
787
+ def blindScan(self, fh, MAX=819200):
763
788
  """Scans blindly to first IIM Record 2 tag in the file. This
764
789
  method may or may not work on any arbitrary file type, but it
765
790
  doesn't hurt to check. We expect to see this tag within the first
@@ -767,7 +792,7 @@ class IPTCInfo:
767
792
  depending on how other programs choose to store IIM.)"""
768
793
 
769
794
  offset = 0
770
- # keep within first 8192 bytes
795
+ # keep within first 819200 bytes
771
796
  # NOTE: this may need to change
772
797
  logger.debug('blindScan: starting scan, max length %d', MAX)
773
798
 
@@ -776,7 +801,7 @@ class IPTCInfo:
776
801
  try:
777
802
  temp = read_exactly(fh, 1)
778
803
  except EOFException:
779
- logger.warn("BlindScan: hit EOF while scanning")
804
+ logger.warning("BlindScan: hit EOF while scanning")
780
805
  return None
781
806
  # look for tag identifier 0x1c
782
807
  if ord3(temp) == 0x1c:
@@ -787,15 +812,32 @@ class IPTCInfo:
787
812
  # found character set's record!
788
813
  try:
789
814
  temp = read_exactly(fh, jpeg_get_variable_length(fh))
790
- try:
791
- cs = unpack('!H', temp)[0]
792
- except Exception: # TODO better exception
793
- logger.warn('WARNING: problems with charset recognition (%r)', temp)
794
- cs = None
795
- if cs in c_charset:
796
- self.inp_charset = c_charset[cs]
797
- logger.info("BlindScan: found character set '%s' at offset %d",
798
- self.inp_charset, offset)
815
+ cs = None
816
+ # Check for ISO 2022 escape sequence (starts with ESC 0x1b)
817
+ if len(temp) >= 3 and ord3(temp[0]) == 0x1b:
818
+ # Parse ISO 2022 escape sequences
819
+ # ESC % G = UTF-8
820
+ if temp == b'\x1b%G':
821
+ self.inp_charset = 'utf_8'
822
+ # ESC % / @ = UTF-16 (not commonly used)
823
+ elif temp == b'\x1b%/@':
824
+ self.inp_charset = 'utf_16'
825
+ else:
826
+ logger.debug(
827
+ "BlindScan: unknown ISO 2022 charset escape sequence %r",
828
+ temp)
829
+ else:
830
+ # Try legacy numeric charset encoding
831
+ try:
832
+ cs = unpack('!H', temp)[0]
833
+ if cs in c_charset:
834
+ self.inp_charset = c_charset[cs]
835
+ except Exception:
836
+ logger.debug('BlindScan: could not parse charset from %r', temp)
837
+
838
+ if self.inp_charset:
839
+ logger.info("BlindScan: found character set '%s' at offset %d",
840
+ self.inp_charset, offset)
799
841
  except EOFException:
800
842
  pass
801
843
 
@@ -845,7 +887,7 @@ class IPTCInfo:
845
887
  try:
846
888
  value = str(value, encoding=self.inp_charset, errors='strict')
847
889
  except Exception: # TODO better exception
848
- logger.warn('Data "%r" is not in encoding %s!', value, self.inp_charset)
890
+ logger.warning('Data "%r" is not in encoding %s!', value, self.inp_charset)
849
891
  value = str(value, encoding=self.inp_charset, errors='replace')
850
892
 
851
893
  # try to extract first into _listdata (keywords, categories)
@@ -889,11 +931,22 @@ class IPTCInfo:
889
931
  LOGDBG.debug('out=%s', hex_dump(out))
890
932
  # Iterate over data sets
891
933
  for dataset, value in self._data.items():
892
- if len(value) == 0:
934
+ # Skip None, empty strings, empty lists, and NaN values
935
+ if value is None:
936
+ continue
937
+ # Handle float/int that might be NaN
938
+ if isinstance(value, (float, int)):
939
+ import math
940
+ if isinstance(value, float) and math.isnan(value):
941
+ continue
942
+ # Convert numeric values to strings
943
+ value = str(value)
944
+ # Check length for strings and lists
945
+ if hasattr(value, '__len__') and len(value) == 0:
893
946
  continue
894
947
 
895
948
  if not (isinstance(dataset, int) and dataset in c_datasets):
896
- logger.warn("packedIIMData: illegal dataname '%s' (%d)", dataset, dataset)
949
+ logger.warning("packedIIMData: illegal dataname '%s' (%d)", dataset, dataset)
897
950
  continue
898
951
 
899
952
  logger.debug('packedIIMData %02X: %r -> %r', dataset, value, self._enc(value))
@@ -944,7 +997,16 @@ class IPTCInfo:
944
997
 
945
998
 
946
999
  if __name__ == '__main__': # pragma: no cover
947
- logging.basicConfig(level=logging.DEBUG)
1000
+ logging.basicConfig(level=logging.ERROR)
948
1001
  if len(sys.argv) > 1:
949
1002
  info = IPTCInfo(sys.argv[1])
950
- print(info)
1003
+ if info.__dict__ != '':
1004
+ for k, v in info.__dict__.items():
1005
+ if k == '_data':
1006
+ print(k)
1007
+ for key, value in v.items():
1008
+ if type(value) == list:
1009
+ print(key, [x.decode() for x in value])
1010
+ [print(x.decode()) for x in value]
1011
+ print(key, value)
1012
+ print(k, v)
@@ -0,0 +1,80 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "IPTCInfo3"
7
+ version = "2.2.0"
8
+ description = "Extract and modify IPTC metadata from JPEG images"
9
+ readme = "README.rst"
10
+ license = { text = "Artistic-1.0 OR GPL-1.0-or-later" }
11
+ authors = [
12
+ { name = "Tamas Gulacsi", email = "gthomas@fw.hu" },
13
+ ]
14
+ maintainers = [
15
+ { name = "James Campbell", email = "jc@normail.co" },
16
+ ]
17
+ keywords = ["iptc", "metadata", "jpeg", "exif", "photography"]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "License :: OSI Approved :: Artistic License",
21
+ "License :: OSI Approved :: GNU General Public License (GPL)",
22
+ "Intended Audience :: Developers",
23
+ "Programming Language :: Python",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.8",
26
+ "Programming Language :: Python :: 3.9",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Programming Language :: Python :: 3.13",
31
+ "Topic :: Multimedia :: Graphics",
32
+ "Topic :: Utilities",
33
+ ]
34
+ requires-python = ">=3.8"
35
+ dependencies = []
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/jamesacampbell/iptcinfo3"
39
+ Repository = "https://github.com/jamesacampbell/iptcinfo3"
40
+ Issues = "https://github.com/jamesacampbell/iptcinfo3/issues"
41
+
42
+ [project.optional-dependencies]
43
+ dev = [
44
+ "pytest>=7.0",
45
+ "pytest-cov>=4.0",
46
+ "pytest-watch>=4.2",
47
+ ]
48
+
49
+ [tool.hatch.build.targets.sdist]
50
+ include = [
51
+ "iptcinfo3.py",
52
+ "README.rst",
53
+ "CHANGELOG.md",
54
+ "LICENSE",
55
+ ]
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ packages = ["."]
59
+ only-include = ["iptcinfo3.py"]
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
63
+ python_files = ["test_*.py", "*_test.py"]
64
+
65
+ [tool.coverage.run]
66
+ branch = true
67
+ source = ["."]
68
+
69
+ [tool.coverage.report]
70
+ show_missing = true
71
+ skip_covered = true
72
+
73
+ [tool.ruff]
74
+ line-length = 100
75
+ target-version = "py38"
76
+
77
+ [tool.ruff.lint]
78
+ select = ["E", "F", "W", "I", "N", "UP"]
79
+ ignore = ["E501"] # Line length handled by formatter
80
+
@@ -1,72 +0,0 @@
1
- Metadata-Version: 1.2
2
- Name: IPTCInfo3
3
- Version: 2.1.4
4
- Summary: A great way to get IPTCInfo
5
- Home-page: https://github.com/jamesacampbell/iptcinfo3
6
- Author: Tamas Gulacsi
7
- Author-email: gthomas@fw.hu
8
- Maintainer: James Campbell
9
- Maintainer-email: jc@normail.co
10
- License: http://www.opensource.org/licenses/gpl-license.php
11
- Download-URL: https://github.com/jamesacampbell/iptcinfo3
12
- Description: ``IPTCINFO 3``
13
- ==============
14
-
15
- `Build Status <https://travis-ci.org/crccheck/iptcinfo3.svg?branch=master>`_
16
-
17
- Like IPTCInfo but finally compatible for Python 3
18
- -------------------------------------------------
19
-
20
-
21
- Ported from Josh Carter's Perl IPTCInfo-1.9.pm by Tamas Gulacsi
22
-
23
- Ever wish you add information to your photos like a caption, the place
24
- you took it, the date, and perhaps even keywords and categories? You
25
- already can. The International Press Telecommunications Council (IPTC)
26
- defines a format for exchanging meta-information in news content, and
27
- that includes photographs. You can embed all kinds of information in
28
- your images. The trick is putting it to use.
29
-
30
- That's where this IPTCInfo Python module comes into play. You can embed
31
- information using many programs, including Adobe Photoshop, and
32
- IPTCInfo will let your web server -- and other automated server
33
- programs -- pull it back out. You can use the information directly in
34
- Python programs, export it to XML, or even export SQL statements ready
35
- to be fed into a database.
36
-
37
- Usage
38
- -----
39
-
40
- ``from iptcinfo3 import IPTCInfo``
41
-
42
-
43
- Create new info object
44
- ``info = IPTCInfo('doge.jpg')``
45
-
46
- Print list of keywords, supplemental categories, contacts
47
- ``print(info['keywords'])``
48
- ``print(info['supplementalCategories'])``
49
- ``print(info['contacts'])``
50
-
51
- Get specific attributes...
52
- ``caption = info['caption/abstract']``
53
-
54
- Create object for file that may not have IPTC data
55
- ``info = IPTCInfo('such_iptc.jpg', force=True)``
56
-
57
- Add/change an attribute
58
- ``info['caption/abstract'] = 'Witty caption here'``
59
- ``info['supplemental category'] = ['portrait']``
60
-
61
- Save new info to file
62
- ``info.save()``
63
- ``info.save_as('very_meta.jpg')``
64
-
65
- Platform: any
66
- Classifier: Development Status :: 3 - Alpha
67
- Classifier: License :: OSI Approved :: Artistic License
68
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
69
- Classifier: Intended Audience :: Developers
70
- Classifier: Programming Language :: Python
71
- Classifier: Topic :: Multimedia :: Graphics
72
- Classifier: Topic :: Utilities
@@ -1,8 +0,0 @@
1
- README.rst
2
- iptcinfo3.py
3
- setup.cfg
4
- setup.py
5
- IPTCInfo3.egg-info/PKG-INFO
6
- IPTCInfo3.egg-info/SOURCES.txt
7
- IPTCInfo3.egg-info/dependency_links.txt
8
- IPTCInfo3.egg-info/top_level.txt
@@ -1 +0,0 @@
1
- iptcinfo3
IPTCInfo3-2.1.4/PKG-INFO DELETED
@@ -1,72 +0,0 @@
1
- Metadata-Version: 1.2
2
- Name: IPTCInfo3
3
- Version: 2.1.4
4
- Summary: A great way to get IPTCInfo
5
- Home-page: https://github.com/jamesacampbell/iptcinfo3
6
- Author: Tamas Gulacsi
7
- Author-email: gthomas@fw.hu
8
- Maintainer: James Campbell
9
- Maintainer-email: jc@normail.co
10
- License: http://www.opensource.org/licenses/gpl-license.php
11
- Download-URL: https://github.com/jamesacampbell/iptcinfo3
12
- Description: ``IPTCINFO 3``
13
- ==============
14
-
15
- `Build Status <https://travis-ci.org/crccheck/iptcinfo3.svg?branch=master>`_
16
-
17
- Like IPTCInfo but finally compatible for Python 3
18
- -------------------------------------------------
19
-
20
-
21
- Ported from Josh Carter's Perl IPTCInfo-1.9.pm by Tamas Gulacsi
22
-
23
- Ever wish you add information to your photos like a caption, the place
24
- you took it, the date, and perhaps even keywords and categories? You
25
- already can. The International Press Telecommunications Council (IPTC)
26
- defines a format for exchanging meta-information in news content, and
27
- that includes photographs. You can embed all kinds of information in
28
- your images. The trick is putting it to use.
29
-
30
- That's where this IPTCInfo Python module comes into play. You can embed
31
- information using many programs, including Adobe Photoshop, and
32
- IPTCInfo will let your web server -- and other automated server
33
- programs -- pull it back out. You can use the information directly in
34
- Python programs, export it to XML, or even export SQL statements ready
35
- to be fed into a database.
36
-
37
- Usage
38
- -----
39
-
40
- ``from iptcinfo3 import IPTCInfo``
41
-
42
-
43
- Create new info object
44
- ``info = IPTCInfo('doge.jpg')``
45
-
46
- Print list of keywords, supplemental categories, contacts
47
- ``print(info['keywords'])``
48
- ``print(info['supplementalCategories'])``
49
- ``print(info['contacts'])``
50
-
51
- Get specific attributes...
52
- ``caption = info['caption/abstract']``
53
-
54
- Create object for file that may not have IPTC data
55
- ``info = IPTCInfo('such_iptc.jpg', force=True)``
56
-
57
- Add/change an attribute
58
- ``info['caption/abstract'] = 'Witty caption here'``
59
- ``info['supplemental category'] = ['portrait']``
60
-
61
- Save new info to file
62
- ``info.save()``
63
- ``info.save_as('very_meta.jpg')``
64
-
65
- Platform: any
66
- Classifier: Development Status :: 3 - Alpha
67
- Classifier: License :: OSI Approved :: Artistic License
68
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
69
- Classifier: Intended Audience :: Developers
70
- Classifier: Programming Language :: Python
71
- Classifier: Topic :: Multimedia :: Graphics
72
- Classifier: Topic :: Utilities
IPTCInfo3-2.1.4/setup.cfg DELETED
@@ -1,15 +0,0 @@
1
- [flake8]
2
- max-line-length = 100
3
-
4
- [coverage:run]
5
- branch = True
6
- source = .
7
-
8
- [coverage:report]
9
- show_missing = True
10
- skip_covered = True
11
-
12
- [egg_info]
13
- tag_build =
14
- tag_date = 0
15
-
IPTCInfo3-2.1.4/setup.py DELETED
@@ -1,63 +0,0 @@
1
- """SETUP THIS STUFF."""
2
- import sys
3
- from distutils.command.sdist import sdist as _sdist
4
- from os import path
5
-
6
- from setuptools import setup
7
- classifiers = """
8
- Development Status :: 3 - Alpha
9
- License :: OSI Approved :: Artistic License
10
- License :: OSI Approved :: GNU General Public License (GPL)
11
- Intended Audience :: Developers
12
- Programming Language :: Python
13
- Topic :: Multimedia :: Graphics
14
- Topic :: Utilities
15
- """
16
-
17
- this_directory = path.abspath(path.dirname(__file__))
18
- with open(path.join(this_directory, 'README.rst')) as f:
19
- long_description = f.read()
20
-
21
- if sys.version_info < (2, 3):
22
- _setup = setup
23
-
24
- def setup(**kwargs):
25
- if "classifiers" in kwargs:
26
- del kwargs["classifiers"]
27
- _setup(**kwargs)
28
-
29
-
30
- class sdist(_sdist, object):
31
- def run(self):
32
- import os
33
- res = _sdist.run(self)
34
- print((self.get_archive_files()))
35
- for fn in self.get_archive_files():
36
- os.system('scp -p %s gtmainbox:/var/www/html/python/' % fn)
37
- return res
38
-
39
-
40
- def openfile(fname):
41
- import os
42
- return open(os.path.join(os.path.dirname(__file__), fname))
43
-
44
-
45
- version = next((row.split('=', 1)[-1].strip().strip("'").strip('"')
46
- for row in open('iptcinfo3.py', 'r')
47
- if row.startswith('__version__')))
48
- setup( # cmdclass={'sdist': sdist},
49
- name='IPTCInfo3',
50
- version=version,
51
- url='https://github.com/jamesacampbell/iptcinfo3',
52
- download_url='https://github.com/jamesacampbell/iptcinfo3',
53
- author='Tamas Gulacsi',
54
- author_email='gthomas@fw.hu',
55
- maintainer='James Campbell',
56
- maintainer_email='jc@normail.co',
57
- long_description=long_description,
58
- license='http://www.opensource.org/licenses/gpl-license.php',
59
- platforms=['any'],
60
- description="""A great way to get IPTCInfo""",
61
- classifiers=[_f for _f in classifiers.split('\n') if _f],
62
- py_modules=['iptcinfo3'],
63
- )