[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Stub initial BandwidthMetric class
commit cb8661ef66a2355ab0ed37e8da5e806362c2ab9b
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Wed Jan 16 14:26:59 2019 -0800
Stub initial BandwidthMetric class
Just stubbing out an initial class and test.
---
stem/descriptor/__init__.py | 13 +++-
stem/descriptor/bandwidth_metric.py | 104 +++++++++++++++++++++++++++++++
test/settings.cfg | 8 ++-
test/unit/descriptor/__init__.py | 1 +
test/unit/descriptor/bandwidth_metric.py | 21 +++++++
5 files changed, 141 insertions(+), 6 deletions(-)
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index a47c1508..e587f9d1 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -108,6 +108,7 @@ except ImportError:
from stem.util.ordereddict import OrderedDict
__all__ = [
+ 'bandwidth_metric',
'export',
'reader',
'remote',
@@ -441,6 +442,11 @@ def _parse_metrics_file(descriptor_type, major_version, minor_version, descripto
for desc in stem.descriptor.hidden_service_descriptor._parse_file(descriptor_file, validate = validate, **kwargs):
yield desc
+ elif descriptor_type == stem.descriptor.bandwidth_metric.BandwidthMetric.TYPE_ANNOTATION_NAME and major_version == 1:
+ document_type = stem.descriptor.bandwidth_metric.BandwidthMetric
+
+ for desc in stem.descriptor.bandwidth_metric._parse_file(descriptor_file, validate = validate, **kwargs):
+ yield desc
else:
raise TypeError("Unrecognized metrics descriptor format. type: '%s', version: '%i.%i'" % (descriptor_type, major_version, minor_version))
@@ -1412,9 +1418,10 @@ def _descriptor_components(raw_contents, validate, extra_keywords = (), non_asci
# importing at the end to avoid circular dependencies on our Descriptor class
-import stem.descriptor.server_descriptor
+import stem.descriptor.bandwidth_metric
import stem.descriptor.extrainfo_descriptor
-import stem.descriptor.networkstatus
+import stem.descriptor.hidden_service_descriptor
import stem.descriptor.microdescriptor
+import stem.descriptor.networkstatus
+import stem.descriptor.server_descriptor
import stem.descriptor.tordnsel
-import stem.descriptor.hidden_service_descriptor
diff --git a/stem/descriptor/bandwidth_metric.py b/stem/descriptor/bandwidth_metric.py
new file mode 100644
index 00000000..bb732f4a
--- /dev/null
+++ b/stem/descriptor/bandwidth_metric.py
@@ -0,0 +1,104 @@
+# Copyright 2019, Damian Johnson and The Tor Project
+# See LICENSE for licensing information
+
+"""
+Parsing for Bandwidth Authority metrics as described in Tor's
+`bandwidth-file-spec <https://gitweb.torproject.org/torspec.git/tree/bandwidth-file-spec.txt>`_.
+
+**Module Overview:**
+
+::
+
+ BandwidthMetric - Tor bandwidth authority measurements.
+
+.. versionadded:: 1.8.0
+"""
+
+import datetime
+
+from stem.descriptor import (
+ Descriptor,
+)
+
+
+def _parse_file(descriptor_file, validate = False, **kwargs):
+ """
+ Iterates over the bandwidth authority metrics in a file.
+
+ :param file descriptor_file: file with descriptor content
+ :param bool validate: checks the validity of the descriptor's content if
+ **True**, skips these checks otherwise
+ :param dict kwargs: additional arguments for the descriptor constructor
+
+ :returns: :class:`stem.descriptor.bandwidth_file.BandwidthMetric` object
+
+ :raises:
+ * **ValueError** if the contents is malformed and validate is **True**
+ * **IOError** if the file can't be read
+ """
+
+ yield BandwidthMetric(descriptor_file.read(), validate, **kwargs)
+
+
+def _parse_header(descriptor, entries):
+ header = {}
+
+ for line in str(descriptor).split('\n'):
+ if line == '=====':
+ break
+ elif line.startswith('node_id='):
+ break # version 1.0 measurement
+
+ if '=' in line:
+ key, value = line.split('=', 1)
+ elif line.isdigit() and 'timestamp' not in header:
+ key, value = 'timestamp', line
+ else:
+ raise ValueError("Header expected to be key=value pairs, but had '%s'" % line)
+
+ header[key] = value
+
+ descriptor.header = header
+
+
+def _parse_timestamp(descriptor, entries):
+ first_line = str(descriptor).split('\n', 1)[0]
+
+ if first_line.isdigit():
+ descriptor.timestamp = datetime.datetime.utcfromtimestamp(int(first_line))
+ else:
+ raise ValueError("First line should be a unix timestamp, but was '%s'" % first_line)
+
+
+def _header_attr(name):
+ def _parse(descriptor, entries):
+ val = descriptor.header.get(name, None)
+ setattr(descriptor, name, val)
+
+ return _parse
+
+
+class BandwidthMetric(Descriptor):
+ """
+ Tor bandwidth authroity measurements.
+
+ :var datetime timestamp: **\*** time when these metrics were published
+
+ :var dict header: **\*** header metadata attributes
+
+ **\*** attribute is either required when we're parsed with validation or has
+ a default value, others are left as **None** if undefined
+ """
+
+ TYPE_ANNOTATION_NAME = 'badnwidth-file' # TODO: needs an official @type
+
+ ATTRIBUTES = {
+ 'timestamp': (None, _parse_timestamp),
+ 'header': ({}, _parse_header),
+ }
+
+ def __init__(self, raw_content, validate = False):
+ super(BandwidthMetric, self).__init__(raw_content, lazy_load = not validate)
+
+ if validate:
+ pass # TODO: implement eager load
diff --git a/test/settings.cfg b/test/settings.cfg
index 2ecd34ea..a5e60e08 100644
--- a/test/settings.cfg
+++ b/test/settings.cfg
@@ -138,12 +138,13 @@ pycodestyle.ignore E131
pycodestyle.ignore E722
pycodestyle.ignore stem/__init__.py => E402: import stem.util.connection
-pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.server_descriptor
+pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.bandwidth_metric
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.extrainfo_descriptor
-pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.networkstatus
+pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.hidden_service_descriptor
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.microdescriptor
+pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.networkstatus
+pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.server_descriptor
pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.tordnsel
-pycodestyle.ignore stem/descriptor/__init__.py => E402: import stem.descriptor.hidden_service_descriptor
pycodestyle.ignore test/unit/util/connection.py => W291: _tor tor 15843 10 pipe 0x0 state:
pycodestyle.ignore test/unit/util/connection.py => W291: _tor tor 15843 11 pipe 0x0 state:
@@ -224,6 +225,7 @@ test.unit_tests
|test.unit.descriptor.networkstatus.bridge_document.TestBridgeNetworkStatusDocument
|test.unit.descriptor.hidden_service_descriptor.TestHiddenServiceDescriptor
|test.unit.descriptor.certificate.TestEd25519Certificate
+|test.unit.descriptor.bandwidth_metric.TestBandwidthMetric
|test.unit.exit_policy.rule.TestExitPolicyRule
|test.unit.exit_policy.policy.TestExitPolicy
|test.unit.endpoint.TestEndpoint
diff --git a/test/unit/descriptor/__init__.py b/test/unit/descriptor/__init__.py
index bce8d3d0..0fe107dd 100644
--- a/test/unit/descriptor/__init__.py
+++ b/test/unit/descriptor/__init__.py
@@ -5,6 +5,7 @@ Unit tests for stem.descriptor.
import os
__all__ = [
+ 'bandwidth_metric',
'export',
'extrainfo_descriptor',
'microdescriptor',
diff --git a/test/unit/descriptor/bandwidth_metric.py b/test/unit/descriptor/bandwidth_metric.py
new file mode 100644
index 00000000..489f4d41
--- /dev/null
+++ b/test/unit/descriptor/bandwidth_metric.py
@@ -0,0 +1,21 @@
+"""
+Unit tests for stem.descriptor.bandwidth_metric.
+"""
+
+import datetime
+import unittest
+
+import stem.descriptor
+import stem.descriptor.bandwidth_metric
+
+import test.unit.descriptor
+
+
+class TestBandwidthMetric(unittest.TestCase):
+ def test_format_v1_0(self):
+ """
+ Parse version 1.0 formatted metrics.
+ """
+
+ desc = list(stem.descriptor.parse_file(test.unit.descriptor.get_resource('bwauth_v1.0'), 'badnwidth-file 1.0'))[0]
+ self.assertEqual(datetime.datetime(2019, 1, 14, 17, 41, 29), desc.timestamp)
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits