libdatachannel-py 2025.1.0.dev13__tar.gz → 2025.1.0.dev15__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 (42) hide show
  1. {libdatachannel_py-2025.1.0.dev13/src/libdatachannel_py.egg-info → libdatachannel_py-2025.1.0.dev15}/PKG-INFO +1 -1
  2. libdatachannel_py-2025.1.0.dev15/VERSION +1 -0
  3. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/buildbase.py +54 -4
  4. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/pyproject.toml +7 -12
  5. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/run.py +64 -14
  6. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/libdatachannel_ext.cpython-313-darwin.so +0 -0
  7. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15/src/libdatachannel_py.egg-info}/PKG-INFO +1 -1
  8. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_websocket.py +4 -2
  9. libdatachannel_py-2025.1.0.dev13/VERSION +0 -1
  10. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/LICENSE +0 -0
  11. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/MANIFEST.in +0 -0
  12. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/README.md +0 -0
  13. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/pypath.py +0 -0
  14. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/setup.cfg +0 -0
  15. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/setup.py +0 -0
  16. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/__init__.py +0 -0
  17. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/codec/__init__.py +0 -0
  18. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/codec/__init__.pyi +0 -0
  19. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/libdatachannel_ext.pyi +0 -0
  20. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/libyuv/__init__.py +0 -0
  21. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/libyuv/__init__.pyi +0 -0
  22. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel/py.typed +0 -0
  23. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel_py.egg-info/SOURCES.txt +0 -0
  24. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel_py.egg-info/dependency_links.txt +0 -0
  25. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/src/libdatachannel_py.egg-info/top_level.txt +0 -0
  26. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_audio_codec.py +0 -0
  27. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_candidate.py +0 -0
  28. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_configuration.py +0 -0
  29. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_description.py +0 -0
  30. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_frameinfo.py +0 -0
  31. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_h265nalunit.py +0 -0
  32. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_libyuv.py +0 -0
  33. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_mediahandler.py +0 -0
  34. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_message.py +0 -0
  35. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_nalunit.py +0 -0
  36. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_packetizationconfig.py +0 -0
  37. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_peerconnection.py +0 -0
  38. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_prop_audio_codec.py +0 -0
  39. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_reliability.py +0 -0
  40. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_rtppacketizer.py +0 -0
  41. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_video_codec.py +0 -0
  42. {libdatachannel_py-2025.1.0.dev13 → libdatachannel_py-2025.1.0.dev15}/tests/test_websocketserver.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: libdatachannel-py
3
- Version: 2025.1.0.dev13
3
+ Version: 2025.1.0.dev15
4
4
  Summary: libdatachannel-py is a Python binding for libdatachannel.
5
5
  Home-page: https://github.com/shiguredo/libdatachannel-py
6
6
  License-Expression: Apache-2.0
@@ -0,0 +1 @@
1
+ 2025.1.0.dev15
@@ -29,6 +29,7 @@ import logging
29
29
  import multiprocessing
30
30
  import os
31
31
  import platform
32
+ import hashlib
32
33
  import shlex
33
34
  import shutil
34
35
  import stat
@@ -143,7 +144,12 @@ def add_path(path: str, is_after=False):
143
144
  os.environ["PATH"] = path + PATH_SEPARATOR + os.environ["PATH"]
144
145
 
145
146
 
146
- def download(url: str, output_dir: Optional[str] = None, filename: Optional[str] = None) -> str:
147
+ def download(
148
+ url: str,
149
+ output_dir: Optional[str] = None,
150
+ filename: Optional[str] = None,
151
+ expected_sha256: Optional[str] = None,
152
+ ) -> str:
147
153
  if filename is None:
148
154
  output_path = urllib.parse.urlparse(url).path.split("/")[-1]
149
155
  else:
