c2pa-python 0.17.0__tar.gz → 0.19.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.
Files changed (22) hide show
  1. {c2pa_python-0.17.0/src/c2pa_python.egg-info → c2pa_python-0.19.0}/PKG-INFO +1 -1
  2. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/pyproject.toml +1 -1
  3. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/scripts/download_artifacts.py +68 -21
  4. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/setup.py +63 -48
  5. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa/c2pa.py +508 -237
  6. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa/lib.py +30 -20
  7. {c2pa_python-0.17.0 → c2pa_python-0.19.0/src/c2pa_python.egg-info}/PKG-INFO +1 -1
  8. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/tests/test_unit_tests.py +11 -2
  9. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/LICENSE-APACHE +0 -0
  10. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/LICENSE-MIT +0 -0
  11. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/MANIFEST.in +0 -0
  12. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/README.md +0 -0
  13. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/requirements.txt +0 -0
  14. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/setup.cfg +0 -0
  15. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa/__init__.py +0 -0
  16. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa/build.py +0 -0
  17. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa_python.egg-info/SOURCES.txt +0 -0
  18. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa_python.egg-info/dependency_links.txt +0 -0
  19. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa_python.egg-info/entry_points.txt +0 -0
  20. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa_python.egg-info/requires.txt +0 -0
  21. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/src/c2pa_python.egg-info/top_level.txt +0 -0
  22. {c2pa_python-0.17.0 → c2pa_python-0.19.0}/tests/test_unit_tests_threaded.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: c2pa-python
3
- Version: 0.17.0
3
+ Version: 0.19.0
4
4
  Summary: Python bindings for the C2PA Content Authenticity Initiative (CAI) library
5
5
  Author-email: Gavin Peacock <gvnpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
6
6
  Maintainer-email: Gavin Peacock <gpeacock@adobe.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "c2pa-python"
7
- version = "0.17.0"
7
+ version = "0.19.0"
8
8
  requires-python = ">=3.10"
9
9
  description = "Python bindings for the C2PA Content Authenticity Initiative (CAI) library"
10
10
  readme = { file = "README.md", content-type = "text/markdown" }
@@ -54,11 +54,20 @@ def detect_arch():
54
54
  else:
55
55
  raise ValueError(f"Unsupported CPU architecture: {machine}")
56
56
 
57
- def get_platform_identifier():
58
- """Get the full platform identifier (arch-os) for the current system,
59
- matching the identifiers used by the Github publisher.
57
+ def get_platform_identifier(target_arch=None):
58
+ """Get the full platform identifier (arch-os) for the current system or target.
59
+
60
+ Args:
61
+ target_arch: Optional target architecture.
62
+ If provided, overrides auto-detection.
63
+ For macOS: 'universal2', 'arm64', or 'x86_64'
64
+ For Linux: 'aarch64' or 'x86_64'
65
+ For Windows: 'arm64' or 'x64'
66
+
60
67
  Returns one of:
61
- - universal-apple-darwin (for Mac)
68
+ - universal-apple-darwin (for macOS universal)
69
+ - aarch64-apple-darwin (for macOS ARM64)
70
+ - x86_64-apple-darwin (for macOS x86_64)
62
71
  - x86_64-pc-windows-msvc (for Windows 64-bit)
63
72
  - x86_64-unknown-linux-gnu (for Linux x86_64)
64
73
  - aarch64-unknown-linux-gnu (for Linux ARM64)
@@ -67,11 +76,27 @@ def get_platform_identifier():
67
76
  machine = platform.machine().lower()
68
77
 
69
78
  if system == "darwin":
70
- return "universal-apple-darwin"
79
+ if target_arch == "arm64":
80
+ return "aarch64-apple-darwin"
81
+ elif target_arch == "x86_64":
82
+ return "x86_64-apple-darwin"
83
+ elif target_arch == "universal2":
84
+ return "universal-apple-darwin"
85
+ else:
86
+ # Auto-detect: prefer specific architecture over universal
87
+ if machine == "arm64":
88
+ return "aarch64-apple-darwin"
89
+ elif machine == "x86_64":
90
+ return "x86_64-apple-darwin"
91
+ else:
92
+ return "universal-apple-darwin"
71
93
  elif system == "windows":
72
- return "x86_64-pc-windows-msvc"
94
+ if target_arch == "arm64":
95
+ return "aarch64-pc-windows-msvc"
96
+ else:
97
+ return "x86_64-pc-windows-msvc"
73
98
  elif system == "linux":
74
- if machine in ["arm64", "aarch64"]:
99
+ if target_arch == "aarch64" or machine in ["arm64", "aarch64"]:
75
100
  return "aarch64-unknown-linux-gnu"
