arize-phoenix 4.27.0__py3-none-any.whl → 4.28.1__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.

Potentially problematic release.


This version of arize-phoenix might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: arize-phoenix
3
- Version: 4.27.0
3
+ Version: 4.28.1
4
4
  Summary: AI Observability and Evaluation
5
5
  Project-URL: Documentation, https://docs.arize.com/phoenix/
6
6
  Project-URL: Issues, https://github.com/Arize-ai/phoenix/issues
@@ -1,12 +1,12 @@
1
1
  phoenix/__init__.py,sha256=TGNWqm2UW-l67yIRpOtmqGHVAmdoobSNqUsiTtip7uQ,1542
2
- phoenix/auth.py,sha256=N8vTFmc5BEsdX4xr6Bmh6OwBrNUQykr74LuCIkC28jA,1455
2
+ phoenix/auth.py,sha256=ugvGZlseYX9NkpWaSqb8D2kzUBlAPqT45Dx5_VUANqk,1621
3
3
  phoenix/config.py,sha256=wYA_8GSSz5rnpfIWDjeBL9ehKuTy9jqXaMZnxUqRYEU,10131
4
4
  phoenix/datetime_utils.py,sha256=yDKjwX2Vtqw9h5F_ProtP-TsXidM43uIvmJ_pOzYc9A,3405
5
5
  phoenix/exceptions.py,sha256=n2L2KKuecrdflB9MsCdAYCiSEvGJptIsfRkXMoJle7A,169
6
6
  phoenix/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
7
7
  phoenix/services.py,sha256=OyML4t2XGnlqF0JXA9_uccL8HslTABxep9Ci7MViKEU,5216
8
8
  phoenix/settings.py,sha256=cO-qgis_S27nHirTobYI9hHPfZH18R--WMmxNdsVUwc,273
9
- phoenix/version.py,sha256=3tdrXCYXhzGl0HhTFxiRhMv5mTezDVgvqXVYnKeIJeo,23
9
+ phoenix/version.py,sha256=Jx45Ra5pNxAdns6eybNAM7MCr8Ahz7F-CtwNB93XmFE,23
10
10
  phoenix/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  phoenix/core/embedding_dimension.py,sha256=zKGbcvwOXgLf-yrJBpQyKtd-LEOPRKHnUToyAU8Owis,87
12
12
  phoenix/core/model.py,sha256=km_a--PBHOuA337ClRw9xqhOHhrUT6Rl9pz_zV0JYkQ,4843
@@ -69,7 +69,7 @@ phoenix/pointcloud/pointcloud.py,sha256=4zAIkKs2xOUbchpj4XDAV-iPMXrfAJ15TG6rlIYG
69
69
  phoenix/pointcloud/projectors.py,sha256=zO_RrtDYSv2rqVOfIP2_9Cv11Dc8EmcZR94xhFcBYPU,1057
70
70
  phoenix/pointcloud/umap_parameters.py,sha256=3UQSjrysVOvq2V4KNpTMqNqNiK0BsTZnPBHWZ4fyJtQ,1708
71
71
  phoenix/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
- phoenix/server/app.py,sha256=rPzpaEpTSViIP-RLbHzYfxAf7zplKOEbFHxCb40YXFc,26954
72
+ phoenix/server/app.py,sha256=7LiZiusw_yHZBVWMk8gH4tX8yFitTJ2jdyhMWVm2DdM,26817
73
73
  phoenix/server/dml_event.py,sha256=MpjCFqljxvgb9OB5Cez9vJesb3oHb3XxXictynBfcis,2851
74
74
  phoenix/server/dml_event_handler.py,sha256=6p-PucctivelVHfO-_9zNxWZYPr_eGjDF3bKjLtc5co,8251
75
75
  phoenix/server/grpc_server.py,sha256=jllxDNkpLQxDkvej4RhTokobowbvydF-SU8gSw1MTCc,3378
@@ -79,7 +79,7 @@ phoenix/server/telemetry.py,sha256=T_2OKrxNViAeaANlNspEekg_Y5uZIFWvKAnpz8Aoqvk,2
79
79
  phoenix/server/thread_server.py,sha256=RwXQGP_QhGD7le6WB7xEygEEuwBl5Ck_Zo8xGIYGi9M,2135
80
80
  phoenix/server/types.py,sha256=S2dReLNboR2nzjRK5j3MUyUDqu6AQFD7KRwJkeKj1q4,3609