@@ -153,22 +159,53 @@ def download(url: str, output_dir: Optional[str] = None, filename: Optional[str]
153
159
  output_path = os.path.join(output_dir, output_path)
154
160
 
155
161
  if os.path.exists(output_path):
156
- return output_path
162
+ if expected_sha256 is not None:
163
+ try:
164
+ verify_sha256(output_path, expected_sha256)
165
+ except ValueError:
166
+ logging.warning(f"Existing file has invalid hash, removing: {output_path}")
167
+ os.remove(output_path)
168
+ return download(url, output_dir, filename, expected_sha256)
169
+ else:
170
+ return output_path
157
171
 
158
172
  try:
173
+ logging.info(f"Downloading {url} to {output_path}")
159
174
  if shutil.which("curl") is not None:
160
175
  cmd(["curl", "-fLo", output_path, url])
161
176
  else:
162
177
  cmd(["wget", "-cO", output_path, url])
178
+
179
+ if expected_sha256 is not None:
180
+ verify_sha256(output_path, expected_sha256)
163
181
  except Exception:
164
182
  # ゴミを残さないようにする
165
183
  if os.path.exists(output_path):
184
+ logging.error(f"Removing incomplete/invalid file: {output_path}")
166
185
  os.remove(output_path)
167
186
  raise
168
187
 
169
188
  return output_path
170
189
 
171
190
 
191
+ def verify_sha256(file_path: str, expected_sha256: str):
192
+ logging.info(f"Verifying SHA256 hash for {file_path}")
193
+ sha256_hash = hashlib.sha256()
194
+ with open(file_path, "rb") as f:
195
+ for byte_block in iter(lambda: f.read(4096), b""):
196
+ sha256_hash.update(byte_block)
197
+ actual_sha256 = sha256_hash.hexdigest()
198
+ if actual_sha256 != expected_sha256.lower():
199
+ error_msg = (
200
+ f"SHA256 hash mismatch for {file_path}:\n"
201
+ f" Expected: {expected_sha256.lower()}\n"
202
+ f" Actual: {actual_sha256}"
203
+ )
204
+ logging.error(error_msg)
205
+ raise ValueError(error_msg)
206
+ logging.info(f"SHA256 hash verified successfully for {file_path}")
207
+
208
+
172
209
  def read_version_file(path: str) -> Dict[str, str]:
173
210
  versions = {}
174
211
 
@@ -1732,7 +1769,13 @@ def install_boringssl(
1732
1769
 
1733
1770
  @versioned
1734
1771
  def install_opus(
1735
- version, source_dir, build_dir, install_dir, configuration: str, cmake_args: List[str]
1772
+ version,
1773
+ source_dir,
1774
+ build_dir,
1775
+ install_dir,
1776
+ configuration: str,
1777
+ cmake_args: List[str],
1778
+ expected_sha256: Optional[str] = None,
1736
1779
  ):
1737
1780
  opus_source_dir = os.path.join(source_dir, "opus")
1738
1781
  opus_build_dir = os.path.join(build_dir, "opus")
@@ -1740,7 +1783,14 @@ def install_opus(
1740
1783
  rm_rf(opus_source_dir)
1741
1784
  rm_rf(opus_build_dir)
1742
1785
  rm_rf(opus_install_dir)
1743
- git_clone_shallow("https://gitlab.xiph.org/xiph/opus", version, opus_source_dir)
1786
+ # Git クローンではなく、配布アーカイブをダウンロードして展開する
1787
+ # 例: OPUS_VERSION=v1.5.2 -> https://oss-mirrors.shiguredo.jp/opus-1.5.2.tar.gz
1788
+ version_nov = version[1:] if version.startswith("v") else version
1789
+ archive_filename = f"opus-{version_nov}.tar.gz"
1790
+ # 公式サイトに負荷をかけないための時雨堂によるミラー
1791
+ url = f"https://oss-mirrors.shiguredo.jp/{archive_filename}"
1792
+ archive_path = download(url, source_dir, expected_sha256=expected_sha256)
1793
+ extract(archive_path, source_dir, "opus")
1744
1794
  mkdir_p(opus_build_dir)
1745
1795
  with cd(opus_build_dir):
1746
1796
  cmd(
@@ -22,17 +22,16 @@ build-backend = "setuptools.build_meta"
22
22
 
23
23
  [dependency-groups]
24
24
  dev = [
25
- "nanobind>=2.7",
26
- "pytest>=8",
25
+ "nanobind>=2.8",
26
+ "pytest",
27
27
  "setuptools>=80.9",
28
- "build>=1.2.2.post1",
28
+ "build>=1.3.0",
29
29
  "wheel>=0.45.1",
30
- "numpy>=2.2",
30
+ "numpy>=2.3",
31
31
  "ty",
32
- "hypothesis>=6.132.0",
33
- "mypy",
34
- "pyrefly",
35
- "pyright",
32
+ "hypothesis",
33
+ "aiohttp",
34
+ "pytest-aiohttp",
36
35
  ]
37
36
 
38
37
  [tool.uv.workspace]
@@ -41,7 +40,3 @@ members = ["examples"]
41
40
  [tool.ruff]
42
41
  target-version = "py313"
43
42
  line-length = 100
44
-
45
- [tool.pyrefly]
46
- project-includes = ["**/*"]
47
- project-excludes = ["**/*venv/**/*"]
@@ -1,8 +1,10 @@
1
1
  import argparse
2
+ import glob
2
3
  import multiprocessing
3
4
  import os
4
5
  import shutil
5
6
  import sys
7
+ from typing import Optional
6
8
 
7
9
  from buildbase import (
8
10
  Platform,
@@ -128,6 +130,7 @@ def install_deps(
128
130
  "install_dir": install_dir,
129
131
  "configuration": "Debug" if debug else "Release",
130
132
  "cmake_args": macos_cmake_args,
133
+ "expected_sha256": version.get("OPUS_SHA256_HASH"),
131
134
  }
132
135
  install_opus(**install_opus_args)
133
136
 
@@ -179,29 +182,52 @@ AVAILABLE_TARGETS = [
179
182
  ]
180
183
 
181
184
 
182
- def main():
183
- parser = argparse.ArgumentParser()
184
- parser.add_argument("--debug", action="store_true")
185
- parser.add_argument("--relwithdebinfo", action="store_true")
186
- parser.add_argument("target", choices=AVAILABLE_TARGETS)
185
+ def _find_clang_binary(name: str) -> Optional[str]:
186
+ if shutil.which(name) is not None:
187
+ return name
188
+ else:
189
+ for n in range(50, 14, -1):
190
+ if shutil.which(f"{name}-{n}") is not None:
191
+ return f"{name}-{n}"
192
+ return None
187
193
 
188
- args = parser.parse_args()
189
- if args.target == "windows_x86_64":
194
+
195
+ def _format(
196
+ clang_format_path: Optional[str] = None,
197
+ ):
198
+ if clang_format_path is None:
199
+ clang_format_path = _find_clang_binary("clang-format")
200
+ if clang_format_path is None:
201
+ raise Exception("clang-format not found. Please install it or specify the path.")
202
+ patterns = [
203
+ "src/**/*.cpp",
204
+ "src/**/*.h",
205
+ ]
206
+ target_files = []
207
+ for pattern in patterns:
208
+ files = glob.glob(pattern, recursive=True)
209
+ target_files.extend(files)
210
+ cmd([clang_format_path, "-i"] + target_files)
211
+
212
+
213
+ def _build(args):
214
+ target = args.target
215
+ if target == "windows_x86_64":
190
216
  platform = Platform("windows", get_windows_osver(), "x86_64")
191
- elif args.target == "macos_x86_64":
217
+ elif target == "macos_x86_64":
192
218
  platform = Platform("macos", get_macos_osver(), "x86_64")
193
- elif args.target == "macos_arm64":
219
+ elif target == "macos_arm64":
194
220
  platform = Platform("macos", get_macos_osver(), "arm64")
195
- elif args.target == "ubuntu-22.04_x86_64":
221
+ elif target == "ubuntu-22.04_x86_64":
196
222
  platform = Platform("ubuntu", "22.04", "x86_64")
197
- elif args.target == "ubuntu-24.04_x86_64":
223
+ elif target == "ubuntu-24.04_x86_64":
198
224
  platform = Platform("ubuntu", "24.04", "x86_64")
199
- elif args.target == "ubuntu-24.04_armv8":
225
+ elif target == "ubuntu-24.04_armv8":
200
226
  platform = Platform("ubuntu", "24.04", "armv8")
201
- elif args.target == "ubuntu-22.04_armv8_jetson":
227
+ elif target == "ubuntu-22.04_armv8_jetson":
202
228
  platform = Platform("jetson", None, "armv8", "ubuntu-22.04")
203
229
  else:
204
- raise Exception(f"Unknown target {args.target}")
230
+ raise Exception(f"Unknown target {target}")
205
231
 
206
232
  source_dir = os.path.join(BASE_DIR, "_source", platform.target.package_name)
207
233
  build_dir = os.path.join(BASE_DIR, "_build", platform.target.package_name)
@@ -341,5 +367,29 @@ def main():
341
367
  )
342
368
 
343
369
 
370
+ def main():
371
+ parser = argparse.ArgumentParser()
372
+ sp = parser.add_subparsers(dest="command")
373
+
374
+ # build コマンド
375
+ bp = sp.add_parser("build")
376
+ bp.add_argument("target", choices=AVAILABLE_TARGETS)
377
+ bp.add_argument("--debug", action="store_true")
378
+ bp.add_argument("--relwithdebinfo", action="store_true")
379
+
380
+ # format コマンド
381
+ fp = sp.add_parser("format")
382
+ fp.add_argument("--clang-format-path", type=str, default=None)
383
+
384
+ args = parser.parse_args()
385
+
386
+ if args.command == "build":
387
+ _build(args)
388
+ elif args.command == "format":
389
+ _format(clang_format_path=args.clang_format_path)
390
+ else:
391
+ parser.print_help()
392
+
393
+
344
394
  if __name__ == "__main__":
345
395
  main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: libdatachannel-py
3
- Version: 2025.1.0.dev13
3
+ Version: 2025.1.0.dev15
4
4
  Summary: libdatachannel-py is a Python binding for libdatachannel.
5
5
  Home-page: https://github.com/shiguredo/libdatachannel-py
6
6
  License-Expression: Apache-2.0
@@ -1,11 +1,13 @@
1
1
  import time
2
2
 
3
+ import pytest
4
+
3
5
  from libdatachannel import WebSocket, WebSocketConfiguration
4
6
 
5
7
 
6
8
  # https://github.com/paullouisageneau/libdatachannel/blob/0e40aeb058b947014a918a448ce2d346e6ab14fe/test/websocket.cpp
7
9
  # を Python に直したもの
8
- def test_websocket():
10
+ def test_websocket(echo_websocket_server):
9
11
  my_message = "Hello world from libdatachannel"
10
12
  config = WebSocketConfiguration()
11
13
  config.disable_tls_verification = True
@@ -37,7 +39,7 @@ def test_websocket():
37
39
  ws.on_closed(ws_on_closed)
38
40
  ws.on_message(ws_on_message)
39
41
 
40
- ws.open("wss://echo.websocket.org:443/")
42
+ ws.open(echo_websocket_server)
41
43
 
42
44
  attempts = 20
43
45
  while (not ws.is_open() or not received) and attempts > 0:
@@ -1 +0,0 @@
1
- 2025.1.0.dev13