# Google sheets API For Python3 v1







Pandas-integrated, Auto-positioning library for Google Sheet API
Features:
- Auto-positioning for value updates on sheets
- Designed to minimize API calls
- Auto-parse values on sheet to get tables with positions and pd.DataFrame interpretations
- Multi-level indexes and columns supported
## 1. Installation
```sh
pip install gsheeter
```
Requires Python 3.9+.
## 2. Basic Usage
1. Authentication
(Only service account usage is allowed so far, I will develop functions to use other auth methods in the future)
```python
# using a service account will create a global api client for the project to use throughout
import gsheeter
filename = 'service-account.json' # add a path of your service account json file
gsheeter.service_account(filename)
```
2. Load spreadsheet
```python
from gsheeter import Drive
# 1. using fileId
fileId = 'spreadsheetFileId' # use the file id of the spreadsheet you want to access
spreadsheet = Drive.get_spreadsheet(fileId)
# 2. using filename
filename = 'spreadsheetFileName' # use the name of the spreadsheet you want to access
parentId = 'folderId' # use id of the parent folder of the spreadsheet above, I recommend using folderId when using filename, not fileId
spreadsheet = Drive.get_spreadsheet(
target=filename,
folderId=parentId)
```
3. Add(Create) spreadsheet
```python
from gsheeter import Drive
filename = 'yourspeadsheet' # use the name you want
sheetname = 'default' # default value is None, use only if you want to create the first sheet with a specific name
parentId = 'anyFolderId' # if empty, spreadsheet will be replaced in your root
spreadsheet = Drive.create_spreadsheet(
filename=filename,
sheetname=sheetname,
parentId=parentId)
```
4. Load sheet
```python
from gsheeter import Drive
spreadsheet = Drive.get_spreadsheet(
target='test',
folderId='parentFolderId')
# 1. using sheetId
sheetId = 0
sheet = spreadsheet.get_sheet(sheetId)
# 2. using sheetname
sheetname = 'Sheet1'
sheet = spreadsheet.get_sheet(sheetname)
```
You can also use kwargs as follows when using Spreadsheet.get_sheet:
- delete_exist: bool = False: if the sheet being searched already exists and delete_exist is set to True, delete the existing sheet and create another one, otherwise, return the existing sheet
```python
# example
sheet = spreadsheet.get_sheet(sheetname, delete_exist=True)
```
- add: bool = True: if the sheet being searched does not exist, add one
```python
# example, throws exception if the sheet does not exist or is not added
sheet = spreadsheet.get_sheet(sheetname, add=False)
```
5. Add(Create) sheet
```python
from gsheeter import Drive
spreadsheet = Drive.get_spreadsheet(
target='test',
folderId='parentFolderId'
)
# default function behavior, Create a sheet with sheetname "Sheet1", 1000 rowCount and 26 columnCount and index of 0
sheet = spreadsheet.add_sheet()
# with a sheetname
sheetname = 'new_sheet'
sheet = spreadsheet.add_sheet(sheetname)
# create a smaller sheet with 100 rows and 10 columns
sheet = spreadsheet.add_sheet(
sheetname=sheetname,
rowCount=10,
columnCount=10,
)
# after creating a new sheet named "new_sheet", with 10 rows and 10 columns
```


6. Read sheet values: entire sheet
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheetname = 'Sheet1'
sheet = spreadsheet.get_sheet(sheetname)
values = sheet.matrix # returns 2D np.ndarray filled with Values.
# If the sheet is empty, An empty np.ndarray with size of (sheet.rowCount, sheet.columnCount)
```


7. Read sheet values: tables
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheetname = 'Sheet1'
sheet = spreadsheet.get_sheet(sheetname)
tables = sheet.tables
for t in tables:
print(t)
```


8. Read sheet values: a table
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheetname = 'Sheet1'
sheet = spreadsheet.get_sheet(sheetname)
table = sheet.table # by default, the first table(table #1) is assigned to sheet.table
```
9. Update values: using sheet
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheetname = 'Sheet1'
sheet = spreadsheet.get_sheet(sheetname)
```
```python
import numpy as np
# all coordinates follow array indexing convention, starting from 0
# gsheeter adds 1 to each coordinate to match cell address on sheet
# 1. set values of 2D np.ndarray with x, y coordinate on sheet
arr = np.zeros(shape=(4, 3))
y_offset = 0 # row 1
x_offset = 0 # column 1(A)
sheet.set_values(
data=arr,
y_offset=y_offset,
x_offset=x_offset)
```

