Giter VIP home page Giter VIP logo

simple-smartsheet's Introduction

Simple Smartsheet

Python library to interact with Smartsheet API easily

Installation

Requires Python 3.6+
pip install simple-smartsheet

Why not smartsheet-python-sdk

smartsheet-python-sdk has very wide object coverage and maps to Smartsheet API very nicely, but it does not have some convenience features (for example, easy access to cells by column titles).
simple-smartsheet library is focused on the user experience in expense of feature coverage. As of now, you can only interact with Sheets and Reports and their children objects (rows, columns, cells).
Additionally, simple-smartsheet supports asyncio and provides both sync and async API at the same time.

Usage

import os
from datetime import date
from pprint import pprint

from simple_smartsheet import Smartsheet
from simple_smartsheet.models import Sheet, Column, Row, Cell, ColumnType

TOKEN = os.getenv("SMARTSHEET_API_TOKEN")
SHEET_NAME = "[TEST] My New Sheet"
smartsheet = Smartsheet(TOKEN)

# retrieve a list of sheets (limited set of attributes)
sheets = smartsheet.sheets.list()
pprint(sheets)

# delete the test sheet if already exists
for sheet in sheets:
    if sheet.name == SHEET_NAME:
        smartsheet.sheets.delete(id=sheet.id)

# create a new Sheet
new_sheet_skeleton = Sheet(
    name=SHEET_NAME,
    columns=[
        Column(primary=True, title="Full Name", type=ColumnType.TEXT_NUMBER),
        Column(title="Number of read books", type=ColumnType.TEXT_NUMBER),
        Column(title="Birth date", type=ColumnType.DATE),
        Column(title="Library member", type=ColumnType.CHECKBOX),
    ],
)

# print the sheet object attributes used by the Smartsheet API (camelCase)
pprint(new_sheet_skeleton.dump())

# add the sheet via API
result = smartsheet.sheets.create(new_sheet_skeleton)
sheet = result.obj
print(f"ID of the created sheet is {sheet.id!r}")

# retrieve a sheet by name
# this object is exactly the same as result.obj
sheet = smartsheet.sheets.get(SHEET_NAME)

# get columns details by column title (case-sensitive)
full_name_column = sheet.get_column("Full Name")
pprint(full_name_column.__dict__)
num_books_column = sheet.get_column("Number of read books")
pprint(num_books_column.__dict__)

# add rows (cells are created using different ways)
# second way is the easiest
new_rows = [
    Row(
        to_top=True,
        cells=[
            Cell(column_id=full_name_column.id, value="Alice Smith"),
            Cell(column_id=num_books_column.id, value=5),
        ],
    ),
    Row(
        to_top=True,
        cells=sheet.make_cells(
            {"Full Name": "Bob Lee", "Number of read books": 2}
        ),
    ),
    Row(
        to_top=True,
        cells=[
            sheet.make_cell("Full Name", "Charlie Brown"),
            sheet.make_cell("Number of read books", 1),
            sheet.make_cell("Birth date", date(1990, 1, 1)),
        ],
    ),
]
smartsheet.sheets.add_rows(sheet.id, new_rows)

# sort rows by column "Full Name" descending / returns updated sheet
sheet = smartsheet.sheets.sort_rows(
    sheet, [{"column_title": "Full Name", "descending": True}]
)

print("\nSheet after adding rows:")
# print a list of dictionaries containing column titles and values for each row
pprint(sheet.as_list())

# get a specific cell and updating it:
row_id_to_delete = None
rows_to_update = []
for row in sheet.rows:
    full_name = row.get_cell("Full Name").value
    num_books = row.get_cell("Number of read books").value
    print(f"{full_name} has read {num_books} books")
    if full_name.startswith("Charlie"):
        updated_row = Row(
            id=row.id, cells=[sheet.make_cell("Number of read books", 15)]
        )
        rows_to_update.append(updated_row)
    elif full_name.startswith("Bob"):
        row_id_to_delete = row.id  # used later