81
81
  phoenix/server/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
- phoenix/server/api/context.py,sha256=N_kqhQIlRyPS6JpN-fgCZ2U4_ZbhaknH-23g5JoRU8g,3282
82
+ phoenix/server/api/context.py,sha256=WuhGT2549C5Yc7pWj2S7NaPeT4a-N-_mmz-Vg5bUkI8,3637
83
83
  phoenix/server/api/interceptor.py,sha256=ykDnoC_apUd-llVli3m1CW18kNSIgjz2qZ6m5JmPDu8,1294
84
84
  phoenix/server/api/queries.py,sha256=GXQzz1KmRqZCOENemdgoqBlTVA_4V2AZE-g0hBcO0Qk,23839
85
85
  phoenix/server/api/schema.py,sha256=BcxdqO5CSGqpKd-AAJHMjFlzaK9oJA8GJuxmMfcdjn4,434
@@ -139,9 +139,10 @@ phoenix/server/api/input_types/TimeRange.py,sha256=yzx-gxj8mDeGLft1FzU_x1MVEgIG5
139
139
  phoenix/server/api/input_types/TraceAnnotationSort.py,sha256=BzwiUnMh2VsgQYnhDlbJ6ljHugqIS4YDUlYzvq_tl3o,365
140
140
  phoenix/server/api/input_types/UserRoleInput.py,sha256=xxhFe0ITZOgRVEJbVem_W6F1Ip_H6xDENdQqMMx-kKE,129
141
141
  phoenix/server/api/input_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
- phoenix/server/api/mutations/__init__.py,sha256=Cu4lPgUFRAGzKO528jKepwKtfre9lkLTN059S2Shmnw,977
142
+ phoenix/server/api/mutations/__init__.py,sha256=JS3WRqYxNeoaLsKjODFvJnZb6CF19IFW-lfOsUq3rtM,1074
143
143
  phoenix/server/api/mutations/api_key_mutations.py,sha256=cv6AT6UAL55lTC_UqMdcN-1TjWAgqqZi__S9Tw12t6I,3688
144
144
  phoenix/server/api/mutations/auth.py,sha256=8o4tTfGCPkpUauuB9ijPH84Od77UX_UrQWfmUsnujI4,524
145
+ phoenix/server/api/mutations/auth_mutations.py,sha256=6--KYnvY3k9JC70Z7iHWhrEa9xKjGH1sW-iOtC13Oxw,2041
145
146
  phoenix/server/api/mutations/dataset_mutations.py,sha256=0feBUW_07FEIx6uzepjxfRVhk5lAck0AkrqS1GVdoF4,27041
146
147
  phoenix/server/api/mutations/experiment_mutations.py,sha256=OXtLYdLA33RGy1MFctfv6ug2sODcDElhJph_J9vkIjk,3157
147
148
  phoenix/server/api/mutations/export_events_mutations.py,sha256=t_wYBxaqvBJYRoHslh3Bmoxmwlzoy0u8SsBKWIKN5hE,4028
@@ -153,7 +154,6 @@ phoenix/server/api/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
153
154
  phoenix/server/api/openapi/main.py,sha256=KNutA_7AvV_WlGX8cOkvvDujcJKQ7AD1HT6rTpCpR8A,616
154
155
  phoenix/server/api/openapi/schema.py,sha256=oVZoflWMfzOrLKMIrjr3iLnJ13rmN-t_DOe9g6KoN5s,471
155
156
  phoenix/server/api/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
- phoenix/server/api/routers/auth.py,sha256=dGug0NjOjW1mmIghmheAgHutG7_0-RjL-FcEReWzTHc,1806
157
157
  phoenix/server/api/routers/utils.py,sha256=M41BoH-fl37izhRuN2aX7lWm7jOC20A_3uClv9TVUUY,583
158
158
  phoenix/server/api/routers/v1/__init__.py,sha256=nb49zcOdAi3DSGuC9gUubN9Yri-o7-WFdlGak4jGuFw,1462
159
159
  phoenix/server/api/routers/v1/datasets.py,sha256=l3Hlc9AVyvX5GdT9iOXBsV-i4c_vtnCaXeSAWdNzcw8,37090
@@ -237,10 +237,10 @@ phoenix/server/static/apple-touch-icon-76x76.png,sha256=CT_xT12I0u2i0WU8JzBZBuOQ
237
237
  phoenix/server/static/apple-touch-icon.png,sha256=fOfpjqGpWYbJ0eAurKsyoZP1EAs6ZVooBJ_SGk2ZkDs,3801
