From 579361e3b051e5bcebf85d588ac7cd75d0a58e7b Mon Sep 17 00:00:00 2001 From: Yusuf Olokoba Date: Fri, 30 Aug 2024 06:43:16 -0400 Subject: [PATCH] Finalize 0.0.38 --- Changelog.md | 3 +++ fxn/services/prediction.py | 48 +++++++++++++++++++++----------------- fxn/version.py | 2 +- fxnc.py | 4 +++- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/Changelog.md b/Changelog.md index 340ea5b..b86c1bd 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,6 @@ +## 0.0.38 ++ Function now supports Linux, across `x86_64` and `arm64` architectures. + ## 0.0.37 + Added `fxn --explore` CLI action to explore predictions on [fxn.ai](https://fxn.ai/explore). diff --git a/fxn/services/prediction.py b/fxn/services/prediction.py index ba889a6..63ea4a9 100644 --- a/fxn/services/prediction.py +++ b/fxn/services/prediction.py @@ -17,6 +17,7 @@ from platform import machine, system from pydantic import BaseModel from requests import get, post +from tempfile import gettempdir from typing import Any, AsyncIterator, Dict, List, Optional, Union from urllib.parse import urlparse @@ -127,32 +128,24 @@ async def stream ( # INCOMPLETE # Streaming support @classmethod def __load_fxnc (self) -> Optional[CDLL]: - # Get resource - package, resource = None, None - os = system() - if os == "Darwin": - package = f"fxn.lib.macos.{machine()}" - resource = f"Function.dylib" - elif os == "Linux" and False: # INCOMPLETE # Linux - package = f"fxn.lib.linux.{machine()}" - resource = f"libFunction.so" - elif os == "Windows": - package = f"fxn.lib.windows.{machine()}" - resource = f"Function.dll" - else: - return None - # Load + os = system().lower() + os = "macos" if os == "darwin" else os + arch = machine() + arch = "arm64" if arch == "aarch64" else arch + arch = "x86_64" if arch == "x64" else arch + package = f"fxn.lib.{os}.{arch}" + resource = "libFunction.so" + resource = "Function.dylib" if os == "macos" else resource + resource = "Function.dll" if os == "windows" else resource with resources.path(package, resource) as fxnc_path: return load_fxnc(fxnc_path) def __get_client_id (self) -> str: # Fallback if fxnc failed to load if not self.__fxnc: - return { - "Darwin": f"macos-{machine()}", - "Linux": f"linux-{machine()}", - "Windows": f"windows-{machine()}" - }[system()] + os = system().lower() + os = "macos" if os == "darwin" else os + return f"{os}-{machine()}" # Get buffer = create_string_buffer(64) status = self.__fxnc.FXNConfigurationGetClientID(buffer, len(buffer)) @@ -383,7 +376,7 @@ def __to_object ( raise RuntimeError(f"Failed to convert Function value to Python value because Function value has unsupported type: {dtype}") def __get_resource_path (self, resource: PredictionResource) -> Path: - cache_dir = Path.home() / ".fxn" / "cache" + cache_dir = self.__class__.__get_resource_dir() / ".fxn" / "cache" cache_dir.mkdir(exist_ok=True) res_name = Path(urlparse(resource.url).path).name res_path = cache_dir / res_name @@ -394,7 +387,18 @@ def __get_resource_path (self, resource: PredictionResource) -> Path: with open(res_path, "wb") as f: f.write(req.content) return res_path - + + @classmethod + def __get_resource_dir (cls) -> Path: + try: + check = Path.home() / ".fxntest" + with open(check, "w") as f: + f.write("fxn") + check.unlink() + return Path.home() + except: + return Path(gettempdir()) + @classmethod def __try_ensure_serializable (cls, object: Any) -> Any: if object is None: diff --git a/fxn/version.py b/fxn/version.py index 39898d9..8873ff1 100644 --- a/fxn/version.py +++ b/fxn/version.py @@ -3,4 +3,4 @@ # Copyright © 2024 NatML Inc. All Rights Reserved. # -__version__ = "0.0.37" \ No newline at end of file +__version__ = "0.0.38" \ No newline at end of file diff --git a/fxnc.py b/fxnc.py index dbabcba..3e001d6 100644 --- a/fxnc.py +++ b/fxnc.py @@ -25,7 +25,7 @@ def _get_latest_version () -> str: release = response.json() return release["tag_name"] -def main (): # INCOMPLETE # Linux +def main (): args = parser.parse_args() version = args.version if args.version else _get_latest_version() LIB_PATH_BASE = Path("fxn") / "lib" @@ -34,6 +34,8 @@ def main (): # INCOMPLETE # Linux ("Function-macos-arm64.dylib", LIB_PATH_BASE / "macos" / "arm64" / "Function.dylib"), ("Function-win-x86_64.dll", LIB_PATH_BASE / "windows" / "x86_64" / "Function.dll"), ("Function-win-arm64.dll", LIB_PATH_BASE / "windows" / "arm64" / "Function.dll"), + ("libFunction-linux-x86_64.so", LIB_PATH_BASE / "linux" / "x86_64" / "libFunction.so"), + ("libFunction-linux-arm64.so", LIB_PATH_BASE / "linux" / "arm64" / "libFunction.so"), ] for name, path in DOWNLOADS: _download_fxnc(name, version, path)