Code Monkey home page Code Monkey logo

pdpyras's Introduction

PDPYRAS: PagerDuty Python REST API Sessions

A module that supplies lightweight Python clients for the PagerDuty REST API v2 and Events API v2.

For how-to, refer to the User Guide.

circleci-build

Overview

This library supplies classes extending requests.Session from the Requests HTTP library that serve as Python interfaces to the REST API v2 and Events API v2 of PagerDuty. One might call it an opinionated wrapper library. It was designed with the philosophy that Requests is a perfectly adequate HTTP client, and that abstraction should focus only on the most generally applicable and frequently-implemented core features, requirements and tasks. Design decisions concerning how any particular PagerDuty resource is accessed or manipulated through APIs are left to the user or implementer to make.

Features

  • Uses Requests' automatic HTTP connection pooling and persistence
  • Tested in / support for Python 3.6 through 3.11
  • Abstraction layer for authentication, pagination, filtering and wrapped entities
  • Configurable cooldown/reattempt logic for handling rate limiting and transient HTTP or network issues

History

This module was borne of necessity for a basic API client to eliminate code duplication in some of PagerDuty Support's internal Python-based API tooling.

We found ourselves frequently performing REST API requests using beta or non-documented API endpoints for one reason or another, so we needed the client that provided easy access to features of the underlying HTTP library (i.e. to obtain the response headers, or set special request headers). We also needed something that eliminated tedious tasks like querying objects by name, pagination and authentication. Finally, we discovered that the way we were using Requests wasn't making use of its connection pooling feature, and wanted a way to easily enforce this as a standard practice.

We evaluated at the time a few other open-source API libraries and deemed them to be either overkill for our purposes or not giving the implementer enough control over how API calls were made.

License

All the code in this distribution is Copyright (c) 2023 PagerDuty.

pdpyras is made available under the MIT License:

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Warranty

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pdpyras's People

Contributors

ashwin153 avatar asmith-pd avatar av1m avatar ctrlaltdel avatar deconstrained avatar hunner avatar jackton1 avatar jjm avatar markafarrell avatar phrend avatar pzhuravlenkopd avatar sesshoumaru404 avatar unixorn avatar waqaspd 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pdpyras's Issues

Add abstraction for date ranges (since/until)

I've just rediscovered how annoying it is to have to cobble together ISO8601 timestamps for when I just want to select an hour in the past or somesuch thing.

There thus needs to be an easier way to generate since and until parameters to reduce repeated work making function calls to datetime.datetime and datetime.timedelta and datetime.datetime.strftime (etc)

triggering events through EventsAPISession fails

Hi,

I'm having some issues using the EventsAPISession object. I've properly instantiated this object with a routing key obtained from the Events API v2 integration attached to my desired service. When calling the 'trigger' method, I get a deduplicate key and even took it a step further by implementing a class that returns the full response object (see below). I can see that my calls are being returned as successful according to the response code of 202 and the response body containing {'message': 'Event processed', 'status': 'success'}.

When I visit the GUI to ensure my incident fired under the desired service, there is no instance of this incident under the service or any other service for that matter. I cannot find any breaking API changes that would be causing this, so unsure how to proceed.

from pdpyras import EventsAPISession, raise_on_error, try_decoding

class EventsAPISessionWrapper(EventsAPISession):
    def send_event(self, action, dedup_key=None, **properties):
        actions = ('trigger', 'acknowledge', 'resolve')
        if action not in actions:
            raise ValueError("Event action must be one of: "+', '.join(actions))

        event = {'event_action':action}

        event.update(properties)
        if isinstance(dedup_key, str):
            event['dedup_key'] = dedup_key
        elif not action == 'trigger':
            raise ValueError("The dedup_key property is required for"
                "event_action=%s events, and it must be a string."%action)
        response = self.post('/v2/enqueue', json=event)
        raise_on_error(response)
        response_body = try_decoding(response)
        if not 'dedup_key' in response_body:
            raise PDClientError("Malformed response body; does not contain "
                "deduplication key.", response=response)
        return response

rput raises PDHTTPError from JSONDecodeError when adding a user to a team

Adding a user to a team with client.rput(f'teams/{team}/users/{user}') raises PDHTTPError from JSONDecodeError encountered trying to decode response text. The raw response from put is a 204 with no content.

Removing a user from a team with client.rdelete(f'teams/{team}/users/{user}') does not raise the same error even though the raw response is also a 204 with no content.

PDClientError doesn't catch 400 for event_rules endpoint for bad format

Reproduce with the following:

from pdpyras import APISession, PDClientError

# Action is missing an extra layer of bracket 
# valid format is:
# 'actions': [['route', '<INSERT_SERVICE_ID>']]
payload = {'condition': ['and', ['contains', ['path', 'payload', 'source'], 'website'], ['contains', ['path', 'payload', 'source'], 'api']], 'actions': ['route', '<INSERT_SERVICE_ID>']}

try: 
    session = APISession(api_token)
    provision_event_rules = session.post("/event_rules", json=payload )
    print(provision_event_rules.status_code) # prints 400
    # prints: {'rules': [{'actions': ['expected array, received Elixir.Api.Schemas.MixedList']}]}
    print(provision_event_rules.json()) 
except PDClientError as e:
   print(e.response)
   print(e.response.url)
   print(e.response.text)

Never returns the 400 response

Events API : Payload overrides everything if set

Hello!

I've been tinkering with the EventsAPISession and notice that if you set a payload it will completely ignore the summary, source and severity instead of merging it with the payload as the docstring says.

Here's the override:
https://github.com/PagerDuty/pdpyras/blob/master/pdpyras.py#L641

I wouldn't mind setting either kwargs OR payload, but right now to make a valid event with any of the fields not supported by the kwargs (component, group and class) if have to do it like this because summary and source are not optional:

session = pdpyras.EventsAPISession(routing_key)

dedup_key = session.trigger(
    summary='ignored',
    source='ignored',
    payload={
        'summary': 'actual summary',
        'source': 'actual source',
        'severity': 'critical',
        'component': 'a component',
        'group': 'a group',
        'class': 'a class',
    },
    custom_details={
        'this': 'works'
    },
)

So maybe:

  • Payload could merge as said in the docstring
  • Payload could be extra_payload_args
  • Payload could be removed to add **kwargs (or add class, component, and group as params)

Just a suggestion,
Thank you

Support for Analytics API

Hello,

I'm trying to query the PD Analytics API but I get a permission error: API responded with non-success status (403)

Based on the documentation, it seems that we have to pass the X-EARLY-ACCESS header in order to use it.

Is there a way to do this using this client?

Thanks

Example incident creation code fails

The example incident creation code fails with a 400 "You must specify a user's email address in the "From" header to perform this"

Traceback:

Traceback (most recent call last):
  File "/Users/jpb/Dropbox/s/pdcrier/bin/examplecode", line 20, in <module>
    pd_incident = session.rpost("incidents", json=payload)
  File "/Users/jpb/Library/Caches/pypoetry/virtualenvs/pdcrier-4jRKjqUa-py3.9/lib/python3.9/site-packages/pdpyras.py", line 145, in call
    r = raise_on_error(method(self, path, **pass_kw))
  File "/Users/jpb/Library/Caches/pypoetry/virtualenvs/pdcrier-4jRKjqUa-py3.9/lib/python3.9/site-packages/pdpyras.py", line 78, in raise_on_error
    raise PDHTTPError("%s %s: API responded with non-success status "
pdpyras.PDHTTPError: POST /incidents: API responded with non-success status (400): {"error":{"message":"You must specify a user's email address in the \"From\" header to perform this

Pagination doesn't seem to work with `iter_all`

When I have code like the following:

from pdpyras import APISession

api_token = '<redacted>'
session = APISession(api_token)

for incident in session.iter_all('incidents', params={'service_ids[]': ['<redacted>'], 'since': '2020-08-01T00:00:00Z'}):
    print("{id}\t{created_at}\t{html_url}\t{description}\t{resolve_reason}".format(**incident))

I only get around 25 incidents. If I change the since date, I get a different 25-ish incidents, so it seems like the pagination isn't working. (Also, I know from the PD website that there are definitely much more than 25 incidents for this query).

Any ideas?

Thanks.

Bug when posting to /schedules/{id}/overrides

Hi,

When posting to /schedules/{id}/overrides, logic defined here (https://github.com/PagerDuty/pdpyras/blob/main/pdpyras.py#L130):

if is_index and http_method=='get' or multi_put:
            # Plural resource name, for index action (GET /<resource>), or for
            # multi-update (PUT /<resource>). In both cases, the response
            # (former) or request (latter) body is {<resource>:[<objects>]}
            envelope_name = resource
        else:
            # Individual resource create/read/update
            # Body = {<singular-resource-type>: {<object>}}
            envelope_name = envelope_name_single

leads to the latter case in which we are updating an individual resource which is not the case. Specifically:

  • is_index is true because url has 3 parts
  • http_method is POST, so we fail in the else part

As a consequence, when performing session.rpost('/schedules/{id}/overrides', json=overrides), overrides provided are being encapsulated as a "override" property of an object.

Workaround is to pass overrides as:
overrides = {
overrides= [ ... ],
override = ''
}
Then, as override property is present, the whole object is being sent.

Support for Events v2 API

I'm really liking pdpyras for working with the PagerDuty API, however it would be really nice if could support the Events API too. As low level handling rate limits and errors for sending events from custom applications would be really helpful.

Usage would be something like:

from pdpyras import EventSession

integration_key = 'your-token-here'
session = EventSession(integration_key)

event = {}

session.enqueue(event)

KeyError when using rget/rput/rpost/list_all for EventOrchestrations API

There is an assumption in resource_envelope used for rget/rpost/rput and list_all functions that the name of the resource provided in the url path is the same as the name of the resource that comes back in the API response:
https://github.com/PagerDuty/pdpyras/blob/main/pdpyras.py#L127
https://github.com/PagerDuty/pdpyras/blob/main/pdpyras.py#L1138

However this doesn't always seem to be the case. For the event orchestrations APIs, the url path is /event_orchestrations and the response contains "orchestrations" or "orchestration_path" for the router/unrouted/service APIs
https://developer.pagerduty.com/api-reference/7ba0fe7bdb26a-list-event-orchestrations

so the result of list_all is a KeyError at pdpyras.py:1187
KeyError: 'event_orchestrations'

Generate docs automatically

Committing doc rebuilds manually is getting really old. It's also contributing to bloat of the repo.

Acceptance criteria: there is an automated build and publish of docs (i.e. with CircleCI or GitHub Actions) so that changes to the restructured text / docstrings don't need doc rebuild commits and we can remove/git-ignore the built docs.

dedup_key Not passed to incident

When I trigger an event like below the dedup key does not appear anywhere on the resulting incident. Is this a bug or am I doing something wrong? My understanding is it would show up there and be usable for querying for the incident post creation.

session = EventsAPISession(token)
# all parameters are variables omitted here 
response = session.trigger(
        summary, source, dedup_key, severity,
        payload, custom_details, images, links)

PDClientError: PUT /incidents: API responded with non-success status (400)

We are using below function to resolve the incident

def resolve_incident(self, incident_ids):
    for incident_id in incident_ids:
        incident = self.session.rget("incidents/" + incident_id)
        try:
            if incident['status'] != 'resolved':
                self.session.rput(
                    "incidents",
                    json=[{'id': incident_id, 'type': 'incident_reference', 'status': 'resolved'}]
                )
            else:
                print "Incident: " + incident_id + " is already resolved!"
        except PDClientError:
            print "Could not resolve incident: " + incident_id
            traceback.print_exc()
            raise RuntimeError("Could not resolve incident: " + incident_id)
    return True

suddenly its started throwing below error :
PDClientError: PUT /incidents: API responded with non-success status (400)

ย As per my finding there is some issue with rput
Is anything changes in the pagerduty API ? or in pdpyras ?

Whitelist for endpoints supported by the r* methods

The rput, rpost, and rget methods aren't guaranteed to work for the experimental / undocumented endpoints, but were intended for the "mainstream" endpoints that follow the self-similar pattern wherein the envelope property name follows from the resource name.

This has caused some user error and confusion when using it for experimental endpoints that contain exceptions to this pattern.

Support for TAGS api

Hi There,

First off, this is a great project and I'm really enjoying using it. I've written a few things so far and they work well.

However, I'm in a spot where I'm trying to assemble a full user list of specific elements (e.g. query all users and their emails, roles, teams, tags) and well, the TAGS api is completely separate and while of course I can write against just a regular client, it would be great if that was another component of pdpyras so I can easily pull it all together.

Thanks!

Alert is overwritten when triggering a new event with the same dedup key

I am trying to create an event, and then create another event with the same dedup. I expect that there will be 2 alerts in the same incident, however there is only 1 (new summary), which means that the alert is overwritten.

This is my code:

from pdpyras import EventsAPISession


class PagerDutyApi:
    def __init__(self, integration_key: str) -> None:
        self._session = EventsAPISession(integration_key)

        # Returns the dedup key
        dedup = self._session.trigger(summary='test summary', source='val1', severity='info')
        self._session.trigger(summary='new summary', source='val1', severity='info', dedup_key=dedup)


PagerDutyApi('Dummy-Integration-Key')

Iteration is disrupted when performing inline update/delete

If performing updates or deletions through the API to objects that are part of the set being iterated over, then the iteration will skip over records when the following happens:

  1. The set in itself changes due to updates/deletions to the objects in the set which render them not applicable to the filter being used for iteration (and if deletion occurs then no filter will match them)
  2. The offset in pagination will reflect paging through the set as it was prior to the updates
  3. Therefore, objects that would be in the next page instead end up on the previous page after the update, because the offset changes by more than the objects shift due to previous objects getting removed from the set

Ideas for addressing this:

  • Warning messages when performing deletion or update to a resource when iteration is currently in progress for that same resource (prompting the developer to use list_all and pre-fetch records instead of iter_all
  • Preferred update_all or delete_all pagination methods that have some clever way of checking for deletion/insertion and adjust the offset accordingly - or just pre-fetch set members' resource URLs before proceeding - and fulfill the bulk-update / bulk-delete need.

HTTP 400 when hitting "log_entries" endpoint

I just noticed this error when trying to use your library to retrieve my organization's log entries

>>> data_list = session.list_all('log_entries')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/gtang/.pyenv/versions/etl_env/lib/python3.6/site-packages/pdpyras.py", line 1074, in list_all
    return list(self.iter_all(path, **kw))
  File "/Users/gtang/.pyenv/versions/etl_env/lib/python3.6/site-packages/pdpyras.py", line 999, in iter_all
    r.status_code, path), response=r)
pdpyras.PDClientError: Encountered HTTP error status (400) response while iterating through index endpoint log_entries.

Not sure if the error is coming from PagerDuty's API or your wrapper but I figure I post this issue here

Retry being defined as None and then redefined as {} causes pylint error

The following line in pdpyras.py:

retry = None

Is then redefined as:

self.retry = {}

This causes pylint to throw the following error about unsupported-assignment-operation, but only when the module is installed via pip.

test.py:11:4: E1137: 'session.retry' does not support item assignment (unsupported-assignment-operation)

The following test file reports the above error when 4.0 is installed via pip, but not when the file is in a checkout of pypdras.

"""Test Pdpyras file for pylint error."""


from pdpyras import APISession


def main(api_key=None):
    """Main function"""
    session = APISession(api_key=api_key)

    session.retry[404] = 5
    session.max_http_attempts = 4
    session.sleep_timer = 1
    session.sleep_timer_base = 2

    response = session.get('/users/PNOEXST')

    return response

if __name__ == '__main__':
    print(main(api_key=None))

Confirmed changing the None to {} fixes the issue. So I'll raise a PR.

Randomize rate limit cooldown to mitigate thundering herd effect

A nice-to-have.

The cooldown time increases by a constant factor after each attempt. If there are many concurrent API requests, they will all retry at exactly the same time.

E.G.

import random
...
                sleep_timer *= self.sleep_timer_base*(1+random.random())

Rewrite examples to use env vars

It's really bad practice to hard-code API keys. Our code examples should reflect that.

We could just do this to begin with:

api_key = os.env.get('PD_API_KEY')

Deprecation warning for `\*\*` in docstrings

For example,

:param \*\*kwargs:

Causes the following deprecation warning.

DeprecationWarning: invalid escape sequence \*

Here's a reproduction.

import warnings
warnings.simplefilter("always")
x = "\*\*kwargs"
# <stdin>:1: DeprecationWarning: invalid escape sequence \*

Definitely not a pressing issue, but it pollutes my build logs. I'd suggest adding another slash (e.g., \\*). Sphinx appears to render \\* and \* the same way. For example, here's how they both render on a sample site.

kwargs

Support for cursor-based pagination

There's no way to handle this new type of pagination currently except with a custom implementation.

Moreover, iter_all was written during a time when nearly all API index endpoints followed the same pattern: of alternating IDs and resource names in the path. The only endpoint that currently supports cursor pagination is the newer audit trail API that breaks from this pattern.

There will need to be some kind of generalization of iteration that can encompass this new scenario (which breaks away from the pattern that was once ubiquitous) and does what's needed to support cursor-based pagination.

Pydras 5.0 throws an error when accessing oncall API

On python 3.10
https://github.com/PagerDuty/pdpyras/blob/main/pdpyras.py#LL787C1-L790C26
Throws an TypeError: not enough arguments for format string error, because no variable is available to be inserted. Suggest rewriting like

        return (
            f"{endpoint}: Success (status {r.status_code}) but an expectation still " \
            f"failed{context_msg}"
        )

This happens when using the paged request for oncall. e.g.

    user_params = {
        "time_zone": TZ_NAME,
        "since": ts["start"].isoformat(),
        "until": ts["end"].isoformat(),
    }

    oncalls = session.iter_all(
        "oncalls", params=user_params, page_size=MAX_ITEMS)
    final_report_rows = {}
    for o in oncalls:

Uncaught Exception on 500 Error

Line 1157 raises an uncaught key error when a 500 is returned, as the request_id is not in the header. https://github.com/PagerDuty/pdpyras/blob/master/pdpyras.py#L1157

The request_id is already available, so this can simply read:

if int(status) == 500:
            self.log.error("PagerDuty API server error (%d)! "
                "For additional diagnostics, contact PagerDuty support "
                "and reference x_request_id=%s / date=%s",
                status, request_id, request_date)

I have a branch ready to go, but i don't have push access to this repo.

Iteration fails for retrieving PagerDuty response plays

Receive TypeError when doing the following

>>> rp = list(session.iter_all("response_plays"))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\Users\[user]\AppData\Local\Programs\Python\Python39\lib\site-packages\pdpyras.py", line 1058, in iter_all
    offset += data['limit']
TypeError: unsupported operand type(s) for +=: 'int' and 'NoneType' ```

Same error occurs with list_all and dict_all. Able to receive list via rget method only

Release 4.5.1 `ModuleNotFoundError: No module named 'requests'`

๐Ÿ‘‹ Hey there @Deconstrained ๐Ÿ˜„. I'm observing a behavior where the changes from here: bab0368#diff-60f61ab7a8d1910d86d9fda2261620314edcae5894d5aaa236b821c7256badd7R3 seem to be manifesting as the following issue upon installation of release 4.5.1.

I assume that anyone else that doesn't explicitly specify requests as a requirement of their own would see the same since this occurs before pdpyras can install its own requests requirement.

Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-h5zdz16c/pdpyras/setup.py", line 3, in <module>
        from pdpyras import __version__
      File "/tmp/pip-install-h5zdz16c/pdpyras/pdpyras.py", line 13, in <module>
        import requests
    ModuleNotFoundError: No module named 'requests'

It looks like this was able to sneak by CI checks due to the one-off requirements.txt install happening here:

pip install -r requirements.txt

Needs to log the `X-Request-Id` response header for easier diagnostics

The X-Request-Id response header should always contain a UUID that PagerDuty Support can use to track down the full trace of a HTTP request through the public API, so that the reason for a 5XX can be more quickly investigated.

This API client should really be logging this response header, at the very least for server error responses.

Connection time-out with list_all('schedules') with thousands of schedules.

Using:
session.list_all('schedules')

I get:

...
HTTP or network error: ReadTimeout: HTTPSConnectionPool(host='api.pagerduty.com', port=443): Read timed out. (read timeout=5); retrying in 12 seconds.

Until it errors for exceeding the maximum number of attempts to connect to the API.

This only happens when making the request on a PagerDuty account with thousands of schedules. The same request works fine with an account with only hundreds of schedules. Also, the same style request works fine for other endpoints (objects).

The same call using requests.get() with paging works fine. I couldn't replicate the issue after copying headers and so on.

Thank you.

Basic auto-JSON w/o unpack for experimental endpoints

To give developers the option of using functions that return JSON in all cases, there should be a set of functions that don't bother unpacking the object from the envelope, but that at least return the JSON and raise an exception if there's a HTTP error. This will make it easier to work with unconventional / early-access / experimental endpoints.

Correction to `j*` methods being usable

#86 was about the team membership API not working with rput. While this is expected, the docs state:

They can still be used with the basic get, post, put and delete methods, as well as the j* methods

This would however not be the case for the team membership API, which responds with status 204 / no content (empty body). That would result in a JSONDecodeError if one used jput.

Alternately, #88 will also resolve this issue.

Super duper basic models

  • Nice-to-have / Syntactic sugar
  • Doesn't need to have explicitly defined schemas; can start with type/resource and ID and then "inherit" from API responses
  • If possible: detect changes, know what the minimum required mandatory fields are for updates (i.e. ID and type) and then PUT only the changes + required fields.
  • Ideally can access properties as property names, i.e. model.field_name

Would need figure out how this could help us internally, i.e. how easy it would be to eliminate code duplication.

Return None in try_decoding if body is empty

If the body is empty, it seems appropriate to return None from try_decoding rather than raise JSONDecodeError.

This will resolve #87 by allowing j* methods to be used on endpoints that may respond with 204 / no content to request methods other than DELETE, i.e. the add-user-to-team endpoint.

Could we get more detailed update examples?

I would like to use the API to change and escalation_rules target from a schedule_reference to a user_reference.

I am getting all the Escalation Policies like so

services = list(session.iter_all('escalation_policies', params={'query': 'myquery'}))

How could I go through them and update the escalation_rules target?

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.