python-mscl 67.0.0__tar.gz → 67.1.0.1__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.
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/.github/workflows/build_wheels.yml +14 -13
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/.gitignore +4 -2
- python_mscl-67.1.0.1/.python-version +1 -0
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/PKG-INFO +20 -18
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/README.md +16 -13
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/build_helpers/release_downloader.py +20 -16
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/build_helpers/release_extractor.py +21 -8
- python_mscl-67.1.0.1/constants.py +38 -0
- python_mscl-67.1.0.1/download_and_extract_assets.py +41 -0
- python_mscl-67.1.0.1/hatch_build.py +112 -0
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/pyproject.toml +17 -14
- python_mscl-67.1.0.1/run_build.py +57 -0
- python_mscl-67.1.0.1/src/python_mscl/__init__.py +13 -0
- python_mscl-67.0.0/.python-version +0 -1
- python_mscl-67.0.0/hatch_build.py +0 -116
- python_mscl-67.0.0/src/python_mscl/__init__.py +0 -5
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/LICENSE +0 -0
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/build_helpers/__init__.py +0 -0
- {python_mscl-67.0.0 → python_mscl-67.1.0.1}/src/python_mscl/py.typed +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Download, extract, build, and test wheels
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
pull_request:
|
|
@@ -10,19 +10,14 @@ on:
|
|
|
10
10
|
|
|
11
11
|
jobs:
|
|
12
12
|
build-wheels:
|
|
13
|
-
name:
|
|
13
|
+
name: Download, extract, build, and wheels
|
|
14
14
|
runs-on: ${{ matrix.os }}
|
|
15
15
|
timeout-minutes: 5
|
|
16
16
|
strategy:
|
|
17
17
|
fail-fast: false
|
|
18
18
|
matrix:
|
|
19
|
-
os: [ubuntu-latest, windows-latest]
|
|
20
|
-
python-version: [3.
|
|
21
|
-
exclude:
|
|
22
|
-
- os: windows-latest
|
|
23
|
-
python-version: 3.9
|
|
24
|
-
- os: windows-latest
|
|
25
|
-
python-version: 3.13
|
|
19
|
+
os: [ubuntu-latest, windows-latest, ubuntu-24.04-arm]
|
|
20
|
+
python-version: [3.13]
|
|
26
21
|
|
|
27
22
|
steps:
|
|
28
23
|
- uses: actions/checkout@v4
|
|
@@ -39,15 +34,21 @@ jobs:
|
|
|
39
34
|
|
|
40
35
|
- name: Install the project
|
|
41
36
|
run: uv sync
|
|
37
|
+
|
|
38
|
+
- name: Download and extract the mscl assets
|
|
39
|
+
run: |
|
|
40
|
+
uv run download_and_extract_assets.py
|
|
42
41
|
|
|
43
|
-
- name: Build the
|
|
44
|
-
run:
|
|
42
|
+
- name: Build the wheels
|
|
43
|
+
run: |
|
|
44
|
+
uv run run_build.py
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
# There should be only one wheel so it should work:
|
|
47
|
+
- name: Initialize test environment and install wheel
|
|
47
48
|
run: |
|
|
48
49
|
uv init --no-workspace test
|
|
49
50
|
cd test
|
|
50
|
-
uv add ../dist/*.whl
|
|
51
|
+
uv add "$(python -c 'import glob; print(glob.glob("../dist/*.whl")[0])')"
|
|
51
52
|
|
|
52
53
|
- name: Verify installation
|
|
53
54
|
run: uv run -- python -c "from python_mscl import mscl"
|
|
@@ -15,10 +15,12 @@ wheels/
|
|
|
15
15
|
# Exclude local .deb and .zip files from mscl:
|
|
16
16
|
mscl_release_assets/*.zip
|
|
17
17
|
mscl_release_assets/*.deb
|
|
18
|
+
mscl_release_assets/
|
|
18
19
|
|
|
19
20
|
# VSCode:
|
|
20
21
|
.vscode/
|
|
21
22
|
|
|
22
23
|
# Exclude build downloaded mscl files:
|
|
23
|
-
src/
|
|
24
|
-
src/
|
|
24
|
+
src/python_mscl/mscl.py
|
|
25
|
+
src/python_mscl/_mscl.so
|
|
26
|
+
src/python_mscl/_mscl.pyd
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14+gil
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: python-mscl
|
|
3
|
-
Version: 67.0.
|
|
3
|
+
Version: 67.1.0.1
|
|
4
4
|
Summary: Easy to install python wrapper for the MSCL library.
|
|
5
5
|
Author-email: Harshil <37377066+harshil21@users.noreply.github.com>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -8,23 +8,25 @@ Classifier: Development Status :: 4 - Beta
|
|
|
8
8
|
Classifier: Intended Audience :: Developers
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
13
|
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
15
|
Classifier: Topic :: Scientific/Engineering
|
|
17
|
-
Requires-Python: >=3.
|
|
16
|
+
Requires-Python: >=3.11
|
|
18
17
|
Description-Content-Type: text/markdown
|
|
19
18
|
|
|
20
19
|
# python-mscl
|
|
21
20
|
|
|
21
|
+
# ARCHIVED: There is now an official mscl library: [`pymscl`](https://pypi.org/project/pymscl). Please use that library instead.
|
|
22
|
+
|
|
23
|
+
[](https://pepy.tech/projects/python-mscl)
|
|
24
|
+
|
|
22
25
|
Unofficial Python package for the [Microstrain Communication Library](https://github.com/LORD-MicroStrain/MSCL/tree/master).
|
|
23
26
|
|
|
24
|
-
This library just makes it so that we can install the MSCL library using pip
|
|
25
|
-
version, and then build the wheel for you.
|
|
27
|
+
This library just makes it so that we can install the MSCL library using pip, and directly provides the wheels!
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
Only Python 3.x wheels are provided. If you need Python 2.x wheels, please open an issue.
|
|
28
30
|
|
|
29
31
|
### Installation
|
|
30
32
|
|
|
@@ -40,11 +42,6 @@ from python_mscl import mscl
|
|
|
40
42
|
# ... use the MSCL library as you normally would
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
### Windows support:
|
|
44
|
-
|
|
45
|
-
The latest mscl version (v67.0.0) only has a .zip for python 3.11. It has been confirmed that it does not work on other python versions (You would get an import error). However the build itself would still go through.
|
|
46
|
-
|
|
47
|
-
|
|
48
45
|
### Versioning system:
|
|
49
46
|
|
|
50
47
|
This repository follows the same versioning system as the MSCL library. This is reflected in the tags of this repository.
|
|
@@ -63,13 +60,18 @@ The below steps assume you have [`uv`](https://docs.astral.sh/uv/) installed.
|
|
|
63
60
|
|
|
64
61
|
1. Clone the repo and `cd` into it.
|
|
65
62
|
2. Optional: Create a .env file and insert your GITHUB_TOKEN= to make requests to the GitHub API.
|
|
66
|
-
3. Edit & run `uv run
|
|
67
|
-
4. Run `uv
|
|
68
|
-
version and architecture.
|
|
63
|
+
3. Edit & run `uv run download_and_extract_assets.py` to fetch the latest tagged MSCL releases and extract them.
|
|
64
|
+
4. Run `uv run run_build.py`, which will build the source distribution and wheel for your python
|
|
65
|
+
version and architecture. The wheels will be placed in the `dist/` directory.
|
|
69
66
|
|
|
70
67
|
Notes for me, the maintainer:
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
|
|
69
|
+
5. Make sure that the constants in `constants.py` are updated, and that the MSCL repo still follows their
|
|
70
|
+
versioning system. If not, update rest of the files accordingly.
|
|
71
|
+
|
|
72
|
+
6. Optional: Run `uv publish` to publish the package to PyPI. To upload to TestPyPI, uncomment lines in `pyproject.toml`, and run `uv publish --index testpypi dist/*.whl`.
|
|
73
|
+
|
|
74
|
+
7. Optional: To check if the package worked correctly: `uv add --index https://test.pypi.org/simple/ --index-strategy unsafe-best-match python-mscl` in a new uv project directory.
|
|
73
75
|
|
|
74
76
|
|
|
75
77
|
## Issues:
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# python-mscl
|
|
2
2
|
|
|
3
|
+
# ARCHIVED: There is now an official mscl library: [`pymscl`](https://pypi.org/project/pymscl). Please use that library instead.
|
|
4
|
+
|
|
5
|
+
[](https://pepy.tech/projects/python-mscl)
|
|
6
|
+
|
|
3
7
|
Unofficial Python package for the [Microstrain Communication Library](https://github.com/LORD-MicroStrain/MSCL/tree/master).
|
|
4
8
|
|
|
5
|
-
This library just makes it so that we can install the MSCL library using pip
|
|
6
|
-
version, and then build the wheel for you.
|
|
9
|
+
This library just makes it so that we can install the MSCL library using pip, and directly provides the wheels!
|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
Only Python 3.x wheels are provided. If you need Python 2.x wheels, please open an issue.
|
|
9
12
|
|
|
10
13
|
### Installation
|
|
11
14
|
|
|
@@ -21,11 +24,6 @@ from python_mscl import mscl
|
|
|
21
24
|
# ... use the MSCL library as you normally would
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
### Windows support:
|
|
25
|
-
|
|
26
|
-
The latest mscl version (v67.0.0) only has a .zip for python 3.11. It has been confirmed that it does not work on other python versions (You would get an import error). However the build itself would still go through.
|
|
27
|
-
|
|
28
|
-
|
|
29
27
|
### Versioning system:
|
|
30
28
|
|
|
31
29
|
This repository follows the same versioning system as the MSCL library. This is reflected in the tags of this repository.
|
|
@@ -44,13 +42,18 @@ The below steps assume you have [`uv`](https://docs.astral.sh/uv/) installed.
|
|
|
44
42
|
|
|
45
43
|
1. Clone the repo and `cd` into it.
|
|
46
44
|
2. Optional: Create a .env file and insert your GITHUB_TOKEN= to make requests to the GitHub API.
|
|
47
|
-
3. Edit & run `uv run
|
|
48
|
-
4. Run `uv
|
|
49
|
-
version and architecture.
|
|
45
|
+
3. Edit & run `uv run download_and_extract_assets.py` to fetch the latest tagged MSCL releases and extract them.
|
|
46
|
+
4. Run `uv run run_build.py`, which will build the source distribution and wheel for your python
|
|
47
|
+
version and architecture. The wheels will be placed in the `dist/` directory.
|
|
50
48
|
|
|
51
49
|
Notes for me, the maintainer:
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
|
|
51
|
+
5. Make sure that the constants in `constants.py` are updated, and that the MSCL repo still follows their
|
|
52
|
+
versioning system. If not, update rest of the files accordingly.
|
|
53
|
+
|
|
54
|
+
6. Optional: Run `uv publish` to publish the package to PyPI. To upload to TestPyPI, uncomment lines in `pyproject.toml`, and run `uv publish --index testpypi dist/*.whl`.
|
|
55
|
+
|
|
56
|
+
7. Optional: To check if the package worked correctly: `uv add --index https://test.pypi.org/simple/ --index-strategy unsafe-best-match python-mscl` in a new uv project directory.
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
## Issues:
|
|
@@ -8,6 +8,8 @@ from github import Github
|
|
|
8
8
|
from github.GitRelease import GitRelease
|
|
9
9
|
from github.GitReleaseAsset import GitReleaseAsset
|
|
10
10
|
|
|
11
|
+
from constants import ASSET_DIRECTORY, ReleaseAsset
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
class GithubDownloader:
|
|
13
15
|
"""Manages downloading the Github release assets for the mscl library, along with the
|
|
@@ -18,6 +20,7 @@ class GithubDownloader:
|
|
|
18
20
|
self.mscl_repo = "LORD-MicroStrain/MSCL"
|
|
19
21
|
self.python_mscl_repo = "harshil21/python-mscl"
|
|
20
22
|
self.latest_release = None
|
|
23
|
+
self.asset_dir = Path(ASSET_DIRECTORY)
|
|
21
24
|
|
|
22
25
|
def get_latest_release(self) -> GitRelease:
|
|
23
26
|
"""Returns the latest stable release for the given repo."""
|
|
@@ -33,13 +36,19 @@ class GithubDownloader:
|
|
|
33
36
|
break
|
|
34
37
|
return self.latest_release
|
|
35
38
|
|
|
36
|
-
def download_release_assets(self,
|
|
37
|
-
"""Downloads the release assets
|
|
39
|
+
def download_release_assets(self, only_release: ReleaseAsset | None = None) -> None:
|
|
40
|
+
"""Downloads the release assets from the MSCL repository.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
only_release: If set, only download the release asset for the given Python version and
|
|
44
|
+
architecture. If not set, download all the release assets.
|
|
45
|
+
"""
|
|
38
46
|
release = self.get_latest_release()
|
|
39
|
-
output_path = Path(
|
|
47
|
+
output_path = Path(self.asset_dir)
|
|
40
48
|
output_path.mkdir(parents=True, exist_ok=True)
|
|
41
49
|
|
|
42
50
|
asset: GitReleaseAsset
|
|
51
|
+
print(f"Downloading release assets for {only_release=}")
|
|
43
52
|
for asset in release.get_assets():
|
|
44
53
|
# Don't download the "Documentation" or "Examples"
|
|
45
54
|
if "Documentation" in asset.name or "Examples" in asset.name:
|
|
@@ -51,22 +60,17 @@ class GithubDownloader:
|
|
|
51
60
|
if "3" not in asset.name:
|
|
52
61
|
continue
|
|
53
62
|
|
|
63
|
+
# Extract the python version, arch, and platform from the only_release, if set:
|
|
64
|
+
if only_release:
|
|
65
|
+
if only_release.python_version not in asset.name:
|
|
66
|
+
continue
|
|
67
|
+
if only_release.arch not in asset.name:
|
|
68
|
+
continue
|
|
69
|
+
|
|
54
70
|
self.download_asset(output_path, asset)
|
|
71
|
+
print(f"Downloaded {asset.name}")
|
|
55
72
|
|
|
56
73
|
def download_asset(self, output_path: Path, asset: GitReleaseAsset) -> None:
|
|
57
74
|
response = requests.get(asset.browser_download_url, timeout=15)
|
|
58
75
|
asset_path = output_path / asset.name
|
|
59
76
|
asset_path.write_bytes(response.content)
|
|
60
|
-
|
|
61
|
-
def download_assets_from_folder(self, tag: str, folder_name: str) -> None:
|
|
62
|
-
"""Downloads all the files under the `folder_name` for the given tag, from the
|
|
63
|
-
root of the repository."""
|
|
64
|
-
|
|
65
|
-
repo = self.github.get_repo(self.python_mscl_repo)
|
|
66
|
-
contents = repo.get_contents(folder_name, ref=tag)
|
|
67
|
-
|
|
68
|
-
for content in contents:
|
|
69
|
-
if content.type == "file":
|
|
70
|
-
response = requests.get(content.download_url, timeout=15)
|
|
71
|
-
file_path = Path(content.name)
|
|
72
|
-
file_path.write_bytes(response.content)
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
"""Extracts the .deb and .zip releases for the mscl library."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import shutil
|
|
4
5
|
import subprocess
|
|
5
6
|
from pathlib import Path
|
|
7
|
+
from zipfile import ZipFile
|
|
8
|
+
|
|
9
|
+
from constants import ASSET_DIRECTORY, MSCL_VERSION
|
|
6
10
|
|
|
7
|
-
MSCL_VERSION = "v67.0.0"
|
|
8
|
-
"""The mscl version to extract."""
|
|
9
11
|
|
|
10
12
|
class ReleaseExtractor:
|
|
11
13
|
"""Will extract the .deb and .zip releases for the mscl library."""
|
|
12
14
|
|
|
13
15
|
def __init__(self):
|
|
14
|
-
self.asset_dir = Path(
|
|
16
|
+
self.asset_dir = Path(ASSET_DIRECTORY)
|
|
15
17
|
|
|
16
18
|
def extract_assets(self):
|
|
17
19
|
"""Extracts the .deb and .zip releases into the same directory."""
|
|
@@ -77,18 +79,19 @@ class ReleaseExtractor:
|
|
|
77
79
|
# Create a directory to extract the .zip file. Syntax: mscl-<arch>-<python-ver>-<mscl-ver>
|
|
78
80
|
parts = file.stem.split("_")
|
|
79
81
|
arch, py_ver = parts[2], parts[3]
|
|
80
|
-
mscl_versioned_name = f"mscl-
|
|
82
|
+
mscl_versioned_name = f"mscl-Windows_{arch}-{py_ver}-{MSCL_VERSION}"
|
|
81
83
|
mscl_versioned_dir = cwd / self.asset_dir / mscl_versioned_name
|
|
82
84
|
|
|
83
85
|
# If output directory exists, remove it:
|
|
84
86
|
if mscl_versioned_dir.exists():
|
|
85
|
-
|
|
87
|
+
shutil.rmtree(mscl_versioned_dir)
|
|
86
88
|
|
|
87
89
|
mscl_versioned_dir.mkdir(parents=True, exist_ok=True)
|
|
88
|
-
file_relative = file.absolute().relative_to(mscl_versioned_dir, walk_up=True)
|
|
89
90
|
|
|
90
91
|
# Extract the .zip file
|
|
91
|
-
|
|
92
|
+
with ZipFile(file, "r") as zip_ref:
|
|
93
|
+
zip_ref.extractall(mscl_versioned_dir)
|
|
94
|
+
print("Extracted the zip file.")
|
|
92
95
|
|
|
93
96
|
found_mscl_py = list(mscl_versioned_dir.rglob("mscl.py"))
|
|
94
97
|
found_mscl_pyd = list(mscl_versioned_dir.rglob("_mscl.pyd"))
|
|
@@ -106,8 +109,18 @@ class ReleaseExtractor:
|
|
|
106
109
|
# Delete the remaining files in mscl_versioned_dir:
|
|
107
110
|
for f in mscl_versioned_dir.iterdir():
|
|
108
111
|
if f.stem in (mscl_py.stem, mscl_pyd.stem):
|
|
112
|
+
print(f"Skipping deletion of {f}")
|
|
109
113
|
continue
|
|
110
114
|
if f.is_dir():
|
|
111
|
-
|
|
115
|
+
print(f"Deleting the directory {f}")
|
|
116
|
+
shutil.rmtree(f)
|
|
112
117
|
else:
|
|
118
|
+
print(f"Deleting {f}")
|
|
113
119
|
f.unlink()
|
|
120
|
+
|
|
121
|
+
# Confirm that the files still exist after deleting the rest:
|
|
122
|
+
found_mscl_py = list(mscl_versioned_dir.rglob("mscl.py"))
|
|
123
|
+
found_mscl_pyd = list(mscl_versioned_dir.rglob("_mscl.pyd"))
|
|
124
|
+
|
|
125
|
+
if not found_mscl_py or not found_mscl_pyd:
|
|
126
|
+
raise FileNotFoundError(f"Deleted mscl.py or _mscl.pyd in {mscl_versioned_dir}!")
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""File to store common constants used in the project."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import NamedTuple
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Named tuple to store the release asset information:
|
|
8
|
+
class ReleaseAsset(NamedTuple):
|
|
9
|
+
"""Named tuple to store the release asset information.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
python_version: The Python version of the release asset. E.g. "Python3.9".
|
|
13
|
+
arch: The architecture of the release asset. E.g. "amd64".
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
python_version: str
|
|
17
|
+
arch: str
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ASSET_DIRECTORY = Path("mscl_release_assets")
|
|
21
|
+
"""The directory to store the downloaded release assets."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Keep this the same as the one in `hatch_build.py`!
|
|
25
|
+
MSCL_VERSION = "v67.1.0"
|
|
26
|
+
"""The mscl version to extract from the `ASSET_DIRECTORY`. The
|
|
27
|
+
downloader will download the latest version despite this version number."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
MACHINE_MAPPING_TO_ARCH = {
|
|
31
|
+
# Linux:
|
|
32
|
+
"x86_64": "amd64",
|
|
33
|
+
"aarch64": "arm64",
|
|
34
|
+
"armv7l": "armhf",
|
|
35
|
+
# Windows:
|
|
36
|
+
"AMD64": "Windows_x64",
|
|
37
|
+
"x86": "Windows_x86",
|
|
38
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Entry point for downloading and extracting mscl release assets."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import platform
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
from build_helpers.release_downloader import GithubDownloader, ReleaseAsset
|
|
8
|
+
from build_helpers.release_extractor import ReleaseExtractor
|
|
9
|
+
from constants import MACHINE_MAPPING_TO_ARCH
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(github_actions: bool = False) -> None:
|
|
13
|
+
"""Entry point to fetch the latest release assets from the Github repository & extract them.
|
|
14
|
+
|
|
15
|
+
:param github_actions: If the script is running in a Github Actions environment. If true,
|
|
16
|
+
the script will download and extract the release asset of only the python version and
|
|
17
|
+
architecture and OS type detected.
|
|
18
|
+
"""
|
|
19
|
+
gh = GithubDownloader()
|
|
20
|
+
if github_actions:
|
|
21
|
+
print(f"Downloading on {sys.version_info=}, {platform.machine()=}")
|
|
22
|
+
gh.download_release_assets(
|
|
23
|
+
ReleaseAsset(
|
|
24
|
+
python_version=f"Python{sys.version_info.major}.{sys.version_info.minor}",
|
|
25
|
+
arch=MACHINE_MAPPING_TO_ARCH.get(platform.machine()),
|
|
26
|
+
)
|
|
27
|
+
)
|
|
28
|
+
else:
|
|
29
|
+
gh.download_release_assets()
|
|
30
|
+
|
|
31
|
+
re = ReleaseExtractor()
|
|
32
|
+
re.extract_assets()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == "__main__":
|
|
36
|
+
if os.getenv("GITHUB_ACTIONS", "false") == "true":
|
|
37
|
+
print("Running in Github Actions environment.")
|
|
38
|
+
main(github_actions=True)
|
|
39
|
+
else:
|
|
40
|
+
print("Running locally")
|
|
41
|
+
main()
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Specifies a hatch build hook to create the wheel for mscl."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import ClassVar
|
|
7
|
+
|
|
8
|
+
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
9
|
+
|
|
10
|
+
# This is specified here instead of in the constants since we get import errors:
|
|
11
|
+
MSCL_VERSION = "v67.1.0"
|
|
12
|
+
"""The mscl version to build the wheels from."""
|
|
13
|
+
|
|
14
|
+
BUILD_ARCH = os.getenv("BUILD_ARCH", "false")
|
|
15
|
+
"""The build architecture to use for the wheels. This determines the tag for the wheel.
|
|
16
|
+
|
|
17
|
+
This will be the arch in folder name (e.g., amd64, arm64, armhf, Windows-x64, Windows-x86).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
PYTHON_BUILD_VERSION = os.getenv("PYTHON_BUILD_VERSION", "false")
|
|
21
|
+
"""The Python build version to use for the wheels. This determines the tag for the wheel.
|
|
22
|
+
|
|
23
|
+
This will be the python version in folder name (e.g., Python3.9, Python3.11, etc).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class CustomBuildHook(BuildHookInterface):
|
|
28
|
+
"""Build hook to build wheels from the extracted .deb/.zip files."""
|
|
29
|
+
|
|
30
|
+
PYTHON_VER_MAPPING: ClassVar[dict[str, str]] = {
|
|
31
|
+
"Python3.9": "cp39",
|
|
32
|
+
"Python3.10": "cp310",
|
|
33
|
+
"Python3.11": "cp311",
|
|
34
|
+
"Python3.12": "cp312",
|
|
35
|
+
"Python3.13": "cp313",
|
|
36
|
+
}
|
|
37
|
+
"""The mapping of Python versions of the folder to the Python tags for the wheel."""
|
|
38
|
+
|
|
39
|
+
PYTHON_BUILD_MAPPING: ClassVar[dict[str, str]] = {
|
|
40
|
+
"amd64": "manylinux2014_x86_64",
|
|
41
|
+
"arm64": "manylinux2014_aarch64",
|
|
42
|
+
"armhf": "manylinux2014_armv7l",
|
|
43
|
+
"Windows_x64": "win_amd64",
|
|
44
|
+
"Windows_x86": "win32",
|
|
45
|
+
}
|
|
46
|
+
"""The mapping of architectures (in the folder name) to the platform tags for the wheel."""
|
|
47
|
+
|
|
48
|
+
def _python_tag(self) -> str | None:
|
|
49
|
+
"""Generate the Python tag (e.g., py39 for Python 3.9)."""
|
|
50
|
+
try:
|
|
51
|
+
return self.PYTHON_VER_MAPPING.get(PYTHON_BUILD_VERSION)
|
|
52
|
+
except KeyError as e:
|
|
53
|
+
raise RuntimeError(f"Unknown Python version: {PYTHON_BUILD_VERSION}") from e
|
|
54
|
+
|
|
55
|
+
def _platform_tag(self) -> str | None:
|
|
56
|
+
"""Generate the platform tag (e.g., linux_x86_64)."""
|
|
57
|
+
try:
|
|
58
|
+
return self.PYTHON_BUILD_MAPPING.get(BUILD_ARCH)
|
|
59
|
+
except KeyError as e:
|
|
60
|
+
raise RuntimeError(f"Unknown platform: {BUILD_ARCH}") from e
|
|
61
|
+
|
|
62
|
+
def _make_tag(self) -> str:
|
|
63
|
+
"""Generate the tag for the wheel (e.g., py39-linux_x86_64)."""
|
|
64
|
+
return f"{self._python_tag()}-{self._python_tag()}-{self._platform_tag()}"
|
|
65
|
+
|
|
66
|
+
def initialize(self, version, build_data):
|
|
67
|
+
"""
|
|
68
|
+
Called before building the wheel/sdist.
|
|
69
|
+
We can download & extract the .deb here, and place
|
|
70
|
+
mscl.py and _mscl.so into src/mscl_pip/.
|
|
71
|
+
"""
|
|
72
|
+
# Don't run build hook when a user is installing the wheel:
|
|
73
|
+
if PYTHON_BUILD_VERSION == "false" and BUILD_ARCH == "false":
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
build_data["pure_python"] = False
|
|
77
|
+
self.app.display_info(
|
|
78
|
+
f"Running on {version=} on {build_data=}, with "
|
|
79
|
+
f"{PYTHON_BUILD_VERSION=} and {BUILD_ARCH=}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# --- STEP 1: Determine which python version and arch we are on: ---
|
|
83
|
+
# Build the folder name based on the python version and arch in the environment variables.
|
|
84
|
+
|
|
85
|
+
folder_name = f"mscl-{BUILD_ARCH}-{PYTHON_BUILD_VERSION}-{MSCL_VERSION}"
|
|
86
|
+
|
|
87
|
+
build_data["tag"] = self._make_tag()
|
|
88
|
+
|
|
89
|
+
# --- STEP 3: Copy the files ("_mscl.so" & "mscl.py") to the src/mscl/ directory: ---
|
|
90
|
+
# Move from root (i.e. cwd) to src/mscl
|
|
91
|
+
|
|
92
|
+
self.remove_existing_files(Path("src/python_mscl/"), ["_mscl.so", "_mscl.pyd", "mscl.py"])
|
|
93
|
+
|
|
94
|
+
# Copy files from mscl_release_assets/folder_name to src/mscl/:
|
|
95
|
+
p = (Path("mscl_release_assets") / folder_name).absolute()
|
|
96
|
+
|
|
97
|
+
shutil.copy(p / "mscl.py", "src/python_mscl/")
|
|
98
|
+
if BUILD_ARCH.startswith("Windows"): # Windows uses _mscl.pyd
|
|
99
|
+
shutil.copy(p / "_mscl.pyd", "src/python_mscl/")
|
|
100
|
+
build_data["artifacts"] = ["_mscl.pyd", "mscl.py"]
|
|
101
|
+
else:
|
|
102
|
+
shutil.copy(p / "_mscl.so", "src/python_mscl/")
|
|
103
|
+
build_data["artifacts"] = ["_mscl.so", "mscl.py"]
|
|
104
|
+
|
|
105
|
+
self.app.display_success("Moved files to src/python_mscl/ successfully. Building wheel...")
|
|
106
|
+
|
|
107
|
+
def remove_existing_files(self, directory: Path, files: list[str]) -> None:
|
|
108
|
+
"""Remove the existing files from the directory."""
|
|
109
|
+
for file in files:
|
|
110
|
+
file_path = directory / file
|
|
111
|
+
if file_path.exists():
|
|
112
|
+
file_path.unlink()
|
|
@@ -1,42 +1,45 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "python-mscl"
|
|
3
|
-
version = "67.0.
|
|
3
|
+
version = "67.1.0.1"
|
|
4
4
|
description = "Easy to install python wrapper for the MSCL library."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
7
7
|
{ name = "Harshil", email = "37377066+harshil21@users.noreply.github.com" }
|
|
8
8
|
]
|
|
9
|
-
requires-python = ">=3.
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
10
|
classifiers = [
|
|
11
11
|
"Development Status :: 4 - Beta",
|
|
12
12
|
"Intended Audience :: Developers",
|
|
13
13
|
"License :: OSI Approved :: MIT License",
|
|
14
14
|
"Programming Language :: Python :: 3",
|
|
15
|
-
"Programming Language :: Python :: 3.9",
|
|
16
|
-
"Programming Language :: Python :: 3.10",
|
|
17
15
|
"Programming Language :: Python :: 3.11",
|
|
18
16
|
"Programming Language :: Python :: 3.12",
|
|
19
17
|
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Programming Language :: Python :: 3.14",
|
|
20
19
|
"Topic :: Scientific/Engineering",
|
|
21
20
|
"Intended Audience :: Developers",
|
|
22
21
|
]
|
|
23
22
|
dependencies = []
|
|
24
23
|
|
|
25
24
|
[dependency-groups]
|
|
26
|
-
dev = [
|
|
25
|
+
dev = [
|
|
26
|
+
"ruff",
|
|
27
|
+
"hatchling",
|
|
28
|
+
"pygithub>=2.5.0",
|
|
29
|
+
]
|
|
27
30
|
|
|
28
|
-
[tool.hatch.build.targets.wheel]
|
|
29
|
-
packages = ["src/python_mscl"]
|
|
31
|
+
# [tool.hatch.build.targets.wheel]
|
|
32
|
+
# packages = ["src/python_mscl"]
|
|
30
33
|
|
|
31
|
-
[tool.hatch.build.hooks.custom]
|
|
32
|
-
path = "hatch_build.py"
|
|
34
|
+
# [tool.hatch.build.hooks.custom]
|
|
35
|
+
# path = "hatch_build.py"
|
|
33
36
|
|
|
34
37
|
[tool.hatch.build.targets.sdist]
|
|
35
38
|
exclude = ["mscl_release_assets/", "uv.lock", "main.py", "src/python_mscl/_mscl.so",
|
|
36
|
-
"src/python_mscl/mscl.py"]
|
|
39
|
+
"src/python_mscl/mscl.py", "src/python_mscl/mscl.pyd"]
|
|
37
40
|
|
|
38
41
|
[build-system]
|
|
39
|
-
requires = ["hatchling"
|
|
42
|
+
requires = ["hatchling"]
|
|
40
43
|
build-backend = "hatchling.build"
|
|
41
44
|
|
|
42
45
|
# [[tool.uv.index]]
|
|
@@ -48,13 +51,13 @@ build-backend = "hatchling.build"
|
|
|
48
51
|
# RUFF:
|
|
49
52
|
[tool.ruff]
|
|
50
53
|
line-length = 100
|
|
51
|
-
target-version = "
|
|
54
|
+
target-version = "py311"
|
|
52
55
|
show-fixes = true
|
|
53
56
|
exclude = ["mscl_release_assets/"]
|
|
54
57
|
|
|
55
58
|
[tool.ruff.lint]
|
|
56
|
-
ignore = ["ISC001", "S603", "S605", "S607", "PLR0912"]
|
|
59
|
+
ignore = ["ISC001", "S603", "S605", "S607", "PLR0912", "T201"]
|
|
57
60
|
select = ["E", "F", "I", "PL", "UP", "RUF", "PTH", "C4", "B", "PIE", "SIM", "RET", "RSE",
|
|
58
61
|
"G", "ISC", "PT", "ASYNC", "TCH", "SLOT", "PERF", "PYI", "FLY", "AIR", "Q", "INP",
|
|
59
62
|
"W", "YTT", "DTZ", "ARG", "T20", "FURB", "D100", "D101", "D300", "D418",
|
|
60
|
-
"D419", "S", "NPY"]
|
|
63
|
+
"D419", "S", "NPY"]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Script to run the hatch build for a given python version and architecture."""
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from constants import MACHINE_MAPPING_TO_ARCH
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def run_hatch_build(python_version: str, build_arch: str) -> None:
|
|
13
|
+
"""Run the hatch build for the given Python version and architecture."""
|
|
14
|
+
|
|
15
|
+
# modify_pyproject_toml(python_version, build_arch)
|
|
16
|
+
env = os.environ.copy()
|
|
17
|
+
env["PYTHON_BUILD_VERSION"] = python_version
|
|
18
|
+
env["BUILD_ARCH"] = build_arch
|
|
19
|
+
|
|
20
|
+
# Run the hatch build with the environment variables set:
|
|
21
|
+
subprocess.run(["uv", "build", "--wheel"], check=True, env=env)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main(github_actions: bool = False) -> None:
|
|
25
|
+
"""Entry point to run the hatch build for the given Python version and architecture.
|
|
26
|
+
|
|
27
|
+
Make sure to have first downloaded and extracted the release assets from the Github repository.
|
|
28
|
+
i.e. run `uv run download_and_extract_assets.py` before running this script.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
github_actions: If the script is running in a Github Actions environment. If true, the
|
|
32
|
+
script will run the hatch build for only the Python version and architecture detected.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# Iterate through the Python versions and architectures:
|
|
36
|
+
# See the file names in the extracted folder for the exact names:
|
|
37
|
+
# This must be the same as the dictionary in the hatch_build.py file
|
|
38
|
+
python_versions = ["Python3.9", "Python3.10", "Python3.11", "Python3.12", "Python3.13"]
|
|
39
|
+
build_architectures = ["amd64", "arm64", "armhf", "Windows_x64", "Windows_x86"]
|
|
40
|
+
|
|
41
|
+
if github_actions:
|
|
42
|
+
detected_python_version = f"Python{sys.version_info.major}.{sys.version_info.minor}"
|
|
43
|
+
detected_arch = MACHINE_MAPPING_TO_ARCH.get(platform.machine())
|
|
44
|
+
run_hatch_build(detected_python_version, detected_arch)
|
|
45
|
+
|
|
46
|
+
else:
|
|
47
|
+
for python_version, build_arch in itertools.product(python_versions, build_architectures):
|
|
48
|
+
run_hatch_build(python_version, build_arch)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
if os.getenv("GITHUB_ACTIONS", "false") == "true":
|
|
53
|
+
print("Building in Github Actions environment.")
|
|
54
|
+
main(github_actions=True)
|
|
55
|
+
else:
|
|
56
|
+
print("Building locally")
|
|
57
|
+
main()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from warnings import warn
|
|
2
|
+
|
|
3
|
+
# from . import mscl
|
|
4
|
+
|
|
5
|
+
warn(
|
|
6
|
+
"The 'python_mscl' package is archived, please use the official `pymscl` package instead.",
|
|
7
|
+
DeprecationWarning,
|
|
8
|
+
stacklevel=2
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# Intentionally make the user can do `from python_mscl import mscl` instead of `import mscl` which
|
|
12
|
+
# can be done by doing a from .mscl import * here.
|
|
13
|
+
# __all__ = ["mscl"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.13
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"""Specifies a hatch build hook to create the wheel for mscl."""
|
|
2
|
-
|
|
3
|
-
import platform
|
|
4
|
-
import shutil
|
|
5
|
-
import sys
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
sys.path.insert(0, str(Path(__file__).parent))
|
|
9
|
-
|
|
10
|
-
from hatchling.builders.hooks.plugin.interface import BuildHookInterface
|
|
11
|
-
|
|
12
|
-
from build_helpers.release_downloader import GithubDownloader
|
|
13
|
-
|
|
14
|
-
MSCL_VERSION = "v67.0.0"
|
|
15
|
-
"""The mscl version to build the wheels of."""
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class CustomBuildHook(BuildHookInterface):
|
|
19
|
-
"""Build hook to build wheels from the extracted .deb/.zip files."""
|
|
20
|
-
|
|
21
|
-
def _python_tag(self) -> str:
|
|
22
|
-
"""Generate the Python tag (e.g., py39 for Python 3.9)."""
|
|
23
|
-
major = sys.version_info.major
|
|
24
|
-
minor = sys.version_info.minor
|
|
25
|
-
return f"cp{major}{minor}"
|
|
26
|
-
|
|
27
|
-
def _platform_tag(self) -> str:
|
|
28
|
-
"""Generate the platform tag (e.g., linux_x86_64)."""
|
|
29
|
-
return platform.system().lower() + "_" + platform.machine()
|
|
30
|
-
|
|
31
|
-
def initialize(self, version, build_data):
|
|
32
|
-
"""
|
|
33
|
-
Called before building the wheel/sdist.
|
|
34
|
-
We can download & extract the .deb here, and place
|
|
35
|
-
mscl.py and _mscl.so into src/mscl_pip/.
|
|
36
|
-
"""
|
|
37
|
-
if self.target_name != "wheel":
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
build_data["pure_python"] = False
|
|
41
|
-
self.app.display_info(f"Running on {version=} and {build_data=}")
|
|
42
|
-
self.app.display_info(self.target_name)
|
|
43
|
-
|
|
44
|
-
# --- STEP 1: Determine which python version and arch we are on: ---
|
|
45
|
-
# a) Python version:
|
|
46
|
-
# syntax: Python<MAJOR>.<MINOR>
|
|
47
|
-
|
|
48
|
-
py_version = f"Python{sys.version_info.major}.{sys.version_info.minor}"
|
|
49
|
-
|
|
50
|
-
# b) Architecture:
|
|
51
|
-
# possible values: amd64, arm64, armhf.
|
|
52
|
-
|
|
53
|
-
arch = platform.machine()
|
|
54
|
-
if arch == "x86_64":
|
|
55
|
-
mscl_arch = "amd64"
|
|
56
|
-
elif arch == "aarch64":
|
|
57
|
-
mscl_arch = "arm64"
|
|
58
|
-
elif arch == "armv7l":
|
|
59
|
-
mscl_arch = "armhf"
|
|
60
|
-
elif arch == "AMD64": # Windows
|
|
61
|
-
mscl_arch = "x64"
|
|
62
|
-
elif arch == "x86": # Windows
|
|
63
|
-
mscl_arch = "x86"
|
|
64
|
-
else:
|
|
65
|
-
raise RuntimeError(f"Unknown architecture: {arch}")
|
|
66
|
-
|
|
67
|
-
# --- STEP 2: Download the 2 mscl files (mscl.py and _mscl.so) from the git repo: ---
|
|
68
|
-
# Folder name: mscl-<mscl_arch>-<python-ver>-<mscl-ver> -> Linux
|
|
69
|
-
# Folder name: mscl-Windows-<mscl_arch>-<python-ver>-<mscl-ver> -> Windows
|
|
70
|
-
|
|
71
|
-
# a) Create the folder name:
|
|
72
|
-
|
|
73
|
-
if platform.system() == "Linux":
|
|
74
|
-
build_data["tag"] = f"{self._python_tag()}-{self._python_tag()}-{self._platform_tag()}"
|
|
75
|
-
folder_name = f"mscl-{mscl_arch}-{py_version}-{MSCL_VERSION}"
|
|
76
|
-
|
|
77
|
-
# Windows is best effort matching since there's only python 3.11 available for v67.0.0:
|
|
78
|
-
else:
|
|
79
|
-
if mscl_arch == "x64":
|
|
80
|
-
build_data["tag"] = "py3-none-win_amd64"
|
|
81
|
-
elif mscl_arch == "x86":
|
|
82
|
-
build_data["tag"] = "py3-none-win32"
|
|
83
|
-
folder_name = f"mscl-Windows-{mscl_arch}-Python3.11-{MSCL_VERSION}"
|
|
84
|
-
|
|
85
|
-
# b) Use PyGithub to download the files from the folder:
|
|
86
|
-
self.app.display_waiting(f"Downloading files for {folder_name}...")
|
|
87
|
-
|
|
88
|
-
gh = GithubDownloader()
|
|
89
|
-
gh.download_assets_from_folder(
|
|
90
|
-
tag=MSCL_VERSION,
|
|
91
|
-
folder_name=f"mscl_release_assets/{folder_name}",
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
self.app.display_success("Downloaded files successfully.")
|
|
95
|
-
|
|
96
|
-
# --- STEP 3: Copy the files ("_mscl.so" & "mscl.py") to the src/mscl/ directory: ---
|
|
97
|
-
# Move from root (i.e. cwd) to src/mscl
|
|
98
|
-
# Use shutil.move() to move the files.
|
|
99
|
-
|
|
100
|
-
self.remove_existing_files(Path("src/python_mscl/"), ["_mscl.so", "_mscl.pyd", "mscl.py"])
|
|
101
|
-
shutil.move("mscl.py", "src/python_mscl/")
|
|
102
|
-
if platform.system() == "Windows":
|
|
103
|
-
shutil.move("_mscl.pyd", "src/python_mscl/")
|
|
104
|
-
build_data["artifacts"] = ["_mscl.pyd", "mscl.py"]
|
|
105
|
-
else:
|
|
106
|
-
shutil.move("_mscl.so", "src/python_mscl/")
|
|
107
|
-
build_data["artifacts"] = ["_mscl.so", "mscl.py"]
|
|
108
|
-
|
|
109
|
-
self.app.display_success("Moved files to src/python_mscl/ successfully. Building wheel...")
|
|
110
|
-
|
|
111
|
-
def remove_existing_files(self, directory: Path, files: list[str]) -> None:
|
|
112
|
-
"""Remove the existing files from the directory."""
|
|
113
|
-
for file in files:
|
|
114
|
-
file_path = directory / file
|
|
115
|
-
if file_path.exists():
|
|
116
|
-
file_path.unlink()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|