pyconnectwise


Namepyconnectwise JSON
Version 0.6.1.2 PyPI version JSON
download
home_pagehttps://github.com/HealthITAU/pyconnectwise
SummaryA full-featured Python client for the ConnectWise APIs
upload_time2024-08-22 16:27:23
maintainerNone
docs_urlNone
authorHealth IT
requires_python<4.0,>=3.10
licenseGPL-3.0-only
keywords connectwise manage automate api python client annotated typed msp
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![Health IT Logo](https://healthit.com.au/wp-content/uploads/2019/06/HIT-proper-logo.png)](https://healthit.com.au)

# pyConnectWise - An API library for ConnectWise Manage and ConnectWise Automate, written in Python

pyConnectWise is a full-featured, type annotated API client written in Python for the ConnectWise APIs based off their OpenAPI schemas.

This library has been developed with the intention of making the ConnectWise APIs simple and accessible to non-coders while allowing experienced coders to utilize all features the API has to offer without the boilerplate.

pyConnectWise currently supports both ConnectWise Manage and ConnectWise Automate.

Features:
=========
- **100% API Coverage.** All endpoints and response models have had their code generated from the ConnectWise Manage and ConnectWise Automate OpenAPI schemas.
- **Non-coder friendly.** 100% annotated for full IDE auto-completion. Clients handle requests and authentication - just plug the right details in and go!
- **Fully annotated.** This library has a strong focus on type safety and type hinting. Models are declared and parsed using [Pydantic](https://github.com/pydantic/pydantic)

pyConnectWise is currently in **pre-release**. This means that while it does work, you may come across issues and inconsistencies.

As all Endpoint and Model code has been generated, not all of it has been tested. YMMV.

Endpoint generation is custom-built, but Pydantic models have been generated using a customised fork of [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator)

Known Issues:
=============
- Currently only parses **Response** models. No input models yet.
- As this project is still a WIP, documentation or code commentary may not always align.

Roadmap:
=============
- **Automate API Support** - :white_check_mark: Done
- **Robust error handling** - :white_check_mark: Done
- **Tests** - :construction: In Progress
- **Input model validation** - :chart_with_upwards_trend: Planned
- **ScreenConnect (Control) API Support** - :chart_with_upwards_trend: Planned
- **Batch requests** - :chart_with_upwards_trend: Planned

How-to:
=============
- [pyConnectWise - An API library for ConnectWise Manage and ConnectWise Automate, written in Python](#pyconnectwise---an-api-library-for-connectwise-manage-and-connectwise-automate-written-in-python)
- [Features:](#features)
- [Known Issues:](#known-issues)
- [Roadmap:](#roadmap)
- [How-to:](#how-to)
- [Install](#install)
- [Initializing the API Clients](#initializing-the-api-clients)
    - [ConnectWise Manage](#connectwise-manage)
    - [ConnectWise Automate](#connectwise-automate)
- [Working with Endpoints](#working-with-endpoints)
    - [Get many](#get-many)
    - [Get one](#get-one)
    - [Get with params](#get-with-params)
- [Child Endpoints](#child-endpoints)
        - [Example using ```/company/companies/{company_id}/sites```](#example-using-companycompaniescompany_idsites)
- [Pagination](#pagination)
- [Additional Configuration](#additional-configuration)
    - [Implementation](#implementation)
    - [Supported Options](#supported-options)
- [Examples](#examples)
    - [Get all agreements, then all additions for an agreement](#get-all-agreements-then-all-additions-for-an-agreement)
    - [Get all service tickets with an ID \> 1000](#get-all-service-tickets-with-an-id--1000)
- [Contributing](#contributing)
  - [Preparing your development environment](#preparing-your-development-environment)
    - [Quick dependencies install on apt-based systems (using pipx to manage python tools)](#quick-dependencies-install-on-apt-based-systems-using-pipx-to-manage-python-tools)
    - [Setting up your development environment](#setting-up-your-development-environment)
  - [Testing](#testing)
  - [Running code generation](#running-code-generation)
- [Supporting the project](#supporting-the-project)

# Install
Open a terminal and run ```pip install pyconnectwise``` or ```poetry add pyconnectwise```

# Initializing the API Clients

### ConnectWise Manage
```python
from pyconnectwise import ConnectWiseManageAPIClient

# init client
manage_api_client = ConnectWiseManageAPIClient(
  # your company name,
  # manage instance url,
  # your api client id,
  # your api public key,
  # your api private key,
  # optionally, a Config object for customizing API interactions. See [Additional Configuration].
)
```

### ConnectWise Automate
```python
from pyconnectwise import ConnectWiseAutomateAPIClient

# init client
automate_api_client = ConnectWiseAutomateAPIClient(
  # your automate url
  # your client id
  # automate api username
  # automate api password,
  # optionally, a Config object for customizing API interactions. See [Additional Configuration].
)
```


# Working with Endpoints
Endpoints are 1:1 to what's available for both the ConnectWise Manage and ConnectWise Automate as code is generated from their OpenAPI spec.

For more information, check out the following resources:
- [ConnectWise Manage REST API Docs (requires ConnectWise Developer account)](https://developer.connectwise.com/Products/ConnectWise_PSA/REST)
- [ConnectWise Automate REST API Docs (requires ConnectWise Developer account)](https://developer.connectwise.com/Products/ConnectWise_Automate/Integrating_with_Automate/API/REST)

### Get many
```python
### Manage ###

# sends GET request to /company/companies endpoint
companies = manage_api_client.company.companies.get()

### Automate ###

# sends GET request to /clients endpoint
clients = automate_api_client.clients.get()
```

### Get one
```python
### Manage ###

# sends GET request to /company/companies/{id} endpoint
company = manage_api_client.company.companies.id(250).get()

### Automate ###

# sends GET request to /clients/{id} endpoint
client = automate_api_client.clients.id(250).get()
```

### Get with params
```python
### Manage ###

# sends GET request to /company/companies with a conditions query string
conditional_company = manage_api_client.company.companies.get(params={
  'conditions': 'company/id=250'
})

### Automate ###
# sends GET request to /clients endpoint with a condition query string
# note that the Automate API expects the string 'condition' where-as the Manage API expects the string 'conditions'
conditional_client = automate_api_client.clients.get(params={
  'condition': 'company/id=250'
})
```

# Child Endpoints
The ConnectWise APIs have many instances of endpoints with path parameters - for example, ```/company/companies/{company_id}/sites```

This also exists in the library. Endpoints provide an ```id``` method for setting the ID and traversing down the path.

##### Example using ```/company/companies/{company_id}/sites```
```python
# equivalent to GET /company/companies/250/sites
sites = manage_api_client.company.companies.id(250).sites.get()
```

# Pagination
The ConnectWise Manage API paginates data for performance reasons through the ```page``` and ```pageSize``` query parameters. ```pageSize``` is limited to a maximum of 1000.

To make working with paginated data easy, Endpoints that implement a GET response with an array also supply a ```paginated()``` method. Under the hood this wraps a GET request, but does a lot of neat stuff to make working with pages easier.

Working with pagination
```python
# initialize a PaginatedResponse instance for /company/companies, starting on page 1 with a pageSize of 100
paginated_companies = manage_api_client.company.companies.paginated(1,100)

# access the data from the current page using the .data field
page_one_data = paginated_companies.data

# if there's a next page, retrieve the next page worth of data
paginated_companies.get_next_page()

# if there's a previous page, retrieve the previous page worth of data
paginated_companies.get_previous_page()

# iterate over all companies on the current page
for company in paginated_companies:
  # ... do things ...

# iterate over all companies in all pages
# this works by yielding every item on the page, then fetching the next page and continuing until there's no data left
for company in paginated_companies.all():
  # ... do things ...
```

# Additional Configuration
As of version ```0.4.6```, pyConnectWise clients now accept a new ```Config``` object for additional API interaction configuration.

### Implementation

```python
from pyconnectwise import ConnectWiseManageAPIClient, ConnectWiseAutomateAPIClient
from pyconnectwise.config import Config

# create an instance of Config with your own changes...
config = Config(max_retries = 5)

# ... and hand off to the clients during initialization
manage_api_client = ConnectWiseManageAPIClient(config = config)
automate_api_client = ConnectWiseAutomateAPIClient(config = config)
```

### Supported Options
As of version ```0.4.6```, the following Config options are supported:
* ```max_retries``` - The number of times to re-attempt a request if a HTTP 500 error occurs. Defaults to 3.

# Examples

### Get all agreements, then all additions for an agreement
```python
agreements = api.finance.agreements.paginated(1, 1000)
for agreement in agreements.all():
    additions = api.finance.agreements.id(agreement.id).additions.get()
```

### Get all service tickets with an ID > 1000
```python
tickets = api.service.tickets.get(params={
    'conditions': 'id > 1000'
})
```

# Contributing
Contributions to the project are welcome. If you find any issues or have suggestions for improvement, please feel free to open an issue or submit a pull request.

When working on the project, please note that there's a few requirements you'll need to install in order to run the project locally. These requirements are stored in [requirements.txt](requirements.txt)

You can install these requirements by opening a terminal, navigating to the repo's directory and running ```pip install -r requirements.txt```

## Preparing your development environment
Prerequisites:
- Python 3.10+
- [Poetry](https://python-poetry.org/docs/#installing-with-pipx)
- [Pre-Commit](https://pre-commit.com/#install)

### Quick dependencies install on apt-based systems (using pipx to manage python tools)
```bash
sudo apt install pipx
pipx install poetry
pipx install pre-commit
```
### Setting up your development environment
```bash
poetry install --with=dev
pre-commit install
```

## Testing
```bash
poetry run pytest
```

## Running code generation
```bash
poetry run python -m pyconnectwise_generator <path to schema file>
```

# Supporting the project
:heart: the project and would like to show your support? Please consider donating to the following charities:
- [Black Dog](https://donate.blackdoginstitute.org.au/)
- [Cure4 CysticFibrosis Foundation](https://app.etapestry.com/onlineforms/Cure4CFFoundation/Donatenow.html)
- [Vinnies CEO Sleepout](https://www.ceosleepout.org.au/donation)
- [Care.org.au's Ukraine Humanitarian Crisis fund](https://www.care.org.au/appeals/ukraine-humanitarian-crisis/)
- [RedFrogs Australia](https://redfrogs.com.au/support/donate)
- [Love Your Sister (Sam's 1000)](https://www.loveyoursister.org/makeadonation)

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/HealthITAU/pyconnectwise",
    "name": "pyconnectwise",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": "ConnectWise, Manage, Automate, API, Python, Client, Annotated, Typed, MSP",
    "author": "Health IT",
    "author_email": "dev@healthit.com.au",
    "download_url": "https://files.pythonhosted.org/packages/0e/88/cdcc9af42dd7f5a2997f1a701f90bd8b3fdfdefa41599e592c4a8a52b125/pyconnectwise-0.6.1.2.tar.gz",
    "platform": null,
    "description": "[![Health IT Logo](https://healthit.com.au/wp-content/uploads/2019/06/HIT-proper-logo.png)](https://healthit.com.au)\n\n# pyConnectWise - An API library for ConnectWise Manage and ConnectWise Automate, written in Python\n\npyConnectWise is a full-featured, type annotated API client written in Python for the ConnectWise APIs based off their OpenAPI schemas.\n\nThis library has been developed with the intention of making the ConnectWise APIs simple and accessible to non-coders while allowing experienced coders to utilize all features the API has to offer without the boilerplate.\n\npyConnectWise currently supports both ConnectWise Manage and ConnectWise Automate.\n\nFeatures:\n=========\n- **100% API Coverage.** All endpoints and response models have had their code generated from the ConnectWise Manage and ConnectWise Automate OpenAPI schemas.\n- **Non-coder friendly.** 100% annotated for full IDE auto-completion. Clients handle requests and authentication - just plug the right details in and go!\n- **Fully annotated.** This library has a strong focus on type safety and type hinting. Models are declared and parsed using [Pydantic](https://github.com/pydantic/pydantic)\n\npyConnectWise is currently in **pre-release**. This means that while it does work, you may come across issues and inconsistencies.\n\nAs all Endpoint and Model code has been generated, not all of it has been tested. YMMV.\n\nEndpoint generation is custom-built, but Pydantic models have been generated using a customised fork of [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator)\n\nKnown Issues:\n=============\n- Currently only parses **Response** models. No input models yet.\n- As this project is still a WIP, documentation or code commentary may not always align.\n\nRoadmap:\n=============\n- **Automate API Support** - :white_check_mark: Done\n- **Robust error handling** - :white_check_mark: Done\n- **Tests** - :construction: In Progress\n- **Input model validation** - :chart_with_upwards_trend: Planned\n- **ScreenConnect (Control) API Support** - :chart_with_upwards_trend: Planned\n- **Batch requests** - :chart_with_upwards_trend: Planned\n\nHow-to:\n=============\n- [pyConnectWise - An API library for ConnectWise Manage and ConnectWise Automate, written in Python](#pyconnectwise---an-api-library-for-connectwise-manage-and-connectwise-automate-written-in-python)\n- [Features:](#features)\n- [Known Issues:](#known-issues)\n- [Roadmap:](#roadmap)\n- [How-to:](#how-to)\n- [Install](#install)\n- [Initializing the API Clients](#initializing-the-api-clients)\n    - [ConnectWise Manage](#connectwise-manage)\n    - [ConnectWise Automate](#connectwise-automate)\n- [Working with Endpoints](#working-with-endpoints)\n    - [Get many](#get-many)\n    - [Get one](#get-one)\n    - [Get with params](#get-with-params)\n- [Child Endpoints](#child-endpoints)\n        - [Example using ```/company/companies/{company_id}/sites```](#example-using-companycompaniescompany_idsites)\n- [Pagination](#pagination)\n- [Additional Configuration](#additional-configuration)\n    - [Implementation](#implementation)\n    - [Supported Options](#supported-options)\n- [Examples](#examples)\n    - [Get all agreements, then all additions for an agreement](#get-all-agreements-then-all-additions-for-an-agreement)\n    - [Get all service tickets with an ID \\> 1000](#get-all-service-tickets-with-an-id--1000)\n- [Contributing](#contributing)\n  - [Preparing your development environment](#preparing-your-development-environment)\n    - [Quick dependencies install on apt-based systems (using pipx to manage python tools)](#quick-dependencies-install-on-apt-based-systems-using-pipx-to-manage-python-tools)\n    - [Setting up your development environment](#setting-up-your-development-environment)\n  - [Testing](#testing)\n  - [Running code generation](#running-code-generation)\n- [Supporting the project](#supporting-the-project)\n\n# Install\nOpen a terminal and run ```pip install pyconnectwise``` or ```poetry add pyconnectwise```\n\n# Initializing the API Clients\n\n### ConnectWise Manage\n```python\nfrom pyconnectwise import ConnectWiseManageAPIClient\n\n# init client\nmanage_api_client = ConnectWiseManageAPIClient(\n  # your company name,\n  # manage instance url,\n  # your api client id,\n  # your api public key,\n  # your api private key,\n  # optionally, a Config object for customizing API interactions. See [Additional Configuration].\n)\n```\n\n### ConnectWise Automate\n```python\nfrom pyconnectwise import ConnectWiseAutomateAPIClient\n\n# init client\nautomate_api_client = ConnectWiseAutomateAPIClient(\n  # your automate url\n  # your client id\n  # automate api username\n  # automate api password,\n  # optionally, a Config object for customizing API interactions. See [Additional Configuration].\n)\n```\n\n\n# Working with Endpoints\nEndpoints are 1:1 to what's available for both the ConnectWise Manage and ConnectWise Automate as code is generated from their OpenAPI spec.\n\nFor more information, check out the following resources:\n- [ConnectWise Manage REST API Docs (requires ConnectWise Developer account)](https://developer.connectwise.com/Products/ConnectWise_PSA/REST)\n- [ConnectWise Automate REST API Docs (requires ConnectWise Developer account)](https://developer.connectwise.com/Products/ConnectWise_Automate/Integrating_with_Automate/API/REST)\n\n### Get many\n```python\n### Manage ###\n\n# sends GET request to /company/companies endpoint\ncompanies = manage_api_client.company.companies.get()\n\n### Automate ###\n\n# sends GET request to /clients endpoint\nclients = automate_api_client.clients.get()\n```\n\n### Get one\n```python\n### Manage ###\n\n# sends GET request to /company/companies/{id} endpoint\ncompany = manage_api_client.company.companies.id(250).get()\n\n### Automate ###\n\n# sends GET request to /clients/{id} endpoint\nclient = automate_api_client.clients.id(250).get()\n```\n\n### Get with params\n```python\n### Manage ###\n\n# sends GET request to /company/companies with a conditions query string\nconditional_company = manage_api_client.company.companies.get(params={\n  'conditions': 'company/id=250'\n})\n\n### Automate ###\n# sends GET request to /clients endpoint with a condition query string\n# note that the Automate API expects the string 'condition' where-as the Manage API expects the string 'conditions'\nconditional_client = automate_api_client.clients.get(params={\n  'condition': 'company/id=250'\n})\n```\n\n# Child Endpoints\nThe ConnectWise APIs have many instances of endpoints with path parameters - for example, ```/company/companies/{company_id}/sites```\n\nThis also exists in the library. Endpoints provide an ```id``` method for setting the ID and traversing down the path.\n\n##### Example using ```/company/companies/{company_id}/sites```\n```python\n# equivalent to GET /company/companies/250/sites\nsites = manage_api_client.company.companies.id(250).sites.get()\n```\n\n# Pagination\nThe ConnectWise Manage API paginates data for performance reasons through the ```page``` and ```pageSize``` query parameters. ```pageSize``` is limited to a maximum of 1000.\n\nTo make working with paginated data easy, Endpoints that implement a GET response with an array also supply a ```paginated()``` method. Under the hood this wraps a GET request, but does a lot of neat stuff to make working with pages easier.\n\nWorking with pagination\n```python\n# initialize a PaginatedResponse instance for /company/companies, starting on page 1 with a pageSize of 100\npaginated_companies = manage_api_client.company.companies.paginated(1,100)\n\n# access the data from the current page using the .data field\npage_one_data = paginated_companies.data\n\n# if there's a next page, retrieve the next page worth of data\npaginated_companies.get_next_page()\n\n# if there's a previous page, retrieve the previous page worth of data\npaginated_companies.get_previous_page()\n\n# iterate over all companies on the current page\nfor company in paginated_companies:\n  # ... do things ...\n\n# iterate over all companies in all pages\n# this works by yielding every item on the page, then fetching the next page and continuing until there's no data left\nfor company in paginated_companies.all():\n  # ... do things ...\n```\n\n# Additional Configuration\nAs of version ```0.4.6```, pyConnectWise clients now accept a new ```Config``` object for additional API interaction configuration.\n\n### Implementation\n\n```python\nfrom pyconnectwise import ConnectWiseManageAPIClient, ConnectWiseAutomateAPIClient\nfrom pyconnectwise.config import Config\n\n# create an instance of Config with your own changes...\nconfig = Config(max_retries = 5)\n\n# ... and hand off to the clients during initialization\nmanage_api_client = ConnectWiseManageAPIClient(config = config)\nautomate_api_client = ConnectWiseAutomateAPIClient(config = config)\n```\n\n### Supported Options\nAs of version ```0.4.6```, the following Config options are supported:\n* ```max_retries``` - The number of times to re-attempt a request if a HTTP 500 error occurs. Defaults to 3.\n\n# Examples\n\n### Get all agreements, then all additions for an agreement\n```python\nagreements = api.finance.agreements.paginated(1, 1000)\nfor agreement in agreements.all():\n    additions = api.finance.agreements.id(agreement.id).additions.get()\n```\n\n### Get all service tickets with an ID > 1000\n```python\ntickets = api.service.tickets.get(params={\n    'conditions': 'id > 1000'\n})\n```\n\n# Contributing\nContributions to the project are welcome. If you find any issues or have suggestions for improvement, please feel free to open an issue or submit a pull request.\n\nWhen working on the project, please note that there's a few requirements you'll need to install in order to run the project locally. These requirements are stored in [requirements.txt](requirements.txt)\n\nYou can install these requirements by opening a terminal, navigating to the repo's directory and running ```pip install -r requirements.txt```\n\n## Preparing your development environment\nPrerequisites:\n- Python 3.10+\n- [Poetry](https://python-poetry.org/docs/#installing-with-pipx)\n- [Pre-Commit](https://pre-commit.com/#install)\n\n### Quick dependencies install on apt-based systems (using pipx to manage python tools)\n```bash\nsudo apt install pipx\npipx install poetry\npipx install pre-commit\n```\n### Setting up your development environment\n```bash\npoetry install --with=dev\npre-commit install\n```\n\n## Testing\n```bash\npoetry run pytest\n```\n\n## Running code generation\n```bash\npoetry run python -m pyconnectwise_generator <path to schema file>\n```\n\n# Supporting the project\n:heart: the project and would like to show your support? Please consider donating to the following charities:\n- [Black Dog](https://donate.blackdoginstitute.org.au/)\n- [Cure4 CysticFibrosis Foundation](https://app.etapestry.com/onlineforms/Cure4CFFoundation/Donatenow.html)\n- [Vinnies CEO Sleepout](https://www.ceosleepout.org.au/donation)\n- [Care.org.au's Ukraine Humanitarian Crisis fund](https://www.care.org.au/appeals/ukraine-humanitarian-crisis/)\n- [RedFrogs Australia](https://redfrogs.com.au/support/donate)\n- [Love Your Sister (Sam's 1000)](https://www.loveyoursister.org/makeadonation)\n",
    "bugtrack_url": null,
    "license": "GPL-3.0-only",
    "summary": "A full-featured Python client for the ConnectWise APIs",
    "version": "0.6.1.2",
    "project_urls": {
        "Homepage": "https://github.com/HealthITAU/pyconnectwise",
        "Repository": "https://github.com/HealthITAU/pyconnectwise"
    },
    "split_keywords": [
        "connectwise",
        " manage",
        " automate",
        " api",
        " python",
        " client",
        " annotated",
        " typed",
        " msp"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "161eb3d28b2f99556aac5bf67e9c7237606d43755734b4cbd43e7b6b994f53d8",
                "md5": "3f32c1146da0ab60ade92f03f09b6a79",
                "sha256": "74b5f0bcac8b1eefb2a6dee53364701d7176359edcc43164879695e201edf247"
            },
            "downloads": -1,
            "filename": "pyconnectwise-0.6.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "3f32c1146da0ab60ade92f03f09b6a79",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 2207094,
            "upload_time": "2024-08-22T16:27:20",
            "upload_time_iso_8601": "2024-08-22T16:27:20.600978Z",
            "url": "https://files.pythonhosted.org/packages/16/1e/b3d28b2f99556aac5bf67e9c7237606d43755734b4cbd43e7b6b994f53d8/pyconnectwise-0.6.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "0e88cdcc9af42dd7f5a2997f1a701f90bd8b3fdfdefa41599e592c4a8a52b125",
                "md5": "b7a1462c08af7d2636a1a7909035a598",
                "sha256": "f650dfc70af190aeb6eab80e8f2b38ce9ea07a07e96a3ee5e9d93c937d726a55"
            },
            "downloads": -1,
            "filename": "pyconnectwise-0.6.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "b7a1462c08af7d2636a1a7909035a598",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 417683,
            "upload_time": "2024-08-22T16:27:23",
            "upload_time_iso_8601": "2024-08-22T16:27:23.605098Z",
            "url": "https://files.pythonhosted.org/packages/0e/88/cdcc9af42dd7f5a2997f1a701f90bd8b3fdfdefa41599e592c4a8a52b125/pyconnectwise-0.6.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-22 16:27:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "HealthITAU",
    "github_project": "pyconnectwise",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pyconnectwise"
}
        
Elapsed time: 5.05749s