76
101
  else:
77
102
  return "x86_64-unknown-linux-gnu"
@@ -101,19 +126,20 @@ def download_and_extract_libs(url, platform_name):
101
126
  response = requests.get(url, headers=headers)
102
127
  response.raise_for_status()
103
128
 
129
+ print(f"Downloaded zip file, extracting lib files...")
104
130
  with zipfile.ZipFile(io.BytesIO(response.content)) as zip_ref:
105
131
  # Extract only files inside the libs/ directory
132
+ extracted_count = 0
106
133
  for member in zip_ref.namelist():
107
- print(f" Processing zip member: {member}")
108
134
  if member.startswith("lib/") and not member.endswith("/"):
109
- print(f" Processing lib file from downloadedzip: {member}")
110
135
  target_path = platform_dir / os.path.relpath(member, "lib")
111
- print(f" Moving file to target path: {target_path}")
112
136
  target_path.parent.mkdir(parents=True, exist_ok=True)
113
137
  with zip_ref.open(member) as source, open(target_path, "wb") as target:
114
138
  target.write(source.read())
139
+ extracted_count += 1
140
+ print(f" Extracted: {member} -> {target_path}")
115
141
 
116
- print(f"Done downloading and extracting libraries for {platform_name}")
142
+ print(f"Done downloading and extracting {extracted_count} library files for {platform_name}")
117
143
 
118
144
  def copy_artifacts_to_root():
119
145
  """Copy the artifacts folder from scripts/artifacts to the root of the repository."""
@@ -122,37 +148,53 @@ def copy_artifacts_to_root():
122
148
  return
123
149
 
124
150
  print("Copying artifacts from scripts/artifacts to root...")
151
+ print("Contents of scripts/artifacts before copying:")
152
+ for item in sorted(SCRIPTS_ARTIFACTS_DIR.iterdir()):
153
+ print(f" {item.name}")
154
+
125
155
  if ROOT_ARTIFACTS_DIR.exists():
126
156
  shutil.rmtree(ROOT_ARTIFACTS_DIR)
127
157
  print(f"Copying from {SCRIPTS_ARTIFACTS_DIR} to {ROOT_ARTIFACTS_DIR}")
128
158
  shutil.copytree(SCRIPTS_ARTIFACTS_DIR, ROOT_ARTIFACTS_DIR)
129
159
  print("Done copying artifacts")
130
- print("\nFolder content of artifacts directory:")
160
+ print("\nFolder content of root artifacts directory:")
131
161
  for item in sorted(ROOT_ARTIFACTS_DIR.iterdir()):
132
162
  print(f" {item.name}")
133
163
 
134
164
  def main():
135
165
  if len(sys.argv) < 2:
136
- print("Usage: python download_artifacts.py <release_tag>")
166
+ print("Usage: python download_artifacts.py <release_tag> [target_architecture]")
137
167
  print("Example: python download_artifacts.py c2pa-v0.49.5")
168
+ print("Example: python download_artifacts.py c2pa-v0.49.5 arm64")
138
169
  sys.exit(1)
139
170
 
140
171
  release_tag = sys.argv[1]
172
+ target_arch = sys.argv[2] if len(sys.argv) > 2 else None
173
+
141
174
  try:
175
+ # Clean up any existing artifacts before starting
176
+ print("Cleaning up existing artifacts...")
177
+ if SCRIPTS_ARTIFACTS_DIR.exists():
178
+ shutil.rmtree(SCRIPTS_ARTIFACTS_DIR)
142
179
  SCRIPTS_ARTIFACTS_DIR.mkdir(exist_ok=True)
143
180
  print(f"Fetching release information for tag {release_tag}...")
144
181
  release = get_release_by_tag(release_tag)
145
182
  print(f"Found release: {release['tag_name']} \n")
146
183
 
147
- # Get the platform identifier for the current system
184
+ # Get the platform identifier for the target architecture
148
185
  env_platform = os.environ.get("C2PA_LIBS_PLATFORM")
149
186
  if env_platform:
150
187
  print(f"Using platform from environment variable C2PA_LIBS_PLATFORM: {env_platform}")
151
- platform_id = env_platform or get_platform_identifier()
188
+ platform_id = env_platform
189
+ else:
190
+ platform_id = get_platform_identifier(target_arch)
191
+ print(f"Using target architecture: {target_arch or 'auto-detected'}")
192
+ print(f"Detected machine architecture: {platform.machine()}")
193
+ print(f"Detected system: {platform.system()}")
194
+
152
195
  print("Looking up releases for platform id: ", platform_id)
