Skip to content

Commit

Permalink
Merge branch 'master' into feature/release_6_0_0
Browse files Browse the repository at this point in the history
  • Loading branch information
alifeee committed Oct 28, 2023
2 parents ba7bfc6 + 933fc1b commit cedc63e
Show file tree
Hide file tree
Showing 9 changed files with 1,344 additions and 7 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

jobs:

build:
release:
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down Expand Up @@ -38,7 +38,7 @@ jobs:
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
repository-url: https://test.pypi.org/legacy/
- name: Publish to PyPi
uses: pypa/gh-action-pypi-publish@release/v1
with:
Expand Down
10 changes: 10 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Release History
===============

5.12.0 (2023-10-22)
-------------------

* feature -- adding `worksheet.get_records` to get specific row ranges by @AndrewBasem1 in https://github.com/burnash/gspread/pull/1301
* Fix list_spreadsheet_files return value by @mephinet in https://github.com/burnash/gspread/pull/1308
* Fix warning message for `worksheet.update` method by @ksj20 in https://github.com/burnash/gspread/pull/1312
* change lambda function to dict (fix pyupgrade issue) by @alifeee in https://github.com/burnash/gspread/pull/1319
* allows users to silence deprecation warnings by @lavigne958 in https://github.com/burnash/gspread/pull/1324
* Add `maintain_size` to keep asked for size in `get`, `get_values` by @alifeee in https://github.com/burnash/gspread/pull/1305

5.11.3 (2023-09-29)
-------------------

Expand Down
65 changes: 60 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Google Spreadsheets Python API v4

