Skip to content

Commit

Permalink
Some fixes and cleanups to functions/relationships/contextualization …
Browse files Browse the repository at this point in the history
…SDKs (#996)
  • Loading branch information
erlendvollset authored Aug 15, 2022
1 parent 7a293b2 commit f4a6337
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 104 deletions.
102 changes: 47 additions & 55 deletions cognite/client/_api/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,26 +434,25 @@ def _zip_and_upload_folder(self, folder: str, name: str, external_id: Optional[s
try:
with TemporaryDirectory() as tmpdir:
zip_path = os.path.join(tmpdir, "function.zip")
zf = ZipFile(zip_path, "w")
for root, dirs, files in os.walk("."):
zf.write(root)

# Validate requirements.txt in root-dir only
if root == "." and REQUIREMENTS_FILE_NAME in files:
# Remove requirement from file list
path = files.pop(files.index(REQUIREMENTS_FILE_NAME))
reqs = _extract_requirements_from_file(path)
# Validate and format requirements
req_path = _validate_requirements(reqs)

# NOTE: the actual file is not written.
# A temporary formatted file is used instead
zf.write(req_path, arcname=REQUIREMENTS_FILE_NAME)

for filename in files:
zf.write(os.path.join(root, filename))

zf.close()
with ZipFile(zip_path, "w") as zf:
for root, dirs, files in os.walk("."):
zf.write(root)

# Validate requirements.txt in root-dir only
if root == "." and REQUIREMENTS_FILE_NAME in files:
# Remove requirement from file list
path = files.pop(files.index(REQUIREMENTS_FILE_NAME))
reqs = _extract_requirements_from_file(path)
# Validate and format requirements
parsed_reqs = _validate_and_parse_requirements(reqs)
with NamedTemporaryFile() as nth:
_write_requirements_to_file(nth.name, parsed_reqs)
# NOTE: the actual file is not written.
# A temporary formatted file is used instead
zf.write(nth.name, arcname=REQUIREMENTS_FILE_NAME)

for filename in files:
zf.write(os.path.join(root, filename))

overwrite = True if external_id else False
file = cast(
Expand All @@ -466,8 +465,6 @@ def _zip_and_upload_folder(self, folder: str, name: str, external_id: Optional[s
file_id = cast(int, file.id)

return file_id
except Exception as e:
raise e
finally:
os.chdir(current_dir)

Expand All @@ -482,16 +479,16 @@ def _zip_and_upload_handle(self, function_handle: Callable, name: str, external_
f.write(source)

# Read and validate requirements
req_path = _get_requirements_handle(fn=function_handle)
with NamedTemporaryFile() as named_temp_file:
requirements_written = _write_fn_docstring_requirements_to_file(function_handle, named_temp_file.name)

zip_path = os.path.join(tmpdir, "function.zip")
zf = ZipFile(zip_path, "w")
zf.write(handle_path, arcname=HANDLER_FILE_NAME)
zip_path = os.path.join(tmpdir, "function.zip")
with ZipFile(zip_path, "w") as zf:
zf.write(handle_path, arcname=HANDLER_FILE_NAME)

# Zip requirements.txt
if req_path:
zf.write(req_path, arcname=REQUIREMENTS_FILE_NAME)
zf.close()
# Zip requirements.txt
if requirements_written:
zf.write(named_temp_file.name, arcname=REQUIREMENTS_FILE_NAME)

overwrite = True if external_id else False
file = cast(
Expand Down Expand Up @@ -602,19 +599,16 @@ def _use_token_exchange(
raise CogniteAPIError("Failed to create session using token exchange flow.", 403) from e


def _using_client_credential_flow(
cognite_client: "CogniteClient",
) -> bool:
def _using_client_credential_flow(cognite_client: "CogniteClient") -> bool:
"""
Determine whether the Cognite client is configured for client-credential flow.
"""
client_config = cognite_client.config
return cast(
bool,
client_config.token_client_secret
and client_config.token_client_id
and client_config.token_url
and client_config.token_scopes,
return (
client_config.token_client_secret is not None
and client_config.token_client_id is not None
and client_config.token_url is not None
and client_config.token_scopes is not None
)


Expand Down Expand Up @@ -716,17 +710,15 @@ def _extract_requirements_from_doc_string(docstr: str) -> Optional[List[str]]:
return None


def _validate_requirements(requirements: List[str]) -> str:
def _validate_and_parse_requirements(requirements: List[str]) -> List[str]:
"""Validates the requirement specifications
Args:
requirements (list[str]): list of requirement specifications
Raises:
ValueError: if validation of requirements fails
Returns:
str: output path of the requirements file
List[str]: The parsed requirements
"""
parsed_reqs: List[str] = []
for req in requirements:
Expand All @@ -736,34 +728,34 @@ def _validate_requirements(requirements: List[str]) -> str:
raise ValueError(str(e))

parsed_reqs.append(str(parsed).strip())
return parsed_reqs

tmp = NamedTemporaryFile()

# Write requirements to temporary file
with open(tmp.name, "w+") as f:
f.write("\n".join(parsed_reqs))
f.close()
def _write_requirements_to_file(file_path: str, requirements: List[str]) -> None:
with open(file_path, "w+") as f:
f.write("\n".join(requirements))

return tmp.name


def _get_requirements_handle(fn: Callable) -> Optional[str]:
"""Read requirements from a function docstring, and validate them
def _write_fn_docstring_requirements_to_file(fn: Callable, file_path: str) -> bool:
"""Read requirements from a function docstring, validate them, and write contents to the provided file path
Args:
fn (Callable): the function to read requirements from
file_path (str): Path of file to write requirements to
Returns:
str: output path of the requirements file, or None if no requirements are specified
bool: whether or not anything was written to the file
"""
docstr = getdoc(fn)

if docstr:
reqs = _extract_requirements_from_doc_string(docstr)
if reqs:
return _validate_requirements(reqs)
parsed_reqs = _validate_and_parse_requirements(reqs)
_write_requirements_to_file(file_path, parsed_reqs)
return True

return None
return False


class FunctionCallsAPI(APIClient):
Expand Down
4 changes: 3 additions & 1 deletion cognite/client/_api/relationships.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,9 @@ def create(
Args:
relationship (Union[Relationship, Sequence[Relationship]]): Relationship or list of relationships to create.
Note: the source_type and target_type field in the Relationship(s) can be any string among "Asset", "TimeSeries", "FileMetadata", "Event", "Sequence"
Note:
- the source_type and target_type field in the Relationship(s) can be any string among "Asset", "TimeSeries", "File", "Event", "Sequence";
- do not provide the value for the source and target arguments of the Relationship class, only source_external_id / source_type and target_external_id / target_type. These (source and target) are used as part of fetching actual resources specified in other fields.
Returns:
Union[Relationship, RelationshipList]: Created relationship(s)
Expand Down
4 changes: 2 additions & 2 deletions cognite/client/data_classes/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ def __init__(
self.response_size_mb = response_size_mb

@classmethod
def _load(cls, api_response: Dict): # type: ignore # Should be fixed by Self class but it will be available on 3.11
def _load(cls, api_response: Dict) -> "FunctionsLimits":
return cls(
timeout_minutes=api_response["timeoutMinutes"],
cpu_cores=api_response["cpuCores"],
Expand All @@ -401,7 +401,7 @@ def __init__(
self.status = status

@classmethod
def _load(cls, api_response: Dict): # type: ignore # Should be fixed by Self class but it will be available on 3.11
def _load(cls, api_response: Dict) -> "FunctionsStatus":
return cls(
status=api_response["status"],
)
2 changes: 1 addition & 1 deletion cognite/client/data_classes/relationships.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def _validate_resource_types(self) -> "Relationship":

@staticmethod
def _validate_resource_type(resource_type: Optional[str]) -> None:
_RESOURCE_TYPES = {"asset", "timeseries", "file", "event", "sequence", "geospatial"}
_RESOURCE_TYPES = {"asset", "timeseries", "file", "event", "sequence"}
if resource_type is None or resource_type.lower() not in _RESOURCE_TYPES:
raise TypeError("Invalid source or target '{}' in relationship".format(resource_type))

Expand Down
Loading

0 comments on commit f4a6337

Please sign in to comment.