fxn 0.0.36__py3-none-any.whl → 0.0.37__py3-none-any.whl

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.
fxn/cli/misc.py CHANGED
@@ -9,18 +9,24 @@ from webbrowser import open as open_browser
9
9
 
10
10
  from ..version import __version__
11
11
 
12
- def _learn_callback (value: bool):
12
+ def _explore (value: bool):
13
+ if value:
14
+ open_browser("https://fxn.ai/explore")
15
+ raise Exit()
16
+
17
+ def _learn (value: bool):
13
18
  if value:
14
19
  open_browser("https://docs.fxn.ai")
15
20
  raise Exit()
16
21
 
17
- def _version_callback (value: bool):
22
+ def _version (value: bool):
18
23
  if value:
19
24
  print(__version__)
20
25
  raise Exit()
21
26
 
22
27
  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.")
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.")
25
31
  ):
26
32
  pass
fxn/function.py CHANGED
@@ -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)
fxn/services/__init__.py CHANGED
@@ -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
fxn/services/predictor.py CHANGED
@@ -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
  """
fxn/version.py CHANGED
@@ -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.37"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fxn
3
- Version: 0.0.36
3
+ Version: 0.0.37
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
@@ -1,7 +1,6 @@
1
1
  fxn/__init__.py,sha256=tWk0-aCNHX_yCS-Dg90pYnniNka9MWFoNMk6xY7u4nI,157
2
- fxn/function.py,sha256=NBEH37NX6GFj6pf3nBja8xeYb1IoKCPiE4Sxwpwj-mM,1452
3
- fxn/magic.py,sha256=PQmXhO9EvJ5EZylioV-6gsCvqhVRYscKBSOBoN4VhTk,1041
4
- fxn/version.py,sha256=BiY9-f6E3ZNjYc2X4h8op-HBbBeHAEepyx3H_ePXT58,95
2
+ fxn/function.py,sha256=W_JkTk3KAMpFGqh95yO-Iy4AvFU22UJZkRt15dyf3IY,1187
3
+ fxn/version.py,sha256=wjJZ4T4vd1dYpP5qvR3wfnAkWkgGYwz6yi2XeM2_KCY,95
5
4
  fxn/api/__init__.py,sha256=rJIDBhYg5jcrWO4hT4-CpwPq6dSgmLTEHCfUYTLpVaI,103
6
5
  fxn/api/client.py,sha256=WCNsebcuwIlP9W5k_8AQCpxOCcy7cpbengfu2rIkGmc,1192
7
6
  fxn/c/__init__.py,sha256=qBnS4_eoBe5biKoyhW0Fsfr3cqJ9SAvzmm-XB56ev0A,438
@@ -18,7 +17,7 @@ fxn/c/version.py,sha256=fnV14LTAXSl6Q03YFIWOINOUrs0DJpyBOcwP5VZvLFc,282
18
17
  fxn/cli/__init__.py,sha256=c9qBvRTHSWnO-8Ny431RlkZWznF7sShJfHYfjBazjRk,1481
19
18
  fxn/cli/auth.py,sha256=tMjgNA6AQeom3I5AsgPvWvN62cM3nFGBcjjXB7x4s8U,1688
20
19
  fxn/cli/env.py,sha256=shqoP4tUiXdOoil73oiUYpqGeVcR119HPYFKgnoF894,1553
21
- fxn/cli/misc.py,sha256=J3WgNjrxRzm-_iKC3Cp0o4VHeBYBQ1ta_t2-ozD9roo,662
20
+ fxn/cli/misc.py,sha256=6zYuuF1pm1LzYkHG4YaSnBxzs7h8CReI6YLk1ysGRso,843
22
21
  fxn/cli/predict.py,sha256=hpd1VZtw1OBNkZwePCFtyTHLSDOzc8fuSODGmvmmG1E,3026
23
22
  fxn/cli/predictors.py,sha256=SSvxf5emr_upcU78vhdB2F9PM351YdP2a1bqf8FRaxE,2248
24
23
  fxn/lib/__init__.py,sha256=c_q01PLV3Mi-qV0_HVbNRHOI2TIUr_cDIJHvCASsYZk,71
@@ -26,11 +25,9 @@ fxn/lib/macos/arm64/Function.dylib,sha256=N-ewU2AXqgVAsYPpEnlWU09uyxLAywtsL0ous4
26
25
  fxn/lib/macos/x86_64/Function.dylib,sha256=DfoGF8v-lvxo8a10QUZ0egbfQZo6B6tNct5NMV1kpYc,269744
27
26
  fxn/lib/windows/arm64/Function.dll,sha256=kvixEsiKalAqMOyCRpcAcFgkXxK_9Vt-WDQgws5M6Xg,425472
28
27
  fxn/lib/windows/x86_64/Function.dll,sha256=lEHVER_6PQUqJHDd6YWMqZ2X6PLnJTmVa68cUgp5lJ8,450560
29
- fxn/services/__init__.py,sha256=OTBRL_wH94hc_scZgRd42VrJQfldNLjv4APN4YaWBAw,366
30
- fxn/services/environment.py,sha256=ITodddygFR9Kw8cdSh3vtTcTpUmUIsTFGpHnqx2RMVo,3714
28
+ fxn/services/__init__.py,sha256=TZBB8xekhfA_Z1Jh68m_GScjXYsLGdx9MlCrjF9Ojsc,249
31
29
  fxn/services/prediction.py,sha256=EfjnwF_GEKSifClzsBWBuKe-NeSk9CeAMQAYDT0lF9A,20228
32
- fxn/services/predictor.py,sha256=yhrg5msrfVsIomPB1jlOa0z7jVGTDZIdvBnB-OYiQdk,5163
33
- fxn/services/storage.py,sha256=qGijBsfdGWQAumNAOYL6-SfSkrvYDuCK12FevdJl4cM,5480
30
+ fxn/services/predictor.py,sha256=0FOrnGJo0Z0IqpY5exe7laHFXTbA6NXmWLeu8zioEJ0,5071
34
31
  fxn/services/user.py,sha256=niExZwZFl_hlgLTz9lvrU3QrVR8oKdMcm623wyQK-cA,1217
35
32
  fxn/types/__init__.py,sha256=GY7ST0Ue_sh4rB3a4MHkvql_Cn0p9qZ4wlf3luPOwk8,398
36
33
  fxn/types/dtype.py,sha256=YpTnIG-yzrQwda27GzfGZcel-zF3gOMMoHhcWD915BY,617
@@ -41,9 +38,9 @@ fxn/types/profile.py,sha256=1KWqPusKieCIcw4KSS2sScpwP0Z-mU4ThMYOZRxZ_68,1123
41
38
  fxn/types/storage.py,sha256=AtVKR3CtHzvSWLiJS_bbUyIA2Of_IKZVeL5_1PqqrQ0,228
42
39
  fxn/types/tag.py,sha256=hWzSDCo8VjRHjS5ZLuFi3xVo8cuCNaNeULQ2mHEuwzM,707
43
40
  fxn/types/user.py,sha256=_hc1YQh0WydniAurywA70EDs4VCY5rnGRYSiRc97Ab0,150
44
- fxn-0.0.36.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
45
- fxn-0.0.36.dist-info/METADATA,sha256=Hk1xVRWsEy87RvJrvIFY9zSetdg_Ms5iTOfxYgh4Bho,16068
46
- fxn-0.0.36.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
47
- fxn-0.0.36.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
48
- fxn-0.0.36.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
49
- fxn-0.0.36.dist-info/RECORD,,
41
+ fxn-0.0.37.dist-info/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
42
+ fxn-0.0.37.dist-info/METADATA,sha256=3-Jhz_avkErQguXTzBGED3_slasVTUI2aH48tFrjl_Y,16068
43
+ fxn-0.0.37.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
44
+ fxn-0.0.37.dist-info/entry_points.txt,sha256=O_AwD5dYaeB-YT1F9hPAPuDYCkw_W0tdNGYbc5RVR2k,45
45
+ fxn-0.0.37.dist-info/top_level.txt,sha256=1ULIEGrnMlhId8nYAkjmRn9g3KEFuHKboq193SEKQkA,4
46
+ fxn-0.0.37.dist-info/RECORD,,
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
- """
fxn/services/storage.py DELETED
@@ -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
File without changes
File without changes