cognite-toolkit 0.7.49__py3-none-any.whl → 0.7.50__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.
- cognite_toolkit/_cdf_tk/builders/_function.py +81 -9
- cognite_toolkit/_cdf_tk/client/{resource_classes/base.py → _resource_base.py} +24 -9
- cognite_toolkit/_cdf_tk/client/cdf_client/api.py +23 -24
- cognite_toolkit/_cdf_tk/client/http_client/__init__.py +5 -3
- cognite_toolkit/_cdf_tk/client/http_client/_client.py +4 -2
- cognite_toolkit/_cdf_tk/client/http_client/_data_classes2.py +1 -106
- cognite_toolkit/_cdf_tk/client/http_client/_item_classes.py +118 -0
- cognite_toolkit/_cdf_tk/client/resource_classes/agent.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/annotation.py +2 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/apm_config.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/asset.py +2 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/charts_data.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/cognite_file.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_constraints.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_container.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_data_model.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_data_types.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_indexes.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_instance.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_space.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_view.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/data_modeling/_view_property.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/dataset.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/event.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/extraction_pipeline.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/filemetadata.py +2 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/function.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/function_schedule.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/graphql_data_model.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/group/acls.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/group/capability.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/group/group.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/group/scopes.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_destination.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_job.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_mapping.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_auth.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_base.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_certificate.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_eventhub.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_kafka.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_mqtt.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/hosted_extractor_source/_rest.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/identifiers.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/infield.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/instance_api.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/label.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/location_filter.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/raw.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/relationship.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/resource_view_mapping.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_capability.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_common.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_data_post_processing.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_frame.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_location.py +2 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_map.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/robotics/_robot.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/search_config.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/securitycategory.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/sequence.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/sequence_rows.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/simulator_model.py +2 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/streamlit_.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/streams.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/three_d.py +9 -2
- cognite_toolkit/_cdf_tk/client/resource_classes/timeseries.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/transformation.py +3 -3
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow_trigger.py +1 -1
- cognite_toolkit/_cdf_tk/client/resource_classes/workflow_version.py +1 -1
- cognite_toolkit/_cdf_tk/commands/_migrate/data_classes.py +1 -1
- cognite_toolkit/_cdf_tk/commands/build_cmd.py +11 -1
- cognite_toolkit/_cdf_tk/data_classes/_tracking_info.py +4 -0
- cognite_toolkit/_cdf_tk/feature_flags.py +4 -0
- cognite_toolkit/_cdf_tk/tk_warnings/__init__.py +2 -0
- cognite_toolkit/_cdf_tk/tk_warnings/fileread.py +20 -0
- cognite_toolkit/_cdf_tk/utils/__init__.py +3 -0
- cognite_toolkit/_cdf_tk/utils/pip_validator.py +96 -0
- cognite_toolkit/_repo_files/GitHub/.github/workflows/deploy.yaml +1 -1
- cognite_toolkit/_repo_files/GitHub/.github/workflows/dry-run.yaml +1 -1
- cognite_toolkit/_resources/cdf.toml +1 -1
- cognite_toolkit/_version.py +1 -1
- {cognite_toolkit-0.7.49.dist-info → cognite_toolkit-0.7.50.dist-info}/METADATA +1 -1
- {cognite_toolkit-0.7.49.dist-info → cognite_toolkit-0.7.50.dist-info}/RECORD +87 -85
- {cognite_toolkit-0.7.49.dist-info → cognite_toolkit-0.7.50.dist-info}/WHEEL +0 -0
- {cognite_toolkit-0.7.49.dist-info → cognite_toolkit-0.7.50.dist-info}/entry_points.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Any, ClassVar, Literal
|
|
2
2
|
|
|
3
|
-
from cognite_toolkit._cdf_tk.client.
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
4
4
|
BaseModelObject,
|
|
5
|
-
RequestUpdateable,
|
|
6
5
|
ResponseResource,
|
|
6
|
+
UpdatableRequestResource,
|
|
7
7
|
)
|
|
8
8
|
from cognite_toolkit._cdf_tk.client.resource_classes.identifiers import DataSetId
|
|
9
9
|
|
|
@@ -36,7 +36,7 @@ class Robot(BaseModelObject):
|
|
|
36
36
|
return DataSetId(data_set_id=self.data_set_id)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
class RobotRequest(Robot,
|
|
39
|
+
class RobotRequest(Robot, UpdatableRequestResource):
|
|
40
40
|
"""Request resource for creating or updating a Robot."""
|
|
41
41
|
|
|
42
42
|
container_fields: ClassVar[frozenset[str]] = frozenset({"metadata"})
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import ClassVar, Literal
|
|
2
2
|
|
|
3
|
-
from cognite_toolkit._cdf_tk.client.
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
4
4
|
BaseModelObject,
|
|
5
|
-
RequestUpdateable,
|
|
6
5
|
ResponseResource,
|
|
6
|
+
UpdatableRequestResource,
|
|
7
7
|
)
|
|
8
8
|
|
|
9
9
|
from .identifiers import ExternalId
|
|
@@ -32,7 +32,7 @@ class Sequence(BaseModelObject):
|
|
|
32
32
|
return ExternalId(external_id=self.external_id)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class SequenceRequest(Sequence,
|
|
35
|
+
class SequenceRequest(Sequence, UpdatableRequestResource):
|
|
36
36
|
container_fields: ClassVar[frozenset[str]] = frozenset({"metadata", "columns"})
|
|
37
37
|
|
|
38
38
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Literal
|
|
2
2
|
|
|
3
|
-
from cognite_toolkit._cdf_tk.client.
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import BaseModelObject, RequestResource, ResponseResource
|
|
4
4
|
|
|
5
5
|
from .identifiers import ExternalId
|
|
6
6
|
|
|
@@ -2,12 +2,12 @@ from typing import Any, Literal
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field
|
|
4
4
|
|
|
5
|
-
from cognite_toolkit._cdf_tk.client.
|
|
5
|
+
from cognite_toolkit._cdf_tk.client._resource_base import ResponseResource, UpdatableRequestResource
|
|
6
6
|
|
|
7
7
|
from .identifiers import ExternalId
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class SimulatorModelRequest(
|
|
10
|
+
class SimulatorModelRequest(UpdatableRequestResource):
|
|
11
11
|
# The 'id' field is not part of the request when creating a new resource,
|
|
12
12
|
# but is needed when updating an existing resource.
|
|
13
13
|
id: int | None = Field(default=None, exclude=True)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Any, Literal
|
|
2
2
|
|
|
3
|
-
from cognite_toolkit._cdf_tk.client.
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
4
4
|
BaseModelObject,
|
|
5
|
-
RequestUpdateable,
|
|
6
5
|
ResponseResource,
|
|
6
|
+
UpdatableRequestResource,
|
|
7
7
|
)
|
|
8
8
|
|
|
9
9
|
from .filemetadata import FileMetadataRequest
|
|
@@ -25,7 +25,7 @@ class StreamlitFile(BaseModelObject):
|
|
|
25
25
|
cognite_toolkit_app_hash: str | None = None
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
class StreamlitRequest(StreamlitFile,
|
|
28
|
+
class StreamlitRequest(StreamlitFile, UpdatableRequestResource):
|
|
29
29
|
"""Request resource for creating/updating Streamlit apps."""
|
|
30
30
|
|
|
31
31
|
def as_id(self) -> ExternalId:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from typing import Literal
|
|
2
2
|
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import BaseModelObject, RequestResource, ResponseResource
|
|
3
4
|
from cognite_toolkit._cdf_tk.constants import StreamTemplateName
|
|
4
5
|
|
|
5
|
-
from .base import BaseModelObject, RequestResource, ResponseResource
|
|
6
6
|
from .identifiers import ExternalId
|
|
7
7
|
|
|
8
8
|
|
|
@@ -3,7 +3,14 @@ from typing import ClassVar, Literal
|
|
|
3
3
|
|
|
4
4
|
from pydantic import Field
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
7
|
+
BaseModelObject,
|
|
8
|
+
Identifier,
|
|
9
|
+
RequestResource,
|
|
10
|
+
ResponseResource,
|
|
11
|
+
UpdatableRequestResource,
|
|
12
|
+
)
|
|
13
|
+
|
|
7
14
|
from .identifiers import InternalId
|
|
8
15
|
from .instance_api import NodeReference
|
|
9
16
|
|
|
@@ -33,7 +40,7 @@ class ThreeDModelRequest(RequestResource):
|
|
|
33
40
|
return InternalId(id=self.id)
|
|
34
41
|
|
|
35
42
|
|
|
36
|
-
class ThreeDModelClassicRequest(ThreeDModelRequest,
|
|
43
|
+
class ThreeDModelClassicRequest(ThreeDModelRequest, UpdatableRequestResource):
|
|
37
44
|
container_fields: ClassVar[frozenset[str]] = frozenset({"metadata"})
|
|
38
45
|
data_set_id: int | None = None
|
|
39
46
|
metadata: dict[str, str] | None = None
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
from typing import Any, ClassVar, Literal
|
|
2
2
|
|
|
3
|
-
from cognite_toolkit._cdf_tk.client.
|
|
3
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
4
4
|
BaseModelObject,
|
|
5
|
-
RequestUpdateable,
|
|
6
5
|
ResponseResource,
|
|
6
|
+
UpdatableRequestResource,
|
|
7
7
|
)
|
|
8
8
|
|
|
9
9
|
from .identifiers import ExternalId, InternalOrExternalId
|
|
@@ -29,7 +29,7 @@ class TimeSeries(BaseModelObject):
|
|
|
29
29
|
return ExternalId(external_id=self.external_id)
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
class TimeSeriesRequest(TimeSeries,
|
|
32
|
+
class TimeSeriesRequest(TimeSeries, UpdatableRequestResource):
|
|
33
33
|
container_fields: ClassVar[frozenset[str]] = frozenset({"metadata", "security_categories"})
|
|
34
34
|
non_nullable_fields: ClassVar[frozenset[str]] = frozenset({"is_step"})
|
|
35
35
|
|
|
@@ -2,10 +2,10 @@ from typing import Annotated, ClassVar, Literal
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field, JsonValue
|
|
4
4
|
|
|
5
|
-
from cognite_toolkit._cdf_tk.client.
|
|
5
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
6
6
|
BaseModelObject,
|
|
7
|
-
RequestUpdateable,
|
|
8
7
|
ResponseResource,
|
|
8
|
+
UpdatableRequestResource,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
11
|
from .identifiers import ExternalId
|
|
@@ -106,7 +106,7 @@ class Transformation(BaseModelObject):
|
|
|
106
106
|
return ExternalId(external_id=self.external_id)
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
class TransformationRequest(Transformation,
|
|
109
|
+
class TransformationRequest(Transformation, UpdatableRequestResource):
|
|
110
110
|
container_fields: ClassVar[frozenset[str]] = frozenset({"tags"})
|
|
111
111
|
non_nullable_fields: ClassVar[frozenset[str]] = frozenset({"is_public", "query", "destination"})
|
|
112
112
|
query: str | None = None
|
|
@@ -2,7 +2,7 @@ from typing import Annotated, Literal
|
|
|
2
2
|
|
|
3
3
|
from pydantic import Field, JsonValue
|
|
4
4
|
|
|
5
|
-
from cognite_toolkit._cdf_tk.client.
|
|
5
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
6
6
|
BaseModelObject,
|
|
7
7
|
RequestResource,
|
|
8
8
|
ResponseResource,
|
|
@@ -3,7 +3,7 @@ from typing import Annotated, Any, Literal
|
|
|
3
3
|
from pydantic import Field, JsonValue, field_validator
|
|
4
4
|
from pydantic_core.core_schema import ValidationInfo
|
|
5
5
|
|
|
6
|
-
from cognite_toolkit._cdf_tk.client.
|
|
6
|
+
from cognite_toolkit._cdf_tk.client._resource_base import (
|
|
7
7
|
BaseModelObject,
|
|
8
8
|
RequestResource,
|
|
9
9
|
ResponseResource,
|
|
@@ -11,7 +11,7 @@ from cognite.client.utils._identifier import InstanceId
|
|
|
11
11
|
from cognite.client.utils._text import to_camel_case
|
|
12
12
|
from pydantic import BaseModel, BeforeValidator, Field, field_validator, model_validator
|
|
13
13
|
|
|
14
|
-
from cognite_toolkit._cdf_tk.client.
|
|
14
|
+
from cognite_toolkit._cdf_tk.client._resource_base import BaseModelObject, RequestResource
|
|
15
15
|
from cognite_toolkit._cdf_tk.client.resource_classes.identifiers import InternalId
|
|
16
16
|
from cognite_toolkit._cdf_tk.client.resource_classes.instance_api import InstanceIdentifier
|
|
17
17
|
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.instances import InstanceApplyList
|
|
@@ -11,7 +11,7 @@ from rich import print
|
|
|
11
11
|
from rich.panel import Panel
|
|
12
12
|
from rich.progress import track
|
|
13
13
|
|
|
14
|
-
from cognite_toolkit._cdf_tk.builders import Builder, create_builder
|
|
14
|
+
from cognite_toolkit._cdf_tk.builders import Builder, FunctionBuilder, create_builder
|
|
15
15
|
from cognite_toolkit._cdf_tk.cdf_toml import CDFToml
|
|
16
16
|
from cognite_toolkit._cdf_tk.client import ToolkitClient
|
|
17
17
|
from cognite_toolkit._cdf_tk.client.resource_classes.legacy.raw import RawDatabase
|
|
@@ -33,6 +33,7 @@ from cognite_toolkit._cdf_tk.cruds import (
|
|
|
33
33
|
DataSetsCRUD,
|
|
34
34
|
ExtractionPipelineConfigCRUD,
|
|
35
35
|
FileCRUD,
|
|
36
|
+
FunctionCRUD,
|
|
36
37
|
LocationFilterCRUD,
|
|
37
38
|
NodeCRUD,
|
|
38
39
|
RawDatabaseCRUD,
|
|
@@ -415,6 +416,15 @@ class BuildCommand(ToolkitCommand):
|
|
|
415
416
|
|
|
416
417
|
build_resources_by_folder[resource_name].extend(built_resources)
|
|
417
418
|
|
|
419
|
+
# Collect validation metrics from FunctionBuilder
|
|
420
|
+
if resource_name == FunctionCRUD.folder_name and isinstance(builder, FunctionBuilder):
|
|
421
|
+
self._additional_tracking_info.function_validation_count += builder.validation_count
|
|
422
|
+
self._additional_tracking_info.function_validation_failures += builder.validation_failures
|
|
423
|
+
self._additional_tracking_info.function_validation_credential_errors += (
|
|
424
|
+
builder.validation_credential_errors
|
|
425
|
+
)
|
|
426
|
+
self._additional_tracking_info.function_validation_time_ms += builder.validation_time_ms
|
|
427
|
+
|
|
418
428
|
return build_resources_by_folder
|
|
419
429
|
|
|
420
430
|
def _get_builder(self, build_dir: Path, resource_name: str) -> Builder:
|
|
@@ -32,6 +32,10 @@ class CommandTrackingInfo(BaseModel):
|
|
|
32
32
|
downloaded_library_ids: set[str] = Field(default_factory=set, alias="downloadedLibraryIds")
|
|
33
33
|
downloaded_package_ids: set[str] = Field(default_factory=set, alias="downloadedPackageIds")
|
|
34
34
|
downloaded_module_ids: set[str] = Field(default_factory=set, alias="downloadedModuleIds")
|
|
35
|
+
function_validation_count: int = Field(default=0, alias="functionValidationCount")
|
|
36
|
+
function_validation_failures: int = Field(default=0, alias="functionValidationFailures")
|
|
37
|
+
function_validation_credential_errors: int = Field(default=0, alias="functionValidationCredentialErrors")
|
|
38
|
+
function_validation_time_ms: int = Field(default=0, alias="functionValidationTimeMs")
|
|
35
39
|
|
|
36
40
|
def to_dict(self) -> dict[str, Any]:
|
|
37
41
|
"""Convert the tracking info to a dictionary for Mixpanel.
|
|
@@ -65,6 +65,10 @@ class Flags(Enum):
|
|
|
65
65
|
visible=True,
|
|
66
66
|
description="Enables the support for simulator model resources",
|
|
67
67
|
)
|
|
68
|
+
FUNCTION_REQUIREMENTS_VALIDATION = FlagMetadata(
|
|
69
|
+
visible=True,
|
|
70
|
+
description="Enables validation of function requirements.txt during build using pip dry-run",
|
|
71
|
+
)
|
|
68
72
|
|
|
69
73
|
def is_enabled(self) -> bool:
|
|
70
74
|
return FeatureFlag.is_enabled(self)
|
|
@@ -12,6 +12,7 @@ from .fileread import (
|
|
|
12
12
|
EnvironmentVariableMissingWarning,
|
|
13
13
|
FileExistsWarning,
|
|
14
14
|
FileReadWarning,
|
|
15
|
+
FunctionRequirementsValidationWarning,
|
|
15
16
|
MissingFileWarning,
|
|
16
17
|
MissingReferencedWarning,
|
|
17
18
|
MissingRequiredParameterWarning,
|
|
@@ -51,6 +52,7 @@ __all__ = [
|
|
|
51
52
|
"EnvironmentVariableMissingWarning",
|
|
52
53
|
"FileExistsWarning",
|
|
53
54
|
"FileReadWarning",
|
|
55
|
+
"FunctionRequirementsValidationWarning",
|
|
54
56
|
"GeneralWarning",
|
|
55
57
|
"HTTPWarning",
|
|
56
58
|
"HighSeverityWarning",
|
|
@@ -270,6 +270,26 @@ class StreamlitRequirementsWarning(FileReadWarning):
|
|
|
270
270
|
return f"Missing dependencies in requirements.txt: {', '.join(self.dependencies)}"
|
|
271
271
|
|
|
272
272
|
|
|
273
|
+
@dataclass(frozen=True)
|
|
274
|
+
class FunctionRequirementsValidationWarning(FileReadWarning):
|
|
275
|
+
severity: ClassVar[SeverityLevel] = SeverityLevel.HIGH
|
|
276
|
+
function_external_id: str
|
|
277
|
+
error_details: str
|
|
278
|
+
is_credential_error: bool
|
|
279
|
+
|
|
280
|
+
def get_message(self) -> str:
|
|
281
|
+
message = (
|
|
282
|
+
f"Function [bold]{self.function_external_id}[/bold] requirements.txt validation failed. "
|
|
283
|
+
f"Packages could not be resolved: {self.error_details}"
|
|
284
|
+
)
|
|
285
|
+
if self.is_credential_error:
|
|
286
|
+
message += (
|
|
287
|
+
f"\n{HINT_LEAD_TEXT}This appears to be a credential/authentication issue. "
|
|
288
|
+
"Check if the Personal Access Token (PAT) or credentials in indexUrl are valid and not expired."
|
|
289
|
+
)
|
|
290
|
+
return message
|
|
291
|
+
|
|
292
|
+
|
|
273
293
|
@dataclass(frozen=True)
|
|
274
294
|
class ResourceFormatWarning(FileReadWarning):
|
|
275
295
|
severity: ClassVar[SeverityLevel] = SeverityLevel.HIGH
|
|
@@ -26,10 +26,12 @@ from .modules import (
|
|
|
26
26
|
module_path_display_name,
|
|
27
27
|
resource_folder_from_path,
|
|
28
28
|
)
|
|
29
|
+
from .pip_validator import PipValidationResult, validate_requirements_with_pip
|
|
29
30
|
from .sentry_utils import sentry_exception_filter
|
|
30
31
|
|
|
31
32
|
__all__ = [
|
|
32
33
|
"GraphQLParser",
|
|
34
|
+
"PipValidationResult",
|
|
33
35
|
"YAMLComment",
|
|
34
36
|
"YAMLWithComments",
|
|
35
37
|
"calculate_directory_hash",
|
|
@@ -57,4 +59,5 @@ __all__ = [
|
|
|
57
59
|
"stringify_value_by_key_in_yaml",
|
|
58
60
|
"tmp_build_directory",
|
|
59
61
|
"to_diff",
|
|
62
|
+
"validate_requirements_with_pip",
|
|
60
63
|
]
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Utilities for validating Python package requirements."""
|
|
2
|
+
|
|
3
|
+
import subprocess
|
|
4
|
+
import sys
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
# Maximum number of error lines to include in warnings
|
|
9
|
+
_MAX_ERROR_LINES = 3
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PipValidationResult:
|
|
14
|
+
"""Result from validating a requirements.txt file."""
|
|
15
|
+
|
|
16
|
+
error_message: str | None = None
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def success(self) -> bool:
|
|
20
|
+
"""Validation succeeded if there's no error message."""
|
|
21
|
+
return self.error_message is None
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def is_credential_error(self) -> bool:
|
|
25
|
+
"""Check if the error appears to be related to authentication/credentials.
|
|
26
|
+
|
|
27
|
+
Only checks for explicit HTTP authentication errors to avoid false positives
|
|
28
|
+
from legitimate package not found errors.
|
|
29
|
+
"""
|
|
30
|
+
if not self.error_message:
|
|
31
|
+
return False
|
|
32
|
+
credential_indicators = [
|
|
33
|
+
"401",
|
|
34
|
+
"403",
|
|
35
|
+
"Unauthorized",
|
|
36
|
+
"Forbidden",
|
|
37
|
+
"Authentication",
|
|
38
|
+
]
|
|
39
|
+
return any(indicator in self.error_message for indicator in credential_indicators)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def validate_requirements_with_pip(
|
|
43
|
+
requirements_txt_path: Path,
|
|
44
|
+
index_url: str | None = None,
|
|
45
|
+
extra_index_urls: list[str] | None = None,
|
|
46
|
+
timeout: int = 10,
|
|
47
|
+
) -> PipValidationResult:
|
|
48
|
+
"""Validate that requirements.txt can be resolved using pip install --dry-run.
|
|
49
|
+
|
|
50
|
+
This simulates package installation without actually installing anything.
|
|
51
|
+
It validates that:
|
|
52
|
+
- All packages exist
|
|
53
|
+
- All specified versions are available
|
|
54
|
+
- Credentials for private repositories are valid
|
|
55
|
+
- Index URLs are accessible
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
requirements_txt_path: Path to the requirements.txt file
|
|
59
|
+
index_url: Optional custom package index URL (replaces PyPI)
|
|
60
|
+
extra_index_urls: Optional additional package index URLs
|
|
61
|
+
timeout: Timeout in seconds for the pip command
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
PipValidationResult with success status and error details if failed
|
|
65
|
+
|
|
66
|
+
"""
|
|
67
|
+
if not requirements_txt_path.exists():
|
|
68
|
+
return PipValidationResult(error_message=f"Requirements file not found: {requirements_txt_path}")
|
|
69
|
+
|
|
70
|
+
# Build pip command with custom index URLs
|
|
71
|
+
args = [
|
|
72
|
+
sys.executable,
|
|
73
|
+
"-m",
|
|
74
|
+
"pip",
|
|
75
|
+
"install",
|
|
76
|
+
"--dry-run",
|
|
77
|
+
"--ignore-installed",
|
|
78
|
+
"--no-deps",
|
|
79
|
+
"--disable-pip-version-check",
|
|
80
|
+
"-r",
|
|
81
|
+
str(requirements_txt_path),
|
|
82
|
+
*(["--index-url", index_url] if index_url else []),
|
|
83
|
+
*([arg for url in (extra_index_urls or []) for arg in ["--extra-index-url", url]]),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
result = subprocess.run(args, capture_output=True, text=True, timeout=timeout, check=False)
|
|
88
|
+
if result.returncode == 0:
|
|
89
|
+
return PipValidationResult()
|
|
90
|
+
return PipValidationResult(
|
|
91
|
+
error_message=f"pip validation failed with exit code {result.returncode}:\n{result.stderr}",
|
|
92
|
+
)
|
|
93
|
+
except subprocess.TimeoutExpired:
|
|
94
|
+
return PipValidationResult(error_message=f"pip validation timed out after {timeout} seconds")
|
|
95
|
+
except (OSError, RuntimeError) as e:
|
|
96
|
+
return PipValidationResult(error_message=f"Error running pip validation: {e!s}")
|
cognite_toolkit/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.7.
|
|
1
|
+
__version__ = "0.7.50"
|