Skip to content

Commit 4d6a37d

Browse files
committed
added new SDK api
1 parent 9189da1 commit 4d6a37d

5 files changed

Lines changed: 83 additions & 2 deletions

File tree

src/datacustomcode/client.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,18 @@
1414
# limitations under the License.
1515
from __future__ import annotations
1616

17+
import io
18+
1719
from enum import Enum
1820
from typing import (
1921
TYPE_CHECKING,
2022
ClassVar,
2123
Optional,
2224
)
23-
2425
from pyspark.sql import SparkSession
25-
2626
from datacustomcode.config import SparkConfig, config
2727
from datacustomcode.io.reader.base import BaseDataCloudReader
28+
from datacustomcode.file.reader.base import BaseFileReader
2829

2930
if TYPE_CHECKING:
3031
from pyspark.sql import DataFrame as PySparkDataFrame
@@ -112,6 +113,7 @@ class Client:
112113
_instance: ClassVar[Optional[Client]] = None
113114
_reader: BaseDataCloudReader
114115
_writer: BaseDataCloudWriter
116+
_file: BaseFileReader
115117
_data_layer_history: dict[DataCloudObjectType, set[str]]
116118

117119
def __new__(
@@ -154,6 +156,7 @@ def __new__(
154156
writer_init = writer
155157
cls._instance._reader = reader_init
156158
cls._instance._writer = writer_init
159+
cls._instance._file = BaseFileReader()
157160
cls._instance._data_layer_history = {
158161
DataCloudObjectType.DLO: set(),
159162
DataCloudObjectType.DMO: set(),
@@ -212,6 +215,12 @@ def write_to_dmo(
212215
self._validate_data_layer_history_does_not_contain(DataCloudObjectType.DLO)
213216
return self._writer.write_to_dmo(name, dataframe, write_mode, **kwargs)
214217

218+
def file_open(self, file_name: str) -> io.TextIOWrapper:
219+
"""Read a file from the local file system.
220+
"""
221+
222+
return self._file.file_open(file_name)
223+
215224
def _validate_data_layer_history_does_not_contain(
216225
self, data_cloud_object_type: DataCloudObjectType
217226
) -> None:

src/datacustomcode/file/__init__.py

Whitespace-only changes.

src/datacustomcode/file/base.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Copyright (c) 2025, Salesforce, Inc.
2+
# SPDX-License-Identifier: Apache-2
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
from __future__ import annotations
16+
17+
from abc import ABC
18+
19+
20+
class BaseDataAccessLayer(ABC):
21+
pass

src/datacustomcode/file/reader/__init__.py

Whitespace-only changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright (c) 2025, Salesforce, Inc.
2+
# SPDX-License-Identifier: Apache-2
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
from __future__ import annotations
16+
17+
import io
18+
import os
19+
20+
from abc import abstractmethod
21+
from pathlib import Path
22+
from datacustomcode.file.base import BaseDataAccessLayer
23+
24+
class BaseFileReader(BaseDataAccessLayer):
25+
def file_open(self, file_name: str) -> io.TextIOWrapper:
26+
default_code_pacakge = 'payload'
27+
file_folder = 'files' # hardcoded folder name
28+
29+
file_path = None
30+
if os.path.exists(default_code_pacakge):
31+
relative = f"{default_code_pacakge}/{file_folder}/{file_name}"
32+
file_path = Path.cwd().joinpath(relative)
33+
else:
34+
# find config.json, files folder is right next to the config.json
35+
config_abs_path = Path(self.find_file_pathlib("config.json", Path.cwd()))
36+
relative = f"{file_folder}/{file_name}"
37+
file_path = config_abs_path.parent.joinpath(relative)
38+
39+
file_handle = open(file_path, 'r')
40+
#print(f"chuy file type: {type(foo), file_path}")
41+
return file_handle
42+
43+
def find_file_pathlib(self, filename, search_path):
44+
"""
45+
Finds a file within a directory and its subdirectories using pathlib.
46+
Returns the full path of the first match found, or None if not found.
47+
"""
48+
path_obj = Path(search_path)
49+
for file_path in path_obj.rglob(filename):
50+
return str(file_path) # Convert Path object to string
51+
return None

0 commit comments

Comments
 (0)