fxn 0.0.36__tar.gz → 0.0.38__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 (60) hide show
  1. {fxn-0.0.36 → fxn-0.0.38}/PKG-INFO +15 -9
  2. {fxn-0.0.36 → fxn-0.0.38}/README.md +14 -8
  3. {fxn-0.0.36 → fxn-0.0.38}/fxn/__init__.py +1 -1
  4. fxn-0.0.38/fxn/cli/misc.py +32 -0
  5. {fxn-0.0.36 → fxn-0.0.38}/fxn/function.py +5 -10
  6. fxn-0.0.38/fxn/lib/linux/arm64/libFunction.so +0 -0
  7. fxn-0.0.38/fxn/lib/linux/x86_64/libFunction.so +0 -0
  8. {fxn-0.0.36 → fxn-0.0.38}/fxn/lib/macos/arm64/Function.dylib +0 -0
  9. fxn-0.0.38/fxn/lib/macos/x86_64/Function.dylib +0 -0
  10. fxn-0.0.38/fxn/lib/windows/arm64/Function.dll +0 -0
  11. fxn-0.0.38/fxn/lib/windows/x86_64/Function.dll +0 -0
  12. {fxn-0.0.36 → fxn-0.0.38}/fxn/services/__init__.py +1 -3
  13. {fxn-0.0.36 → fxn-0.0.38}/fxn/services/prediction.py +29 -30
  14. {fxn-0.0.36 → fxn-0.0.38}/fxn/services/predictor.py +2 -4
  15. {fxn-0.0.36 → fxn-0.0.38}/fxn/types/__init__.py +1 -4
  16. {fxn-0.0.36 → fxn-0.0.38}/fxn/types/predictor.py +4 -4
  17. fxn-0.0.36/fxn/types/profile.py → fxn-0.0.38/fxn/types/user.py +6 -1
  18. {fxn-0.0.36 → fxn-0.0.38}/fxn/version.py +1 -1
  19. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/PKG-INFO +15 -9
  20. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/SOURCES.txt +2 -7
  21. fxn-0.0.36/fxn/cli/misc.py +0 -26
  22. fxn-0.0.36/fxn/lib/macos/x86_64/Function.dylib +0 -0
  23. fxn-0.0.36/fxn/lib/windows/arm64/Function.dll +0 -0
  24. fxn-0.0.36/fxn/lib/windows/x86_64/Function.dll +0 -0
  25. fxn-0.0.36/fxn/magic.py +0 -35
  26. fxn-0.0.36/fxn/services/environment.py +0 -111
  27. fxn-0.0.36/fxn/services/storage.py +0 -159
  28. fxn-0.0.36/fxn/types/environment.py +0 -17
  29. fxn-0.0.36/fxn/types/storage.py +0 -14
  30. fxn-0.0.36/fxn/types/tag.py +0 -28
  31. fxn-0.0.36/fxn/types/user.py +0 -11
  32. {fxn-0.0.36 → fxn-0.0.38}/LICENSE +0 -0
  33. {fxn-0.0.36 → fxn-0.0.38}/fxn/api/__init__.py +0 -0
  34. {fxn-0.0.36 → fxn-0.0.38}/fxn/api/client.py +0 -0
  35. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/__init__.py +0 -0
  36. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/configuration.py +0 -0
  37. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/dtype.py +0 -0
  38. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/fxnc.py +0 -0
  39. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/map.py +0 -0
  40. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/prediction.py +0 -0
  41. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/predictor.py +0 -0
  42. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/status.py +0 -0
  43. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/stream.py +0 -0
  44. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/value.py +0 -0
  45. {fxn-0.0.36 → fxn-0.0.38}/fxn/c/version.py +0 -0
  46. {fxn-0.0.36 → fxn-0.0.38}/fxn/cli/__init__.py +0 -0
  47. {fxn-0.0.36 → fxn-0.0.38}/fxn/cli/auth.py +0 -0
  48. {fxn-0.0.36 → fxn-0.0.38}/fxn/cli/env.py +0 -0
  49. {fxn-0.0.36 → fxn-0.0.38}/fxn/cli/predict.py +0 -0
  50. {fxn-0.0.36 → fxn-0.0.38}/fxn/cli/predictors.py +0 -0
  51. {fxn-0.0.36 → fxn-0.0.38}/fxn/lib/__init__.py +0 -0
  52. {fxn-0.0.36 → fxn-0.0.38}/fxn/services/user.py +0 -0
  53. {fxn-0.0.36 → fxn-0.0.38}/fxn/types/dtype.py +0 -0
  54. {fxn-0.0.36 → fxn-0.0.38}/fxn/types/prediction.py +0 -0
  55. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/dependency_links.txt +0 -0
  56. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/entry_points.txt +0 -0
  57. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/requires.txt +0 -0
  58. {fxn-0.0.36 → fxn-0.0.38}/fxn.egg-info/top_level.txt +0 -0
  59. {fxn-0.0.36 → fxn-0.0.38}/pyproject.toml +0 -0
  60. {fxn-0.0.36 → fxn-0.0.38}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fxn