# update rows
smartsheet.sheets.update_rows(sheet.id, rows_to_update)
# or a single row
# smartsheet.sheets.update_row(sheet.id, rows_to_update[0])

# get an updated sheet
sheet = smartsheet.sheets.get(id=sheet.id)
print("\nSheet after updating rows:")
pprint(sheet.as_list())

# delete a row
smartsheet.sheets.delete_row(sheet.id, row_id_to_delete)

# get an updated sheet
sheet = smartsheet.sheets.get(id=sheet.id)
print("\nSheet after deleting rows:")
pprint(sheet.as_list())

# delete a sheet by name
smartsheet.sheets.delete(SHEET_NAME)
sheets = smartsheet.sheets.list()
pprint(sheets)

API reference

While a separate docs page is work in progress, available public API is described here

Class simple_smartsheet.Smartsheet

This class a main entry point for the library
Methods:

  • def __init__(token: str): constructor for the class

Attributes:

  • token: Smartsheet API token, obtained in Personal Settings -> API access
  • sheets: simple_smartsheet.models.sheet.SheetCRUD object which provides methods to interact with sheets
  • reports: simple_smartsheet.models.report.ReportCRUD object which provides methods to interact with reports

Class simple_smartsheet.models.sheet.SheetCRUD

Methods:

  • def get(name: Optional[str], id: Optional[int]) -> Sheet: fetches Sheet by name or ID.
  • def list() -> List[Sheet]: fetches a list of all sheets (summary only)
  • def create(obj: Sheet) -> Result: adds a new sheet
  • def update(obj: Sheet) -> Result: updates a sheet
  • def delete(name: Optional[str], id: Optional[int]) -> Result: deletes a sheet by name or ID
  • def add_rows(sheet_id: int, rows: Sequence[Row]) -> Result: adds rows to the sheet
  • def add_row(sheet_id: int, row: Row) -> Result: add a single row to the sheet
  • def update_rows(sheet_id: int, rows: Sequence[Row]) -> Result: updates several rows in the sheet
  • def update_row(sheet_id: int, row: Row) -> Result: updates a single row
  • def delete_rows(sheet_id: int, row_ids: Sequence[int]) -> Result: deletes several rows with provided ids
  • def delete_row(sheet_id: int, row_id: int) -> Result: deletes a single row with a provided id
  • def sort_rows(sheet: Sheet, order: List[Dict[str, Any]]) -> Sheet: sorts sheet rows with the specified order, e.g.:
sheet.sort_rows([
    {"column_title": "Birth date", "descending": True},
    {"column_title": "Full Name"}
])

Class simple_smartsheet.models.sheet.AsyncSheetCRUD

The methods listed below are asynchronous version of methods in SheetCRUD, listed for completeness:

  • async def get(name: Optional[str], id: Optional[int]) -> Sheet
  • async def list() -> List[Sheet]
  • async def create(obj: Sheet) -> Result
  • async def update(obj: Sheet) -> Result
  • async def delete(name: Optional[str], id: Optional[int]) -> Result
  • async def add_rows(sheet_id: int, rows: Sequence[Row]) -> Result
  • async def add_row(sheet_id: int, row: Row) -> Result
  • async def update_rows(sheet_id: int, rows: Sequence[Row]) -> Result
  • async def update_row(sheet_id: int, row: Row) -> Result
  • async def delete_rows(sheet_id: int, row_ids: Sequence[int]) -> Result
  • async def delete_row(sheet_id: int, row_id: int) -> Result
  • async def sort_rows(sheet: Sheet, order: List[Dict[str, Any]]) -> Sheet

Class simple_smartsheet.models.Sheet

Attributes (converted from camelCase to snake_case):

Methods:

  • def get_row(row_num: Optional[int], row_id: Optional[int], filter: Optional[Dict[str, Any]]) -> Optional[Row]: returns a Row object by row number, ID or by filter, if a unique index was built (see section "Custom Indexes")
  • def get_rows(index_query: Dict[str, Any]) -> List[Row]: returns list of Row objects by filter, if an index was built (see section "Custom Indexes")
  • def get_column(column_title: Optional[str], column_id: Optional[int]) -> Column: returns a Column object by column title or id
  • def build_index(indexes: List[IndexKeysDict]) -> None: builds one or more indexes for quick row lookup using get_row or get_rows, e.g.:
sheet.build_index([
    {"columns": ("Company Name",), "unique": False},
    {"columns": ("Company Name", "Full Name"), "unique": True}
])
  • def make_cell(column_title: str, field_value: Union[float, str, datetime, None]) -> Cell: creates a Cell object with provided column title and an associated value
  • def make_cells(fields: Dict[str, Union[float, str, datetime, None]]) -> List[Cell]: creates a list of Cell objects from an input dictionary where column title is key associated with the field value
  • def as_list() -> List[Dict[str, Any]]: returns a list of dictionaries where column title is key associated with the field value

Class simple_smartsheet.models.row.Row

Attributes (converted from camelCase to snake_case):

Methods:

  • def get_cell(column_title: Optional[str], column_id: Optional[int]) -> Cell - returns a Cell object by column title (case-sensitive) or column id
  • def as_dict() -> Dict[str, Any] - returns a dictionary of column title to cell value mappings

Class simple_smartsheet.models.column.Column

Attributes (converted from camelCase to snake_case):

Class simple_smartsheet.models.cell.Cell

Attributes (converted from camelCase to snake_case):

Class simple_smartsheet.models.extra.Result:

Attributes (converted from camelCase to snake_case):

Class simple_smartsheet.models.Report

Attributes (converted from camelCase to snake_case):

Implements the following Sheet methods:

  • def get_row(row_num: Optional[int], row_id: Optional[int], filter: Optional[Dict[str, Any]]) -> ReportRow: returns a ReportRow object by row number, ID or by filter, if a unique index was built (see section "Custom Indexes")
  • def get_rows(index_query: Dict[str, Any]) -> List[ReportRow]: returns list of ReportRow objects by filter, if an index was built (see section "Custom Indexes")
  • def get_column(column_title: Optional[str], column_id: Optional[int]) -> ReportColumn: returns a ReportColumn object by column title or id
  • def build_index(indexes: List[IndexKeysDict]) -> None: builds one or more indexes for quick row lookup using get_row or get_rows, e.g.:
sheet.build_index([
    {"columns": ("Company Name",), "unique": False},
    {"columns": ("Company Name", "Full Name"), "unique": True}
])
  • def as_list() -> List[Dict[str, Any]]: returns a list of dictionaries where column title is key associated with the field value

Custom Indexes

It is possible to build indexes to enable quick rows lookups for sheets and reports. For this, after retrieving the sheet, call sheet.build_index function. It takes only one argument: a list of dictionaries, where every dictionary has two keys columns and unique. columns should contain a tuple with column titles (case sensitive). unique controls if the index always points to a single row (value True, lookups are done using get_row method) or multiple rows (value False, lookups are done using get_rows method).

Below you can find a code snippet (see the full example in examples/custom_indexes.py):

INDEXES = [
    {"columns": ("Company",), "unique": False},
    {"columns": ("Company", "Full Name"), "unique": True},
    {"columns": ("Email address",), "unique": True},
]
sheet = smartsheet.sheets.get("[TEST] Index Sheet")
sheet.build_index(INDEXES)

print("\nRow where email address is '[email protected]':")
print(sheet.get_row(filter={"Email Address": "[email protected]"}).as_dict())
# >
# {'Company Name': 'Globex',
#  'Email Address': '[email protected]',
#  'Full Name': 'Charlie Brown'}