238
238
  phoenix/server/static/favicon.ico,sha256=bY0vvCKRftemZfPShwZtE93DiiQdaYaozkPGwNFr6H8,34494
239
239
  phoenix/server/static/modernizr.js,sha256=mvK-XtkNqjOral-QvzoqsyOMECXIMu5BQwSVN_wcU9c,2564
240
- phoenix/server/static/.vite/manifest.json,sha256=NCacyzu0qbu92qY-iwPA7JHvzK56ZJnp_usNyMD3fZw,1929
241
- phoenix/server/static/assets/components-1MfQimGx.js,sha256=NfJgri_ChJVeYEExpGOvfr5SLFuX_bZcvjfEVGH3HWI,187209
242
- phoenix/server/static/assets/index-B263sE2x.js,sha256=PZG-hlU6oncPYh7r6tfdNm5pjuL94SFLHg4fCyr5Oe8,7515
243
- phoenix/server/static/assets/pages-CqZDVx20.js,sha256=_Lor33vSFj6dZBGvOK4fPt1vXj9pndZFpyyi5BG_8AY,467596
240
+ phoenix/server/static/.vite/manifest.json,sha256=1BcJFFm0NeLAAfZ6r47H6TP_44e5P36X2rORXCQE5e0,1929
241
+ phoenix/server/static/assets/components-BYH03rjA.js,sha256=P4bMCzZcpwxqWV4NaUU4jpmay0GZusDgXbT9t9IUyeM,189918
242
+ phoenix/server/static/assets/index-fqdjNpYm.js,sha256=SDvWOvsXmEJY3350kb2M0bRmC58xw7M3zDZ0MmdneeU,7515
243
+ phoenix/server/static/assets/pages-DnbxgoTK.js,sha256=OLwZw5mVqnO6AelWT6ndr4kDOhf_8l6ezF5buwHBB7E,502087
244
244
  phoenix/server/static/assets/vendor-DxkFTwjz.css,sha256=nZrkr0u6NNElFGvpWHk9GTHeGoibCXCli1bE7mXZGZg,1816
245
245
  phoenix/server/static/assets/vendor-aSQri0vz.js,sha256=x_07SENutKMhtJ9HgFqkQHvwsDTfPkMmzQznY3HY7Zo,1359197
246
246
  phoenix/server/static/assets/vendor-arizeai-CsdcB1NH.js,sha256=VEn7hFJXcHV_DODmeDi9pEpF_D2NQ1bZYewbPe3BhIw,304008
@@ -291,8 +291,8 @@ phoenix/utilities/logging.py,sha256=lDXd6EGaamBNcQxL4vP1au9-i_SXe0OraUDiJOcszSw,
291
291
  phoenix/utilities/project.py,sha256=8IJuMM4yUMoooPi37sictGj8Etu9rGmq6RFtc9848cQ,436
292
292
  phoenix/utilities/re.py,sha256=PDve_OLjRTM8yQQJHC8-n3HdIONi7aNils3ZKRZ5uBM,2045
293
293
  phoenix/utilities/span_store.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
294
- arize_phoenix-4.27.0.dist-info/METADATA,sha256=P6671H1bFkfBHk7FF-1pEwq0_9AoN8zR0RRwVJRqZ2w,11936
295
- arize_phoenix-4.27.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
296
- arize_phoenix-4.27.0.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
297
- arize_phoenix-4.27.0.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
298
- arize_phoenix-4.27.0.dist-info/RECORD,,
294
+ arize_phoenix-4.28.1.dist-info/METADATA,sha256=YRglZu4_XOWN3jc_U8mD8QkVN5m1t6me2zuhNiw5iFk,11936
295
+ arize_phoenix-4.28.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
296
+ arize_phoenix-4.28.1.dist-info/licenses/IP_NOTICE,sha256=JBqyyCYYxGDfzQ0TtsQgjts41IJoa-hiwDrBjCb9gHM,469
297
+ arize_phoenix-4.28.1.dist-info/licenses/LICENSE,sha256=HFkW9REuMOkvKRACuwLPT0hRydHb3zNg-fdFt94td18,3794
298
+ arize_phoenix-4.28.1.dist-info/RECORD,,
phoenix/auth.py CHANGED
@@ -39,7 +39,10 @@ def validate_password_format(password: str) -> None:
39
39
  raise ValueError("Password cannot contain whitespace characters")