```python
# 2. set values of 1D np.ndarray with x and y coordinate on sheet
arr = np.array([0,1,2,3,4])
y_offset = 1 # row 2
x_offset = 2 # column 3(C)
sheet.set_values(
data=arr,
y_offset=y_offset,
x_offset=x_offset)
```

```python
# 3. set values of pd.DataFrame with x and y coordinate on sheet
df = pd.DataFrame(...)
y_offset = 0
x_offset = 0
sheet.set_values(
data=df,
y_offset=y_offset,
x_offset=x_offset)
```
```python
# 4. set values of pd.Series
row = pd.Series(...)
# default values of y_offset and x_offset are 0
# if the input to .set_values() is of type pd.Series, the output value is transposed.
sheet.set_values(row)
```

```python
# 5. append values at the next row after the last non-empty row
# x_offset determines the index at which the search for non-empty row starts
arr = np.zeros(shape=(4, 3))
sheet.set_values(
data=arr,
x_offset=1, # searches for the next empty row after the last non-empty row starting from x coordinate of 1 to x coordinate of 1 + width of input data
append=True)
```


```python
arr = np.zeros(shape=(4, 3))
sheet.set_values(
data=arr,
x_offset=1,
y_offset=1, # paste the input data 1 index array along y-axis from the last-fill row
append=True
)
```