print("\nRows where the company name is 'ACME':")
print([row.as_dict() for row in sheet.get_rows(filter={"Company Name": "ACME"})])
# >
# [{'Company Name': 'ACME',
#   'Email Address': '[email protected]',
#   'Full Name': 'Alice Smith'},
#  {'Company Name': 'ACME',
#   'Email Address': '[email protected]',
#   'Full Name': 'Bob Lee'}]

Asyncio

The library supports asyncio for all i/o methods, instead of calling:

smartsheet = Smartsheet(token)
sheet = smartsheets.sheets.get('my-sheet')

you need to call asynchronous context manager with an async version of smartsheet class:

with AsyncSmartsheet(token) as smartsheet:
   sheet = await smartsheet.sheets.get('my-sheet')

A complete asyncio example with different operations on sheets and reports can be found in examples/async.py

Pandas

If pandas is installed (either separately or as extras pip install simple-smartsheet[pandas]), sheets and rows can be exported as pandas.DataFrame or pandas.Series respectively. Besides column titles and respective values from the sheet, they will also include row IDs and row numbers

sheet = smartsheets.sheets.get('my-sheet')
df = sheet.as_dataframe()
series = sheet.rows[0].as_series()

simple-smartsheet's People

Contributors

dmfigol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

simple-smartsheet's Issues

ValueError: Not a valid ISO8601-formatted date string

~/projects/my/public/simple-smartsheet/simple_smartsheet/models/sheet.py in update_row_index(self, index_keys)
    172             self.row_num_to_row[row.num] = row
    173             self.row_id_to_row[row.id] = row
