Skip to content

Commit

Permalink
feat: Implement AOT publishing for Python project (#125)
Browse files Browse the repository at this point in the history
* try expose api as c lib and use aot

* code cleanup and c error code

* feat: use aot publishing for python project

* fix: add catch all for unmanaged entry point
  • Loading branch information
kahojyun authored Mar 28, 2024
1 parent 77653c8 commit a5b42fe
Show file tree
Hide file tree
Showing 38 changed files with 1,015 additions and 160 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ charset = utf-8
spelling_exclusion_path = exclusion.dic

# Xml files
[*.xml]
[*.{xml,csproj,props,targets}]
indent_size = 2

[*.{js,ts,cjs,mjs,jsx,tsx}]
Expand Down
7 changes: 7 additions & 0 deletions Qynit.PulseGen.sln
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WaveGenBenchmarks", "exampl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Qynit.PulseGen.Server", "src\Qynit.PulseGen.Server\Qynit.PulseGen.Server.csproj", "{3AF1B594-E5D8-43A1-9E74-A8F9570BD0FA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Qynit.PulseGen.Aot", "src\Qynit.PulseGen.Aot\Qynit.PulseGen.Aot.csproj", "{50443AA3-B148-4D75-87EE-55AFB5A53D69}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -46,6 +48,10 @@ Global
{3AF1B594-E5D8-43A1-9E74-A8F9570BD0FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AF1B594-E5D8-43A1-9E74-A8F9570BD0FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AF1B594-E5D8-43A1-9E74-A8F9570BD0FA}.Release|Any CPU.Build.0 = Release|Any CPU
{50443AA3-B148-4D75-87EE-55AFB5A53D69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50443AA3-B148-4D75-87EE-55AFB5A53D69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50443AA3-B148-4D75-87EE-55AFB5A53D69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50443AA3-B148-4D75-87EE-55AFB5A53D69}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -55,6 +61,7 @@ Global
{33659EDC-29F9-45DB-A9FA-E01E648BE4B9} = {3B8B8B3E-9095-4A7E-9309-661439C30D9A}
{ECE2579D-700C-4BB3-9009-F35395177B7A} = {6741804E-962A-4762-B289-CD4899A62AD8}
{3AF1B594-E5D8-43A1-9E74-A8F9570BD0FA} = {3EBAD22F-230A-4BCB-B16C-A9063E2A4E9A}
{50443AA3-B148-4D75-87EE-55AFB5A53D69} = {3EBAD22F-230A-4BCB-B16C-A9063E2A4E9A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1DC52AEE-D9FC-4B2F-9492-0C92B0479A3C}
Expand Down
2 changes: 1 addition & 1 deletion exclusion.dic
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Qynit
Biquad
Biquad
144 changes: 50 additions & 94 deletions hatch_build.py
Original file line number Diff line number Diff line change
@@ -1,107 +1,63 @@
import platform
import shutil
import subprocess
import sys
from typing import Any, Dict, List

from hatchling.builders.hooks.plugin.interface import BuildHookInterface

SERVER_PROJECT_DIR = "src/Qynit.PulseGen.Server"
if sys.platform == "win32":
NPM = "npm.cmd"
else:
NPM = "npm"
SRC_DIR = "src/Qynit.PulseGen.Aot"
DST_DIR = "python/pulsegen_cs/lib"


def _check_dotnet() -> None:
try:
subprocess.run(
[
"dotnet",
"--version",
],
check=True,
capture_output=True,
)
except FileNotFoundError as e:
msg = "dotnet is not installed"
raise RuntimeError(msg) from e


def _dotnet_publish(version: str) -> None:
if version == "editable":
configuration = "Debug"
ci = "false"
else:
configuration = "Release"
ci = "true"
try:
subprocess.run(
[
"dotnet",
"publish",
SRC_DIR,
"--output",
DST_DIR,
"--configuration",
configuration,
"--nologo",
"--use-current-runtime",
f"-p:ContinuousIntegrationBuild={ci}",
],
check=True,
)
except subprocess.CalledProcessError as e:
msg = "dotnet publish failed"
raise RuntimeError(msg) from e


class CustomBuildHook(BuildHookInterface):
def initialize(self, version: str, build_data: Dict[str, Any]) -> None:
if self.target_name == "wheel":
self._check_dotnet()
self._check_npm()
self._npm_ci()
self._npm_build()
self._dotnet_publish(version)
_check_dotnet()
_dotnet_publish(version)

def clean(self, versions: List[str]) -> None:
shutil.rmtree("artifacts", ignore_errors=True)

def _check_dotnet(self) -> None:
try:
subprocess.run(
[
"dotnet",
"--version",
],
check=True,
capture_output=True,
)
except FileNotFoundError as e:
msg = "dotnet is not installed"
raise RuntimeError(msg) from e

def _check_npm(self) -> None:
try:
subprocess.run(
[
NPM,
"--version",
],
check=True,
capture_output=True,
)
except FileNotFoundError as e:
msg = "npm is not installed"
raise RuntimeError(msg) from e


def _npm_ci(self) -> None:
try:
subprocess.run(
[
NPM,
"ci",
],
check=True,
cwd=SERVER_PROJECT_DIR,
)
except subprocess.CalledProcessError as e:
msg = "npm ci failed"
raise RuntimeError(msg) from e

def _npm_build(self) -> None:
try:
subprocess.run(
[
NPM,
"run",
"build",
],
check=True,
cwd=SERVER_PROJECT_DIR,
)
except subprocess.CalledProcessError as e:
msg = "npm build failed"
raise RuntimeError(msg) from e

def _dotnet_publish(self, version: str) -> None:
if version == "editable":
configuration = "Debug"
ci = "false"
else:
configuration = "Release"
ci = "true"
try:
subprocess.run(
[
"dotnet",
"publish",
"--configuration",
configuration,
"--nologo",
"/p:UseAppHost=false",
f"/p:ContinuousIntegrationBuild={ci}",
],
check=True,
)
except subprocess.CalledProcessError as e:
msg = "dotnet publish failed"
raise RuntimeError(msg) from e

shutil.rmtree(DST_DIR, ignore_errors=True)
12 changes: 5 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "pulsegen-client"
name = "pulsegen-cs"
dynamic = ["version"]
description = "Client for Qynit.PulseGen.Server"
description = "Bindings for Qynit.PulseGen"
readme = "README.md"
requires-python = ">=3.8"
license = "MIT"
Expand All @@ -16,7 +16,7 @@ classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: Implementation :: CPython",
]
dependencies = ["numpy", "msgpack", "attrs", "pythonnet>=3.0.0"]
dependencies = ["numpy", "msgpack", "attrs"]

[project.urls]
Documentation = "https://github.com/kahojyun/Qynit.PulseGen#readme"
Expand All @@ -30,10 +30,8 @@ pattern = "(?P<version>.*)"
[tool.hatch.build.hooks.custom]

[tool.hatch.build.targets.wheel]
packages = ["python/pulsegen_client"]

[tool.hatch.build.targets.wheel.force-include]
"artifacts/publish/Qynit.PulseGen.Server/release" = "pulsegen_client/lib"
packages = ["python/pulsegen_cs"]
artifacts = ["*.so", "*.dll"]

[tool.hatch.envs.default]
dependencies = ["scipy", "matplotlib", "ipython"]
2 changes: 1 addition & 1 deletion python/example/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@

import numpy as np
from matplotlib import pyplot as plt
from pulsegen_cs import *
from scipy import signal

from pulsegen_client import *

def get_biquad(amp, tau, fs):
z = -1 / (tau * (1 + amp))
Expand Down
6 changes: 2 additions & 4 deletions python/example/schedule_stress.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
The server must be running for this example to work.
"""

from itertools import cycle
import time
from itertools import cycle

import numpy as np

from pulsegen_client import *
from pulsegen_cs import *


def gen_n(n: int):
Expand Down Expand Up @@ -76,5 +75,4 @@ def main():


if __name__ == "__main__":
start_server()
main()
45 changes: 0 additions & 45 deletions python/pulsegen_client/dotnet.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@
This package is still in development and the API may change in the future.
"""

from ._native import generate_waveforms
from .models import (
Biquad, ChannelInfo, IqCalibration, Options,
HannShape, InterpolatedShape, TriangleShape,
Absolute,
Alignment,
Barrier,
Biquad,
ChannelInfo,
Grid,
HannShape,
InterpolatedShape,
IqCalibration,
Options,
Play,
Repeat,
Request,
Expand All @@ -28,8 +33,8 @@
ShiftPhase,
Stack,
SwapPhase,
TriangleShape,
)
from .dotnet import generate_waveforms, start_server

__all__ = [
"ChannelInfo",
Expand All @@ -53,5 +58,4 @@
"InterpolatedShape",
"TriangleShape",
"generate_waveforms",
"start_server",
]
Loading

0 comments on commit a5b42fe

Please sign in to comment.