-
Notifications
You must be signed in to change notification settings - Fork 102
/
files.py
213 lines (177 loc) · 8.01 KB
/
files.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/usr/bin/env python3
#
# Copyright (c) 2012-2023 Snowflake Computing Inc. All rights reserved.
#
"""
SnowflakeFile for UDFs and stored procedures in Snowpark.
This class is intended for usage within stored procedures and UDFs and many methods do not work locally.
"""
from __future__ import annotations
import array
import io
import sys
from io import RawIOBase
# Python 3.8 needs to use typing.Iterable because collections.abc.Iterable is not subscriptable
# Python 3.9 can use both
# Python 3.10 needs to use collections.abc.Iterable because typing.Iterable is removed
if sys.version_info <= (3, 9):
from typing import Iterable
else:
from collections.abc import Iterable
_DEFER_IMPLEMENTATION_ERR_MSG = "SnowflakeFile currently only works in UDF and Stored Procedures. It doesn't work locally yet."
class SnowflakeFile(RawIOBase):
"""
SnowflakeFile provides an interface to operate on files as Python IOBase-like objects in UDFs and stored procedures.
SnowflakeFile supports most operations supported by Python IOBase objects.
A SnowflakeFile object can be used as a Python IOBase object.
The constructor of this class is not supposed to be called directly. Call :meth:`~snowflake.snowpark.file.SnowflakeFile.open` to create a SnowflakeFile object.
This class is intended for usage within UDFs and stored procedures and many methods do not work locally.
"""
def __init__(
self,
file_location: str,
mode: str = "r",
is_owner_file: bool = False,
*,
require_scoped_url: bool = True,
) -> None:
super().__init__()
# The URL/URI of the file to be opened by the SnowflakeFile object
self._file_location: str = file_location
# The mode of file stream
self._mode: str = mode
# Whether it is intended to access owner's files
self._is_owner_file = is_owner_file
# Whether a non-scoped URL can be accessed
self._require_scoped_url = require_scoped_url
# The attributes supported as part of IOBase
self.buffer = None
self.encoding = None
self.errors = None
@classmethod
def open(
cls,
file_location: str,
mode: str = "r",
is_owner_file: bool = False,
*,
require_scoped_url: bool = True,
) -> SnowflakeFile:
"""
Returns a :class:`~snowflake.snowpark.file.SnowflakeFile`.
In UDF and Stored Procedures, the object works like a Python IOBase object and as a wrapper for an IO stream of remote files. The IO Stream is to support the file operations defined in this class.
All files are accessed in the context of the UDF owner (with the exception of caller's rights stored procedures which use the caller's context).
UDF callers should use scoped URLs to allow the UDF to access their files. By accepting only scoped URLs the UDF owner can ensure
the UDF caller had access to the provided file. Removing the requirement that the URL is a scoped URL (require_scoped_url=false) allows the caller
to provide URLs that may be only accessible by the UDF owner.
is_owner_file is marked for deprecation. For Snowflake release 7.8 and onwards please use require_scoped_url instead.
Args:
file_location: scoped URL, file URL, or string path for files located in a stage
mode: A string used to mark the type of an IO stream.
is_owner_file: (Deprecated) A boolean value, if True, the API is intended to access owner's files and all URI/URL are allowed. If False, the API is intended to access files passed into the function by the caller and only scoped URL is allowed.
require_scoped_url: A boolean value, if True, file_location must be a scoped URL. A scoped URL ensures that the caller cannot access the UDF owners files that the caller does not have access to.
"""
return cls(
file_location, mode, is_owner_file, require_scoped_url=require_scoped_url
)
def close(self) -> None:
"""
In UDF and Stored Procedures, the close func closes the IO Stream included in the SnowflakeFile.
"""
return
def detach(self) -> None:
"""
Not yet supported in UDF and Stored Procedures.
See https://docs.python.org/3/library/io.html#io.BufferedIOBase.detach
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def fileno(self) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.fileno
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def flush(self) -> None:
"""
Not yet supported in UDF and Stored Procedures.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def isatty(self) -> None:
"""
Returns false, file streams in stored procedures and UDFs are never interactive in Snowflake.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def read(self, size: int = -1) -> None:
"""
See https://docs.python.org/3/library/io.html#io.RawIOBase.read
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def read1(self, size: int = -1) -> None:
"""
See https://docs.python.org/3/library/io.html#io.BufferedIOBase.read1
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readline(self, size: int = -1) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.readline
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readable(self) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.readable
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readall(self) -> None:
"""
See https://docs.python.org/3/library/io.html#io.RawIOBase.readall
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readinto(self, b: bytes | bytearray | array.array) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.readinto
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readinto1(self, b: bytes | bytearray | array.array) -> None:
"""
See https://docs.python.org/3/library/io.html#io.BufferedIOBase.readinto1
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def readlines(self, hint: int = -1) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.readlines
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def seek(self, offset: int, whence: int = io.SEEK_SET) -> int:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.seek
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def seekable(self) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.seekable
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def tell(self) -> None:
"""
See https://docs.python.org/3/library/io.html#io.IOBase.tell
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def truncate(self, size: int | None = None) -> None:
"""
Not yet supported in UDF and Stored Procedures.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def write(self, b: bytes | bytearray | array.array) -> None:
"""
Not yet supported in UDF and Stored Procedures.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def writable(self) -> None:
"""
Not yet supported in UDF and Stored Procedures.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)
def writelines(self, lines: Iterable[str] | list[str]) -> None:
"""
Not yet supported in UDF and Stored Procedures.
"""
raise NotImplementedError(_DEFER_IMPLEMENTATION_ERR_MSG)