Skip to content
Merged
35 changes: 35 additions & 0 deletions src/snowflake/snowpark/dataframe.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,22 @@ def collect(

See also:
:meth:`collect_nowait()`

The default blocking call retrieves all result rows into client memory.
For large results, consider :meth:`to_local_iterator` instead of
materializing a list. Use :meth:`sort` before collecting when the order
of rows matters.

Example::

>>> df = session.create_dataframe([(2, "Bob"), (1, "Alice")], schema=["id", "name"])
>>> rows = df.sort("id").collect()
>>> rows
[Row(ID=1, NAME='Alice'), Row(ID=2, NAME='Bob')]
>>> rows[0]["NAME"]
'Alice'
>>> rows[1].ID
2
"""

kwargs = {}
Expand Down Expand Up @@ -6905,6 +6921,25 @@ def queries(self) -> Dict[str, List[str]]:
Returns a ``dict`` that contains a list of queries that will be executed to
evaluate this DataFrame with the key `queries`, and a list of post-execution
actions (e.g., queries to clean up temporary objects) with the key `post_actions`.

``queries`` contains SQL statements in the DataFrame's execution plan;
a plan can contain more than one statement. ``post_actions`` contains
cleanup statements associated with that plan and can be empty. These
lists aren't result rows or a history of previously executed queries.

Use :meth:`explain` for a printed query list and, when available, a
database execution plan. Use :meth:`Session.query_history` to record
queries executed through a session. Generated SQL can change between
library versions and configurations; don't rely on exact SQL text.

Example::

>>> df = session.range(3)
>>> planned_sql = df.queries
>>> sorted(planned_sql)
['post_actions', 'queries']
>>> isinstance(planned_sql["queries"], list)
True
"""
plan_queries = self._plan.execution_queries
return {
Expand Down
6 changes: 6 additions & 0 deletions src/snowflake/snowpark/dataframe_stat_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,12 @@ def sample_by(
) -> "snowflake.snowpark.DataFrame":
"""Returns a DataFrame containing a stratified sample without replacement, based on a ``dict`` that specifies the fraction for each stratum.

``df.stat`` is the :class:`DataFrameStatFunctions` accessor for ``df``;
it groups statistical operations and doesn't select a column named
``stat``. ``df.stat.sample_by(...)``, ``df.sample_by(...)``, and
``df.sampleBy(...)`` call the same sampling operation. Separate calls
can return different random samples.

Example::

>>> df = session.create_dataframe([("Bob", 17), ("Alice", 10), ("Nico", 8), ("Bob", 12)], schema=["name", "age"])
Expand Down
5 changes: 3 additions & 2 deletions src/snowflake/snowpark/dataframe_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,9 @@ def save_as_table(

column_order: When ``mode`` is "append", data will be inserted into the target table by matching column sequence or column name. Default is "index". When ``mode`` is not "append", the ``column_order`` makes no difference.

"index": Data will be inserted into the target table by column sequence.
"name": Data will be inserted into the target table by matching column names. If the target table has more columns than the source DataFrame, use this one.
- ``"index"``: Data will be inserted into the target table by column sequence.
- ``"name"``: Data will be inserted into the target table by matching column names.
If the target table has more columns than the source DataFrame, use this one.

create_temp_table: (Deprecated) The to-be-created table will be temporary if this is set to ``True``.
table_type: The table type of table to be created. The supported values are: ``temp``, ``temporary``,
Expand Down
24 changes: 23 additions & 1 deletion src/snowflake/snowpark/file_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,29 @@


class PutResult(NamedTuple):
"""Represents the results of uploading a local file to a stage location."""
"""Represents the results of uploading a local file to a stage location.

:meth:`FileOperation.put` returns a list of these objects. Inspect each
object's ``source``, ``target``, ``status``, and ``message`` attributes to
identify the file and its upload outcome. ``SKIPPED`` means the file wasn't
uploaded; it doesn't mean a new upload succeeded.

This example requires an existing internal stage named ``example_stage``
and a session authorized to upload to it. It creates only a local text
fixture; use a stage intended for testing. File names and sizes in the
returned objects depend on the input and compression options.

Example::

>>> from pathlib import Path
>>> from tempfile import TemporaryDirectory
>>> with TemporaryDirectory() as directory: # doctest: +SKIP
... path = Path(directory) / "message.txt"
... _ = path.write_text("hello", encoding="utf-8")
... results = session.file.put(str(path), "@example_stage", auto_compress=False)
... for result in results:
... print(result.source, result.target, result.status, result.message)
"""

source: str #: The source file path.
target: str #: The file path in the stage where the source file is uploaded.
Expand Down
22 changes: 22 additions & 0 deletions src/snowflake/snowpark/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7005,6 +7005,16 @@ def array_agg(
"""Returns the input values, pivoted into an ARRAY. If the input is empty, an empty
ARRAY is returned.

Element order is unpredictable unless you specify :meth:`Column.within_group`
on the aggregate expression. Sorting the result DataFrame orders result
rows, not the elements inside each array. This also applies to the
``collect_list`` alias. When ``is_distinct=True``, the ordering expression
must refer to the same column as the aggregate input.

For example, this expression orders elements within each array by ``a``::

>>> ordered_values = array_agg("a").within_group("a")

Example::
>>> df = session.create_dataframe([[1], [2], [3], [1]], schema=["a"])
>>> df.select(array_agg("a", True).within_group("a").alias("result")).show()
Expand All @@ -7018,6 +7028,18 @@ def array_agg(
|] |
------------
<BLANKLINE>

``collect_list`` is an alias of ``array_agg`` with the same arguments and
behavior. The two names share this documentation, which is why the example
above uses ``array_agg``. By default, duplicates are retained.

This example produces an array containing ``[1, 2, 2]``:

Example using the alias::

>>> from snowflake.snowpark.functions import collect_list
>>> df = session.create_dataframe([[2], [1], [2]], schema=["a"])
>>> result = df.select(collect_list("a").within_group("a").alias("values")).collect()
"""
ast = build_function_expr("array_agg", [col, is_distinct]) if _emit_ast else None
c = _to_col_if_str(col, "array_agg")
Expand Down
31 changes: 31 additions & 0 deletions src/snowflake/snowpark/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -3269,6 +3269,24 @@ def get_session_stage(
These artifacts include libraries and packages for UDFs that you define
in this session via :func:`add_import`.

The return value is a Snowflake stage reference beginning with ``@``,
not a local directory or the contents of a file. Pass it to file
operations such as :meth:`FileOperation.put` to upload artifacts to
Snowflake. Treat this session-scoped temporary storage as disposable,
not as a permanent location for application data.

Example::

>>> stage = session.get_session_stage() # doctest: +SKIP
>>> stage.startswith("@") # doctest: +SKIP
True
>>> session.get_session_stage() == stage # doctest: +SKIP
True

The stage name is generated by Snowpark, so don't hardcode the name
returned by another session. The first call can create a temporary
stage in Snowflake and requires a connection with appropriate privileges.

Note:
This temporary stage is created once under the current database and schema of a Snowpark session.
Therefore, if you switch database or schema during the session, the stage will not be re-created
Expand Down Expand Up @@ -4302,6 +4320,19 @@ def get_current_account(self) -> Optional[str]:
"""
Returns the name of the current account for the Python connector session attached
to this session.

The value comes from the attached connection; it isn't a database or
schema name. The returned string depends on the connection's account
configuration. It can be ``None`` if that parameter isn't available.

Example::

>>> account = session.get_current_account()
>>> isinstance(account, (str, type(None)))
True

Use ``account`` when you need the account configured for an existing
session, rather than creating a new connection to inspect it.
"""
return self._conn._get_current_parameter("account")

Expand Down
16 changes: 15 additions & 1 deletion src/snowflake/snowpark/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,9 @@ def sample(
This is the main difference between :meth:`DataFrame.sample` and this method.

Args:
frac: The percentage of rows to be sampled.
frac: The fraction of rows to sample, from 0.0 to 1.0 inclusive.
For example, ``0.25`` requests approximately 25 percent of rows,
not exactly one quarter of the table. Specify either ``frac`` or ``n``.
n: The fixed number of rows to sample in the range of 0 to 1,000,000 (inclusive). Either ``frac`` or ``n`` should be provided.
seed: Specifies a seed value to make the sampling deterministic. Can be any integer between 0 and 2147483647 inclusive.
Default value is ``None``.
Expand All @@ -461,6 +463,18 @@ def sample(
- Fixed-size sampling can be slower than equivalent fraction-based sampling because fixed-size sampling prevents some query optimization.
- Fixed-size sampling doesn't work with SYSTEM | BLOCK sampling.

These examples require an existing table named ``sample_source``.
Sampling doesn't guarantee row order, and fraction-based sampling
doesn't guarantee a particular row count.

Examples::

>>> table = session.table("sample_source") # doctest: +SKIP
>>> fraction_sample = table.sample(frac=0.25, seed=7) # doctest: +SKIP
>>> fixed_sample = table.sample(n=5) # doctest: +SKIP
>>> len(fixed_sample.collect()) <= 5 # doctest: +SKIP
True

"""
DataFrame._validate_sample_input(frac, n)
if sampling_method and sampling_method.upper() not in (
Expand Down
Loading