--> 174             row.update_index(self, index_keys)
    175
    176     def get_row(

~/projects/my/public/simple-smartsheet/simple_smartsheet/models/row.py in update_index(self, sheet, index_keys)
    108             if cell.value is not None:
    109                 if column_type == "DATE":
--> 110                     cell.value = utils.from_iso_date(cell.value)
    111                 elif column_type in ("DATETIME", "ABSTRACT_DATETIME"):
    112                     cell.value = utils.from_iso_datetime(cell.value)

~/projects/my/public/simple-smartsheet/.venv/lib/python3.6/site-packages/marshmallow/utils.py in from_iso_date(datestring, use_dateutil)
    308 def from_iso_date(datestring, use_dateutil=True):
    309     if not _iso8601_date_re.match(datestring):
--> 310         raise ValueError('Not a valid ISO8601-formatted date string')
    311     if dateutil_available and use_dateutil:
    312         return parser.isoparse(datestring).date()

ValueError: Not a valid ISO8601-formatted date string

Crash when name is missing in contact options

Traceback (most recent call last):
  ...
    self.sheet = self.smartsheet_api.sheets.get(id=sheet_id)
  File ".../site-packages/simple_smartsheet/models/base.py", line 182, in get
    obj_data, self.get_include_fields, self.get_exclude_fields, **kwargs
  File ".../site-packages/simple_smartsheet/models/base.py", line 74, in load
    obj = converter.structure(normalized_data, cls)
  File ".../site-packages/cattr/converters.py", line 178, in structure
    return self._structure_func.dispatch(cl)(obj, cl)
  File ".../site-packages/cattr/converters.py", line 296, in structure_attrs_fromdict
    conv_obj[name] = dispatch(type_)(val, type_)
  File ".../site-packages/cattr/converters.py", line 309, in _structure_list
    for e in obj
  File ".../site-packages/cattr/converters.py", line 309, in <listcomp>
    for e in obj
  File ".../site-packages/cattr/converters.py", line 296, in structure_attrs_fromdict
    conv_obj[name] = dispatch(type_)(val, type_)
  File ".../site-packages/cattr/converters.py", line 373, in _structure_union
    return self._structure_func.dispatch(other)(obj, other)
  File ".../site-packages/cattr/converters.py", line 309, in _structure_list
    for e in obj
  File ".../site-packages/cattr/converters.py", line 309, in <listcomp>
    for e in obj
  File ".../site-packages/cattr/converters.py", line 298, in structure_attrs_fromdict
    return cl(**conv_obj)
TypeError: __init__() missing 1 required keyword-only argument: 'name'
> .../site-packages/cattr/converters.py(296)structure_attrs_fromdict()
    295                 continue
--> 296             conv_obj[name] = dispatch(type_)(val, type_)
    297

ipdb> name
'contact_options'
ipdb> val
[{'email': '[email protected]'}, {'email': '[email protected]'}, {'email': '[email protected]'}]

Big list of row ids to delete should not crash

10/25/2019 3:53:33 AM    retry_fn(smartsheet.sheets.delete_rows)(sheet.id, row_ids_to_delete)
10/25/2019 3:53:33 AM  File "/app/utils.py", line 77, in f_retry
10/25/2019 3:53:33 AM    return f(*args, **kwargs)
10/25/2019 3:53:33 AM  File "/app/.venv/lib/python3.7/site-packages/simple_smartsheet/models/sheet.py", line 770, in delete_rows
10/25/2019 3:53:33 AM    result = self.smartsheet._delete(endpoint, params=params)
10/25/2019 3:53:33 AM  File "/app/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 166, in _delete
10/25/2019 3:53:33 AM    result = self._request("DELETE", endpoint, params=params, result_obj=True)
10/25/2019 3:53:33 AM  File "/app/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 102, in _request
10/25/2019 3:53:33 AM    raise exceptions.SmartsheetHTTPError.from_response(response)
10/25/2019 3:53:33 AMsimple_smartsheet.exceptions.SmartsheetHTTPClientError: HTTP response code 414 - <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
10/25/2019 3:53:33 AM<html><head>
10/25/2019 3:53:33 AM<title>414 Request-URI Too Large</title>
10/25/2019 3:53:33 AM</head><body>
10/25/2019 3:53:33 AM<h1>Request-URI Too Large</h1>
10/25/2019 3:53:33 AM<p>The requested URL's length exceeds the capacity
10/25/2019 3:53:33 AMlimit for this server.<br />
10/25/2019 3:53:33 AM</p>
10/25/2019 3:53:33 AM</body></html>

TypeError: Invalid first argument to register

Hello,

I am using simple_smartsheet version 0.5.0 with python 3.10.6 and after importing "Smartsheet" I am seeing the following error:

from simple_smartsheet import Smartsheet
Traceback (most recent call last):
File "", line 1, in
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/init.py", line 1, in
from .smartsheet import Smartsheet, AsyncSmartsheet
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/smartsheet.py", line 8, in
from simple_smartsheet import exceptions
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/exceptions.py", line 7, in
from simple_smartsheet.models.extra import Error
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/models/init.py", line 1, in
from .cell import Cell
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/models/cell.py", line 11, in
from simple_smartsheet.models.base import Schema, Object
File "/home/user/.local/lib/python3.10/site-packages/simple_smartsheet/models/base.py", line 30, in
converter.register_structure_hook(IndexesType, lambda x, _: x)
File "/home/user/.local/lib/python3.10/site-packages/cattrs/converters.py", line 280, in register_structure_hook
self._structure_func.register_cls_list([(cl, func)])
File "/home/user/.local/lib/python3.10/site-packages/cattrs/dispatch.py", line 57, in register_cls_list
self._single_dispatch.register(cls, handler)
File "/usr/lib/python3.10/functools.py", line 856, in register
raise TypeError(
TypeError: Invalid first argument to register(). typing.Dict[typing.Tuple[str, ...], simple_smartsheet.types.IndexType] is not a class.

Any ideas on how to solve this? Please let me know if there is any other information that is needed. Thank you.

TypeError: update_context() missing 1 required positional argument: 'many'

Hello,

I recently started receiving the following error when trying to access a smartsheet by name:

Traceback (most recent call last):
sheet = ss_client.sheets.get("SHEET_NAME")
File "C:\Program Files (x86)\Python37-32\lib\site-packages\simple_smartsheet\crud.py", line 144, in get
id_ = self.get_id(name)
File "C:\Program Files (x86)\Python37-32\lib\site-packages\simple_smartsheet\crud.py", line 125, in get_id
objects = self.list()
File "C:\Program Files (x86)\Python37-32\lib\site-packages\simple_smartsheet\crud.py", line 162, in list
return self._create_objects_from_data(objects_data)
File "C:\Program Files (x86)\Python37-32\lib\site-packages\simple_smartsheet\crud.py", line 113, in _create_objects_from_data
obj_data, self.list_include_fields, self.list_exclude_fields
File "C:\Program Files (x86)\Python37-32\lib\site-packages\simple_smartsheet\models\base.py", line 69, in load
normalized_data = schema.load(data)
File "C:\Program Files (x86)\Python37-32\lib\site-packages\marshmallow\schema.py", line 708, in load
postprocess=True,
File "C:\Program Files (x86)\Python37-32\lib\site-packages\marshmallow\schema.py", line 809, in _do_load
original_data=data,
File "C:\Program Files (x86)\Python37-32\lib\site-packages\marshmallow\schema.py", line 1036, in _invoke_load_processors
data=data, many=many, original_data=original_data,
File "C:\Program Files (x86)\Python37-32\lib\site-packages\marshmallow\schema.py", line 1158, in _invoke_processors
data = processor(data)
TypeError: update_context() missing 1 required positional argument: 'many'

For context, I am not using the os.getenv() method with the access token as I previously received the following response: "HTTP response code 401 - Error code 1002 - Your Access Token is invalid."

requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

  File ".../.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 71, in get
    response = self.session.get(url, params=params)
  File ".../.venv/lib/python3.7/site-packages/requests/sessions.py", line 546, in get
    return self.request('GET', url, **kwargs)
  File ".../.venv/lib/python3.7/site-packages/requests/sessions.py", line 533, in request
    resp = self.send(prep, **send_kwargs)
  File ".../.venv/lib/python3.7/site-packages/requests/sessions.py", line 646, in send
    r = adapter.send(request, **kwargs)
  File ".../.venv/lib/python3.7/site-packages/requests/adapters.py", line 498, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

ValidationError: {'workspace': ['Unknown field.']}

In [6]: api.sheets.get(id=id_)
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
<ipython-input-6-327c1b45c38e> in <module>
----> 1 api.sheets.get(id=id_)

.../simple_smartsheet/models/base.py in get(self, name, id, **kwargs)
    180             )
    181             obj = self.factory.load(
--> 182                 obj_data, self.get_include_fields, self.get_exclude_fields, **kwargs
    183             )
    184             if not obj.id:

.../simple_smartsheet/models/base.py in load(cls, data, only, exclude, **kwargs)
     70     ) -> T:
     71         schema = cls.schema(only=only, exclude=exclude)
