oracle-ads 2.11.17__py3-none-any.whl → 2.11.18__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.
Files changed (26) hide show
  1. ads/common/auth.py +4 -4
  2. ads/jobs/builders/infrastructure/dsc_job.py +11 -5
  3. ads/jobs/builders/infrastructure/dsc_job_runtime.py +12 -25
  4. ads/jobs/builders/runtimes/artifact.py +0 -5
  5. ads/jobs/builders/runtimes/container_runtime.py +26 -3
  6. ads/opctl/conda/cmds.py +100 -42
  7. ads/opctl/conda/pack.py +3 -2
  8. ads/opctl/operator/lowcode/anomaly/const.py +1 -0
  9. ads/opctl/operator/lowcode/anomaly/model/base_model.py +58 -37
  10. ads/opctl/operator/lowcode/anomaly/model/factory.py +2 -0
  11. ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py +116 -0
  12. ads/opctl/operator/lowcode/anomaly/schema.yaml +1 -0
  13. ads/opctl/operator/lowcode/forecast/const.py +1 -1
  14. ads/opctl/operator/lowcode/forecast/model/arima.py +6 -2
  15. ads/opctl/operator/lowcode/forecast/model/automlx.py +6 -1
  16. ads/opctl/operator/lowcode/forecast/model/autots.py +3 -1
  17. ads/opctl/operator/lowcode/forecast/model/factory.py +1 -1
  18. ads/opctl/operator/lowcode/forecast/model/ml_forecast.py +24 -15
  19. ads/opctl/operator/lowcode/forecast/model/neuralprophet.py +6 -1
  20. ads/opctl/operator/lowcode/forecast/model/prophet.py +3 -1
  21. ads/opctl/operator/lowcode/forecast/schema.yaml +1 -1
  22. {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/METADATA +4 -1
  23. {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/RECORD +26 -25
  24. {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/LICENSE.txt +0 -0
  25. {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/WHEEL +0 -0
  26. {oracle_ads-2.11.17.dist-info → oracle_ads-2.11.18.dist-info}/entry_points.txt +0 -0
ads/common/auth.py CHANGED
@@ -73,7 +73,7 @@ class AuthState(metaclass=SingletonMeta):
73
73
  self.oci_key_profile = self.oci_key_profile or os.environ.get(
74
74
  "OCI_CONFIG_PROFILE", DEFAULT_PROFILE
75
75
  )
76
- self.oci_config = self.oci_config or {}
76
+ self.oci_config = self.oci_config or {"region": os.environ["OCI_RESOURCE_REGION"]} if os.environ.get("OCI_RESOURCE_REGION") else {}
77
77
  self.oci_signer_kwargs = self.oci_signer_kwargs or {}
78
78
  self.oci_client_kwargs = self.oci_client_kwargs or {}
79
79
 
@@ -82,7 +82,7 @@ def set_auth(
82
82
  auth: Optional[str] = AuthType.API_KEY,
83
83
  oci_config_location: Optional[str] = DEFAULT_LOCATION,
84
84
  profile: Optional[str] = DEFAULT_PROFILE,
85
- config: Optional[Dict] = {},
85
+ config: Optional[Dict] = {"region": os.environ["OCI_RESOURCE_REGION"]} if os.environ.get("OCI_RESOURCE_REGION") else {},
86
86
  signer: Optional[Any] = None,
87
87
  signer_callable: Optional[Callable] = None,
88
88
  signer_kwargs: Optional[Dict] = {},
@@ -678,7 +678,7 @@ class ResourcePrincipal(AuthSignerGenerator):
678
678
  >>> signer_generator = AuthFactory().signerGenerator(AuthType.RESOURCE_PRINCIPAL)
679
679
  >>> signer_generator(signer_args).create_signer()
680
680
  """
681
- configuration = ads.telemetry.update_oci_client_config()
681
+ configuration = ads.telemetry.update_oci_client_config(AuthState().oci_config)
682
682
  signer_dict = {
683
683
  "config": configuration,
684
684
  "signer": oci.auth.signers.get_resource_principals_signer(),
@@ -739,7 +739,7 @@ class InstancePrincipal(AuthSignerGenerator):
739
739
  >>> signer_generator = AuthFactory().signerGenerator(AuthType.INSTANCE_PRINCIPAL)
740
740
  >>> signer_generator(signer_args).create_signer()
741
741
  """
742
- configuration = ads.telemetry.update_oci_client_config()
742
+ configuration = ads.telemetry.update_oci_client_config(AuthState().oci_config)
743
743
  signer_dict = {
744
744
  "config": configuration,
745
745
  "signer": oci.auth.signers.InstancePrincipalsSecurityTokenSigner(
@@ -312,7 +312,7 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
312
312
  logger.debug(oci_model)
313
313
  res = self.client.create_job(oci_model)
314
314
  self.update_from_oci_model(res.data)
315
- if self.lifecycle_state == "ACTIVE":
315
+ if not self.artifact:
316
316
  return
317
317
  try:
318
318
  if issubclass(self.artifact.__class__, Artifact):
@@ -487,7 +487,9 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
487
487
  oci.data_science.models.DefaultJobConfigurationDetails().swagger_types.keys()
488
488
  )
489
489
  env_config_swagger_types = {}
490
- if hasattr(oci.data_science.models, "OcirContainerJobEnvironmentConfigurationDetails"):
490
+ if hasattr(
491
+ oci.data_science.models, "OcirContainerJobEnvironmentConfigurationDetails"
492
+ ):
491
493
  env_config_swagger_types = (
492
494
  oci.data_science.models.OcirContainerJobEnvironmentConfigurationDetails().swagger_types.keys()
493
495
  )
@@ -501,7 +503,7 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
501
503
  value = kwargs.pop(key)
502
504
  if key in [
503
505
  ContainerRuntime.CONST_CMD,
504
- ContainerRuntime.CONST_ENTRYPOINT
506
+ ContainerRuntime.CONST_ENTRYPOINT,
505
507
  ] and isinstance(value, str):
506
508
  value = ContainerRuntimeHandler.split_args(value)
507
509
  env_config_kwargs[key] = value
@@ -535,9 +537,13 @@ class DSCJob(OCIDataScienceMixin, oci.data_science.models.Job):
535
537
 
536
538
  if env_config_kwargs:
537
539
  env_config_kwargs["jobEnvironmentType"] = "OCIR_CONTAINER"
538
- env_config_override = kwargs.get("job_environment_configuration_override_details", {})
540
+ env_config_override = kwargs.get(
541
+ "job_environment_configuration_override_details", {}
542
+ )
539
543
  env_config_override.update(env_config_kwargs)
540
- kwargs["job_environment_configuration_override_details"] = env_config_override
544
+ kwargs["job_environment_configuration_override_details"] = (
545
+ env_config_override
546
+ )
541
547
 
542
548
  wait = kwargs.pop("wait", False)
543
549
  run = DataScienceJobRun(**kwargs, **self.auth).create()
@@ -181,9 +181,9 @@ class RuntimeHandler:
181
181
  "jobType": self.data_science_job.job_type,
182
182
  }
183
183
  if runtime.maximum_runtime_in_minutes:
184
- job_configuration_details[
185
- "maximum_runtime_in_minutes"
186
- ] = runtime.maximum_runtime_in_minutes
184
+ job_configuration_details["maximum_runtime_in_minutes"] = (
185
+ runtime.maximum_runtime_in_minutes
186
+ )
187
187
  job_configuration_details["environment_variables"] = self._translate_env(
188
188
  runtime
189
189
  )
@@ -310,7 +310,7 @@ class RuntimeHandler:
310
310
  for extraction in extractions:
311
311
  runtime_spec.update(extraction(dsc_job))
312
312
  return self.RUNTIME_CLASS(self._format_env_var(runtime_spec))
313
-
313
+
314
314
  def _extract_properties(self, dsc_job) -> dict:
315
315
  """Extract the job runtime properties from data science job.
316
316
 
@@ -968,23 +968,10 @@ class ContainerRuntimeHandler(RuntimeHandler):
968
968
  payload["job_environment_configuration_details"] = job_env_config
969
969
  return payload
970
970
 
971
- def _translate_artifact(self, runtime: Runtime):
972
- """Specifies a dummy script as the job artifact.
973
- runtime is not used in this method.
974
-
975
- Parameters
976
- ----------
977
- runtime : Runtime
978
- This is not used.
979
-
980
- Returns
981
- -------
982
- str
983
- Path to the dummy script.
984
- """
985
- return os.path.join(
986
- os.path.dirname(__file__), "../../templates", "container.py"
987
- )
971
+ def _translate_artifact(self, runtime: ContainerRuntime):
972
+ """Additional artifact for the container"""
973
+ if runtime.artifact_uri:
974
+ return ScriptArtifact(runtime.artifact_uri, runtime)
988
975
 
989
976
  def _translate_env_config(self, runtime: Runtime) -> dict:
990
977
  """Converts runtime properties to ``OcirContainerJobEnvironmentConfigurationDetails`` payload required by OCI Data Science job.
@@ -1007,7 +994,7 @@ class ContainerRuntimeHandler(RuntimeHandler):
1007
994
  property = runtime.get_spec(key, None)
1008
995
  if key in [
1009
996
  ContainerRuntime.CONST_CMD,
1010
- ContainerRuntime.CONST_ENTRYPOINT
997
+ ContainerRuntime.CONST_ENTRYPOINT,
1011
998
  ] and isinstance(property, str):
1012
999
  property = self.split_args(property)
1013
1000
  if property is not None:
@@ -1063,7 +1050,7 @@ class ContainerRuntimeHandler(RuntimeHandler):
1063
1050
  spec[ContainerRuntime.CONST_ENV_VAR] = envs
1064
1051
 
1065
1052
  return spec
1066
-
1053
+
1067
1054
  def _extract_properties(self, dsc_job) -> dict:
1068
1055
  """Extract the runtime properties from data science job.
1069
1056
 
@@ -1078,10 +1065,10 @@ class ContainerRuntimeHandler(RuntimeHandler):
1078
1065
  A runtime specification dictionary for initializing a runtime.
1079
1066
  """
1080
1067
  spec = super()._extract_envs(dsc_job)
1081
-
1068
+
1082
1069
  job_env_config = getattr(dsc_job, "job_environment_configuration_details", None)
1083
1070
  job_env_type = getattr(job_env_config, "job_environment_type", None)
1084
-
1071
+
1085
1072
  if not (job_env_config and job_env_type == "OCIR_CONTAINER"):
1086
1073
  raise IncompatibleRuntime()
1087
1074
 
@@ -183,11 +183,6 @@ class ScriptArtifact(Artifact):
183
183
  if os.path.isdir(source):
184
184
  basename = os.path.basename(str(source).rstrip("/"))
185
185
  source = str(source).rstrip("/")
186
- # Runtime must have entrypoint if the source is a directory
187
- if self.runtime and not self.runtime.entrypoint:
188
- raise ValueError(
189
- "Please specify entrypoint when script source is a directory."
190
- )
191
186
  output = os.path.join(self.temp_dir.name, basename)
192
187
  shutil.make_archive(
193
188
  output, "zip", os.path.dirname(source), base_dir=basename
@@ -56,6 +56,7 @@ class ContainerRuntime(MultiNodeRuntime):
56
56
  CONST_CMD = "cmd"
57
57
  CONST_IMAGE_DIGEST = "imageDigest"
58
58
  CONST_IMAGE_SIGNATURE_ID = "imageSignatureId"
59
+ CONST_SCRIPT_PATH = "scriptPathURI"
59
60
  attribute_map = {
60
61
  CONST_IMAGE: CONST_IMAGE,
61
62
  CONST_ENTRYPOINT: CONST_ENTRYPOINT,
@@ -121,7 +122,7 @@ class ContainerRuntime(MultiNodeRuntime):
121
122
  def image_digest(self) -> str:
122
123
  """The container image digest."""
123
124
  return self.get_spec(self.CONST_IMAGE_DIGEST)
124
-
125
+
125
126
  def with_image_digest(self, image_digest: str) -> "ContainerRuntime":
126
127
  """Sets the digest of custom image.
127
128
 
@@ -136,12 +137,12 @@ class ContainerRuntime(MultiNodeRuntime):
136
137
  The runtime instance.
137
138
  """
138
139
  return self.set_spec(self.CONST_IMAGE_DIGEST, image_digest)
139
-
140
+
140
141
  @property
141
142
  def image_signature_id(self) -> str:
142
143
  """The container image signature id."""
143
144
  return self.get_spec(self.CONST_IMAGE_SIGNATURE_ID)
144
-
145
+
145
146
  def with_image_signature_id(self, image_signature_id: str) -> "ContainerRuntime":
146
147
  """Sets the signature id of custom image.
147
148
 
@@ -217,3 +218,25 @@ class ContainerRuntime(MultiNodeRuntime):
217
218
  entrypoint=["bash", "--login", "-c"],
218
219
  cmd="{Container CMD. For MLflow and Operator will be auto generated}",
219
220
  )
221
+
222
+ @property
223
+ def artifact_uri(self) -> str:
224
+ """The URI of the source code"""
225
+ return self.get_spec(self.CONST_SCRIPT_PATH)
226
+
227
+ def with_artifact(self, uri: str):
228
+ """Specifies the artifact to be added to the container.
229
+
230
+ Parameters
231
+ ----------
232
+ uri : str
233
+ URI to the source code script, which can be any URI supported by fsspec,
234
+ including http://, https:// and OCI object storage.
235
+ For example: oci://your_bucket@your_namespace/path/to/script.py
236
+
237
+ Returns
238
+ -------
239
+ self
240
+ The runtime instance.
241
+ """
242
+ return self.set_spec(self.CONST_SCRIPT_PATH, uri)
ads/opctl/conda/cmds.py CHANGED
@@ -80,7 +80,7 @@ def _check_job_image_exists(gpu: bool) -> None:
80
80
  def _get_name(name: str, env_file: str) -> str:
81
81
  if not name and env_file:
82
82
  with open(env_file) as f:
83
- name = yaml.safe_load(f.read()).get("name", None)
83
+ name = yaml.safe_load(f.read()).get("manifest").get("name", None)
84
84
  if not name:
85
85
  raise ValueError(
86
86
  "Either specify environment name in environment yaml or with `--name`."
@@ -146,7 +146,14 @@ def _create(
146
146
  if not os.path.exists(env_file):
147
147
  raise FileNotFoundError(f"Environment file {env_file} is not found.")
148
148
 
149
- slug = f"{name}_v{version}".replace(" ", "").replace(".", "_").lower()
149
+ conda_dep = None
150
+ with open(env_file) as mfile:
151
+ conda_dep = yaml.safe_load(mfile.read())
152
+ # If manifest exists in the environment.yaml file, use that
153
+ manifest = conda_dep.get("manifest", {})
154
+ slug = manifest.get(
155
+ "slug", f"{name}_v{version}".replace(" ", "").replace(".", "_").lower()
156
+ )
150
157
  pack_folder_path = os.path.join(
151
158
  os.path.abspath(os.path.expanduser(conda_pack_folder)), slug
152
159
  )
@@ -171,27 +178,46 @@ def _create(
171
178
 
172
179
  os.makedirs(pack_folder_path, exist_ok=True)
173
180
 
174
- manifest = _fetch_manifest_template()
175
- manifest["manifest"]["name"] = name
176
- manifest["manifest"]["slug"] = slug
177
- manifest["manifest"]["type"] = "published"
178
- manifest["manifest"]["version"] = version
179
- manifest["manifest"]["arch_type"] = "GPU" if gpu else "CPU"
180
-
181
- manifest["manifest"]["create_date"] = datetime.utcnow().strftime(
181
+ logger.info(
182
+ f"Preparing manifest. Manifest in the environment: {conda_dep.get('manifest')}"
183
+ )
184
+ manifest_template = _fetch_manifest_template()
185
+ if "name" not in manifest:
186
+ manifest_template["manifest"]["name"] = name
187
+ manifest_template["manifest"]["slug"] = slug
188
+ if "type" not in manifest:
189
+ logger.info("Setting manifest to published")
190
+ manifest_template["manifest"]["type"] = "published"
191
+ if "version" not in manifest:
192
+ manifest_template["manifest"]["version"] = version
193
+ manifest_template["manifest"]["arch_type"] = "GPU" if gpu else "CPU"
194
+
195
+ manifest_template["manifest"]["create_date"] = datetime.utcnow().strftime(
182
196
  "%a, %b %d, %Y, %H:%M:%S %Z UTC"
183
197
  )
184
- manifest["manifest"]["manifest_version"] = "1.0"
198
+
199
+ if not "manifest_version" in manifest:
200
+ manifest_template["manifest"]["manifest_version"] = "1.0"
185
201
 
186
202
  logger.info(f"Creating conda environment {slug}")
187
- conda_dep = None
188
- with open(env_file) as mfile:
189
- conda_dep = yaml.safe_load(mfile.read())
190
- conda_dep["manifest"] = manifest["manifest"]
203
+ manifest_dict = {
204
+ k: manifest_template["manifest"][k]
205
+ for k in manifest_template["manifest"]
206
+ if manifest_template["manifest"][k]
207
+ }
208
+ if "manifest" in conda_dep:
209
+ conda_dep["manifest"].update(manifest_dict)
210
+ else:
211
+ conda_dep["manifest"] = manifest_dict
212
+ logger.info(f"Updated conda environment manifest: {conda_dep.get('manifest')}")
191
213
 
192
214
  if is_in_notebook_session() or NO_CONTAINER:
193
215
  command = f"conda env create --prefix {pack_folder_path} --file {os.path.abspath(os.path.expanduser(env_file))}"
194
- run_command(command, shell=True)
216
+ proc = run_command(command, shell=True)
217
+ if proc.returncode != 0:
218
+ raise RuntimeError(
219
+ f"Failed to create conda environment. (exit code {proc.returncode})"
220
+ )
195
221
  else:
196
222
  _check_job_image_exists(gpu)
197
223
  docker_pack_folder_path = os.path.join(DEFAULT_IMAGE_HOME_DIR, slug)
@@ -200,13 +226,12 @@ def _create(
200
226
  )
201
227
 
202
228
  create_command = f"conda env create --prefix {docker_pack_folder_path} --file {docker_env_file_path}"
203
-
229
+
204
230
  volumes = {
205
231
  pack_folder_path: {"bind": docker_pack_folder_path},
206
232
  os.path.abspath(os.path.expanduser(env_file)): {
207
233
  "bind": docker_env_file_path
208
234
  },
209
-
210
235
  }
211
236
 
212
237
  if gpu:
@@ -217,26 +242,42 @@ def _create(
217
242
  if prepare_publish:
218
243
  tmp_file = tempfile.NamedTemporaryFile(suffix=".yaml")
219
244
  # Save the manifest in the temp file that can be mounted inside the container so that archiving will work
220
- with open(tmp_file.name, 'w') as f:
221
- yaml.safe_dump(conda_dep, f)
245
+ with open(tmp_file.name, "w") as f:
246
+ yaml.safe_dump(conda_dep, f)
222
247
 
223
- pack_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pack.py")
248
+ pack_script = os.path.join(
249
+ os.path.dirname(os.path.abspath(__file__)), "pack.py"
250
+ )
224
251
  pack_command = f"python {os.path.join(DEFAULT_IMAGE_HOME_DIR, 'pack.py')} --conda-path {docker_pack_folder_path} --manifest-location {os.path.join(DEFAULT_IMAGE_HOME_DIR, 'manifest.yaml')}"
225
252
 
226
253
  # add pack script and manifest file to the mount so that archive can be created in the same container run
227
254
  condapack_script = {
228
- pack_script: {"bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "pack.py")},
229
- tmp_file.name: {"bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "manifest.yaml")}
255
+ pack_script: {
256
+ "bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "pack.py")
257
+ },
258
+ tmp_file.name: {
259
+ "bind": os.path.join(DEFAULT_IMAGE_HOME_DIR, "manifest.yaml")
260
+ },
230
261
  }
231
- volumes = {**volumes, **condapack_script} # | not supported in python 3.8
262
+ volumes = {
263
+ **volumes,
264
+ **condapack_script,
265
+ } # | not supported in python 3.8
232
266
 
233
267
  run_container(
234
- image=image, bind_volumes=volumes, entrypoint="/bin/bash -c ", env_vars={}, command=f" '{create_command} && {pack_command}'"
268
+ image=image,
269
+ bind_volumes=volumes,
270
+ entrypoint="/bin/bash -c ",
271
+ env_vars={},
272
+ command=f" '{create_command} && {pack_command}'",
235
273
  )
236
274
  else:
237
275
  run_container(
238
- image=image, bind_volumes=volumes, env_vars={}, command=create_command
239
- )
276
+ image=image,
277
+ bind_volumes=volumes,
278
+ env_vars={},
279
+ command=create_command,
280
+ )
240
281
  except Exception:
241
282
  if os.path.exists(pack_folder_path):
242
283
  shutil.rmtree(pack_folder_path)
@@ -507,9 +548,11 @@ def publish(**kwargs) -> None:
507
548
  conda_pack_folder=exec_config["conda_pack_folder"],
508
549
  gpu=exec_config.get("gpu", False),
509
550
  overwrite=exec_config["overwrite"],
510
- prepare_publish=True
551
+ prepare_publish=True,
552
+ )
553
+ skip_archive = (
554
+ True # The conda pack archive is already created during create process.
511
555
  )
512
- skip_archive = True # The conda pack archive is already created during create process.
513
556
  else:
514
557
  slug = exec_config.get("slug")
515
558
  if not slug:
@@ -526,10 +569,10 @@ def publish(**kwargs) -> None:
526
569
  oci_profile=exec_config.get("oci_profile"),
527
570
  overwrite=exec_config["overwrite"],
528
571
  auth_type=exec_config["auth"],
529
- skip_archive=skip_archive
572
+ skip_archive=skip_archive,
530
573
  )
531
574
 
532
-
575
+
533
576
  def _publish(
534
577
  conda_slug: str,
535
578
  conda_uri_prefix: str,
@@ -538,7 +581,7 @@ def _publish(
538
581
  oci_profile: str,
539
582
  overwrite: bool,
540
583
  auth_type: str,
541
- skip_archive: bool = False
584
+ skip_archive: bool = False,
542
585
  ) -> None:
543
586
  """Publish a local conda pack to object storage location
544
587
 
@@ -616,8 +659,16 @@ def _publish(
616
659
  pack_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "pack.py")
617
660
  if not skip_archive:
618
661
  if is_in_notebook_session() or NO_CONTAINER:
662
+ # Set the CONDA_PUBLISH_TYPE environment variable so that the `type` attribute inside the manifest is not changed
663
+ publish_type = os.environ.get("CONDA_PUBLISH_TYPE")
619
664
  command = f"python {pack_script} --conda-path {pack_folder_path}"
620
- run_command(command, shell=True)
665
+ if publish_type:
666
+ command = f"CONDA_PUBLISH_TYPE={publish_type} {command}"
667
+ proc = run_command(command, shell=True)
668
+ if proc.returncode != 0:
669
+ raise RuntimeError(
670
+ f"Failed to archive the conda environment. (exit code {proc.returncode})"
671
+ )
621
672
  else:
622
673
  volumes = {
623
674
  pack_folder_path: {
@@ -641,7 +692,9 @@ def _publish(
641
692
  NOT_ALLOWED_CHARS = "@#$%^&*/"
642
693
 
643
694
  if any(chr in conda_slug for chr in NOT_ALLOWED_CHARS):
644
- raise ValueError(f"Invalid conda_slug. Found {NOT_ALLOWED_CHARS} in slug name. Please use a different slug name.")
695
+ raise ValueError(
696
+ f"Invalid conda_slug. Found {NOT_ALLOWED_CHARS} in slug name. Please use a different slug name."
697
+ )
645
698
  pack_file = os.path.join(pack_folder_path, f"{conda_slug}.tar.gz")
646
699
  if not os.path.exists(pack_file):
647
700
  raise RuntimeError(f"Pack {pack_file} was not created.")
@@ -664,14 +717,19 @@ def _publish(
664
717
  str(manifest["version"]),
665
718
  publish_slug,
666
719
  )
667
- manifest["pack_path"] = os.path.join(
668
- prefix,
669
- manifest.get("arch_type", "CPU").lower(),
670
- manifest["name"],
671
- str(manifest["version"]),
672
- publish_slug,
673
- )
674
- manifest["pack_uri"] = pack_uri
720
+ if os.environ.get("CONDA_PUBLISH_TYPE") != "service":
721
+ # Set these values only for published conda pack
722
+ manifest["pack_path"] = os.path.join(
723
+ prefix,
724
+ manifest.get("arch_type", "CPU").lower(),
725
+ manifest["name"],
726
+ str(manifest["version"]),
727
+ publish_slug,
728
+ )
729
+ manifest["pack_uri"] = pack_uri
730
+ else:
731
+ manifest["type"] = "published"
732
+
675
733
  with open(manifest_location, "w") as f:
676
734
  yaml.safe_dump(env, f)
677
735
  if pack_size > 100:
ads/opctl/conda/pack.py CHANGED
@@ -20,7 +20,6 @@ import argparse
20
20
 
21
21
 
22
22
  def main(pack_folder_path, manifest_file=None):
23
- slug = os.path.basename(pack_folder_path)
24
23
  manifest_path = (
25
24
  manifest_file or glob.glob(os.path.join(pack_folder_path, "*_manifest.yaml"))[0]
26
25
  )
@@ -47,7 +46,9 @@ def main(pack_folder_path, manifest_file=None):
47
46
  raise e
48
47
 
49
48
  manifest = env["manifest"]
50
- manifest["type"] = "published"
49
+ slug = manifest.get("slug", os.path.basename(pack_folder_path))
50
+ if os.environ.get("CONDA_PUBLISH_TYPE") != "service":
51
+ manifest["type"] = "published"
51
52
  new_env_info["manifest"] = manifest
52
53
  with open(manifest_path, "w") as f:
53
54
  yaml.safe_dump(new_env_info, f)
@@ -21,6 +21,7 @@ class NonTimeADSupportedModels(str, metaclass=ExtendedEnumMeta):
21
21
 
22
22
  OneClassSVM = "oneclasssvm"
23
23
  IsolationForest = "isolationforest"
24
+ RandomCutForest = "randomcutforest"
24
25
  # TODO : Add DBScan
25
26
  # DBScan = "dbscan"
26
27
 
@@ -16,7 +16,11 @@ from sklearn import linear_model
16
16
 
17
17
  from ads.common.object_storage_details import ObjectStorageDetails
18
18
  from ads.opctl import logger
19
- from ads.opctl.operator.lowcode.anomaly.const import OutputColumns, SupportedMetrics, SUBSAMPLE_THRESHOLD
19
+ from ads.opctl.operator.lowcode.anomaly.const import (
20
+ SUBSAMPLE_THRESHOLD,
21
+ OutputColumns,
22
+ SupportedMetrics,
23
+ )
20
24
  from ads.opctl.operator.lowcode.anomaly.utils import _build_metrics_df, default_signer
21
25
  from ads.opctl.operator.lowcode.common.utils import (
22
26
  disable_print,
@@ -55,6 +59,7 @@ class AnomalyOperatorBaseModel(ABC):
55
59
  def generate_report(self):
56
60
  """Generates the report."""
57
61
  import matplotlib.pyplot as plt
62
+ plt.rcParams.update({'figure.max_open_warning': 0})
58
63
  import report_creator as rc
59
64
 
60
65
  start_time = time.time()
@@ -87,43 +92,59 @@ class AnomalyOperatorBaseModel(ABC):
87
92
  self.spec.datetime_column.name if self.spec.datetime_column else "index"
88
93
  )
89
94
 
95
+ (
96
+ model_description,
97
+ other_sections,
98
+ ) = self._generate_report()
99
+
90
100
  blocks = []
91
101
  for target, df in self.datasets.full_data_dict.items():
92
- figure_blocks = []
93
- time_col = df[date_column].reset_index(drop=True)
94
- anomaly_col = anomaly_output.get_anomalies_by_cat(category=target)[
95
- OutputColumns.ANOMALY_COL
96
- ]
97
- anomaly_indices = [i for i, index in enumerate(anomaly_col) if index == 1]
98
- downsampled_time_col = time_col
99
- selected_indices = list(range(len(time_col)))
100
- if self.spec.subsample_report_data:
101
- non_anomaly_indices = [i for i in range(len(time_col)) if i not in anomaly_indices]
102
- # Downsample non-anomalous data if it exceeds the threshold (1000)
103
- if len(non_anomaly_indices) > SUBSAMPLE_THRESHOLD:
104
- downsampled_non_anomaly_indices = non_anomaly_indices[::len(non_anomaly_indices)//SUBSAMPLE_THRESHOLD]
105
- selected_indices = anomaly_indices + downsampled_non_anomaly_indices
106
- selected_indices.sort()
107
- downsampled_time_col = time_col[selected_indices]
108
-
109
- columns = set(df.columns).difference({date_column})
110
- for col in columns:
111
- y = df[col].reset_index(drop=True)
112
-
113
- downsampled_y = y[selected_indices]
114
-
115
- fig, ax = plt.subplots(figsize=(8, 3), layout="constrained")
116
- ax.grid()
117
- ax.plot(downsampled_time_col, downsampled_y, color="black")
118
- # Plot anomalies
119
- for i in anomaly_indices:
120
- ax.scatter(time_col[i], y[i], color="red", marker="o")
121
- plt.xlabel(date_column)
122
- plt.ylabel(col)
123
- plt.title(f"`{col}` with reference to anomalies")
124
- figure_blocks.append(rc.Widget(ax))
125
-
126
- blocks.append(rc.Group(*figure_blocks, label=target))
102
+ if target in anomaly_output.list_categories():
103
+ figure_blocks = []
104
+ time_col = df[date_column].reset_index(drop=True)
105
+ anomaly_col = anomaly_output.get_anomalies_by_cat(category=target)[
106
+ OutputColumns.ANOMALY_COL
107
+ ]
108
+ anomaly_indices = [
109
+ i for i, index in enumerate(anomaly_col) if index == 1
110
+ ]
111
+ downsampled_time_col = time_col
112
+ selected_indices = list(range(len(time_col)))
113
+ if self.spec.subsample_report_data:
114
+ non_anomaly_indices = [
115
+ i for i in range(len(time_col)) if i not in anomaly_indices
116
+ ]
117
+ # Downsample non-anomalous data if it exceeds the threshold (1000)
118
+ if len(non_anomaly_indices) > SUBSAMPLE_THRESHOLD:
119
+ downsampled_non_anomaly_indices = non_anomaly_indices[
120
+ :: len(non_anomaly_indices) // SUBSAMPLE_THRESHOLD
121
+ ]
122
+ selected_indices = (
123
+ anomaly_indices + downsampled_non_anomaly_indices
124
+ )
125
+ selected_indices.sort()
126
+ downsampled_time_col = time_col[selected_indices]
127
+
128
+ columns = set(df.columns).difference({date_column})
129
+ for col in columns:
130
+ y = df[col].reset_index(drop=True)
131
+
132
+ downsampled_y = y[selected_indices]
133
+
134
+ fig, ax = plt.subplots(figsize=(8, 3), layout="constrained")
135
+ ax.grid()
136
+ ax.plot(downsampled_time_col, downsampled_y, color="black")
137
+ # Plot anomalies
138
+ for i in anomaly_indices:
139
+ ax.scatter(time_col[i], y[i], color="red", marker="o")
140
+ plt.xlabel(date_column)
141
+ plt.ylabel(col)
142
+ plt.title(f"`{col}` with reference to anomalies")
143
+ figure_blocks.append(rc.Widget(ax))
144
+ else:
145
+ figure_blocks = None
146
+
147
+ blocks.append(rc.Group(*figure_blocks, label=target)) if figure_blocks else None
127
148
  plots = rc.Select(blocks)
128
149
 
129
150
  report_sections = []
@@ -133,7 +154,7 @@ class AnomalyOperatorBaseModel(ABC):
133
154
  yaml_appendix = rc.Yaml(self.config.to_dict())
134
155
  summary = rc.Block(
135
156
  rc.Group(
136
- rc.Text(f"You selected the **`{self.spec.model}`** model."),
157
+ rc.Text(f"You selected the **`{self.spec.model}`** model.\n{model_description.text}\n"),
137
158
  rc.Text(
138
159
  "Based on your dataset, you could have also selected "
139
160
  f"any of the models: `{'`, `'.join(SupportedModels.keys() if self.spec.datetime_column else NonTimeADSupportedModels.keys())}`."
@@ -15,6 +15,7 @@ from .autots import AutoTSOperatorModel
15
15
  from .base_model import AnomalyOperatorBaseModel
16
16
  from .isolationforest import IsolationForestOperatorModel
17
17
  from .oneclasssvm import OneClassSVMOperatorModel
18
+ from .randomcutforest import RandomCutForestOperatorModel
18
19
 
19
20
 
20
21
  class UnSupportedModelError(Exception):
@@ -52,6 +53,7 @@ class AnomalyOperatorModelFactory:
52
53
  _NonTime_MAP = {
53
54
  NonTimeADSupportedModels.OneClassSVM: OneClassSVMOperatorModel,
54
55
  NonTimeADSupportedModels.IsolationForest: IsolationForestOperatorModel,
56
+ NonTimeADSupportedModels.RandomCutForest: RandomCutForestOperatorModel,
55
57
  # TODO: Add DBScan model for non time based anomaly
56
58
  # NonTimeADSupportedModels.DBScan: DBScanOperatorModel,
57
59
  }
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python
2
+
3
+ # Copyright (c) 2023, 2024 Oracle and/or its affiliates.
4
+ # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+
9
+ from ads.common.decorator.runtime_dependency import runtime_dependency
10
+ from ads.opctl import logger
11
+ from ads.opctl.operator.lowcode.anomaly.const import OutputColumns
12
+
13
+ from .anomaly_dataset import AnomalyOutput
14
+ from .base_model import AnomalyOperatorBaseModel
15
+
16
+
17
+ class RandomCutForestOperatorModel(AnomalyOperatorBaseModel):
18
+ """
19
+ Class representing Random Cut Forest Anomaly Detection operator model.
20
+ """
21
+
22
+ @runtime_dependency(
23
+ module="rrcf",
24
+ err_msg=(
25
+ "Please run `pip install rrcf` to "
26
+ "install the required dependencies for RandomCutForest."
27
+ ),
28
+ )
29
+ def _build_model(self) -> AnomalyOutput:
30
+ from rrcf import RCTree
31
+
32
+ model_kwargs = self.spec.model_kwargs
33
+
34
+ anomaly_output = AnomalyOutput(date_column="index")
35
+
36
+ # Set tree parameters
37
+ num_trees = model_kwargs.get("num_trees", 200)
38
+ shingle_size = model_kwargs.get("shingle_size", None)
39
+ anomaly_threshold = model_kwargs.get("anamoly_threshold", 95)
40
+
41
+ for target, df in self.datasets.full_data_dict.items():
42
+ try:
43
+ if df.shape[0] == 1:
44
+ raise ValueError("Dataset size must be greater than 1")
45
+ df_values = df[self.spec.target_column].astype(float).values
46
+
47
+ cal_shingle_size = (
48
+ shingle_size
49
+ if shingle_size
50
+ else int(2 ** np.floor(np.log2(df.shape[0])) / 2)
51
+ )
52
+ points = np.vstack(list(rrcf.shingle(df_values, size=cal_shingle_size)))
53
+
54
+ sample_size_range = (1, points.shape[0])
55
+ n = points.shape[0]
56
+ avg_codisp = pd.Series(0.0, index=np.arange(n))
57
+ index = np.zeros(n)
58
+
59
+ forest = []
60
+ while len(forest) < num_trees:
61
+ ixs = np.random.choice(n, size=sample_size_range, replace=False)
62
+ trees = [rrcf.RCTree(points[ix], index_labels=ix) for ix in ixs]
63
+ forest.extend(trees)
64
+
65
+ for tree in forest:
66
+ codisp = pd.Series(
67
+ {leaf: tree.codisp(leaf) for leaf in tree.leaves}
68
+ )
69
+ avg_codisp[codisp.index] += codisp
70
+ np.add.at(index, codisp.index.values, 1)
71
+
72
+ avg_codisp /= index
73
+ avg_codisp.index = df.iloc[(cal_shingle_size - 1) :].index
74
+ avg_codisp = (avg_codisp - avg_codisp.min()) / (
75
+ avg_codisp.max() - avg_codisp.min()
76
+ )
77
+
78
+ y_pred = (
79
+ avg_codisp > np.percentile(avg_codisp, anomaly_threshold)
80
+ ).astype(int)
81
+
82
+ index_col = df.columns[0]
83
+
84
+ anomaly = pd.DataFrame(
85
+ {index_col: y_pred.index, OutputColumns.ANOMALY_COL: y_pred}
86
+ ).reset_index(drop=True)
87
+ score = pd.DataFrame(
88
+ {"index": avg_codisp.index, OutputColumns.SCORE_COL: avg_codisp}
89
+ ).reset_index(drop=True)
90
+
91
+ anomaly_output.add_output(target, anomaly, score)
92
+ except Exception as e:
93
+ logger.warn(f"Encountered Error: {e}. Skipping series {target}.")
94
+
95
+ return anomaly_output
96
+
97
+ def _generate_report(self):
98
+ """Generates the report."""
99
+ import report_creator as rc
100
+
101
+ other_sections = [
102
+ rc.Heading("Selected Models Overview", level=2),
103
+ rc.Text(
104
+ "The following tables provide information regarding the chosen model."
105
+ ),
106
+ ]
107
+
108
+ model_description = rc.Text(
109
+ "The Random Cut Forest (RCF) is an unsupervised machine learning algorithm that is used for anomaly detection."
110
+ " It works by building an ensemble of binary trees (random cut trees) and using them to compute anomaly scores for data points."
111
+ )
112
+
113
+ return (
114
+ model_description,
115
+ other_sections,
116
+ )
@@ -363,6 +363,7 @@ spec:
363
363
  - auto
364
364
  - oneclasssvm
365
365
  - isolationforest
366
+ - randomcutforest
366
367
  meta:
367
368
  description: "The model to be used for anomaly detection"
368
369
 
@@ -14,7 +14,7 @@ class SupportedModels(str, metaclass=ExtendedEnumMeta):
14
14
  Prophet = "prophet"
15
15
  Arima = "arima"
16
16
  NeuralProphet = "neuralprophet"
17
- MLForecast = "mlforecast"
17
+ LGBForecast = "lgbforecast"
18
18
  AutoMLX = "automlx"
19
19
  AutoTS = "autots"
20
20
  Auto = "auto"
@@ -126,8 +126,12 @@ class ArimaOperatorModel(ForecastOperatorBaseModel):
126
126
 
127
127
  logger.debug("===========Done===========")
128
128
  except Exception as e:
129
- self.errors_dict[s_id] = {"model_name": self.spec.model, "error": str(e)}
130
- logger.debug(f"Encountered Error: {e}. Skipping.")
129
+ self.errors_dict[s_id] = {
130
+ "model_name": self.spec.model,
131
+ "error": str(e),
132
+ "error_trace": traceback.format_exc()}
133
+ logger.warn(f"Encountered Error: {e}. Skipping.")
134
+ logger.warn(traceback.format_exc())
131
135
 
132
136
  def _build_model(self) -> pd.DataFrame:
133
137
  full_data_dict = self.datasets.get_data_by_series()
@@ -149,6 +149,9 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
149
149
  if f"{target}_ci_lower" not in summary_frame:
150
150
  summary_frame[f"{target}_ci_lower"] = np.NAN
151
151
 
152
+ if summary_frame[target].isna().all():
153
+ raise ValueError("The forecasts are completely NaN")
154
+
152
155
  self.forecast_output.populate_series_output(
153
156
  series_id=s_id,
154
157
  fit_val=fitted_values,
@@ -167,8 +170,10 @@ class AutoMLXOperatorModel(ForecastOperatorBaseModel):
167
170
  self.errors_dict[s_id] = {
168
171
  "model_name": self.spec.model,
169
172
  "error": str(e),
173
+ "error_trace": traceback.format_exc()
170
174
  }
171
- logger.debug(f"Encountered Error: {e}. Skipping.")
175
+ logger.warn(f"Encountered Error: {e}. Skipping.")
176
+ logger.warn(traceback.format_exc())
172
177
 
173
178
  logger.debug("===========Forecast Generated===========")
174
179
 
@@ -208,8 +208,10 @@ class AutoTSOperatorModel(ForecastOperatorBaseModel):
208
208
  self.errors_dict[s_id] = {
209
209
  "model_name": self.spec.model,
210
210
  "error": str(e),
211
+ "error_trace": traceback.format_exc()
211
212
  }
212
- logger.debug(f"Encountered Error: {e}. Skipping.")
213
+ logger.warn(f"Encountered Error: {e}. Skipping.")
214
+ logger.warn(traceback.format_exc())
213
215
 
214
216
  logger.debug("===========Done===========")
215
217
 
@@ -33,7 +33,7 @@ class ForecastOperatorModelFactory:
33
33
  SupportedModels.Prophet: ProphetOperatorModel,
34
34
  SupportedModels.Arima: ArimaOperatorModel,
35
35
  SupportedModels.NeuralProphet: NeuralProphetOperatorModel,
36
- SupportedModels.MLForecast: MLForecastOperatorModel,
36
+ SupportedModels.LGBForecast: MLForecastOperatorModel,
37
37
  SupportedModels.AutoMLX: AutoMLXOperatorModel,
38
38
  SupportedModels.AutoTS: AutoTSOperatorModel
39
39
  }
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*--
3
2
 
4
3
  # Copyright (c) 2024 Oracle and/or its affiliates.
5
4
  # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
6
- import pandas as pd
7
5
  import numpy as np
6
+ import pandas as pd
8
7
 
9
- from ads.opctl import logger
10
8
  from ads.common.decorator import runtime_dependency
9
+ from ads.opctl import logger
11
10
  from ads.opctl.operator.lowcode.forecast.utils import _select_plot_list
11
+
12
+ from ..const import ForecastOutputColumns, SupportedModels
13
+ from ..operator_config import ForecastOperatorConfig
12
14
  from .base_model import ForecastOperatorBaseModel
13
15
  from .forecast_datasets import ForecastDatasets, ForecastOutput
14
- from ..operator_config import ForecastOperatorConfig
15
- from ..const import ForecastOutputColumns, SupportedModels
16
16
 
17
17
 
18
18
  class MLForecastOperatorModel(ForecastOperatorBaseModel):
@@ -58,18 +58,25 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
58
58
  from mlforecast.target_transforms import Differences
59
59
 
60
60
  lgb_params = {
61
- "verbosity": -1,
62
- "num_leaves": 512,
61
+ "verbosity": model_kwargs.get("verbosity", -1),
62
+ "num_leaves": model_kwargs.get("num_leaves", 512),
63
63
  }
64
64
  additional_data_params = {}
65
65
  if len(self.datasets.get_additional_data_column_names()) > 0:
66
66
  additional_data_params = {
67
- "target_transforms": [Differences([12])],
67
+ "target_transforms": [
68
+ Differences([model_kwargs.get("Differences", 12)])
69
+ ],
68
70
  "lags": model_kwargs.get("lags", [1, 6, 12]),
69
71
  "lag_transforms": (
70
72
  {
71
73
  1: [ExpandingMean()],
72
- 12: [RollingMean(window_size=24)],
74
+ 12: [
75
+ RollingMean(
76
+ window_size=model_kwargs.get("RollingMean", 24),
77
+ min_samples=1,
78
+ )
79
+ ],
73
80
  }
74
81
  ),
75
82
  }
@@ -147,7 +154,7 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
147
154
  )
148
155
 
149
156
  self.model_parameters[s_id] = {
150
- "framework": SupportedModels.MLForecast,
157
+ "framework": SupportedModels.LGBForecast,
151
158
  **lgb_params,
152
159
  }
153
160
 
@@ -157,8 +164,10 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
157
164
  self.errors_dict[self.spec.model] = {
158
165
  "model_name": self.spec.model,
159
166
  "error": str(e),
167
+ "error_trace": traceback.format_exc()
160
168
  }
161
- logger.debug(f"Encountered Error: {e}. Skipping.")
169
+ logger.warn(f"Encountered Error: {e}. Skipping.")
170
+ logger.warn(traceback.format_exc())
162
171
  raise e
163
172
 
164
173
  def _build_model(self) -> pd.DataFrame:
@@ -204,10 +213,10 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
204
213
  self.datasets.list_series_ids(),
205
214
  )
206
215
 
207
- # Section 2: MlForecast Model Parameters
216
+ # Section 2: LGBForecast Model Parameters
208
217
  sec2_text = rc.Block(
209
- rc.Heading("MlForecast Model Parameters", level=2),
210
- rc.Text("These are the parameters used for the MlForecast model."),
218
+ rc.Heading("LGBForecast Model Parameters", level=2),
219
+ rc.Text("These are the parameters used for the LGBForecast model."),
211
220
  )
212
221
 
213
222
  blocks = [
@@ -221,7 +230,7 @@ class MLForecastOperatorModel(ForecastOperatorBaseModel):
221
230
 
222
231
  all_sections = [sec1_text, sec_1, sec2_text, sec_2]
223
232
  model_description = rc.Text(
224
- "mlforecast is a framework to perform time series forecasting using machine learning models"
233
+ "LGBForecast uses mlforecast framework to perform time series forecasting using machine learning models"
225
234
  "with the option to scale to massive amounts of data using remote clusters."
226
235
  "Fastest implementations of feature engineering for time series forecasting in Python."
227
236
  "Support for exogenous variables and static covariates."
@@ -217,7 +217,12 @@ class NeuralProphetOperatorModel(ForecastOperatorBaseModel):
217
217
 
218
218
  logger.debug("===========Done===========")
219
219
  except Exception as e:
220
- self.errors_dict[s_id] = {"model_name": self.spec.model, "error": str(e)}
220
+ self.errors_dict[s_id] = {
221
+ "model_name": self.spec.model,
222
+ "error": str(e),
223
+ "error_trace": traceback.format_exc()
224
+ }
225
+ logger.warn(traceback.format_exc())
221
226
  raise e
222
227
 
223
228
  def _build_model(self) -> pd.DataFrame:
@@ -130,8 +130,10 @@ class ProphetOperatorModel(ForecastOperatorBaseModel):
130
130
  self.errors_dict[series_id] = {
131
131
  "model_name": self.spec.model,
132
132
  "error": str(e),
133
+ "error_trace": traceback.format_exc()
133
134
  }
134
- logger.debug(f"Encountered Error: {e}. Skipping.")
135
+ logger.warn(f"Encountered Error: {e}. Skipping.")
136
+ logger.warn(traceback.format_exc())
135
137
 
136
138
  def _build_model(self) -> pd.DataFrame:
137
139
  full_data_dict = self.datasets.get_data_by_series()
@@ -379,7 +379,7 @@ spec:
379
379
  - prophet
380
380
  - arima
381
381
  - neuralprophet
382
- - mlforecast
382
+ - lgbforecast
383
383
  - automlx
384
384
  - autots
385
385
  - auto-select
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: oracle_ads
3
- Version: 2.11.17
3
+ Version: 2.11.18
4
4
  Summary: Oracle Accelerated Data Science SDK
5
5
  Keywords: Oracle Cloud Infrastructure,OCI,Machine Learning,ML,Artificial Intelligence,AI,Data Science,Cloud,Oracle
6
6
  Author: Oracle Data Science
@@ -37,6 +37,8 @@ Requires-Dist: oracle_ads[opctl] ; extra == "anomaly"
37
37
  Requires-Dist: autots ; extra == "anomaly"
38
38
  Requires-Dist: oracledb ; extra == "anomaly"
39
39
  Requires-Dist: report-creator==1.0.9 ; extra == "anomaly"
40
+ Requires-Dist: rrcf==0.4.4 ; extra == "anomaly"
41
+ Requires-Dist: scikit-learn ; extra == "anomaly"
40
42
  Requires-Dist: jupyter_server ; extra == "aqua"
41
43
  Requires-Dist: hdfs[kerberos] ; extra == "bds"
42
44
  Requires-Dist: ibis-framework[impala] ; extra == "bds"
@@ -75,6 +77,7 @@ Requires-Dist: plotly ; extra == "forecast"
75
77
  Requires-Dist: oracledb ; extra == "forecast"
76
78
  Requires-Dist: report-creator==1.0.9 ; extra == "forecast"
77
79
  Requires-Dist: geopandas<1.0.0 ; extra == "geo"
80
+ Requires-Dist: fiona<=1.9.6 ; extra == "geo"
78
81
  Requires-Dist: oracle_ads[viz] ; extra == "geo"
79
82
  Requires-Dist: transformers ; extra == "huggingface"
80
83
  Requires-Dist: tf-keras ; extra == "huggingface"
@@ -72,7 +72,7 @@ ads/catalog/project.py,sha256=eiCBOu9bHyQUH9SquSi880PDQftyRy3dONO_Qxtdeyk,16092
72
72
  ads/catalog/summary.py,sha256=Zy_koBb5FTsP64zyNbqmQZJEWqtoV0lOvI-ZRCQSXa4,5790
73
73
  ads/common/__init__.py,sha256=NBFa_nDAtft8NSiHIfDh5yfxbcJnXISamVH6DrJR_50,293
74
74
  ads/common/analyzer.py,sha256=MrFxBNJwFJwv_kbuJheqvOTz537z7ITE3Il244l3eZU,1893
75
- ads/common/auth.py,sha256=3Jw-O_aC06B9XS4-crvt17a4i8lrIw8Cz4f_SxO6lls,45733
75
+ ads/common/auth.py,sha256=xU9R_WwtOhe9x815lgmdn0Q2lXlxaY6RDCcfjyjhhFI,45961
76
76
  ads/common/card_identifier.py,sha256=csCCSQNka8wpHE90IGUJqFmFvjbFd42eEIlmUZuOwMA,2458
77
77
  ads/common/config.py,sha256=5QNJaJ5A2tMrDRJemJt62jxZ0pSGRz4bPkn9HGA__N0,20253
78
78
  ads/common/data.py,sha256=jQHf9Kc7llzdnQjseGgMhVuR0XLRafBvEQVk0OY2s_8,6939
@@ -417,13 +417,13 @@ ads/jobs/builders/base.py,sha256=o_njFwWQpGY755KbYwpYhvup7UGdcDnN06RdVtAbOkM,483
417
417
  ads/jobs/builders/infrastructure/__init__.py,sha256=SgpGnF6ppE6LneSPWysGVdBrYMvVd-jYZD8oQfqtR34,246
418
418
  ads/jobs/builders/infrastructure/base.py,sha256=cm4QXdQ-3Qk3Jz-oVzmeKqLaWW06HgSpc4Q9P3vIHFQ,4405
419
419
  ads/jobs/builders/infrastructure/dataflow.py,sha256=XTuDhcz96vqskE5dFXWqzic1YcYcD5qPlKGhP4J82J0,39281
420
- ads/jobs/builders/infrastructure/dsc_job.py,sha256=T6fLHtGsmpdoKpeGg6IsUxkxO023sXF4OXEjpUe7Ml4,64958
421
- ads/jobs/builders/infrastructure/dsc_job_runtime.py,sha256=IMCRImp6zwAUmjPQDY1Q3YXM2gfa0cLoCdTLtskFaYw,46559
420
+ ads/jobs/builders/infrastructure/dsc_job.py,sha256=xnFAP-vH20UraYndQPniHnvC7grZ8BmmctQynkeoua8,65028
421
+ ads/jobs/builders/infrastructure/dsc_job_runtime.py,sha256=uY_HsBIA5fdfUKIQPdrXq_iu_ZJ32zrVzk-oNV0BWDA,46294
422
422
  ads/jobs/builders/infrastructure/utils.py,sha256=SfGvKiIUsbnMnYFxmMnRtmCDkaiJR0_CuRenP94iQyI,1623
423
423
  ads/jobs/builders/runtimes/__init__.py,sha256=-aGtuFul2fJIMa7xNoOKNFaBAQeBNcZk71hf6dVSohA,204
424
- ads/jobs/builders/runtimes/artifact.py,sha256=w5ZLRSeXxHbhK1cCSrlp-oloJNNLmmibNuJNvkiwiV0,12823
424
+ ads/jobs/builders/runtimes/artifact.py,sha256=7RPm-7hd8zG15iCJDIBbfMr7d003Bed9_0ioM-mu5nE,12555
425
425
  ads/jobs/builders/runtimes/base.py,sha256=KcZMZnyL4eA7EVawYCfa7M11f6lvGbuXZRnqsaVFZBQ,10436
426
- ads/jobs/builders/runtimes/container_runtime.py,sha256=WPgq7L2YU8HRcnvNTRPFJcUpQgM8cOU1oCYAFjLNuGc,6891
426
+ ads/jobs/builders/runtimes/container_runtime.py,sha256=T_M7uQW-2tTd9taYC6kz5OD1dG_urIkhNhpQPbatO00,7598
427
427
  ads/jobs/builders/runtimes/python_runtime.py,sha256=lr4XIAfJ-c_cuewf8E-qq-gSNgT2C2qFG57VNwCLODY,35568
428
428
  ads/jobs/builders/runtimes/pytorch_runtime.py,sha256=jQ7iIS3juvzkK9qAPuQdMM_YVk4QepM14e8P6RY0D4E,7238
429
429
  ads/jobs/schema/__init__.py,sha256=xMyuwB5xsIEW9MFmvyjmF1YnRarsIjeFe2Ib-aprCG4,210
@@ -561,11 +561,11 @@ ads/opctl/backend/marketplace/models/marketplace_type.py,sha256=Uy_trT3jTlzMINFE
561
561
  ads/opctl/backend/marketplace/models/ocir_details.py,sha256=SHCCMXUR1Bn3IdcIW5rrJ48XXF50bGNYjVUQKGjZU8w,1606
562
562
  ads/opctl/conda/__init__.py,sha256=DwYupQz6SOfMLmmAjJ9danchK0shQRJKTGPU--naQgY,204
563
563
  ads/opctl/conda/cli.py,sha256=D6PPHebEXS4srO9dEBTE4YGUJjQvwx0w9v2M5VWs27A,4873
564
- ads/opctl/conda/cmds.py,sha256=_eodC2A0FINrsBAE_d7K91TBNduKNIhelKZfRbDjpn4,24247
564
+ ads/opctl/conda/cmds.py,sha256=grUBw6CI4bzSixtZhaYwKjM7HnFRoD9ewFpmw4kX5gk,26334
565
565
  ads/opctl/conda/config.yaml,sha256=yDg1cQOCxG2-BvHLfIuc1YT9adlm9kDqDpe4Q882ngY,1026
566
566
  ads/opctl/conda/manifest_template.yaml,sha256=V_uxOhe_eGgsV92u_6onPK-w0rKTLHL_tIhZ9FKqmAI,194
567
567
  ads/opctl/conda/multipart_uploader.py,sha256=1R09ajToBYZsQjgM3-ASnheIOsnZf7sYCHIcBoCjB30,6180
568
- ads/opctl/conda/pack.py,sha256=HNkb-5YnBCi4LvOx3lV4dRpchQHGowBHQFW6-TRyYx4,2829
568
+ ads/opctl/conda/pack.py,sha256=ghv-mudoS2KVZ2qbEjW7cK1bRu6R3Hto1_3bga0HCMQ,2921
569
569
  ads/opctl/config/__init__.py,sha256=DwYupQz6SOfMLmmAjJ9danchK0shQRJKTGPU--naQgY,204
570
570
  ads/opctl/config/base.py,sha256=R4Grgdjjnax7LLNiNC90VzeUHtsPPjbOcOs1WN5Tlxs,1472
571
571
  ads/opctl/config/merger.py,sha256=DMSTnZj7OOmbO_QM4uKrWUjS9REvMn8zkK8V0uZHO1I,11332
@@ -631,19 +631,20 @@ ads/opctl/operator/lowcode/anomaly/README.md,sha256=E3vpyc5iKvIq8iuvGj8ZvLq3i_Q5
631
631
  ads/opctl/operator/lowcode/anomaly/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
632
632
  ads/opctl/operator/lowcode/anomaly/__main__.py,sha256=q7TSFpSmLSAXlwjWNMi_M5y9ndF86RPd7KJ_kanltjM,3328
633
633
  ads/opctl/operator/lowcode/anomaly/cmd.py,sha256=e6ATBJcPXEdZ85hlSb7aWselA-8LlvtpI0AuO4Yw6Iw,1002
634
- ads/opctl/operator/lowcode/anomaly/const.py,sha256=oHsguh6vr5YdrjC80uiugA00NfgUyn6QQ_1dQRUztQU,2890
634
+ ads/opctl/operator/lowcode/anomaly/const.py,sha256=nNZqjH-YNB2GVsk890v3B88pml15xrSOPjvfW2P5M1o,2930
635
635
  ads/opctl/operator/lowcode/anomaly/environment.yaml,sha256=J6KiIHOb5a2AcgZm1sisMgbjABlizyYRUq_aYZBk228,156
636
636
  ads/opctl/operator/lowcode/anomaly/operator_config.py,sha256=A1LBD0n3_M6M_2NuFQ6FrLq4vukUL47iPbPDBkIS3OY,4328
637
- ads/opctl/operator/lowcode/anomaly/schema.yaml,sha256=oWfFO_AyzMImEkgpWNpkoR8xm-YnMHeMZ76LYT32oeo,9174
637
+ ads/opctl/operator/lowcode/anomaly/schema.yaml,sha256=jMSoCqb58Dz4_LeB55LO9_NRQ8TKPeVdl5VkGZHlqYs,9200
638
638
  ads/opctl/operator/lowcode/anomaly/utils.py,sha256=Uj98FO5oM-sLjoqsOnoBmgSMF7iJiL0XX-gvphw9yiU,2746
639
639
  ads/opctl/operator/lowcode/anomaly/model/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
640
640
  ads/opctl/operator/lowcode/anomaly/model/anomaly_dataset.py,sha256=zpRRAtbjRgX9HPJb_7-eZ96c1AGQgDjjs-CsLTvYtuY,5402
641
641
  ads/opctl/operator/lowcode/anomaly/model/automlx.py,sha256=Zn4ySrGfLbaKW0KIduwdnY0-YK8XAprCcMhElA4g-Vc,3401
642
642
  ads/opctl/operator/lowcode/anomaly/model/autots.py,sha256=WlA39DA3GeQfW5HYiBLCArVQBXGzIVQH3D09cZYGjtg,3689
643
- ads/opctl/operator/lowcode/anomaly/model/base_model.py,sha256=BKT9nIHXUQfdX1yzg5dd9WGJlTRybpc2xXvfIU3gbXc,14692
644
- ads/opctl/operator/lowcode/anomaly/model/factory.py,sha256=fgtWEkkMIlfThNvXvccRfLXmWmJ_kKuOLNVm0uhKeRA,3126
643
+ ads/opctl/operator/lowcode/anomaly/model/base_model.py,sha256=bq2VgRxLIRFov8pEoYCPGw3AXUmTJktA2nszQN8La2c,15365
644
+ ads/opctl/operator/lowcode/anomaly/model/factory.py,sha256=XEh5bdnWDjIEBswrOb36CeTmRcWQ2uUGDrC3e3iJVxY,3264
645
645
  ads/opctl/operator/lowcode/anomaly/model/isolationforest.py,sha256=Kjsuio7cM-dKv63p58B9Jj0XPly6Z0hqfghs5nnXepA,2671
646
646
  ads/opctl/operator/lowcode/anomaly/model/oneclasssvm.py,sha256=eQpNyax1hnufLHhL8Rbzee28comD2fF7TLn3TpzMrs8,2583
647
+ ads/opctl/operator/lowcode/anomaly/model/randomcutforest.py,sha256=HUyWQOFjfLkIWsnmhfEn9354slKStlv6jIwQi5xzVj0,4270
647
648
  ads/opctl/operator/lowcode/anomaly/model/tods.py,sha256=_v0KkdTKD3nqzOu3P5tE7bSV63Jy91h6Hr88Eequ0RU,4175
648
649
  ads/opctl/operator/lowcode/common/__init__.py,sha256=rZrmh1nho40OCeabXCNWtze-mXi-PGKetcZdxZSn3_0,204
649
650
  ads/opctl/operator/lowcode/common/const.py,sha256=1dUhgup4L_U0s6BSYmgLPpZAe6xqfSHPPoLqW0j46U8,265
@@ -670,23 +671,23 @@ ads/opctl/operator/lowcode/forecast/README.md,sha256=kbCCEdo-0pwKlZp9ctnWUK6Z31n
670
671
  ads/opctl/operator/lowcode/forecast/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
671
672
  ads/opctl/operator/lowcode/forecast/__main__.py,sha256=5Vh-kClwxTsvZLEuECyQBvbZFfH37HQW2G09RwX11Kw,2503
672
673
  ads/opctl/operator/lowcode/forecast/cmd.py,sha256=Q-R3yfK7aPfE4-0zIqzLFSjnz1tVMxJ1bbvrCirVZHQ,1246
673
- ads/opctl/operator/lowcode/forecast/const.py,sha256=K1skrAliy2xceSDmzDfsNTeDMl11rsFhHQXaRitBOYs,2616
674
+ ads/opctl/operator/lowcode/forecast/const.py,sha256=PBEhOGZaFWzkd5H9Vw687lq2A5q5RZNlS6Mj6ZelOuw,2618
674
675
  ads/opctl/operator/lowcode/forecast/environment.yaml,sha256=eVMf9pcjADI14_GRGdZOB_gK5_MyG_-cX037TXqzFho,330
675
676
  ads/opctl/operator/lowcode/forecast/errors.py,sha256=X9zuV2Lqb5N9FuBHHshOFYyhvng5r9KGLHnQijZ5b8c,911
676
677
  ads/opctl/operator/lowcode/forecast/model_evaluator.py,sha256=dSV1aj25wzv0V3y72YdYj4rCPjXAog13ppxYDNY9HQU,8913
677
678
  ads/opctl/operator/lowcode/forecast/operator_config.py,sha256=XskXuOWtZZb6_EcR_t6XAEdr6jt1wT30oBcWt-8zeWA,6396
678
- ads/opctl/operator/lowcode/forecast/schema.yaml,sha256=Y5j5qZQukjytZwXr2Gj0Fb9KeFjQbdzUNuAnUcH6k0Q,10137
679
+ ads/opctl/operator/lowcode/forecast/schema.yaml,sha256=Zfhh_wfWxNeTtN4bqAe623Vf0HbQWCLyNx8LkiCTCgo,10138
679
680
  ads/opctl/operator/lowcode/forecast/utils.py,sha256=oc6eBH9naYg4BB14KS2HL0uFdZHMgKsxx9vG28dJrXA,14347
680
681
  ads/opctl/operator/lowcode/forecast/model/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
681
- ads/opctl/operator/lowcode/forecast/model/arima.py,sha256=WREV3xCiCHgqdER4SLx7rZ7MNUF-7g6MIfNhMpf66FY,10779
682
- ads/opctl/operator/lowcode/forecast/model/automlx.py,sha256=bN-lqb5J7YlccEY0KfZ_oPruXvAtupQHjNW7oZDSKVI,14610
683
- ads/opctl/operator/lowcode/forecast/model/autots.py,sha256=EruAl4BFEOPGT0iM0bnCbDVNKDB0wOf3v25li4MW8Gw,13057
682
+ ads/opctl/operator/lowcode/forecast/model/arima.py,sha256=6ZXtzXcqoEMVF9DChzX0cnTJ-9tXKdbPiiSPQq4a9oM,10914
683
+ ads/opctl/operator/lowcode/forecast/model/automlx.py,sha256=nMqljeHnhuYGMmRa8e0PkDtx-ClSclQeJVowBIkq0Sk,14848
684
+ ads/opctl/operator/lowcode/forecast/model/autots.py,sha256=QxU24eZeaRpnC5rTqBFe6-5ylMorPN0sCamHUiNQVaE,13162
684
685
  ads/opctl/operator/lowcode/forecast/model/base_model.py,sha256=s4_lvasasCqvrj49ubD0H_2wA9pvh16_f5BiivqvL20,30876
685
- ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=GPwbZCe65-HZBUcg05_xaL1VPX8R1022E5W-NGJOohA,3487
686
+ ads/opctl/operator/lowcode/forecast/model/factory.py,sha256=NV_m2sEgj3byHHqLs9Vbth7d5yfvFuXj8QI3-y9x2Po,3488
686
687
  ads/opctl/operator/lowcode/forecast/model/forecast_datasets.py,sha256=d9rDmrIAbKTStOVroIKZkTEP1FP2AP0dq9XDEWt6w2c,16968
687
- ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=W2EgOrI-GswygxeDRlICbdeEkIQArEsHHKZlQy2ZnTA,9106
688
- ads/opctl/operator/lowcode/forecast/model/neuralprophet.py,sha256=SSJPFnrDqoWYIm96c48UQ5WHvEa72a6G4bLNqv8R2tQ,19198
689
- ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=3OEy8YSbuJd3ayhPNt93LBVffgdpuaQZh5nuChze1cQ,14453
688
+ ads/opctl/operator/lowcode/forecast/model/ml_forecast.py,sha256=EOFZR5wjZcpKACW3ZNnxd31Okz_ehOSaO5_dKL-Ktgw,9558
689
+ ads/opctl/operator/lowcode/forecast/model/neuralprophet.py,sha256=pRmhLHjP027gmPbkgqzR2SZYKvj1rG9Heev2P8mSZ_k,19347
690
+ ads/opctl/operator/lowcode/forecast/model/prophet.py,sha256=0OBnyVP9bFpo1zSAqA5qtobZxICRTLVT9mwPOlHb3sM,14554
690
691
  ads/opctl/operator/lowcode/pii/MLoperator,sha256=GKCuiXRwfGLyBqELbtgtg-kJPtNWNVA-kSprYTqhF64,6406
691
692
  ads/opctl/operator/lowcode/pii/README.md,sha256=2P3tpKv6v__Eehj6iLfTXgyDhS4lmi1BTfEdmJhT0K4,9237
692
693
  ads/opctl/operator/lowcode/pii/__init__.py,sha256=sAqmLhogrLXb3xI7dPOj9HmSkpTnLh9wkzysuGd8AXk,204
@@ -804,8 +805,8 @@ ads/type_discovery/unknown_detector.py,sha256=yZuYQReO7PUyoWZE7onhhtYaOg6088wf1y
804
805
  ads/type_discovery/zipcode_detector.py,sha256=3AlETg_ZF4FT0u914WXvTT3F3Z6Vf51WiIt34yQMRbw,1421
805
806
  ads/vault/__init__.py,sha256=x9tMdDAOdF5iDHk9u2di_K-ze5Nq068x25EWOBoWwqY,245
806
807
  ads/vault/vault.py,sha256=hFBkpYE-Hfmzu1L0sQwUfYcGxpWmgG18JPndRl0NOXI,8624
807
- oracle_ads-2.11.17.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
808
- oracle_ads-2.11.17.dist-info/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
809
- oracle_ads-2.11.17.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
810
- oracle_ads-2.11.17.dist-info/METADATA,sha256=jajJ9OV8L1sKIjD9uFhG5o-HaXf_UbZgkbJbuLtYydo,15895
811
- oracle_ads-2.11.17.dist-info/RECORD,,
808
+ oracle_ads-2.11.18.dist-info/entry_points.txt,sha256=9VFnjpQCsMORA4rVkvN8eH6D3uHjtegb9T911t8cqV0,35
809
+ oracle_ads-2.11.18.dist-info/LICENSE.txt,sha256=zoGmbfD1IdRKx834U0IzfFFFo5KoFK71TND3K9xqYqo,1845
810
+ oracle_ads-2.11.18.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
811
+ oracle_ads-2.11.18.dist-info/METADATA,sha256=iFxKKVAC8wzz6V79zwLCYZHHPx741I_hEsdXY4fKjpo,16037
812
+ oracle_ads-2.11.18.dist-info/RECORD,,