40
40
  if not password.isascii():
41
41
  raise ValueError("Password can contain only ASCII characters")
42
+ if not len(password) >= MIN_PASSWORD_LENGTH:
43
+ raise ValueError(f"Password must be at least {MIN_PASSWORD_LENGTH} characters long")
42
44
 
43
45
 
44
46
  EMAIL_PATTERN = re.compile(r"^[^@\s]+@[^@\s]+[.][^@\s]+\Z")
45
47
  NUM_ITERATIONS = 10_000
48
+ MIN_PASSWORD_LENGTH = 4
@@ -2,6 +2,7 @@ from dataclasses import dataclass
2
2
  from pathlib import Path
3
3
  from typing import Any, Optional
4
4
 
5
+ from starlette.responses import Response as StarletteResponse
5
6
  from strawberry.fastapi import BaseContext
6
7
 
7
8
  from phoenix.core.model_schema import Model
@@ -77,7 +78,7 @@ class Context(BaseContext):
77
78
  secret: Optional[str] = None
78
79
 
79
80
  def get_secret(self) -> str:
80
- """A type safe way to get the application secret. Throws an error if the secret is not set.
81
+ """A type-safe way to get the application secret. Throws an error if the secret is not set.
81
82
 
82
83
  Returns:
83
84
  str: the phoenix secret
@@ -88,3 +89,11 @@ class Context(BaseContext):
88
89
  " Please set the PHOENIX_SECRET environment variable and re-deploy the application."
89
90
  )
90
91
  return self.secret
92
+
93
+ def get_response(self) -> StarletteResponse:
94
+ """
95
+ A type-safe way to get the response object. Throws an error if the response is not set.
96
+ """
97
+ if (response := self.response) is None:
98
+ raise ValueError("no response is set")
99
+ return response
@@ -1,6 +1,7 @@
1
1
  import strawberry
2
2
 
3
3
  from phoenix.server.api.mutations.api_key_mutations import ApiKeyMutationMixin
4
+ from phoenix.server.api.mutations.auth_mutations import AuthMutationMixin
4
5
  from phoenix.server.api.mutations.dataset_mutations import DatasetMutationMixin
5
6
  from phoenix.server.api.mutations.experiment_mutations import ExperimentMutationMixin
6
7
  from phoenix.server.api.mutations.export_events_mutations import ExportEventsMutationMixin
@@ -12,13 +13,14 @@ from phoenix.server.api.mutations.user_mutations import UserMutationMixin
12
13
 
13
14
  @strawberry.type
14
15
  class Mutation(
15
- ProjectMutationMixin,
16
+ ApiKeyMutationMixin,
17
+ AuthMutationMixin,
16
18
  DatasetMutationMixin,
17
19
  ExperimentMutationMixin,
18
20
  ExportEventsMutationMixin,
21
+ ProjectMutationMixin,
19
22
  SpanAnnotationMutationMixin,
20
23
  TraceAnnotationMutationMixin,
21
- ApiKeyMutationMixin,
22
24
  UserMutationMixin,
23
25
  ):
24
26
  pass