---> 72         normalized_data = schema.load(data)
     73         normalized_data.update(kwargs)
     74         obj = converter.structure(normalized_data, cls)

.../.venv/lib/python3.6/site-packages/marshmallow/schema.py in load(self, data, many, partial, unknown)
    502         return self._do_load(
    503             data, many, partial=partial, unknown=unknown,
--> 504             postprocess=True,
    505         )
    506

.../.venv/lib/python3.6/site-packages/marshmallow/schema.py in _do_load(self, data, many, partial, unknown, postprocess)
    650             )
    651             self.handle_error(exc, data)
--> 652             raise exc
    653
    654         return result

ValidationError: {'workspace': ['Unknown field.']}

Change __repr__ for Rows

Currently new rows have repr like this:
Row(id=None, num=None)
It looks ugly, we should change it.

API token is invalid

Hi,

I receive the below error message:

Traceback (most recent call last):
File "C:\Smartsheet\Smartsheet-Data-Tracker-master\simple.py", line 20, in
sheets = smartsheet.sheets.list()
File "C:\Python\Python37-32\lib\site-packages\simple_smartsheet\crud.py", line 115, in list
self.list_url, params={"includeAll": "true"}
File "C:\Python\Python37-32\lib\site-packages\simple_smartsheet\smartsheet.py", line 88, in get
raise exceptions.SmartsheetHTTPError.from_response(response)
simple_smartsheet.exceptions.SmartsheetHTTPClientError: HTTP response code 401 - Error code 1002 - Your Access Token is invalid.
[Finished in 1.404s]

