Skip to content

Commit 1cb68ff

Browse files
authored
Merge branch 'main' into FSTORE-1537
2 parents 4447e3b + 4e761c8 commit 1cb68ff

33 files changed

+230
-146
lines changed

CONTRIBUTING.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
We follow a few best practices for writing the Python documentation:
3838

39-
1. Use the google docstring style:
39+
1. Use the Google docstring style:
4040

4141
```python
4242
"""[One Line Summary]
@@ -72,16 +72,17 @@ We use `mkdocs` together with `mike` ([for versioning](https://github.com/jimpor
7272
**Background about `mike`:**
7373
`mike` builds the documentation and commits it as a new directory to the gh-pages branch. Each directory corresponds to one version of the documentation. Additionally, `mike` maintains a json in the root of gh-pages with the mappings of versions/aliases for each of the directories available. With aliases you can define extra names like `dev` or `latest`, to indicate stable and unstable releases.
7474

75-
1. Install Hopsworks with `dev-docs` extras:
75+
1. Install Hopsworks with `requirements-docs.txt`:
7676

7777
```bash
78-
pip install -e ".[dev-docs]"
78+
pip install -r requirements-docs.txt
79+
pip install -e "python[dev]"
7980
```
8081

8182
2. To build the docs, first run the auto doc script:
8283

8384
```bash
84-
python auto_doc.py
85+
python python/auto_doc.py
8586
```
8687

8788
##### Option 1: Build only current version of docs

docs/templates/api/connection.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
# Connection API
1+
# Connection
22

3-
## Creation
4-
5-
{{connection_create}}
3+
{{connection}}
64

75
## Properties
86

97
{{connection_properties}}
108

119
## Methods
1210

13-
{{connection_methods}}
11+
{{connection_methods}}

docs/templates/api/connection_api.md

-11
This file was deleted.

docs/templates/api/job.md

-11
This file was deleted.

docs/templates/api/jobs.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Jobs API
22

3-
## Handle
3+
## Handle
44

55
{{job_api_handle}}
66

docs/templates/connection_api.md

-11
This file was deleted.

mkdocs.yml

+5-7
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ nav:
1616
- Guides: https://docs.hopsworks.ai/
1717
- Setup and Installation: https://docs.hopsworks.ai/
1818
- Administration: https://docs.hopsworks.ai/
19-
- API<div class="dropdown"><button class="dropbtn"> API </button> <div id="myDropdown" class="dropdown-content"> <a id="hopsworks_api_link" href="https://docs.hopsworks.ai/hopsworks-api/latest">Hopsworks API</a> <a id="hsfs_api_link" href="https://docs.hopsworks.ai/feature-store-api/latest">Feature Store API</a> <a id="hsfs_javadoc_link" href="https://docs.hopsworks.ai/feature-store-api/latest/javadoc">Feature Store JavaDoc</a> <a id="hsml_api_link" href="https://docs.hopsworks.ai/machine-learning-api/latest">MLOps API</a> </div></div>:
20-
- API Reference:
19+
- API<div class="dropdown"><button class="dropbtn"> API </button> <div id="myDropdown" class="dropdown-content"> <a id="hopsworks_api_link" href="https://docs.hopsworks.ai/hopsworks-api/latest">Python API</a> <a id="hsfs_javadoc_link" href="https://docs.hopsworks.ai/hopsworks-api/latest/javadoc">Feature Store JavaDoc</a> </div></div>:
20+
- Platform API:
2121
- Login: generated/api/login.md
2222
- Connection: generated/api/connection.md
2323
- Projects: generated/api/projects.md
@@ -33,7 +33,7 @@ nav:
3333
- KafkaSchema: generated/api/kafka_schema.md
3434
- Secrets: generated/api/secrets.md
3535
- OpenSearch: generated/api/opensearch.md
36-
- Connection (HSFS): generated/api/connection_api.md
36+
- Feature Store API:
3737
- ExpectationSuite: generated/api/expectation_suite_api.md
3838
- FeatureStore: generated/api/feature_store_api.md
3939
- FeatureGroup: generated/api/feature_group_api.md
@@ -48,11 +48,10 @@ nav:
4848
- UDF: generated/api/udf.md
4949
- HopsworksUDF: generated/api/hopsworks_udf.md
5050
- TransformationFunction: generated/api/transformation_functions_api.md
51-
- Transformation Statistics:
51+
- Transformation Statistics:
5252
- TransformationStatistics: generated/api/transformation_statistics.md
5353
- FeatureTransformationStatistics: generated/api/feature_transformation_statistics.md
5454
- ValidationReport: generated/api/validation_report_api.md
55-
- Job: generated/api/job.md
5655
- Provenance Links: generated/api/links.md
5756
- Statistics:
5857
- Statistics: generated/api/statistics_api.md
@@ -66,7 +65,7 @@ nav:
6665
- EmbeddingIndex: generated/api/embedding_index_api.md
6766
- EmbeddingFeature: generated/api/embedding_feature_api.md
6867
- SimilarityFunctionType: generated/api/similarity_function_type_api.md
69-
- Connection (HSML): generated/connection_api.md
68+
- Machine Learning API:
7069
- Model Registry:
7170
- Model Registry: generated/model-registry/model_registry_api.md
7271
- Model: generated/model-registry/model_api.md
@@ -82,7 +81,6 @@ nav:
8281
- Inference Batcher: generated/model-serving/inference_batcher_api.md
8382
- Resources: generated/model-serving/resources_api.md
8483
# Added to allow navigation using the side drawer
85-
- Hopsworks API: https://docs.hopsworks.ai/hopsworks-api/latest/
8684
- Feature Store JavaDoc: https://docs.hopsworks.ai/feature-store-javadoc/latest/
8785
- Contributing: CONTRIBUTING.md
8886
- Community ↗: https://community.hopsworks.ai/

python/auto_doc.py

+5-24
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"udf": ["hopsworks.udf"],
4141
},
4242
"api/connection.md": {
43-
"connection_create": ["hopsworks.connection.Connection.connection"],
43+
"connection": ["hopsworks.connection.Connection.connection"],
4444
"connection_properties": keras_autodoc.get_properties(
4545
"hopsworks.connection.Connection"
4646
),
@@ -61,7 +61,10 @@
6161
"job_get": ["hopsworks.core.job_api.JobApi.get_job"],
6262
"job_get_all": ["hopsworks.core.job_api.JobApi.get_jobs"],
6363
"job_properties": keras_autodoc.get_properties("hopsworks.job.Job"),
64-
"job_config": ["hopsworks.core.job_api.JobApi.get_configuration"],
64+
"job_config": [
65+
"hopsworks.core.job_api.JobApi.get_configuration",
66+
"hopsworks_common.core.job_configuration.JobConfiguration",
67+
],
6568
"job_methods": keras_autodoc.get_methods(
6669
"hopsworks.job.Job", exclude=["from_response_json", "json"]
6770
),
@@ -190,13 +193,6 @@
190193
"hopsworks.core.opensearch_api.OpenSearchApi"
191194
),
192195
},
193-
"api/connection_api.md": {
194-
"connection": ["hsfs.connection.Connection"],
195-
"connection_properties": keras_autodoc.get_properties(
196-
"hsfs.connection.Connection"
197-
),
198-
"connection_methods": keras_autodoc.get_methods("hsfs.connection.Connection"),
199-
},
200196
"api/spine_group_api.md": {
201197
"fg": ["hsfs.feature_group.SpineGroup"],
202198
"fg_create": ["hsfs.feature_store.FeatureStore.get_or_create_spine_group"],
@@ -413,14 +409,6 @@
413409
"hsfs.validation_report.ValidationReport"
414410
),
415411
},
416-
"api/job.md": {
417-
"job_configuration": ["hsfs.core.job_configuration.JobConfiguration"],
418-
"job": ["hsfs.core.job.Job"],
419-
"job_methods": [
420-
"hsfs.core.job.Job.get_state",
421-
"hsfs.core.job.Job.get_final_state",
422-
],
423-
},
424412
"api/query_api.md": {
425413
"query_methods": keras_autodoc.get_methods(
426414
"hsfs.constructor.query.Query",
@@ -550,13 +538,6 @@
550538
"similarity_function_type": ["hsfs.embedding.SimilarityFunctionType"],
551539
},
552540
# Model registry
553-
"connection_api.md": {
554-
"connection": ["hsml.connection.Connection"],
555-
"connection_properties": keras_autodoc.get_properties(
556-
"hsml.connection.Connection", exclude=["trust_store_path"]
557-
),
558-
"connection_methods": keras_autodoc.get_methods("hsml.connection.Connection"),
559-
},
560541
"model-registry/model_registry_api.md": {
561542
"mr_get": ["hsml.connection.Connection.get_model_registry"],
562543
"mr_modules": keras_autodoc.get_properties(

python/hopsworks_common/client/hopsworks.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
from hopsworks_common.client import auth, base
2222

2323

24+
try:
25+
import jks
26+
except ImportError:
27+
pass
28+
29+
2430
class Client(base.Client):
2531
HOPSWORKS_HOSTNAME_VERIFICATION = "HOPSWORKS_HOSTNAME_VERIFICATION"
2632
DOMAIN_CA_TRUSTSTORE_PEM = "DOMAIN_CA_TRUSTSTORE_PEM"
@@ -50,7 +56,7 @@ def __init__(self, hostname_verification):
5056
self._hostname_verification = os.environ.get(
5157
self.HOPSWORKS_HOSTNAME_VERIFICATION, "{}".format(hostname_verification)
5258
).lower() in ("true", "1", "y", "yes")
53-
self._hopsworks_ca_trust_store_path = self._get_ca_chain_path()
59+
self._hopsworks_ca_trust_store_path = self._materialize_ca_chain()
5460

5561
self._project_id = os.environ[self.PROJECT_ID]
5662
self._project_name = self._project_name()
@@ -67,10 +73,23 @@ def __init__(self, hostname_verification):
6773

6874
credentials = self._get_credentials(self._project_id)
6975

70-
self._write_pem_file(credentials["caChain"], self._get_ca_chain_path())
7176
self._write_pem_file(credentials["clientCert"], self._get_client_cert_path())
7277
self._write_pem_file(credentials["clientKey"], self._get_client_key_path())
7378

79+
def _materialize_ca_chain(self):
80+
"""Convert truststore from jks to pem and return the location"""
81+
ca_chain_path = Path(self._get_ca_chain_path())
82+
if not ca_chain_path.exists():
83+
keystore_pw = self._cert_key
84+
ks = jks.KeyStore.load(
85+
self._get_jks_key_store_path(), keystore_pw, try_decrypt_keys=True
86+
)
87+
ts = jks.KeyStore.load(
88+
self._get_jks_trust_store_path(), keystore_pw, try_decrypt_keys=True
89+
)
90+
self._write_ca_chain(ks, ts, ca_chain_path)
91+
return str(ca_chain_path)
92+
7493
def _get_hopsworks_rest_endpoint(self):
7594
"""Get the hopsworks REST endpoint for making requests to the REST API."""
7695
return os.environ[self.REST_ENDPOINT]

python/hopsworks_common/connection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
HOPSWORKS_PORT_DEFAULT = 443
4040
HOSTNAME_VERIFICATION_DEFAULT = os.environ.get(
41-
"HOPSWORKS_HOSTNAME_VERIFICATION", "True"
41+
"HOPSWORKS_HOSTNAME_VERIFICATION", "False"
4242
).lower() in ("true", "1", "y", "yes")
4343
# alias for backwards compatibility:
4444
HOPSWORKS_HOSTNAME_VERIFICATION_DEFAULT = HOSTNAME_VERIFICATION_DEFAULT

python/hopsworks_common/core/constants.py

+17-7
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,35 @@
2525
HAS_CONFLUENT_KAFKA: bool = importlib.util.find_spec("confluent_kafka") is not None
2626
confluent_kafka_not_installed_message = (
2727
"Confluent Kafka package not found. "
28-
"If you want to use Kafka with Hopsworks you can install the corresponding extras "
29-
"""`pip install hopsworks[python]` or `pip install "hopsworks[python]"` if using zsh. """
30-
"You can also install confluent-kafka directly in your environment e.g `pip install confluent-kafka`. "
28+
"If you want to use Kafka with Hopsworks you can install the corresponding extras via "
29+
'`pip install "hopsworks[python]"`. '
30+
"You can also install confluent-kafka directly in your environment with `pip install confluent-kafka`. "
3131
"You will need to restart your kernel if applicable."
3232
)
33+
3334
# Data Validation / Great Expectations
3435
HAS_GREAT_EXPECTATIONS: bool = (
3536
importlib.util.find_spec("great_expectations") is not None
3637
)
3738
great_expectations_not_installed_message = (
3839
"Great Expectations package not found. "
39-
"If you want to use data validation with Hopsworks you can install the corresponding extras "
40-
"""`pip install hopsworks[great_expectations]` or `pip install "hopsworks[great_expectations]"` if using zsh. """
41-
"You can also install great-expectations directly in your environment e.g `pip install great-expectations`. "
40+
"If you want to use data validation with Hopsworks you can install the corresponding extras via "
41+
'`pip install "hopsworks[great_expectations]"`. '
42+
"You can also install great-expectations directly in your environment with `pip install great-expectations`. "
4243
"You will need to restart your kernel if applicable."
4344
)
4445
initialise_expectation_suite_for_single_expectation_api_message = "Initialize Expectation Suite by attaching to a Feature Group to enable single expectation API"
4546

46-
HAS_ARROW: bool = importlib.util.find_spec("pyarrow") is not None
47+
# Pyarrow
48+
HAS_PYARROW: bool = importlib.util.find_spec("pyarrow") is not None
49+
pyarrow_not_installed_message = (
50+
"Pyarrow package not found. "
51+
"If you want to use Apache Arrow with Hopsworks you can install the corresponding extras via "
52+
'`pip install "hopsworks[python]"`. '
53+
"You can also install pyarrow directly in your environment with `pip install pyarrow`. "
54+
"You will need to restart your kernel if applicable."
55+
)
56+
4757
HAS_PANDAS: bool = importlib.util.find_spec("pandas") is not None
4858
HAS_NUMPY: bool = importlib.util.find_spec("numpy") is not None
4959
HAS_POLARS: bool = importlib.util.find_spec("polars") is not None

python/hopsworks_common/core/type_systems.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323

2424
import pytz
2525
from hopsworks_common.core.constants import (
26-
HAS_ARROW,
2726
HAS_PANDAS,
2827
HAS_POLARS,
28+
HAS_PYARROW,
2929
)
3030
from hopsworks_common.decorators import uses_polars
3131

@@ -35,7 +35,7 @@
3535
import pandas as pd
3636
import polars as pl
3737

38-
if HAS_ARROW:
38+
if HAS_PYARROW:
3939
import pyarrow as pa
4040

4141
# Decimal types are currently not supported

python/hopsworks_common/project.py

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(
5151
services=None,
5252
datasets=None,
5353
creation_status=None,
54+
project_namespace=None,
5455
**kwargs,
5556
):
5657
self._id = project_id
@@ -67,6 +68,7 @@ def __init__(
6768
self._git_api = git_api.GitApi()
6869
self._dataset_api = dataset_api.DatasetApi()
6970
self._environment_api = environment_api.EnvironmentApi()
71+
self._project_namespace = project_namespace
7072

7173
@classmethod
7274
def from_response_json(cls, json_dict):
@@ -101,6 +103,11 @@ def created(self):
101103
"""Timestamp when the project was created"""
102104
return self._created
103105

106+
@property
107+
def project_namespace(self):
108+
"""Kubernetes namespace used by project"""
109+
return self._project_namespace
110+
104111
def get_feature_store(
105112
self, name: Optional[str] = None, engine: Optional[str] = None
106113
): # -> hsfs.feature_store.FeatureStore

python/hsfs/constructor/query.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from hsfs.constructor import join
3030
from hsfs.constructor.filter import Filter, Logic
3131
from hsfs.constructor.fs_query import FsQuery
32-
from hsfs.core import arrow_flight_client, query_constructor_api, storage_connector_api
32+
from hsfs.core import query_constructor_api, storage_connector_api
3333
from hsfs.decorators import typechecked
3434
from hsfs.feature import Feature
3535

@@ -101,6 +101,8 @@ def _prep_read(
101101
online_conn = None
102102

103103
if engine.get_instance().is_flyingduck_query_supported(self, read_options):
104+
from hsfs.core import arrow_flight_client
105+
104106
sql_query = self._to_string(fs_query, online, asof=True)
105107
sql_query = arrow_flight_client.get_instance().create_query_object(
106108
self, sql_query, fs_query.on_demand_fg_aliases

python/hsfs/core/arrow_flight_client.py

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
from functools import wraps
2424
from typing import Any, Dict, Optional, Union
2525

26+
from hopsworks_common.core.constants import HAS_PYARROW, pyarrow_not_installed_message
27+
28+
29+
if not HAS_PYARROW:
30+
raise ModuleNotFoundError(pyarrow_not_installed_message)
31+
2632
import pyarrow
2733
import pyarrow._flight
2834
import pyarrow.flight

0 commit comments

Comments
 (0)