Skip to content

Commit d77f921

Browse files
author
James Campbell
committed
Release v2.2.0: Fix all issues and modernize build system
1 parent 256872b commit d77f921

File tree

5 files changed

+226
-61
lines changed

5 files changed

+226
-61
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
- **Issue #38**: Verified backup file behavior (use `options={'overwrite': True}` to avoid ~ files)
1616
- Better error handling and logging throughout
1717

18+
### Build System Modernization
19+
- Migrated from legacy `setup.py` to modern `pyproject.toml`
20+
- Now uses `uv` and `hatchling` for building (PEP 517/518 compliant)
21+
- Simplified setup.py to minimal backward compatibility shim
22+
- Added comprehensive publishing guide (`PUBLISHING.md`)
23+
- Supports Python 3.8 through 3.13
24+
1825
### Notes
1926
- **Issue #39, #41**: Ready for PyPI release with all fixes from master branch
2027

PUBLISHING.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Publishing Guide for IPTCInfo3
2+
3+
This project now uses modern Python packaging with `pyproject.toml` and `uv`.
4+
5+
## Prerequisites
6+
7+
```bash
8+
# Install uv (if not already installed)
9+
curl -LsSf https://astral.sh/uv/install.sh | sh
10+
11+
# Install twine for PyPI uploads (optional, uv can also publish)
12+
uv pip install twine
13+
```
14+
15+
## Building the Package
16+
17+
```bash
18+
# Clean previous builds
19+
rm -rf dist/
20+
21+
# Build with uv (creates both .tar.gz and .whl)
22+
uv build
23+
```
24+
25+
This will create:
26+
- `dist/iptcinfo3-2.2.0.tar.gz` (source distribution)
27+
- `dist/iptcinfo3-2.2.0-py3-none-any.whl` (wheel)
28+
29+
## Publishing to PyPI
30+
31+
### Option 1: Using uv (recommended)
32+
33+
```bash
34+
# Publish to PyPI (requires PyPI credentials)
35+
uv publish
36+
37+
# Or publish to TestPyPI first
38+
uv publish --publish-url https://test.pypi.org/legacy/
39+
```
40+
41+
### Option 2: Using twine
42+
43+
```bash
44+
# Check the distributions
45+
twine check dist/*
46+
47+
# Upload to TestPyPI first (optional)
48+
twine upload --repository testpypi dist/*
49+
50+
# Upload to PyPI
51+
twine upload dist/*
52+
```
53+
54+
## Testing the Package
55+
56+
### Test locally
57+
58+
```bash
59+
# Install in development mode
60+
uv pip install -e .
61+
62+
# Or install from the built wheel
63+
uv pip install dist/iptcinfo3-2.2.0-py3-none-any.whl
64+
```
65+
66+
### Test from TestPyPI
67+
68+
```bash
69+
uv pip install --index-url https://test.pypi.org/simple/ iptcinfo3
70+
```
71+
72+
### Test from PyPI (after publishing)
73+
74+
```bash
75+
uv pip install iptcinfo3
76+
```
77+
78+
## Version Updates
79+
80+
To release a new version:
81+
82+
1. Update `__version__` in `iptcinfo3.py`
83+
2. Update version in `pyproject.toml`
84+
3. Update `CHANGELOG.md` with changes
85+
4. Commit changes
86+
5. Create a git tag: `git tag v2.2.0`
87+
6. Push with tags: `git push origin master --tags`
88+
7. Build and publish as shown above
89+
90+
## PyPI Credentials
91+
92+
You'll need to configure your PyPI credentials. Create `~/.pypirc`:
93+
94+
```ini
95+
[pypi]
96+
username = __token__
97+
password = pypi-...your-token...
98+
99+
[testpypi]
100+
username = __token__
101+
password = pypi-...your-token...
102+
```
103+
104+
Or use environment variables:
105+
```bash
106+
export TWINE_USERNAME=__token__
107+
export TWINE_PASSWORD=pypi-...your-token...
108+
```
109+
110+
## Notes
111+
112+
- The package name on PyPI is `IPTCInfo3` (with capital letters)
113+
- The module name is `iptcinfo3` (all lowercase)
114+
- Always test on TestPyPI before publishing to production PyPI
115+
- Once published to PyPI, you cannot delete or re-upload the same version
116+

README.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,23 @@ programs -- pull it back out. You can use the information directly in
2323
Python programs, export it to XML, or even export SQL statements ready
2424
to be fed into a database.
2525

26+
Installation
27+
------------
28+
29+
Install from PyPI::
30+
31+
pip install IPTCInfo3
32+
33+
Or with uv::
34+
35+
uv pip install IPTCInfo3
36+
37+
Requirements
38+
------------
39+
40+
- Python 3.8 or higher
41+
- No external dependencies required
42+
2643
Usage
2744
-----
2845

pyproject.toml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+

setup.py

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,8 @@
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
151
"""
2+
Legacy setup.py for backward compatibility.
3+
Modern installations should use pyproject.toml with pip/uv.
4+
"""
5+
from setuptools import setup
166

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='Artistic-1.0 OR GPL-1.0-or-later',
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-
)
7+
# All configuration is now in pyproject.toml
8+
setup()

0 commit comments

Comments
 (0)