![main workflow](https://img.shields.io/github/actions/workflow/status/burnash/gspread/main.yaml?logo=github)
![github license](https://img.shields.io/pypi/l/gspread?logo=github)
![latest download](https://img.shields.io/github/downloads-pre/burnash/gspread/latest/total?logo=github)
![GitHub licence](https://img.shields.io/pypi/l/gspread?logo=github)
![GitHub downloads](https://img.shields.io/github/downloads-pre/burnash/gspread/latest/total?logo=github)
![documentation](https://img.shields.io/readthedocs/gspread?logo=readthedocs)
![pypi download](https://img.shields.io/pypi/dm/gspread?logo=pypi)
![pypi version](https://img.shields.io/pypi/v/gspread?logo=pypi)
![PyPi download](https://img.shields.io/pypi/dm/gspread?logo=pypi)
![PyPi version](https://img.shields.io/pypi/v/gspread?logo=pypi)
![python version](https://img.shields.io/pypi/pyversions/gspread?style=pypi)

Simple interface for working with Google Sheets.
Expand All @@ -29,7 +29,7 @@ Requirements: Python 3.8+.

1. [Create credentials in Google API Console](http://gspread.readthedocs.org/en/latest/oauth2.html)

2. Start using gspread:
2. Start using gspread

```python
import gspread
Expand All @@ -49,6 +49,45 @@ wks.update('B42', "it's down there somewhere, let me take another look.")
wks.format('A1:B1', {'textFormat': {'bold': True}})
```

## v5.12 to v6.0 Migration Guide

### Upgrade from Python 3.7

Python 3.7 is [end-of-life](https://devguide.python.org/versions/). gspread v6 requires a minimum of Python 3.8.

### Change `Worksheet.update` arguments

The first two arguments (`values` & `range_name`) have swapped (to `range_name` & `values`). Either swap them (works in v6 only), or use named arguments (works in v5 & v6).

As well, `values` can no longer be a list, and must be a 2D array.

```diff
- file.sheet1.update(["54"], "B2")
+ file.sheet1.update(range_name="I7", values=[["54"]])
```

### Change colors from dictionary to text

v6 uses hexadecimal color representation. Change all colors to hex. You can use the compatibility function `gspread.utils.convert_colors_to_hex_value()` to convert a dictionary to a hex string.

```diff
- tab_color = {"red": 1, "green": 0.5, "blue": 1}
+ tab_color = "#FF7FFF"
file.sheet1.update_tab_color(tab_color)
```

### Switch lastUpdateTime from property to method

```diff
- age = spreadsheet.lastUpdateTime
+ age = spreadsheet.get_lastUpdateTime()
```

### Silence warnings

In version 5 there are many warnings to mark deprecated feature/functions/methods.
They can be silenced by setting the `GSPREAD_SILENCE_WARNINGS` environment variable to `1`

## More Examples

### Opening a Spreadsheet
Expand Down Expand Up @@ -135,6 +174,22 @@ values_list = worksheet.col_values(1)
list_of_lists = worksheet.get_values()
```

### Getting a range of values

Receive only the cells with a value in them
```python
>>> worksheet.get_values("A1:B4")
[['A1', 'B1'], ['A2']]
```

Receive a lists of lists matching the requested size
regardless if values are empty or not

```python
>>> worksheet.get_values("A1:B4", maintain_size=True)
[['A1', 'B1'], ['A2', ''], ['', ''], ['', '']]
```

### Finding a Cell

```python
Expand Down
60 changes: 60 additions & 0 deletions gspread/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
MAGIC_NUMBER = 64
CELL_ADDR_RE = re.compile(r"([A-Za-z]+)([1-9]\d*)")
A1_ADDR_ROW_COL_RE = re.compile(r"([A-Za-z]+)?([1-9]\d*)?$")
A1_ADDR_FULL_RE = re.compile(r"[A-Za-z]+\d+:[A-Za-z]+\d+") # e.g. A1:B2 not A1:B

URL_KEY_V1_RE = re.compile(r"key=([^&#]+)")
URL_KEY_V2_RE = re.compile(r"/spreadsheets/d/([a-zA-Z0-9-_]+)")
Expand Down Expand Up @@ -818,6 +819,65 @@ def to_hex(value: float) -> str:
return f"#{to_hex(red)}{to_hex(green)}{to_hex(blue)}"


def is_full_a1_notation(range_name: str) -> bool:
"""Check if the range name is a full A1 notation.
"A1:B2", "Sheet1!A1:B2" are full A1 notations
"A1:B", "A1" are not
Args:
range_name (str): The range name to check.
Returns:
bool: True if the range name is a full A1 notation, False otherwise.
Examples:
>>> is_full_a1_notation("A1:B2")
True
>>> is_full_a1_notation("A1:B")
False
"""
return A1_ADDR_FULL_RE.search(range_name) is not None


def get_a1_from_absolute_range(range_name: str) -> str:
"""Get the A1 notation from an absolute range name.
"Sheet1!A1:B2" -> "A1:B2"
"A1:B2" -> "A1:B2"
Args:
range_name (str): The range name to check.
Returns:
str: The A1 notation of the range name stripped of the sheet.
"""
if "!" in range_name:
return range_name.split("!")[1]
return range_name


# SHOULD NOT BE NEEDED UNTIL NEXT MAJOR VERSION
# def deprecation_warning(version: str, msg: str) -> None:
# """Emit a deprecation warning.

# ..note::

# This warning can be silenced by setting the environment variable:
# GSPREAD_SILENCE_WARNINGS=1
# """

# # do not emit warning if env variable is set specifically to 1
# if os.getenv(SILENCE_WARNINGS_ENV_KEY, "0") == "1":
# return

# warnings.warn(
# DEPRECATION_WARNING_TEMPLATE.format(v_deprecated=version, msg_deprecated=msg),
# DeprecationWarning,
# 4, # showd the 4th stack: [1]:current->[2]:deprecation_warning->[3]:<gspread method/function>->[4]:<user's code>
# )


if __name__ == "__main__":
import doctest

Expand Down
37 changes: 37 additions & 0 deletions gspread/worksheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
convert_hex_to_colors_dict,
fill_gaps,
finditem,
get_a1_from_absolute_range,
is_full_a1_notation,
numericise_all,
rowcol_to_a1,
)
Expand Down Expand Up @@ -394,6 +396,7 @@ def get_values(
major_dimension: Optional[Dimension] = None,
value_render_option: Optional[ValueRenderOption] = None,
date_time_render_option: Optional[DateTimeOption] = None,
maintain_size: bool = False,
) -> List[List[Any]]:
"""Returns a list of lists containing all values from specified range.
Expand Down Expand Up @@ -470,6 +473,25 @@ def get_values(
Empty trailing rows and columns will not be included.
:param bool maintain_size: (optional) Returns a matrix of values matching the size of the requested range.
.. warning::
This can only work if the requested range is a complete bounded A1 notation.
Example: ``A1:D4``: OK, ``C3:F``: Not OK, we don't know the end size of the requested range.
This does not work with ``named_range`` either.
Examples::
# Works
>>> worksheet.get("A1:B2", maintain_size=True)
[['A1', 'B1'], ['A2', '']]
# Does NOT maintain the requested size
>>> worksheet.get("A1:B", maintain_size=True)
[['A1', 'B1'], ['A2'], [], ['A4', 'B4'], ['A5']]
Examples::
# Return all values from the sheet
Expand Down Expand Up @@ -497,6 +519,7 @@ def get_values(
major_dimension=major_dimension,
value_render_option=value_render_option,
date_time_render_option=date_time_render_option,
maintain_size=maintain_size,
)
)
if combine_merged_cells is True:
Expand Down Expand Up @@ -954,6 +977,7 @@ def get(
major_dimension: Optional[Dimension] = None,
value_render_option: Optional[ValueRenderOption] = None,
date_time_render_option: Optional[DateTimeOption] = None,
maintain_size: bool = False,
) -> ValueRange:
"""Reads values of a single range or a cell of a sheet.
Expand Down Expand Up @@ -1042,6 +1066,19 @@ def get(
self.spreadsheet_id, range_name, params=params
)

values = response.get("values", [])

# range_name must be a full grid range so that we can guarantee
# startRowIndex and endRowIndex properties
if maintain_size is True and is_full_a1_notation(range_name):
a1_range = get_a1_from_absolute_range(range_name)
grid_range = a1_range_to_grid_range(a1_range)
rows = grid_range["endRowIndex"] - grid_range["startRowIndex"]
cols = grid_range["endColumnIndex"] - grid_range["startColumnIndex"]
values = fill_gaps(values, rows=rows, cols=cols)

response["values"] = values

return ValueRange.from_json(response)

def batch_get(
Expand Down
Loading

1 comment on commit cedc63e

@alifeee
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lavigne958 I'm only mentioning you to marvel at the strangeness of this. This commit was fine apart from the Python 3.x workflow failed

image

flake8's complaint was:

image

How strange, right? The ":" is inside a string. I'm not proud of the fix but hey ho, it worked.

Please sign in to comment.