10. Update values: replace values in a row of a table
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheet = spreadsheet.get_sheet('Sheet1')
table = sheet.table
row = table.df.iloc[2] # select third row from this table
row['x'] = 'test'
row['y'] = 'test'
table.update_row(row) # then update the values of the row
```
11. Update values: delete a row of a table
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheet = spreadsheet.get_sheet('Sheet1')
table = sheet.table
# delete second row
row = table.df.iloc[1]
table.delete_row(row)
```
12. Update values: delete a table
```python
from gsheeter import Drive
fileId = 'fileId'
spreadsheet = Drive.get_spreadsheet(fileId)
sheet = spreadsheet.get_sheet('Sheet1')
table = sheet.tables[2] # select third table in the sheet
sheet.delete_table(table)
sheet.delete_table(1) # you can also use table index
```
## Advanced Usage and Object structures
1. Drive
2. Spreadsheet
3. Sheet
4. Table
## Future updates
1. Chart
2. Other authentication methods
3. Cell format
Raw data
{
"_id": null,
"home_page": null,
"name": "gsheeter",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "Yunjong Guk <haydenkuk@gmail.com>",
"keywords": "spreadsheets, google-spreadsheets, google-sheets",
"author": null,
"author_email": "Yunjong Guk <haydenkuk@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/35/af/69edddb3bb830910101c6436b47b93a4a19b3fbf851eb0f0dccce199c44d/gsheeter-0.2.6.tar.gz",
"platform": null,
"description": "# Google sheets API For Python3 v1\n\n\n\n\n\n\n\n\n\nPandas-integrated, Auto-positioning library for Google Sheet API\n\nFeatures:\n- Auto-positioning for value updates on sheets\n- Designed to minimize API calls\n- Auto-parse values on sheet to get tables with positions and pd.DataFrame interpretations\n- Multi-level indexes and columns supported\n\n## 1. Installation\n```sh\npip install gsheeter\n```\nRequires Python 3.9+.\n\n## 2. Basic Usage\n\n1. Authentication\n(Only service account usage is allowed so far, I will develop functions to use other auth methods in the future)\n```python\n# using a service account will create a global api client for the project to use throughout\nimport gsheeter\nfilename = 'service-account.json' # add a path of your service account json file\ngsheeter.service_account(filename)\n```\n2. Load spreadsheet\n```python\nfrom gsheeter import Drive\n\n# 1. using fileId\nfileId = 'spreadsheetFileId' # use the file id of the spreadsheet you want to access\n\nspreadsheet = Drive.get_spreadsheet(fileId)\n\n# 2. using filename\nfilename = 'spreadsheetFileName' # use the name of the spreadsheet you want to access\nparentId = 'folderId' # use id of the parent folder of the spreadsheet above, I recommend using folderId when using filename, not fileId\n\nspreadsheet = Drive.get_spreadsheet(\n target=filename,\n folderId=parentId)\n\n```\n3. Add(Create) spreadsheet\n```python\nfrom gsheeter import Drive\n\nfilename = 'yourspeadsheet' # use the name you want\nsheetname = 'default' # default value is None, use only if you want to create the first sheet with a specific name\nparentId = 'anyFolderId' # if empty, spreadsheet will be replaced in your root\nspreadsheet = Drive.create_spreadsheet(\n filename=filename,\n sheetname=sheetname,\n parentId=parentId)\n\n```\n\n4. Load sheet\n```python\nfrom gsheeter import Drive\n\n\nspreadsheet = Drive.get_spreadsheet(\n target='test',\n folderId='parentFolderId')\n\n# 1. using sheetId\nsheetId = 0\nsheet = spreadsheet.get_sheet(sheetId)\n\n# 2. using sheetname\nsheetname = 'Sheet1'\nsheet = spreadsheet.get_sheet(sheetname)\n```\n\nYou can also use kwargs as follows when using Spreadsheet.get_sheet:\n- delete_exist: bool = False: if the sheet being searched already exists and delete_exist is set to True, delete the existing sheet and create another one, otherwise, return the existing sheet\n```python\n# example\nsheet = spreadsheet.get_sheet(sheetname, delete_exist=True)\n```\n- add: bool = True: if the sheet being searched does not exist, add one\n```python\n# example, throws exception if the sheet does not exist or is not added\nsheet = spreadsheet.get_sheet(sheetname, add=False)\n```\n\n5. Add(Create) sheet\n```python\nfrom gsheeter import Drive\n\nspreadsheet = Drive.get_spreadsheet(\n target='test',\n folderId='parentFolderId'\n)\n\n# default function behavior, Create a sheet with sheetname \"Sheet1\", 1000 rowCount and 26 columnCount and index of 0\nsheet = spreadsheet.add_sheet()\n\n# with a sheetname\nsheetname = 'new_sheet'\nsheet = spreadsheet.add_sheet(sheetname)\n\n# create a smaller sheet with 100 rows and 10 columns\nsheet = spreadsheet.add_sheet(\n sheetname=sheetname,\n rowCount=10,\n columnCount=10,\n)\n# after creating a new sheet named \"new_sheet\", with 10 rows and 10 columns\n```\n\n\n\n6. Read sheet values: entire sheet\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheetname = 'Sheet1'\nsheet = spreadsheet.get_sheet(sheetname)\nvalues = sheet.matrix # returns 2D np.ndarray filled with Values.\n# If the sheet is empty, An empty np.ndarray with size of (sheet.rowCount, sheet.columnCount)\n```\n\n\n\n7. Read sheet values: tables\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheetname = 'Sheet1'\nsheet = spreadsheet.get_sheet(sheetname)\ntables = sheet.tables\n\nfor t in tables:\n print(t)\n```\n\n\n\n\n8. Read sheet values: a table\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheetname = 'Sheet1'\nsheet = spreadsheet.get_sheet(sheetname)\ntable = sheet.table # by default, the first table(table #1) is assigned to sheet.table\n```\n\n9. Update values: using sheet\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheetname = 'Sheet1'\nsheet = spreadsheet.get_sheet(sheetname)\n```\n```python\nimport numpy as np\n\n# all coordinates follow array indexing convention, starting from 0\n# gsheeter adds 1 to each coordinate to match cell address on sheet\n# 1. set values of 2D np.ndarray with x, y coordinate on sheet\narr = np.zeros(shape=(4, 3))\ny_offset = 0 # row 1\nx_offset = 0 # column 1(A)\nsheet.set_values(\n data=arr,\n y_offset=y_offset,\n x_offset=x_offset)\n```\n\n\n```python\n# 2. set values of 1D np.ndarray with x and y coordinate on sheet\narr = np.array([0,1,2,3,4])\ny_offset = 1 # row 2\nx_offset = 2 # column 3(C)\nsheet.set_values(\n data=arr,\n y_offset=y_offset,\n x_offset=x_offset)\n```\n\n\n```python\n# 3. set values of pd.DataFrame with x and y coordinate on sheet\ndf = pd.DataFrame(...)\ny_offset = 0\nx_offset = 0\nsheet.set_values(\n data=df,\n y_offset=y_offset,\n x_offset=x_offset)\n```\n\n```python\n# 4. set values of pd.Series\nrow = pd.Series(...)\n# default values of y_offset and x_offset are 0\n# if the input to .set_values() is of type pd.Series, the output value is transposed.\nsheet.set_values(row)\n```\n\n\n```python\n# 5. append values at the next row after the last non-empty row\n# x_offset determines the index at which the search for non-empty row starts\narr = np.zeros(shape=(4, 3))\nsheet.set_values(\n data=arr,\n x_offset=1, # searches for the next empty row after the last non-empty row starting from x coordinate of 1 to x coordinate of 1 + width of input data\n append=True)\n```\n\n\n\n```python\narr = np.zeros(shape=(4, 3))\nsheet.set_values(\n data=arr,\n x_offset=1,\n y_offset=1, # paste the input data 1 index array along y-axis from the last-fill row\n append=True\n)\n```\n\n\n\n10. Update values: replace values in a row of a table\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheet = spreadsheet.get_sheet('Sheet1')\ntable = sheet.table\nrow = table.df.iloc[2] # select third row from this table\nrow['x'] = 'test'\nrow['y'] = 'test'\ntable.update_row(row) # then update the values of the row\n```\n11. Update values: delete a row of a table\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheet = spreadsheet.get_sheet('Sheet1')\ntable = sheet.table\n\n# delete second row\nrow = table.df.iloc[1]\ntable.delete_row(row)\n```\n12. Update values: delete a table\n```python\nfrom gsheeter import Drive\n\nfileId = 'fileId'\nspreadsheet = Drive.get_spreadsheet(fileId)\nsheet = spreadsheet.get_sheet('Sheet1')\ntable = sheet.tables[2] # select third table in the sheet\nsheet.delete_table(table)\nsheet.delete_table(1) # you can also use table index\n```\n\n\n## Advanced Usage and Object structures\n\n1. Drive\n2. Spreadsheet\n3. Sheet\n4. Table\n\n## Future updates\n1. Chart\n2. Other authentication methods\n3. Cell format\n\n",
"bugtrack_url": null,
"license": null,
"summary": "Google spreadsheet Python API Abstractor integrated with pandas",
"version": "0.2.6",
"project_urls": {
"Documentation": "https://github.com/haydenkuk/gsheeter/blob/main/README.md",
"Issues": "https://github.com/haydenkuk/gsheeter/issues",
"Source": "https://github.com/haydenkuk/gsheeter"
},
"split_keywords": [
"spreadsheets",
" google-spreadsheets",
" google-sheets"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ce2819102c756aee6fcf3be99b76d13579f8b62815f1f755be4bd7eef2bbe9b9",
"md5": "9b6f0f5414bd35134fbcf888cadb86a4",
"sha256": "99e973dd6bda71adebc3de261c478bf3c948be3b4ff429db4104e17435f2e3aa"
},
"downloads": -1,
"filename": "gsheeter-0.2.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "9b6f0f5414bd35134fbcf888cadb86a4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 28278,
"upload_time": "2025-07-09T01:00:28",
"upload_time_iso_8601": "2025-07-09T01:00:28.929234Z",
"url": "https://files.pythonhosted.org/packages/ce/28/19102c756aee6fcf3be99b76d13579f8b62815f1f755be4bd7eef2bbe9b9/gsheeter-0.2.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "35af69edddb3bb830910101c6436b47b93a4a19b3fbf851eb0f0dccce199c44d",
"md5": "9efcf5d568268c6415844aa864809ce0",
"sha256": "35706321221501835faec7c41c603a568b3000ea55535db18626d4067f00c322"
},
"downloads": -1,
"filename": "gsheeter-0.2.6.tar.gz",
"has_sig": false,
"md5_digest": "9efcf5d568268c6415844aa864809ce0",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 23696,
"upload_time": "2025-07-09T01:00:30",
"upload_time_iso_8601": "2025-07-09T01:00:30.194908Z",
"url": "https://files.pythonhosted.org/packages/35/af/69edddb3bb830910101c6436b47b93a4a19b3fbf851eb0f0dccce199c44d/gsheeter-0.2.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-09 01:00:30",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "haydenkuk",
"github_project": "gsheeter",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "asttokens",
"specs": [
[
"==",
"3.0.0"
]
]
},
{
"name": "build",
"specs": [
[
"==",
"1.2.2.post1"
]
]
},
{
"name": "cachetools",
"specs": [
[
"==",
"5.5.2"
]
]
},
{
"name": "certifi",
"specs": [
[
"==",
"2025.1.31"
]
]
},
{
"name": "cffi",
"specs": [
[
"==",
"1.17.1"
]
]
},
{
"name": "charset-normalizer",
"specs": [
[
"==",
"3.4.1"
]
]
},
{
"name": "colorama",
"specs": [
[
"==",
"0.4.6"
]
]
},
{
"name": "cryptography",
"specs": [
[
"==",
"44.0.3"
]
]
},
{
"name": "dateparser",
"specs": [
[
"==",
"1.2.1"
]
]
},
{
"name": "docutils",
"specs": [
[
"==",
"0.21.2"
]
]
},
{
"name": "et_xmlfile",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "executing",
"specs": [
[
"==",
"2.2.0"
]
]
},
{
"name": "google-api-core",
"specs": [
[
"==",
"2.24.2"
]
]
},
{
"name": "google-api-python-client",
"specs": [
[
"==",
"2.166.0"
]
]
},
{
"name": "google-auth",
"specs": [
[
"==",
"2.38.0"
]
]
},
{
"name": "google-auth-httplib2",
"specs": [
[
"==",
"0.2.0"
]
]
},
{
"name": "google-auth-oauthlib",
"specs": [
[
"==",
"1.2.1"
]
]
},
{
"name": "googleapis-common-protos",
"specs": [
[
"==",
"1.69.2"
]
]
},
{
"name": "httplib2",
"specs": [
[
"==",
"0.22.0"
]
]
},
{
"name": "id",
"specs": [
[
"==",
"1.5.0"
]
]
},
{
"name": "idna",
"specs": [
[
"==",
"3.10"
]
]
},
{
"name": "jaraco.classes",
"specs": [
[
"==",
"3.4.0"
]
]
},
{
"name": "jaraco.context",
"specs": [
[
"==",
"6.0.1"
]
]
},
{
"name": "jaraco.functools",
"specs": [
[
"==",
"4.1.0"
]
]
},
{
"name": "jeepney",
"specs": [
[
"==",
"0.9.0"
]
]
},
{
"name": "keyring",
"specs": [
[
"==",
"25.6.0"
]
]
},
{
"name": "markdown-it-py",
"specs": [
[
"==",
"3.0.0"
]
]
},
{
"name": "mdurl",
"specs": [
[
"==",
"0.1.2"
]
]
},
{
"name": "more-itertools",
"specs": [
[
"==",
"10.7.0"
]
]
},
{
"name": "nh3",
"specs": [
[
"==",
"0.2.21"
]
]
},
{
"name": "numpy",
"specs": [
[
"==",
"2.2.4"
]
]
},
{
"name": "oauthlib",
"specs": [
[
"==",
"3.2.2"
]
]
},
{
"name": "openpyxl",
"specs": [
[
"==",
"3.1.5"
]
]
},
{
"name": "packaging",
"specs": [
[
"==",
"25.0"
]
]
},
{
"name": "pandas",
"specs": [
[
"==",
"2.2.3"
]
]
},
{
"name": "proto-plus",
"specs": [
[
"==",
"1.26.1"
]
]
},
{
"name": "protobuf",
"specs": [
[
"==",
"6.30.2"
]
]
},
{
"name": "pyasn1",
"specs": [
[
"==",
"0.6.1"
]
]
},
{
"name": "pyasn1_modules",
"specs": [
[
"==",
"0.4.2"
]
]
},
{
"name": "pycparser",
"specs": [
[
"==",
"2.22"
]
]
},
{
"name": "Pygments",
"specs": [
[
"==",
"2.19.1"
]
]
},
{
"name": "pyparsing",
"specs": [
[
"==",
"3.2.3"
]
]
},
{
"name": "pyproject_hooks",
"specs": [
[
"==",
"1.2.0"
]
]
},
{
"name": "python-dateutil",
"specs": [
[
"==",
"2.9.0.post0"
]
]
},
{
"name": "pytz",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "readme_renderer",
"specs": [
[
"==",
"44.0"
]
]
},
{
"name": "regex",
"specs": [
[
"==",
"2024.11.6"
]
]
},
{
"name": "requests",
"specs": [
[
"==",
"2.32.3"
]
]
},
{
"name": "requests-oauthlib",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "requests-toolbelt",
"specs": [
[
"==",
"1.0.0"
]
]
},
{
"name": "rfc3986",
"specs": [
[
"==",
"2.0.0"
]
]
},
{
"name": "rich",
"specs": [
[
"==",
"14.0.0"
]
]
},
{
"name": "rsa",
"specs": [
[
"==",
"4.9"
]
]
},
{
"name": "SecretStorage",
"specs": [
[
"==",
"3.3.3"
]
]
},
{
"name": "six",
"specs": [
[
"==",
"1.17.0"
]
]
},
{
"name": "twine",
"specs": [
[
"==",
"6.1.0"
]
]
},
{
"name": "typing_extensions",
"specs": [
[
"==",
"4.13.2"
]
]
},
{
"name": "tzdata",
"specs": [
[
"==",
"2025.2"
]
]
},
{
"name": "tzlocal",
"specs": [
[
"==",
"5.3.1"
]
]
},
{
"name": "uritemplate",
"specs": [
[
"==",
"4.1.1"
]
]
},
{
"name": "urllib3",
"specs": [
[
"==",
"2.4.0"
]
]
},
{
"name": "XlsxWriter",
"specs": [
[
"==",
"3.2.3"
]
]
}
],
"lcname": "gsheeter"
}