@@ -0,0 +1,63 @@
1
+ import asyncio
2
+ from datetime import timedelta
3
+
4
+ import strawberry
5
+ from sqlalchemy import select
6
+ from strawberry.types import Info
7
+
8
+ from phoenix.auth import is_valid_password
9
+ from phoenix.db import models
10
+ from phoenix.server.api.context import Context
11
+ from phoenix.server.api.mutations.auth import HasSecret
12
+
13
+ PHOENIX_ACCESS_TOKEN_COOKIE_NAME = "phoenix-access-token"
14
+ PHOENIX_ACCESS_TOKEN_COOKIE_MAX_AGE_IN_SECONDS = int(timedelta(days=31).total_seconds())
15
+
16
+
17
+ @strawberry.input
18
+ class LoginMutationInput:
19
+ email: str
20
+ password: str
21
+
22
+
23
+ @strawberry.type
24
+ class AuthMutationMixin:
25
+ @strawberry.mutation(permission_classes=[HasSecret]) # type: ignore
26
+ async def login(
27
+ self,
28
+ info: Info[Context, None],
29
+ input: LoginMutationInput,
30
+ ) -> None:
31
+ async with info.context.db() as session:
32
+ if (
33
+ user := await session.scalar(
34
+ select(models.User).where(models.User.email == input.email)
35
+ )
36
+ ) is None or (password_hash := user.password_hash) is None:
37
+ raise ValueError
38
+ secret = info.context.get_secret()
39
+ loop = asyncio.get_running_loop()
40
+ if not await loop.run_in_executor(
41
+ executor=None,
42
+ func=lambda: is_valid_password(
43
+ password=input.password, salt=secret, password_hash=password_hash
44
+ ),
45
+ ):
46
+ raise ValueError
47
+ response = info.context.get_response()
48
+ response.set_cookie(
49
+ key=PHOENIX_ACCESS_TOKEN_COOKIE_NAME,
50
+ value="token", # todo: compute access token
51
+ secure=True,
52
+ httponly=True,
53
+ samesite="strict",
54
+ max_age=PHOENIX_ACCESS_TOKEN_COOKIE_MAX_AGE_IN_SECONDS,
55
+ )
56
+
57
+ @strawberry.mutation(permission_classes=[HasSecret]) # type: ignore
58
+ async def logout(
59
+ self,
60
+ info: Info[Context, None],
61
+ ) -> None:
62
+ response = info.context.get_response()
63
+ response.delete_cookie(key=PHOENIX_ACCESS_TOKEN_COOKIE_NAME)
phoenix/server/app.py CHANGED
@@ -79,7 +79,6 @@ from phoenix.server.api.dataloaders import (
79
79
  TokenCountDataLoader,
80
80
  TraceRowIdsDataLoader,
81
81
  )
82
- from phoenix.server.api.routers.auth import router as auth_router
83
82
  from phoenix.server.api.routers.v1 import REST_API_VERSION
84
83
  from phoenix.server.api.routers.v1 import router as v1_router
85
84
  from phoenix.server.api.schema import schema
@@ -662,8 +661,6 @@ def create_app(
662
661
  app.include_router(router)
663
662
  app.include_router(graphql_router)
664
663
  app.add_middleware(GZipMiddleware)
665
- if authentication_enabled:
666
- app.include_router(auth_router)
667
664
  if serve_ui:
668
665
  app.mount(
669
666
  "/",
@@ -1,21 +1,21 @@
1
1
  {
2
- "_components-1MfQimGx.js": {
3
- "file": "assets/components-1MfQimGx.js",
2
+ "_components-BYH03rjA.js": {
3
+ "file": "assets/components-BYH03rjA.js",
4
4
  "name": "components",
5
5
  "imports": [
6
6
  "_vendor-aSQri0vz.js",
7
7
  "_vendor-arizeai-CsdcB1NH.js",
8
- "_pages-CqZDVx20.js",
8
+ "_pages-DnbxgoTK.js",
9
9
  "_vendor-three-DwGkEfCM.js",
10
10
  "_vendor-codemirror-CYHkhs7D.js"
11
11
  ]
12
12
  },
13
- "_pages-CqZDVx20.js": {
14
- "file": "assets/pages-CqZDVx20.js",
13
+ "_pages-DnbxgoTK.js": {
14
+ "file": "assets/pages-DnbxgoTK.js",
15
15
  "name": "pages",
16
16
  "imports": [
17
17
  "_vendor-aSQri0vz.js",
18
- "_components-1MfQimGx.js",
18
+ "_components-BYH03rjA.js",
19
19
  "_vendor-arizeai-CsdcB1NH.js",
20
20
  "_vendor-recharts-B0sannek.js",
21
21
  "_vendor-codemirror-CYHkhs7D.js"
@@ -61,15 +61,15 @@
61
61
  "name": "vendor-three"
62
62
  },
63
63
  "index.tsx": {
64
- "file": "assets/index-B263sE2x.js",
64
+ "file": "assets/index-fqdjNpYm.js",
65
65
  "name": "index",
66
66
  "src": "index.tsx",
67
67
  "isEntry": true,
68
68
  "imports": [
69
69
  "_vendor-aSQri0vz.js",
70
70
  "_vendor-arizeai-CsdcB1NH.js",
71
- "_pages-CqZDVx20.js",
72
- "_components-1MfQimGx.js",
71
+ "_pages-DnbxgoTK.js",
72
+ "_components-BYH03rjA.js",
73
73
  "_vendor-three-DwGkEfCM.js",
74
74
  "_vendor-recharts-B0sannek.js",
75
75
  "_vendor-codemirror-CYHkhs7D.js"