153
- print("Environment variable set for lookup: ", env_platform)
154
- platform_source = "environment variable" if env_platform else "auto-detection"
155
- print(f"Target platform: {platform_id} (set through{platform_source})")
196
+ platform_source = "environment variable" if env_platform else "target architecture" if target_arch else "auto-detection"
197
+ print(f"Target platform: {platform_id} (set through {platform_source})")
156
198
 
157
199
  # Construct the expected asset name
158
200
  expected_asset_name = f"{release_tag}-{platform_id}.zip"
@@ -160,18 +202,23 @@ def main():
160
202
 
161
203
  # Find the matching asset in the release
162
204
  matching_asset = None
205
+ print(f"Looking for asset: {expected_asset_name}")
206
+ print("Available assets in release:")
163
207
  for asset in release['assets']:
208
+ print(f" - {asset['name']}")
164
209
  if asset['name'] == expected_asset_name:
165
210
  matching_asset = asset
166
- break
211
+ print(f"Using native library: {matching_asset['name']}")
167
212
 
168
213
  if matching_asset:
169
- print(f"Found matching asset: {matching_asset['name']}")
214
+ print(f"\nDownloading asset: {matching_asset['name']}")
170
215
  download_and_extract_libs(matching_asset['browser_download_url'], platform_id)
171
216
  print("\nArtifacts have been downloaded and extracted successfully!")
172
217
  copy_artifacts_to_root()
173
218
  else:
174
- print(f"\nNo matching asset found: {expected_asset_name}")
219
+ print(f"\nNo matching asset found for platform: {platform_id}")
220
+ print(f"Expected asset name: {expected_asset_name}")
221
+ print("Please check if the asset exists in the release or if the platform identifier is correct.")
175
222
 
176
223
  except requests.exceptions.RequestException as e:
177
224
  print(f"Error: {e}")
