|
10 | 10 | from urllib.parse import quote |
11 | 11 |
|
12 | 12 | from .drive import File |
13 | | -from .utils import ApiComponent, TrackerSet, to_snake_case |
| 13 | +from .utils import ApiComponent, TrackerSet, to_snake_case, col_index_to_label |
14 | 14 |
|
15 | 15 | log = logging.getLogger(__name__) |
16 | 16 |
|
@@ -1948,6 +1948,55 @@ def add_named_range(self, name, reference, comment="", is_formula=False): |
1948 | 1948 | parent=self, **{self._cloud_data_key: response.json()} |
1949 | 1949 | ) |
1950 | 1950 |
|
| 1951 | + def update_cells(self, address, rows): |
| 1952 | + """ |
| 1953 | + Updates the cells at a given range in this worksheet. This is a convenience method since there is no |
| 1954 | + direct endpoint API for tableless row updates. |
| 1955 | + :param str|Range address: the address to resolve to a range which can be used for updating cells. |
| 1956 | + :param list[list[str]] rows: list of rows to push to this range. If updating a single cell, pass a list |
| 1957 | + containing a single row (list) containing a single cell worth of data. |
| 1958 | + """ |
| 1959 | + if isinstance(address, str): |
| 1960 | + address = self.get_range(address) |
| 1961 | + |
| 1962 | + if not isinstance(address, Range): |
| 1963 | + raise ValueError("address was not an accepted type: str or Range") |
| 1964 | + |
| 1965 | + if not isinstance(rows, list): |
| 1966 | + raise ValueError("rows was not an accepted type: list[list[str]]") |
| 1967 | + |
| 1968 | + # Let's not even try pushing to API if the range rectangle mismatches the input row and column count. |
| 1969 | + row_count = len(rows) |
| 1970 | + col_count = len(rows[0]) if row_count > 0 else 1 |
| 1971 | + |
| 1972 | + if address.row_count != row_count or address.column_count != col_count: |
| 1973 | + raise ValueError("rows and columns are not the same size as the range selected. This is required by the Microsoft Graph API.") |
| 1974 | + |
| 1975 | + address.values = rows |
| 1976 | + address.update() |
| 1977 | + |
| 1978 | + def append_rows(self, rows): |
| 1979 | + """ |
| 1980 | + Appends rows to the end of a worksheet. There is no direct Graph API to do this operation without a Table |
| 1981 | + instance. Instead, this method identifies the last row in the worksheet and requests a range after that row |
| 1982 | + and updates that range. |
| 1983 | + :param list[list[str]] rows: list of rows to push to this range. If updating a single cell, pass a list |
| 1984 | + containing a single row (list) containing a single cell worth of data. |
| 1985 | + """ |
| 1986 | + row_count = len(rows) |
| 1987 | + col_count = len(rows[0]) if row_count > 0 else 0 |
| 1988 | + |
| 1989 | + # Find the last row index so we can grab a range after it. |
| 1990 | + current_range = self.get_used_range() |
| 1991 | + target_index = current_range.row_count |
| 1992 | + |
| 1993 | + # Generate the address needed to outline the bounding rectangle to use to fill in data. |
| 1994 | + col_name = col_index_to_label(col_count) |
| 1995 | + insert_range_address = 'A{}:{}{}'.format(target_index + 1, col_name, target_index + row_count) |
| 1996 | + |
| 1997 | + # Request to push the data to the given range. |
| 1998 | + self.update_cells(insert_range_address, rows) |
| 1999 | + |
1951 | 2000 | def get_named_range(self, name): |
1952 | 2001 | """Retrieves a Named range by it's name""" |
1953 | 2002 | url = self.build_url(self._endpoints.get("get_named_range").format(name=name)) |
|
0 commit comments