3
- Version: 0.0.36
3
+ Version: 0.0.38
4
4
  Summary: Run prediction functions locally in Python. Register at https://fxn.ai.
5
5
  Author-email: "NatML Inc." <hi@fxn.ai>
6
6
  License: Apache License
@@ -239,20 +239,24 @@ $ pip install --upgrade fxn
239
239
  ```
240
240
 
241
241
  > [!NOTE]
242
- > Function requires Python 3.9+
242
+ > Function requires Python 3.10+
243
243
 
244
244
  ## Retrieving your Access Key
245
- Head over to [fxn.ai](https://fxn.ai) to create an account by logging in. Once you do, generate an access key:
245
+ Head over to [fxn.ai](https://www.fxn.ai/account/developer) to create an account by logging in. Once you do, generate an access key:
246
246
 
247
247
  ![generate access key](https://raw.githubusercontent.com/fxnai/.github/main/access_key.gif)
248
248
 
249
249
  ## Making a Prediction
250
- Let's run the [`@fxn/greeting`](https://fxn.ai/@fxn/greeting) predictor which accepts a `name` and returns a congenial greeting. Run the following Python script:
250
+ First, create a Function client, specifying your access key:
251
251
  ```py
252
252
  from fxn import Function
253
253
 
254
254
  # Create the Function client
255
255
  fxn = Function(access_key="<Function access key>")
256
+ ```
257
+
258
+ Then make a prediction:
259
+ ```py
256
260
  # Create a prediction
