[Python-modules-commits] [ripe-atlas-cousteau] 01/03: Import ripe-atlas-cousteau_1.3.orig.tar.gz
Apollon Oikonomopoulos
apoikos at moszumanska.debian.org
Fri Dec 16 13:16:56 UTC 2016
This is an automated email from the git hooks/post-receive script.
apoikos pushed a commit to branch master
in repository ripe-atlas-cousteau.
commit 031b0638498abccc222dca6f860eed4150b5ee75
Author: Apollon Oikonomopoulos <apoikos at debian.org>
Date: Fri Dec 16 15:12:33 2016 +0200
Import ripe-atlas-cousteau_1.3.orig.tar.gz
---
CHANGES.rst | 15 +++++++
README.rst | 14 ++++---
docs/use.rst | 5 ++-
ripe/__init__.py | 2 +-
ripe/atlas/__init__.py | 2 +-
ripe/atlas/cousteau/__init__.py | 2 +-
ripe/atlas/cousteau/api_meta_data.py | 28 +++++++++----
ripe/atlas/cousteau/exceptions.py | 2 +-
ripe/atlas/cousteau/measurement.py | 2 +-
ripe/atlas/cousteau/request.py | 18 ++++++--
ripe/atlas/cousteau/source.py | 2 +-
ripe/atlas/cousteau/stream.py | 80 ++++++++++++++++++++++++++++--------
ripe/atlas/cousteau/version.py | 4 +-
tests/test_api_meta_data.py | 7 ++--
tests/test_real_server.py | 2 +-
tests/test_requests.py | 49 ++++++++++++++++++----
16 files changed, 177 insertions(+), 57 deletions(-)
diff --git a/CHANGES.rst b/CHANGES.rst
index 195226a..89304cd 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,5 +1,20 @@
Releases History
================
+1.3 (released 2016-10-21)
+-------------------------
+Changes:
+~~~~~~~~
+- Improved streaming support:
+
+ - Introduce error handling
+ - Channels errors binded by default
+ - Introduced debug mode
+ - Update features set. See all here https://atlas.ripe.net/docs/result-streaming/
+ - Deprecated short events name and local event name checking. See the event names here https://atlas.ripe.net/docs/result-streaming/
+
+- Introduced support for proxies and additional headers
+- Timezone aware objects for measurement meta data
+
1.2 (released 2016-03-02)
-------------------------
Changes:
diff --git a/README.rst b/README.rst
index 1d966ed..bdc4e0e 100644
--- a/README.rst
+++ b/README.rst
@@ -7,6 +7,10 @@ A python wrapper around RIPE ATLAS API.
(Until version 0.9.* this wrapper supported v1 API. After version 0.10 and above v2 RIPE ATLAS API is only supported.)
+Complete documentation can be found on `Read the Docs`_.
+
+.. _Read the Docs: http://ripe-atlas-cousteau.readthedocs.org/en/latest/
+
Installation
------------
@@ -71,7 +75,7 @@ ahead and do the HTTP query. On the contrary, it will raise an exception
with some info in it.
The available measurements types are Ping, Traceroute, Dns, Sslcert, Ntp, Http.
-.. _documentation pages: https://atlas.ripe.net/docs/measurement-creation-api/
+.. _documentation pages: https://atlas.ripe.net/docs/api/v2/manual/measurements/types/
Changing Measurement Sources
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -105,7 +109,7 @@ change "action" key to "remove" and specify probes you want to remove.
Keep in mind remove action supports only a list of probes and not the rest of the source types.
For more info check the appropriate `docs`_.
-.. _docs: https://atlas.ripe.net/docs/rest/#participation-request
+.. _docs: https://atlas.ripe.net/docs/api/v2/reference/#!/participation-requests/Participant_Request_Detail_GET
Stopping Measurement
~~~~~~~~~~~~~~~~~~~~
@@ -160,8 +164,8 @@ dates.
kwargs = {
"msm_id": 2016892,
- "start": datetime(2015, 05, 19),
- "stop": datetime(2015, 05, 20),
+ "start": datetime(2015, 5, 19),
+ "stop": datetime(2015, 5, 20),
"probe_ids": [1,2,3,4]
}
@@ -253,7 +257,7 @@ Fetches all specified measurements.
# Print total count of found measurements
print(measurements.total_count)
-.. _filter_api: https://atlas.ripe.net/docs/rest/
+.. _filter_api: https://atlas.ripe.net/docs/api/v2/manual/
Represent Probes/Measurements Meta data in python
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/use.rst b/docs/use.rst
index df6eb5e..bd69612 100644
--- a/docs/use.rst
+++ b/docs/use.rst
@@ -260,6 +260,7 @@ Example:
from ripe.atlas.cousteau import AtlasLatestRequest
kwargs = {
+ "msm_id": 2016892,
"probe_ids": [1,2,3,4]
}
@@ -423,7 +424,7 @@ should be according to `filter api documentation`_. Underneath it will follow al
Probe
^^^^^
-The following example will fetch all measurements with Status equals to "Specified". More info on filters for these call are on `measurement's filtering documentation`_.
+The following example will fetch all measurements with Status equals to "Specified". More info on filters for these call are on `probe's filtering documentation`_.
.. code:: python
@@ -441,7 +442,7 @@ The following example will fetch all measurements with Status equals to "Specifi
Measurement
^^^^^^^^^^^
-The following example will fetch all probes from NL with asn\_v4 3333 and with tag NAT. More info on filters for these call are on `probe's filtering documentation`_.
+The following example will fetch all probes from NL with asn\_v4 3333 and with tag NAT. More info on filters for these call are on `measurement's filtering documentation`_.
.. code:: python
diff --git a/ripe/__init__.py b/ripe/__init__.py
index 552b781..67dfd40 100644
--- a/ripe/__init__.py
+++ b/ripe/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/__init__.py b/ripe/atlas/__init__.py
index 552b781..67dfd40 100644
--- a/ripe/atlas/__init__.py
+++ b/ripe/atlas/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/cousteau/__init__.py b/ripe/atlas/cousteau/__init__.py
index 02c3d10..c88117e 100644
--- a/ripe/atlas/cousteau/__init__.py
+++ b/ripe/atlas/cousteau/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/cousteau/api_meta_data.py b/ripe/atlas/cousteau/api_meta_data.py
index 81673ae..58faf63 100644
--- a/ripe/atlas/cousteau/api_meta_data.py
+++ b/ripe/atlas/cousteau/api_meta_data.py
@@ -13,6 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
+from dateutil.tz import tzutc
from .request import AtlasRequest
from .exceptions import CousteauGenericError, APIResponseError
@@ -79,12 +80,6 @@ class EntityRepresentation(object):
"""
raise NotImplementedError()
- def __str__(self):
- return "Probe #{0}".format(self.id)
-
- def __repr__(self):
- return str(self)
-
class Probe(EntityRepresentation):
"""
@@ -110,6 +105,12 @@ class Probe(EntityRepresentation):
self.tags = self.meta_data.get("tags")
self.status = self.meta_data.get("status", {}).get("name")
+ def __str__(self):
+ return "Probe #{0}".format(self.id)
+
+ def __repr__(self):
+ return str(self)
+
class Measurement(EntityRepresentation):
"""
@@ -164,12 +165,21 @@ class Measurement(EntityRepresentation):
"""
stop_time = self.meta_data.get("stop_time")
if stop_time:
- self.stop_time = datetime.fromtimestamp(stop_time)
+ stop_naive = datetime.utcfromtimestamp(stop_time)
+ self.stop_time = stop_naive.replace(tzinfo=tzutc())
creation_time = self.meta_data.get("creation_time")
if creation_time:
- self.creation_time = datetime.fromtimestamp(creation_time)
+ creation_naive = datetime.utcfromtimestamp(creation_time)
+ self.creation_time = creation_naive.replace(tzinfo=tzutc())
start_time = self.meta_data.get("start_time")
if start_time:
- self.start_time = datetime.fromtimestamp(start_time)
+ start_naive = datetime.utcfromtimestamp(start_time)
+ self.start_time = start_naive.replace(tzinfo=tzutc())
+
+ def __str__(self):
+ return "Measurement #{0}".format(self.id)
+
+ def __repr__(self):
+ return str(self)
diff --git a/ripe/atlas/cousteau/exceptions.py b/ripe/atlas/cousteau/exceptions.py
index 7b136de..f9d2556 100644
--- a/ripe/atlas/cousteau/exceptions.py
+++ b/ripe/atlas/cousteau/exceptions.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/cousteau/measurement.py b/ripe/atlas/cousteau/measurement.py
index 1d56b41..ff1065a 100644
--- a/ripe/atlas/cousteau/measurement.py
+++ b/ripe/atlas/cousteau/measurement.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/cousteau/request.py b/ripe/atlas/cousteau/request.py
index bafb66e..28a7a8e 100644
--- a/ripe/atlas/cousteau/request.py
+++ b/ripe/atlas/cousteau/request.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -45,6 +45,8 @@ class AtlasRequest(object):
self.url_path = kwargs.get("url_path", "")
self.server = kwargs.get("server") or "atlas.ripe.net"
self.verify = kwargs.get("verify", True)
+ self.proxies = kwargs.get("proxies", {})
+ self.headers = kwargs.get("headers", None)
default_user_agent = "RIPE ATLAS Cousteau v{0}".format(__version__)
self.http_agent = kwargs.get("user_agent") or default_user_agent
@@ -52,17 +54,23 @@ class AtlasRequest(object):
self.http_method_args = {
"params": {"key": self.key},
"headers": self.get_headers(),
- "verify": self.verify
+ "verify": self.verify,
+ "proxies": self.proxies
}
+
self.post_data = {}
def get_headers(self):
"""Return header for the HTTP request."""
- return {
+ headers = {
"User-Agent": self.http_agent,
"Content-Type": "application/json",
"Accept": "application/json"
}
+ if self.headers:
+ headers.update(self.headers)
+
+ return headers
def http_method(self, method):
"""
@@ -179,6 +187,10 @@ class AtlasCreateRequest(AtlasRequest):
"probes": probes,
"is_oneoff": self.is_oneoff
}
+
+ if self.is_oneoff:
+ self.post_data.update({"is_oneoff": self.is_oneoff})
+
if self.start_time:
self.post_data.update(
{"start_time": int(calendar.timegm(self.start_time.timetuple()))}
diff --git a/ripe/atlas/cousteau/source.py b/ripe/atlas/cousteau/source.py
index d7b0b28..67e9329 100644
--- a/ripe/atlas/cousteau/source.py
+++ b/ripe/atlas/cousteau/source.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/ripe/atlas/cousteau/stream.py b/ripe/atlas/cousteau/stream.py
index 02d2ebc..2e34ad2 100644
--- a/ripe/atlas/cousteau/stream.py
+++ b/ripe/atlas/cousteau/stream.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -14,26 +14,41 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from socketIO_client import SocketIO
+from functools import partial
class AtlasStream(object):
- CHANNEL_RESULT = "atlas_result"
- CHANNEL_PROBE = "atlas_probestatus"
- CHANNEL_ERROR = "atlas_error"
+ EVENT_NAME_RESULTS = "atlas_result"
+ EVENT_NAME_SUBSCRIBE = "atlas_subscribe"
+ EVENT_NAME_ERROR = "atlas_error"
+
+ # Remove the following list when deprecation time expires
CHANNELS = {
- "result": CHANNEL_RESULT,
- "probe": CHANNEL_PROBE,
- "error": CHANNEL_ERROR,
+ "result": "atlas_result",
+ "probe": "atlas_probestatus",
+ "error": "atlas_error",
}
+ # -------------------------------------------------------
- def __init__(self):
+ def __init__(self, debug=False, server=False, proxies=None, headers=None):
"""Initialize stream"""
-
self.iosocket_server = "atlas-stream.ripe.net"
self.iosocket_resource = "/stream/socket.io"
-
self.socketIO = None
+ self.debug = debug
+ self.error_callback = None
+ self.proxies = proxies or {}
+ self.headers = headers or {}
+
+ if self.debug and server:
+ self.iosocket_server = server
+
+ def handle_error(self, error):
+ if self.error_callback is not None:
+ self.error_callback(error)
+ else:
+ print(error)
def connect(self):
"""Initiate the channel we want to start streams from."""
@@ -41,32 +56,61 @@ class AtlasStream(object):
host=self.iosocket_server,
port=80,
resource=self.iosocket_resource,
+ proxies=self.proxies,
+ headers=self.headers,
transports=["websocket"]
)
+ self.socketIO.on(self.EVENT_NAME_ERROR, self.handle_error)
+
def disconnect(self):
"""Exits the channel k shuts down connection."""
self.socketIO.disconnect()
self.socketIO.__exit__([])
+ def unpack_results(self, callback, data):
+ if isinstance(data, list):
+ for result in data:
+ callback(result)
+ else:
+ callback(data)
+
def bind_channel(self, channel, callback):
"""Bind given channel with the given callback"""
- try:
- self.socketIO.on(self.CHANNELS[channel], callback)
- except KeyError:
- print("The given channel: <{0}> is not valid".format(channel))
+
+ # Remove the following list when deprecation time expires
+ if channel in self.CHANNELS:
+ warning = (
+ "The event name '{}' will soon be deprecated. Use "
+ "the real event name '{}' instead."
+ ).format(channel, self.CHANNELS[channel])
+
+ self.handle_error(warning)
+ channel = self.CHANNELS[channel]
+ # -------------------------------------------------------
+
+ if channel == self.EVENT_NAME_ERROR:
+ self.error_callback = callback
+ elif channel == self.EVENT_NAME_RESULTS:
+ self.socketIO.on(channel, partial(self.unpack_results, callback))
+ else:
+ self.socketIO.on(channel, callback)
def start_stream(self, stream_type, **stream_parameters):
"""Starts new stream for given type with given parameters"""
- if stream_type in ("result", "probestatus"):
+ if stream_type:
self.subscribe(stream_type, **stream_parameters)
else:
- print("Given stream type: <{0}> is not valid".format(stream_type))
+ self.handle_error("You need to set a stream type")
def subscribe(self, stream_type, **parameters):
"""Subscribe to stream with give parameters."""
- parameters.update({"stream_type": stream_type})
- self.socketIO.emit('atlas_subscribe', parameters)
+ parameters["stream_type"] = stream_type
+
+ if (stream_type == "result") and ("buffering" not in parameters):
+ parameters["buffering"] = True
+
+ self.socketIO.emit(self.EVENT_NAME_SUBSCRIBE, parameters)
def timeout(self, seconds=None):
"""
diff --git a/ripe/atlas/cousteau/version.py b/ripe/atlas/cousteau/version.py
index 5e1ade3..b24e1cf 100644
--- a/ripe/atlas/cousteau/version.py
+++ b/ripe/atlas/cousteau/version.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015 RIPE NCC
+# Copyright (c) 2016 RIPE NCC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -13,4 +13,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-__version__ = "1.2"
+__version__ = "1.3"
diff --git a/tests/test_api_meta_data.py b/tests/test_api_meta_data.py
index 4f74419..d874eef 100644
--- a/tests/test_api_meta_data.py
+++ b/tests/test_api_meta_data.py
@@ -20,6 +20,7 @@ except ImportError:
import mock
from unittest import TestCase
from datetime import datetime
+from dateutil.tz import tzutc
from ripe.atlas.cousteau import Probe, Measurement
from ripe.atlas.cousteau.exceptions import APIResponseError
@@ -138,9 +139,9 @@ class TestMeasurementRepresentation(TestCase):
self.assertEqual(measurement.is_public, True)
self.assertEqual(measurement.interval, 1800)
self.assertEqual(measurement.status, "Stopped")
- self.assertEqual(measurement.creation_time, datetime.fromtimestamp(1439379910))
- self.assertEqual(measurement.start_time, datetime.fromtimestamp(1439379910))
- self.assertEqual(measurement.stop_time, datetime.fromtimestamp(1439380502))
+ self.assertEqual(measurement.creation_time, datetime.utcfromtimestamp(1439379910).replace(tzinfo=tzutc()))
+ self.assertEqual(measurement.start_time, datetime.utcfromtimestamp(1439379910).replace(tzinfo=tzutc()))
+ self.assertEqual(measurement.stop_time, datetime.utcfromtimestamp(1439380502).replace(tzinfo=tzutc()))
self.assertEqual(measurement.type, "HTTP")
self.assertEqual(measurement.result_url, "/api/v1/measurement/2310448/result/")
diff --git a/tests/test_real_server.py b/tests/test_real_server.py
index d307551..40bde79 100644
--- a/tests/test_real_server.py
+++ b/tests/test_real_server.py
@@ -235,7 +235,7 @@ class TestRealServer(unittest.TestCase):
atlas_stream = AtlasStream()
atlas_stream.connect()
- channel = "probe"
+ channel = "atlas_probestatus"
atlas_stream.bind_channel(channel, on_result_response)
stream_parameters = {"enrichProbes": True}
atlas_stream.start_stream(stream_type="probestatus", **stream_parameters)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index 483ca6f..db366e1 100644
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -75,7 +75,8 @@ class TestAtlasRequest(TestCase):
"User-Agent": "RIPE ATLAS Cousteau v{0}".format(__version__),
"Content-Type": "application/json",
"Accept": "application/json"
- }
+ },
+ "proxies": {},
}
self.assertEqual(expected_output, self.request.http_method_args)
@@ -92,9 +93,10 @@ class TestAtlasRequest(TestCase):
"User-Agent": "RIPE ATLAS Cousteau v{0}".format(__version__),
"Content-Type": "application/json",
"Accept": "application/json"
- }
+ },
+ "proxies": {},
}
- with mock.patch('ripe.atlas.cousteau.request.AtlasRequest.http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.request.AtlasRequest.http_method") as mock_get:
mock_get.return_value = True
self.request.get(**extra_params)
self.assertEqual(self.request.http_method_args, expected_args)
@@ -106,7 +108,7 @@ class TestAtlasRequest(TestCase):
def test_success_http_method(self):
"""Tests the main http method function of the request in case of success"""
- with mock.patch('ripe.atlas.cousteau.AtlasRequest.get_http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.AtlasRequest.get_http_method") as mock_get:
fake = FakeResponse(json_return={"blaaa": "b"})
mock_get.return_value = fake
self.assertEqual(
@@ -123,7 +125,7 @@ class TestAtlasRequest(TestCase):
def test_not_success_http_method(self):
"""Tests the main http method function of the request in case of fail"""
- with mock.patch('ripe.atlas.cousteau.AtlasRequest.get_http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.AtlasRequest.get_http_method") as mock_get:
fake = FakeResponse(json_return={"blaaa": "b"}, ok=False)
mock_get.return_value = fake
self.assertEqual(
@@ -140,7 +142,7 @@ class TestAtlasRequest(TestCase):
def test_exception_http_method(self):
"""Tests the main http method function of the request in case of fail"""
- with mock.patch('ripe.atlas.cousteau.AtlasRequest.get_http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.AtlasRequest.get_http_method") as mock_get:
mock_get.side_effect = requests.exceptions.RequestException("excargs")
self.assertEqual(
self.request.http_method("GET"),
@@ -199,8 +201,9 @@ class TestAtlasCreateRequest(TestCase):
"Content-Type": "application/json",
"Accept": "application/json"
},
+ "proxies": {},
}
- with mock.patch('ripe.atlas.cousteau.request.AtlasRequest.http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.request.AtlasRequest.http_method") as mock_get:
self.request._construct_post_data()
mock_get.return_value = True
self.request.post()
@@ -230,8 +233,9 @@ class TestAtlasCreateRequest(TestCase):
"Content-Type": "application/json",
"Accept": "application/json"
},
+ "proxies": {},
}
- with mock.patch('ripe.atlas.cousteau.request.AtlasRequest.http_method') as mock_get:
+ with mock.patch("ripe.atlas.cousteau.request.AtlasRequest.http_method") as mock_get:
request._construct_post_data()
mock_get.return_value = True
request.post()
@@ -391,3 +395,32 @@ class TestAtlasLatestRequest(TestCase):
).http_method_args["params"],
{"key": None, "probe_ids": "1, 2, 3, 24"}
)
+
+
+class TestAtlasRequestCustomHeaders(TestCase):
+ def setUp(self):
+ self.create_source = AtlasSource(
+ **{"type": "area", "value": "WW", "requested": 3}
+ )
+ self.measurement = Ping(**{
+ "target": "testing", "af": 6,
+ "description": "testing"
+ })
+ self.request = AtlasCreateRequest(**{
+ "start_time": datetime(2015, 10, 16),
+ "stop_time": 1445040000,
+ "key": "path_to_key",
+ "measurements": [self.measurement],
+ "sources": [self.create_source],
+ "is_oneoff": True,
+ "headers": {"hello": "world"},
+ })
+
+ def test_custom_headers(self):
+ expected_headers = {
+ "Content-Type": "application/json",
+ "hello": "world",
+ "Accept": "application/json",
+ "User-Agent": "RIPE ATLAS Cousteau v{0}".format(__version__)
+ }
+ self.assertEqual(self.request.get_headers(), expected_headers)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/ripe-atlas-cousteau.git
More information about the Python-modules-commits
mailing list