The token is valid as it works with Smartsheet API.

Sheet schema has a new field isMultiPicklistEnabled

Sheet schema has a new field, which should be added

            self.handle_error(exc, data, many=many, partial=partial)
>           raise exc
E           marshmallow.exceptions.ValidationError: {'isMultiPicklistEnabled': ['Unknown field.']}

Crash on getting sheets with options or tags

marshmallow.exceptions.ValidationError: {'columns': {2: {'options': ['Not a valid string.']}, 3: {'options': ['Not a valid string.']}}}

This is an incorrect marshmallow schema

aiohttp.client_exceptions.ServerDisconnectedError: None

When the payload is incorrect, this is what I get from async call smartsheet.sheets.add_rows(sheet2.id, new_rows_group):

Traceback (most recent call last):
  File "scripts/move_rows.py", line 54, in <module>
    asyncio.run(main())
  File "/Users/dmfigol/.pyenv/versions/3.7.4/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/Users/dmfigol/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File "scripts/move_rows.py", line 44, in main
    await smartsheet.sheets.add_rows(sheet2.id, new_rows_group)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/models/sheet.py", line 826, in add_rows
    result = await self.smartsheet._post(endpoint, data=data)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 245, in _post
    result = await self._request("POST", endpoint, data=data, result_obj=result_obj)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 205, in _request
    method=method, url=url, params=params, json=data
  File "<project-dir>/.venv/lib/python3.7/site-packages/aiohttp/client.py", line 1013, in __aenter__
    self._resp = await self._coro
  File "<project-dir>/.venv/lib/python3.7/site-packages/aiohttp/client.py", line 505, in _request
    await resp.start(conn)
  File "<project-dir>/.venv/lib/python3.7/site-packages/aiohttp/client_reqrep.py", line 848, in start
    message, payload = await self._protocol.read()  # type: ignore  # noqa
  File "<project-dir>/.venv/lib/python3.7/site-packages/aiohttp/streams.py", line 592, in read
    await self._waiter
aiohttp.client_exceptions.ServerDisconnectedError: None

However, sync version returns more complete exception:

Traceback (most recent call last):
  File "scripts/move_rows.py", line 42, in <module>
    asyncio.run(main())
  File "/Users/dmfigol/.pyenv/versions/3.7.4/lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/Users/dmfigol/.pyenv/versions/3.7.4/lib/python3.7/asyncio/base_events.py", line 579, in run_until_complete
    return future.result()
  File "scripts/move_rows.py", line 36, in main
    smartsheet.sheets.add_rows(sheet2.id, new_rows_group)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/models/sheet.py", line 699, in add_rows
    result = self.smartsheet._post(endpoint, data=data)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 140, in _post
    result = self._request("POST", endpoint, data=data, result_obj=result_obj)
  File "<project-dir>/.venv/lib/python3.7/site-packages/simple_smartsheet/smartsheet.py", line 102, in _request
    raise exceptions.SmartsheetHTTPError.from_response(response)
simple_smartsheet.exceptions.SmartsheetHTTPClientError: HTTP response code 400 - Error code 1062 - Invalid row location: You must use at least 1 location specifier.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.