@@ -38,6 +38,8 @@ PLATFORM_EXTENSIONS = {
38
38
  # Based on what c2pa-rs repo publishes
39
39
  PLATFORM_FOLDERS = {
40
40
  'universal-apple-darwin': 'dylib',
41
+ 'aarch64-apple-darwin': 'dylib',
42
+ 'x86_64-apple-darwin': 'dylib',
41
43
  'x86_64-pc-windows-msvc': 'dll',
42
44
  'x86_64-unknown-linux-gnu': 'so',
43
45
  'aarch64-unknown-linux-gnu': 'so',
@@ -48,16 +50,20 @@ ARTIFACTS_DIR = Path('artifacts') # Where downloaded libraries are stored
48
50
  PACKAGE_LIBS_DIR = Path('src/c2pa/libs') # Where libraries will be copied for the wheel
49
51
 
50
52
 
51
- def get_platform_identifier() -> str:
52
- """Get a platform identifier (arch-os) for the current system,
53
- matching downloaded identifiers used by the Github publisher.
53
+ def get_platform_identifier(target_arch=None) -> str:
54
+ """Get a platform identifier (arch-os) for the current system or target architecture.
54
55
 
55
56
  Args:
56
- Only used on macOS systems.:
57
- cpu_arch: Optional CPU architecture for macOS. If not provided, returns universal build.
57
+ target_arch: Optional target architecture.
58
+ If provided, overrides auto-detection.
59
+ For macOS: 'universal2', 'arm64', or 'x86_64'
60
+ For Linux: 'aarch64' or 'x86_64'
61
+ For Windows: 'arm64' or 'x64'
58
62
 
59
63
  Returns one of:
60
- - universal-apple-darwin (for macOS)
64
+ - universal-apple-darwin (for macOS universal)
65
+ - aarch64-apple-darwin (for macOS ARM64)
66
+ - x86_64-apple-darwin (for macOS x86_64)
61
67
  - x86_64-pc-windows-msvc (for Windows 64-bit)
62
68
  - x86_64-unknown-linux-gnu (for Linux 64-bit)
63
69
  - aarch64-unknown-linux-gnu (for Linux ARM64)
@@ -65,13 +71,22 @@ def get_platform_identifier() -> str:
65
71
  system = platform.system().lower()
66
72
 
67
73
  if system == "darwin":
68
- return "universal-apple-darwin"
74
+ if target_arch == "arm64":
75
+ return "aarch64-apple-darwin"
76
+ elif target_arch == "x86_64":
77
+ return "x86_64-apple-darwin"
78
+ else:
79
+ return "universal-apple-darwin"
69
80
  elif system == "windows":
70
- return "x86_64-pc-windows-msvc"
81
+ if target_arch == "arm64":
82
+ return "aarch64-pc-windows-msvc"
83
+ else:
84
+ return "x86_64-pc-windows-msvc"
71
85
  elif system == "linux":
72
- if platform.machine() == "aarch64":
86
+ if target_arch == "aarch64" or platform.machine() == "aarch64":
73
87
  return "aarch64-unknown-linux-gnu"
74
- return "x86_64-unknown-linux-gnu"
88
+ else:
89
+ return "x86_64-unknown-linux-gnu"
75
90
  else:
76
91
  raise ValueError(f"Unsupported operating system: {system}")
77
92
 
@@ -157,9 +172,38 @@ if 'develop' in sys.argv or 'install' in sys.argv:
157
172
 
158
173
  # For wheel building (both bdist_wheel and build)
159
174
  if 'bdist_wheel' in sys.argv or 'build' in sys.argv:
160
- available_platforms = find_available_platforms()
161
- if not available_platforms:
162
- print("No platform-specific libraries found. Building wheel without platform-specific libraries.")
175
+ # Check if we're building for a specific architecture
176
+ # This is mostly to support macOS wheel builds
177
+ target_arch = None
178
+ for i, arg in enumerate(sys.argv):
179
+ if arg == '--plat-name':
180
+ if i + 1 < len(sys.argv):
181
+ plat_name = sys.argv[i + 1]
182
+ if 'arm64' in plat_name:
183
+ target_arch = 'arm64'
184
+ elif 'x86_64' in plat_name:
185
+ target_arch = 'x86_64'
186
+ elif 'universal2' in plat_name:
187
+ target_arch = 'universal2'
188
+ break
189
+
190
+ # Get the platform identifier for the target architecture
191
+ target_platform = get_platform_identifier(target_arch)
192
+ print(f"Building wheel for target platform: {target_platform}")
193
+
194
+ # Check if we have libraries for this platform
195
+ platform_dir = ARTIFACTS_DIR / target_platform
196
+ if not platform_dir.exists() or not any(platform_dir.iterdir()):
197
+ print(f"Warning: No libraries found for platform {target_platform}")
198
+ print("Available platforms:")
199
+ for platform_name in find_available_platforms():
200
+ print(f" - {platform_name}")
201
+
202
+ # Copy libraries for the target platform
203
+ try:
204
+ copy_platform_libraries(target_platform, clean_first=True)
205
+
206
+ # Build the wheel
163
207
  setup(
164
208
  name=PACKAGE_NAME,
165
209
  version=VERSION,
@@ -167,50 +211,21 @@ if 'bdist_wheel' in sys.argv or 'build' in sys.argv:
167
211
  packages=find_namespace_packages(where="src"),
168
212
  include_package_data=True,
169
213
  package_data={
170
- "c2pa": ["libs/*"], # Include all files in libs directory
214
+ "c2pa": ["libs/*"],
171
215
  },
172
216
  classifiers=[
173
217
  "Programming Language :: Python :: 3",
174
- get_platform_classifier(get_current_platform()),
218
+ get_platform_classifier(target_platform),
175
219
  ],
176
220
  python_requires=">=3.10",
177
221
  long_description=open("README.md").read(),
178
222
  long_description_content_type="text/markdown",
179
223
  license="MIT OR Apache-2.0",
180
224
  )
181
- sys.exit(0)
182
-
183
- print(f"Found libraries for platforms: {', '.join(available_platforms)}")
184
-
185
- for platform_name in available_platforms:
186
- print(f"\nBuilding wheel for {platform_name}...")
187
- try:
188
- # Copy libraries for this platform (cleaning first)
189
- copy_platform_libraries(platform_name, clean_first=True)
190
-
191
- # Build the wheel
192
- setup(
193
- name=PACKAGE_NAME,
194
- version=VERSION,
195
- package_dir={"": "src"},
196
- packages=find_namespace_packages(where="src"),
197
- include_package_data=True,
198
- package_data={
199
- "c2pa": ["libs/*"], # Include all files in libs directory
200
- },
201
- classifiers=[
202
- "Programming Language :: Python :: 3",
203
- get_platform_classifier(platform_name),
204
- ],
205
- python_requires=">=3.10",
206
- long_description=open("README.md").read(),
207
- long_description_content_type="text/markdown",
208
- license="MIT OR Apache-2.0",
209
- )
210
- finally:
211
- # Clean up by removing the package libs directory
212
- if PACKAGE_LIBS_DIR.exists():
213
- shutil.rmtree(PACKAGE_LIBS_DIR)
225
+ finally:
226
+ # Clean up
227
+ if PACKAGE_LIBS_DIR.exists():
228
+ shutil.rmtree(PACKAGE_LIBS_DIR)
214
229
  sys.exit(0)
215
230
 
216
231
  # For sdist and development installation