257
261
  prediction = fxn.predictions.create(
258
262
  tag="@fxn/greeting",
@@ -264,16 +268,18 @@ print(prediction.results[0])
264
268
 
265
269
  > [!TIP]
266
270
  > Explore public predictors [on Function](https://fxn.ai/explore) or [create your own](https://fxn.ai/waitlist).
267
- r
268
- ## Using the Function CLI
269
- Open up a terminal and run the following command:
270
271
 
272
+ ## Using the Function CLI
273
+ Open up a terminal and login to the Function CLI:
271
274
  ```sh
272
275
  # Login to Function
273
- fxn auth login <ACCESS KEY>
276
+ $ fxn auth login <ACCESS KEY>
277
+ ```
274
278
 
279
+ Then make a prediction:
280
+ ```sh
275
281
  # Make a prediction using the Function CLI
276
- fxn predict @fxn/greeting --name Peter
282
+ $ fxn predict @fxn/greeting --name Peter
277
283
  ```
278
284
 
279
285
  ___
@@ -14,20 +14,24 @@ $ pip install --upgrade fxn
14
14
  ```
15
15
 
16
16
  > [!NOTE]
17
- > Function requires Python 3.9+
17
+ > Function requires Python 3.10+
18
18
 
19
19
  ## Retrieving your Access Key
20
- Head over to [fxn.ai](https://fxn.ai) to create an account by logging in. Once you do, generate an access key:
20
+ Head over to [fxn.ai](https://www.fxn.ai/account/developer) to create an account by logging in. Once you do, generate an access key:
21
21
 
22
22
  ![generate access key](https://raw.githubusercontent.com/fxnai/.github/main/access_key.gif)
23
23
 
24
24
  ## Making a Prediction
25
- Let's run the [`@fxn/greeting`](https://fxn.ai/@fxn/greeting) predictor which accepts a `name` and returns a congenial greeting. Run the following Python script:
25
+ First, create a Function client, specifying your access key:
26
26
  ```py
27
27
  from fxn import Function
28
28
 
29
29
  # Create the Function client
30
30
  fxn = Function(access_key="<Function access key>")
31
+ ```
32
+
33
+ Then make a prediction:
34
+ ```py
31
35
  # Create a prediction
32
36
  prediction = fxn.predictions.create(
33
37
  tag="@fxn/greeting",
@@ -39,16 +43,18 @@ print(prediction.results[0])
39
43
 
40
44
  > [!TIP]
41
45
  > Explore public predictors [on Function](https://fxn.ai/explore) or [create your own](https://fxn.ai/waitlist).
42
- r
43
- ## Using the Function CLI
44
- Open up a terminal and run the following command:
45
46
 
47
+ ## Using the Function CLI
48
+ Open up a terminal and login to the Function CLI:
46
49
  ```sh
47
50
  # Login to Function
48
- fxn auth login <ACCESS KEY>
51
+ $ fxn auth login <ACCESS KEY>
52
+ ```
49
53
 
54
+ Then make a prediction:
55
+ ```sh
50
56
  # Make a prediction using the Function CLI
51
- fxn predict @fxn/greeting --name Peter
57
+ $ fxn predict @fxn/greeting --name Peter
52
58
  ```
53
59
 
54
60
  ___
@@ -5,4 +5,4 @@
5
5
 
6
6
  from .function import Function
7
7
  from .types import *
8
- from .version import __version__
8
+ from .version import *
@@ -0,0 +1,32 @@
1
+ #
2
+ # Function
3
+ # Copyright © 2024 NatML Inc. All Rights Reserved.
4
+ #
5
+
6
+ from rich import print
7
+ from typer import Exit, Option
8
+ from webbrowser import open as open_browser
9
+
10
+ from ..version import __version__
11
+
12
+ def _explore (value: bool):
13
+ if value:
14
+ open_browser("https://fxn.ai/explore")
15
+ raise Exit()
16
+
17
+ def _learn (value: bool):
18
+ if value:
19
+ open_browser("https://docs.fxn.ai")
20
+ raise Exit()
21
+
22
+ def _version (value: bool):
23
+ if value:
24
+ print(__version__)
25
+ raise Exit()
26
+
27
+ def cli_options (
28
+ explore: bool = Option(None, "--explore", callback=_explore, help="Explore predictors on Function."),
29
+ learn: bool = Option(None, "--learn", callback=_learn, help="Learn about Function."),
30
+ version: bool = Option(None, "--version", callback=_version, help="Get the Function CLI version.")
31
+ ):
32
+ pass
@@ -6,7 +6,7 @@
6
6
  from os import environ
7
7
 
8
8
  from .api import GraphClient
9
- from .services import EnvironmentVariableService, PredictionService, PredictorService, StorageService, UserService
9
+ from .services import PredictionService, PredictorService, UserService
10
10
 
11
11
  class Function:
12
12
  """
@@ -26,16 +26,11 @@ class Function:
26
26
  users: UserService
27
27
  predictors: PredictorService
28
28
  predictions: PredictionService
29
- #environment_variables: EnvironmentVariableService
30
- #storage: StorageService
31
29
 
32
30
  def __init__ (self, access_key: str=None, api_url: str=None):
33
31
  access_key = access_key or environ.get("FXN_ACCESS_KEY", None)
34
32
  api_url = api_url or environ.get("FXN_API_URL", "https://api.fxn.ai")
35
- client = GraphClient(access_key, api_url)
36
- storage = StorageService(client)
37
- self.client = client
38
- self.users = UserService(client)
39
- self.predictors = PredictorService(client, storage)
40
- self.predictions = PredictionService(client)
41
- #self.environment_variables = EnvironmentVariableService(self.client)
33
+ self.client = GraphClient(access_key, api_url)
34
+ self.users = UserService(self.client)
35
+ self.predictors = PredictorService(self.client)
36
+ self.predictions = PredictionService(self.client)
@@ -5,6 +5,4 @@
5
5
 
6
6
  from .user import UserService, PROFILE_FIELDS, USER_FIELDS
7
7
  from .predictor import PredictorService, PREDICTOR_FIELDS
8
- from .prediction import PredictionService, PREDICTION_FIELDS
9
- from .environment import EnvironmentVariableService, ENVIRONMENT_VARIABLE_FIELDS
10
- from .storage import StorageService
8
+ from .prediction import PredictionService, PREDICTION_FIELDS
@@ -17,6 +17,7 @@ from PIL import Image
17
17
  from platform import machine, system
18
18
  from pydantic import BaseModel
19
19
  from requests import get, post
20
+ from tempfile import gettempdir
20
21
  from typing import Any, AsyncIterator, Dict, List, Optional, Union
21
22
  from urllib.parse import urlparse
22
23
 
@@ -35,7 +36,7 @@ class PredictionService:
35
36
  self,
36
37
  tag: str,
37
38
  *,
38
- inputs: Optional[Dict[str, Union[ndarray, str, float, int, bool, List, Dict[str, Any], Path, Image.Image]]] = None,
39
+ inputs: Optional[Dict[str, ndarray | str | float | int | bool | List[Any] | Dict[str, Any] | Path | Image.Image]] = None,
39
40
  acceleration: Acceleration=Acceleration.Default,
40
41
  client_id: str=None,
41
42
  configuration_id: str=None
@@ -58,7 +59,7 @@ class PredictionService:
58
59
  return self.__predict(tag=tag, predictor=self.__cache[tag], inputs=inputs)
59
60
  # Query
60
61
  response = post(
61
- f"{self.client.api_url}/predict/{tag}?rawOutputs=true",
62
+ f"{self.client.api_url}/predict/{tag}",
62
63
  json={ },
63
64
  headers={
64
65
  "Authorization": f"Bearer {self.client.access_key}",
@@ -124,35 +125,27 @@ class PredictionService:
124
125
  prediction = self.__predict(tag=tag, predictor=predictor, inputs=inputs)
125
126
  # Yield
126
127
  yield prediction
127
-
128
+
128
129
  @classmethod
129
130
  def __load_fxnc (self) -> Optional[CDLL]:
130
- # Get resource
131
- package, resource = None, None
132
- os = system()
133
- if os == "Darwin":
134
- package = f"fxn.lib.macos.{machine()}"
135
- resource = f"Function.dylib"
136
- elif os == "Linux" and False: # INCOMPLETE # Linux
137
- package = f"fxn.lib.linux.{machine()}"
138
- resource = f"libFunction.so"
139
- elif os == "Windows":
140
- package = f"fxn.lib.windows.{machine()}"
141
- resource = f"Function.dll"
142
- else:
143
- return None
144
- # Load
131
+ os = system().lower()
132
+ os = "macos" if os == "darwin" else os
133
+ arch = machine()
134
+ arch = "arm64" if arch == "aarch64" else arch
135
+ arch = "x86_64" if arch == "x64" else arch
136
+ package = f"fxn.lib.{os}.{arch}"
137
+ resource = "libFunction.so"
138
+ resource = "Function.dylib" if os == "macos" else resource
139
+ resource = "Function.dll" if os == "windows" else resource
145
140
  with resources.path(package, resource) as fxnc_path:
146
141
  return load_fxnc(fxnc_path)
147
142
 
148
143
  def __get_client_id (self) -> str:
149
144
  # Fallback if fxnc failed to load
150
145
  if not self.__fxnc:
151
- return {
152
- "Darwin": f"macos-{machine()}",
153
- "Linux": f"linux-{machine()}",
154
- "Windows": f"windows-{machine()}"
155
- }[system()]
146
+ os = system().lower()
147
+ os = "macos" if os == "darwin" else os
148
+ return f"{os}-{machine()}"
156
149
  # Get
157
150
  buffer = create_string_buffer(64)
158
151
  status = self.__fxnc.FXNConfigurationGetClientID(buffer, len(buffer))
@@ -383,7 +376,7 @@ class PredictionService:
383
376
  raise RuntimeError(f"Failed to convert Function value to Python value because Function value has unsupported type: {dtype}")
384
377
 
385
378
  def __get_resource_path (self, resource: PredictionResource) -> Path:
386
- cache_dir = Path.home() / ".fxn" / "cache"
379
+ cache_dir = self.__class__.__get_resource_dir() / ".fxn" / "cache"
387
380
  cache_dir.mkdir(exist_ok=True)
388
381
  res_name = Path(urlparse(resource.url).path).name
389
382
  res_path = cache_dir / res_name
@@ -394,7 +387,18 @@ class PredictionService:
394
387
  with open(res_path, "wb") as f:
395
388
  f.write(req.content)
396
389
  return res_path
397
-
390
+
391
+ @classmethod
392
+ def __get_resource_dir (cls) -> Path:
393
+ try:
394
+ check = Path.home() / ".fxntest"
395
+ with open(check, "w") as f:
396
+ f.write("fxn")
397
+ check.unlink()
398
+ return Path.home()
399
+ except:
400
+ return Path(gettempdir())
401
+
398
402
  @classmethod
399
403
  def __try_ensure_serializable (cls, object: Any) -> Any:
400
404
  if object is None:
@@ -427,11 +431,6 @@ resources {{
427
431
  url
428
432
  name
429
433
  }}
430
- results {{
431
- data
432
- type
433
- shape
434
- }}
435
434
  latency
436
435
  error
437
436
  logs
@@ -7,14 +7,12 @@ from typing import List
7
7
 
8
8
  from ..api import GraphClient
9
9
  from ..types import Predictor, PredictorStatus
10
- from .storage import StorageService
11
10
  from .user import PROFILE_FIELDS
12
11
 
13
12
  class PredictorService:
14
13
 
15
- def __init__ (self, client: GraphClient, storage: StorageService) -> None:
14
+ def __init__ (self, client: GraphClient) -> None:
16
15
  self.client = client
17
- self.storage = storage
18
16
 
19
17
  def retrieve (self, tag: str) -> Predictor:
20
18
  """
@@ -85,7 +83,7 @@ class PredictorService:
85
83
  predictors = [Predictor(**predictor) for predictor in predictors]
86
84
  # Return
87
85
  return predictors
88
-
86
+
89
87
  def search (
90
88
  self,
91
89
  query: str,
@@ -4,9 +4,6 @@
4
4
  #
5
5
 
6
6
  from .dtype import Dtype
7
- from .environment import EnvironmentVariable
8
7
  from .prediction import Prediction, PredictionResource
9
8
  from .predictor import Acceleration, AccessMode, EnumerationMember, Parameter, Predictor, PredictorStatus, Signature
10
- from .profile import Profile
11
- from .storage import UploadType
12
- from .user import User
9
+ from .user import Profile, User
@@ -11,16 +11,16 @@ from pydantic import AliasChoices, BaseModel, ConfigDict, Field
11
11
  from typing import Any, Dict, List, Optional, Tuple
12
12
 
13
13
  from .dtype import Dtype
14
- from .profile import Profile
14
+ from .user import Profile
15
15
 
16
16
  class Acceleration (IntFlag):
17
17
  """
18
18
  Predictor acceleration.
19
19
  """
20
20
  Default = 0,
21
- CPU = 1 << 0,
22
- GPU = 1 << 1,
23
- NPU = 1 << 2
21
+ CPU = 1 << 0,
22
+ GPU = 1 << 1,
23
+ NPU = 1 << 2
24
24
 
25
25
  class AccessMode (str, Enum):
26
26
  """
@@ -27,4 +27,9 @@ class Profile (BaseModel):
27
27
  avatar: Optional[str] = Field(default=None, description="User avatar URL.")
28
28
  bio: Optional[str] = Field(default=None, description="User bio.")
29
29
  website: Optional[str] = Field(default=None, description="User website.")
30
- github: Optional[str] = Field(default=None, description="User GitHub handle.")
30
+ github: Optional[str] = Field(default=None, description="User GitHub handle.")
31
+
32
+ class User (Profile):
33
+ """
34
+ User.
35
+ """
@@ -3,4 +3,4 @@
3
3
  # Copyright © 2024 NatML Inc. All Rights Reserved.
4
4
  #
5
5
 
6
- __version__ = "0.0.36"
6
+ __version__ = "0.0.38"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fxn
3
- Version: 0.0.36
3
+ Version: 0.0.38
4
4
  Summary: Run prediction functions locally in Python. Register at https://fxn.ai.
5
5
  Author-email: "NatML Inc." <hi@fxn.ai>
6
6
  License: Apache License
@@ -239,20 +239,24 @@ $ pip install --upgrade fxn
239
239
  ```
240
240
 
241
241
  > [!NOTE]
242
- > Function requires Python 3.9+
242
+ > Function requires Python 3.10+
243
243
 
244
244
  ## Retrieving your Access Key
245
- Head over to [fxn.ai](https://fxn.ai) to create an account by logging in. Once you do, generate an access key:
245
+ Head over to [fxn.ai](https://www.fxn.ai/account/developer) to create an account by logging in. Once you do, generate an access key:
246
246
 
247
247
  ![generate access key](https://raw.githubusercontent.com/fxnai/.github/main/access_key.gif)
248
248
 
249
249
  ## Making a Prediction
250
- Let's run the [`@fxn/greeting`](https://fxn.ai/@fxn/greeting) predictor which accepts a `name` and returns a congenial greeting. Run the following Python script:
250
+ First, create a Function client, specifying your access key:
251
251
  ```py
252
252
  from fxn import Function
253
253
 
254
254
  # Create the Function client
255
255
  fxn = Function(access_key="<Function access key>")
256
+ ```
257
+
258
+ Then make a prediction:
259
+ ```py
256
260
  # Create a prediction
257
261
  prediction = fxn.predictions.create(
258
262
  tag="@fxn/greeting",
@@ -264,16 +268,18 @@ print(prediction.results[0])
264
268
 
265
269
  > [!TIP]
266
270
  > Explore public predictors [on Function](https://fxn.ai/explore) or [create your own](https://fxn.ai/waitlist).
267
- r
268
- ## Using the Function CLI
269
- Open up a terminal and run the following command:
270
271
 
272
+ ## Using the Function CLI
273
+ Open up a terminal and login to the Function CLI:
271
274
  ```sh
272
275
  # Login to Function
273
- fxn auth login <ACCESS KEY>
276
+ $ fxn auth login <ACCESS KEY>
277
+ ```
274
278
 
279
+ Then make a prediction:
280
+ ```sh
275
281
  # Make a prediction using the Function CLI
276
- fxn predict @fxn/greeting --name Peter
282
+ $ fxn predict @fxn/greeting --name Peter
277
283
  ```
278
284
 
279
285
  ___
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  fxn/__init__.py
5
5
  fxn/function.py
6
- fxn/magic.py
7
6
  fxn/version.py
8
7
  fxn.egg-info/PKG-INFO
9
8
  fxn.egg-info/SOURCES.txt
@@ -31,22 +30,18 @@ fxn/cli/misc.py
31
30
  fxn/cli/predict.py
32
31
  fxn/cli/predictors.py
33
32
  fxn/lib/__init__.py
33
+ fxn/lib/linux/arm64/libFunction.so
34
+ fxn/lib/linux/x86_64/libFunction.so
34
35
  fxn/lib/macos/arm64/Function.dylib
35
36
  fxn/lib/macos/x86_64/Function.dylib
36
37
  fxn/lib/windows/arm64/Function.dll
37
38
  fxn/lib/windows/x86_64/Function.dll
38
39
  fxn/services/__init__.py
39
- fxn/services/environment.py
40
40
  fxn/services/prediction.py
41
41
  fxn/services/predictor.py
42
- fxn/services/storage.py
43
42
  fxn/services/user.py
44
43
  fxn/types/__init__.py
45
44
  fxn/types/dtype.py
46
- fxn/types/environment.py
47
45
  fxn/types/prediction.py
48
46
  fxn/types/predictor.py
49
- fxn/types/profile.py
50
- fxn/types/storage.py
51
- fxn/types/tag.py
52
47
  fxn/types/user.py
@@ -1,26 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from rich import print
7
- from typer import Exit, Option
8
- from webbrowser import open as open_browser
9
-
10
- from ..version import __version__
11
-
12
- def _learn_callback (value: bool):
13
- if value:
14
- open_browser("https://docs.fxn.ai")
15
- raise Exit()
16
-
17
- def _version_callback (value: bool):
18
- if value:
19
- print(__version__)
20
- raise Exit()
21
-
22
- def cli_options (
23
- learn: bool = Option(None, "--learn", callback=_learn_callback, help="Learn about Function."),
24
- version: bool = Option(None, "--version", callback=_version_callback, help="Get the Function CLI version.")
25
- ):
26
- pass
fxn-0.0.36/fxn/magic.py DELETED
@@ -1,35 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from IPython.core.interactiveshell import InteractiveShell
7
- from IPython.core.magic import Magics, magics_class, line_magic
8
- from typing import List
9
-
10
- @magics_class
11
- class FunctionMagics (Magics):
12
-
13
- @line_magic
14
- def fxn (self, line: str):
15
- COMMANDS = {
16
- "python": self.__python,
17
- "image": self.__image,
18
- }
19
- args = line.split(" ")
20
- command = COMMANDS.get(args[0], None)
21
- if command is not None:
22
- command(args[1:])
23
- else:
24
- raise RuntimeError(f"Unrecognized Function command: {args[0]}")
25
-
26
- def __python (self, args: List[str]):
27
- version = args[0]
28
- print(f"Predictor will use Python {version} when running on Function")
29
-
30
- def __image (self, args: List[str]):
31
- image = args[0]
32
- print(f"Predictor will use base image {image} when running on Function")
33
-
34
- def load_ipython_extension (ipython: InteractiveShell):
35
- ipython.register_magics(FunctionMagics)
@@ -1,111 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from typing import List
7
-
8
- from ..api import GraphClient
9
- from ..types import EnvironmentVariable
10
-
11
- class EnvironmentVariableService:
12
-
13
- def __init__ (self, client: GraphClient) -> None:
14
- self.client = client
15
- self.__value = "xxxxxxxx"
16
-
17
- def list (self, organization: str=None) -> List[EnvironmentVariable]:
18
- """
19
- List the current user's environment variables.
20
-
21
- Note that the variable values can only viewed at https://fxn.ai.
22
-
23
- Parameters:
24
- organization (str): Organization username.
25
-
26
- Returns:
27
- list: User environment variables.
28
- """
29
- # Query
30
- response = self.client.query(f"""
31
- query ($input: UserInput) {{
32
- user (input: $input) {{
33
- ... on User {{
34
- environmentVariables {{
35
- {ENVIRONMENT_VARIABLE_FIELDS}
36
- }}
37
- }}
38
- ... on Organization {{
39
- environmentVariables {{
40
- {ENVIRONMENT_VARIABLE_FIELDS}
41
- }}
42
- }}
43
- }}
44
- }}
45
- """,
46
- { "input": { "username": organization } if organization is not None else None }
47
- )
48
- # Create envs
49
- assert response["user"] is not None, "Failed to list environment variables because user could not be found. Check that you are authenticated."
50
- environments = response["user"]["environmentVariables"]
51
- environments = [EnvironmentVariable(**env, value=self.__value) for env in environments]
52
- # Return
53
- return environments
54
-
55
- def create (self, name: str, value: str, organization: str=None) -> EnvironmentVariable:
56
- """
57
- Create an environment variable.
58
-
59
- This environment variable will apply to all predictors you create.
60
-
61
- Parameters:
62
- name (str): Variable name.
63
- value (str): Variable value.
64
- organization (str): Organization username. Use this for organization environment variables.
65
-
66
- Returns:
67
- EnvironmentVariable: Created environment variable.
68
- """
69
- # Query
70
- response = self.client.query(f"""
71
- mutation ($input: CreateEnvironmentVariableInput!) {{
72
- environment: createEnvironmentVariable (input: $input) {{
73
- {ENVIRONMENT_VARIABLE_FIELDS}
74
- }}
75
- }}
76
- """,
77
- { "input": { "name": name, "value": value, "organization": organization } }
78
- )
79
- # Create env
80
- environment = response["environment"]
81
- environment = EnvironmentVariable(**environment, value=self.__value)
82
- # Return
83
- return environment
84
-
85
- def delete (self, name: str, organization: str=None) -> bool:
86
- """
87
- Delete an environment variable.
88
-
89
- Parameters:
90
- name (str): Variable name.
91
- organization (str): Organization username. Use this for organization environment variables.
92
- access_key (str): Function access key.
93
-
94
- Returns:
95
- bool: Whether the environment variable was successfully deleted.
96
- """
97
- # Query
98
- response = self.client.query(f"""
99
- mutation ($input: DeleteEnvironmentVariableInput!) {{
100
- result: deleteEnvironmentVariable (input: $input)
101
- }}
102
- """,
103
- { "input": { "name": name, "organization": organization } }
104
- )
105
- # Return
106
- return response["result"]
107
-
108
-
109
- ENVIRONMENT_VARIABLE_FIELDS = f"""
110
- name
111
- """
@@ -1,159 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from base64 import b64encode
7
- from io import BytesIO
8
- from magika import Magika
9
- from pathlib import Path
10
- from requests import put
11
- from rich.progress import open as open_progress, wrap_file
12
- from urllib.parse import urlparse, urlunparse
13
-
14
- from ..api import GraphClient
15
- from ..types import UploadType
16
-
17
- class StorageService:
18
-
19
- def __init__ (self, client: GraphClient) -> None:
20
- self.client = client
21
-
22
- def create_upload_url (self, name: str, type: UploadType, key: str=None) -> str:
23
- """
24
- Create an upload URL.
25
-
26
- Parameters:
27
- name (str): File name.
28
- type (UploadType): Upload type.
29
- key (str): File key. This is useful for grouping related files.
30
-
31
- Returns:
32
- str: File upload URL.
33
- """
34
- # Query
35
- response = self.client.query(f"""
36
- mutation ($input: CreateUploadUrlInput!) {{
37
- createUploadUrl (input: $input)
38
- }}
39
- """,
40
- { "input": { "type": type, "name": name, "key": key } }
41
- )
42
- # Return
43
- return response["createUploadUrl"]
44
-
45
- def upload (
46
- self,
47
- file: str | Path | BytesIO,
48
- *,
49
- type: UploadType,
50
- name: str=None,
51
- data_url_limit: int=None,
52
- key: str=None,
53
- verbose: bool=False
54
- ) -> str:
55
- """
56
- Upload a file and return the URL.
57
-
58
- Parameters:
59
- file (str | Path | BytesIO): Input file.
60
- type (UploadType): File type.
61
- name (str): File name. This MUST be provided if `file` is not a file path.
62
- data_url_limit (int): Return a data URL if the file is smaller than this limit (in bytes).
63
- key (str): File key. This is useful for grouping related files.
64
- verbose (bool): Print a progress bar for the upload.
65
-
66
- Returns:
67
- str: Upload URL.
68
- """
69
- file = Path(file) if isinstance(file, str) else file
70
- if isinstance(file, Path):
71
- return self.__upload_file(file, type=type, name=name, key=key, data_url_limit=data_url_limit, verbose=verbose)
72
- else:
73
- return self.__upload_buffer(file, type=type, name=name, key=key, data_url_limit=data_url_limit, verbose=verbose)
74
-
75
- def __upload_file (
76
- self,
77
- file: Path,
78
- *,
79
- type: UploadType,
80
- name: str=None,
81
- key: str=None,
82
- data_url_limit: int=None,
83
- verbose: bool=False
84
- ) -> str:
85
- # Check file
86
- assert file.exists(), f"Cannot upload {file.name} because the file does not exist"
87
- assert file.is_file(), f"Cannot upload {file.name} becaause it does not point to a file"
88
- # Create data URL
89
- mime = self.__infer_mime(file)
90
- if file.stat().st_size < (data_url_limit or 0):
91
- with open(file, mode="rb") as f:
92
- buffer = BytesIO(f.read())
93
- return self.__create_data_url(buffer, mime=mime)
94
- # Upload
95
- name = name or file.name
96
- url = self.create_upload_url(name, type, key=key)
97
- with open_progress(file, mode="rb", description=name, disable=not verbose) as f:
98
- put(url, data=f, headers={ "Content-Type": mime }).raise_for_status()
99
- # Return
100
- return self.__simplify_url(url)
101
-
102
- def __upload_buffer (
103
- self,
104
- file: BytesIO,
105
- *,
106
- type: UploadType,
107
- name: str=None,
108
- key: str=None,
109
- data_url_limit: int=None,
110
- verbose: bool=False
111
- ) -> str:
112
- # Check name
113
- assert name, "You must specify the file `name` if the `file` is not a path"
114
- # Create data URL
115
- file.seek(0)
116
- mime = self.__infer_mime(file)
117
- size = file.getbuffer().nbytes
118
- if size < (data_url_limit or 0):
119
- return self.__create_data_url(file, mime=mime)
120
- # Upload
121
- url = self.create_upload_url(name, type, key=key)
122
- with wrap_file(file, total=size, description=name, disable=not verbose) as f:
123
- put(url, data=f, headers={ "Content-Type": mime }).raise_for_status()
124
- # Return
125
- return self.__simplify_url(url)
126
-
127
- def __create_data_url (self, file: BytesIO, *, mime: str) -> str:
128
- encoded_data = b64encode(file.getvalue()).decode("ascii")
129
- url = f"data:{mime};base64,{encoded_data}"
130
- return url
131
-
132
- def __simplify_url (self, url: str) -> str:
133
- if url.startswith("data:"):
134
- return url
135
- parsed_url = urlparse(url)
136
- parsed_url = parsed_url._replace(netloc="cdn.fxn.ai", query="")
137
- url = urlunparse(parsed_url)
138
- return url
139
-
140
- def __infer_mime (self, file: str | Path | BytesIO) -> str:
141
- MAGIC_TO_MIME = {
142
- b"\x00\x61\x73\x6d": "application/wasm"
143
- }
144
- # Read magic
145
- file = Path(file) if isinstance(file, str) else file
146
- if isinstance(file, Path):
147
- with open(file, "rb") as f:
148
- magic = f.read(4)
149
- elif isinstance(file, BytesIO):
150
- magic = file.getvalue()[:4]
151
- # Check known mime
152
- mime = MAGIC_TO_MIME.get(magic)
153
- # Infer
154
- if mime is None:
155
- magika = Magika()
156
- result = magika.identify_bytes(file.getvalue()) if isinstance(file, BytesIO) else magika.identify_path(file)
157
- mime = result.output.mime_type
158
- # Return
159
- return mime
@@ -1,17 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from pydantic import BaseModel, Field
7
-
8
- class EnvironmentVariable (BaseModel):
9
- """
10
- Predictor environment variable.
11
-
12
- Members:
13
- name (str): Variable name.
14
- value (str): Variable value.
15
- """
16
- name: str = Field(description="Variable name.")
17
- value: str = Field(description="Variable value.")
@@ -1,14 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from enum import Enum
7
-
8
- class UploadType (str, Enum):
9
- """
10
- Upload URL type.
11
- """
12
- Media = "MEDIA"
13
- Notebook = "NOTEBOOK"
14
- Value = "VALUE"
@@ -1,28 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from __future__ import annotations
7
- from pydantic import BaseModel, Field
8
-
9
- class Tag (BaseModel):
10
- """
11
- Predictor tag.
12
-
13
- Members:
14
- username (str): Predictor owner username.
15
- name (str): Predictor name.
16
- """
17
- username: str = Field(description="Predictor owner username.")
18
- name: str = Field(description="Predictor name.")
19
-
20
- def from_str (cls, tag: str) -> Tag:
21
- """
22
- Parse a predictor tag from a string.
23
- """
24
- username, name = tag.lower()[1:].split("/")
25
- return Tag(username=username, name=name)
26
-
27
- def __str__ (self):
28
- return f"@{self.username}/{self.name}"
@@ -1,11 +0,0 @@
1
- #
2
- # Function
3
- # Copyright © 2024 NatML Inc. All Rights Reserved.
4
- #
5
-
6
- from .profile import Profile
7
-
8
- class User (Profile):
9
- """
10
- User.
11
- """
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes