ripe.atlas.sagan 0.2.0

RIPE Atlas generates a **lot** of data, and the format of that data changes overtime. Often you want to do something simple like fetch the median RTT for eachmeasurement result between date `X` and date `Y`. Unfortunately, there are aredozens of edge cases to account for while parsing the JSON, like the format oferrors and firmware upgrades that changed the format entirely.

To make this easier for our users (and for ourselves), we wrote an easy to useparser that's smart enough to figure out the best course of action for eachresult, and return to you a useful, native Python object.

## Changelog

* 0.2.0 * Totally reworked error and malformation handling. We now differentiate between a result (or portion thereof) being malformed (and therefore unparsable) and simply containing an error such as a timeout. Look for an `is_error` property or an `is_malformed` property on every object to check for it, or simply pass `on_malformation=Result.ACTION_FAIL` if you'd prefer things to explode with an exception. See the documentation for more details * Removed the deprecated propertiesfrom `dns.Response`. You must now access values like `edns0` from `dns.Response.abuf.edns0`. * More edge cases have been found and accommodated.* 0.1.15 * Added a bunch of abuf parsing features from [b4ldr]https://github.com/b4ldr with some help from [phicoh]https://github.com/phicoh)* 0.1.14 * Fixed the deprecation warnings in `DnsResult` to point to the right place.* 0.1.13 * Better handling of `DNSResult` errors * Rearranged the way abufs were handled in the `DnsResult` class to make way for `qbuf` values as well. The old method of accessing `header`, `answers`, `questions`, etc is still available via `Response`, but this will go away when we move to 0.2. Deprecation warnings are in place.* 0.1.12 * Smarter code for checking whether the target was reached in `TracerouteResults`. * We now handle the `destination_option_size` and `hop_by_hop_option_size` values in `TracerouteResult`. * Extended support for ICMP header info in traceroute `Hop` class by introducing a new `IcmpHeader` class.* 0.1.8 * Broader support for SSL checksums. We now make use of `md5` and `sha1`, as well as the original `sha256`.

## How to use it

You can parse a result in a few ways. You can just pass the JSON-encodedstring:

Every result type has its own properties, with a few common between all types.

Specifically, these attributes exist on all `*Result` objects:

* `created` An arrow object (like datetime, but better) of the `timestamp` field* `measurement_id`* `probe_id`* `firmware` An integer representing the firmware version* `origin` The `from` attribute in the result* `is_error` Set to `True` if an error was found

Additionally, each of the result types have their own properties, like`packet_size`, `responses`, `certificates`, etc. You can take a look at theclasses themselves, or just look at the tests if you're curious. But to get youstarted, here are some examples:

# DNSdns_result.responses # A list of Response objectsdns_result.responses[0].response_time # Float, rounded to 3 decimal placesdns_result.responses[0].headers # A list of Header objectsdns_result.responses[0].headers[0].nscount # The NSCOUNT value for the first headerdns_result.responses[0].questions # A list of Question objectsdns_result.responses[0].questions[0].type # The TYPE value for the first questiondns_result.responses[0].abuf # The raw, unparsed abuf string

# SSL Certificatesssl_result.af # 4 or 6ssl_result.certificates # A list of Certificate objectsssl_result.certificates[0].checksum # The checksum for the first certificate

# HTTPhttp_result.af # 4 or 6http_result.uri # A URL stringhttp_result.responses # A list of Response objectshttp_result.responses[0].body_size # The size of the body of the first response```

### "But... I'd rather my code explode when there's an error"

If you'd like Sagan to be less forgiving, you only need to pass`on_error=Result.ACTION_FAIL` when you're instantiating your object. To use oneof our previous examples:

Essentially, we tried to support everything. If you pass in a DNS resultstring, the parser will return a `DNSResult` object, which contains a list of`Response`s, each with an `abuf` property, as well as all of the information inthat abuf: header, question, answer, etc.

Additionally, we recommend that you also install[ujson]https://pypi.python.org/pypi/ujson as it will speed up theJSON-decoding step considerably, and [sphinx]https://pypi.python.org/pypi/Sphinx if you intend to build thedocumentation files for offline use.

## How to install

The stable version should always be in PyPi, so you can install it with `pip`:

```bash$ pip install ripe.atlas.sagan```

### Troubleshooting

Some setups (like MacOS) have trouble with some of the dependencies we'reusing, so if they explode during the installation, you can still make use of*some* of the parsers by deliberately excluding the problematic ones atinstall time.

For example, if you want to skip the installation of `pyOpenSSL` (required forparsing SSL certificate results), you can do this:

```bash$ SAGAN_WITHOUT_SSL=1 pip install ripe.atlas.sagan```

Similarly, you can skip the installation of `dnspython` and forego any DNSresult parsing:

```bash$ SAGAN_WITHOUT_DNS=1 pip install ripe.atlas.sagan```

## Further Documentation

Complete documentation can always be found on[the RIPE Atlas project page]https://atlas.ripe.net/docs/sagan/) and if you'renot online, the project itself contains a `docs` directory -- everything youshould need is in there.

## Colophon

But why *Sagan*? The RIPE Atlas team decided to name all of its modules afterexplorers, and what better name for a parser than that of the man who spentdecades reaching out to the public about the wonders of the cosmos?