Skip to content
This repository was archived by the owner on Dec 31, 2023. It is now read-only.

Commit f135202

Browse files
authored
fix: fix as_dataframe (#91)
1 parent 4cdb1ff commit f135202

File tree

5 files changed

+71
-34
lines changed

5 files changed

+71
-34
lines changed

google/cloud/monitoring_v3/_dataframe.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@
2121
except ImportError: # pragma: NO COVER
2222
pandas = None
2323

24-
from google.cloud.monitoring_v3.types import TimeSeries
24+
from google.cloud import monitoring_v3
25+
2526

2627
TOP_RESOURCE_LABELS = ("project_id", "aws_account", "location", "region", "zone")
2728

2829

2930
def _extract_header(time_series):
3031
"""Return a copy of time_series with the points removed."""
31-
return TimeSeries(
32+
return monitoring_v3.TimeSeries(
3233
metric=time_series.metric,
3334
resource=time_series.resource,
3435
metric_kind=time_series.metric_kind,
@@ -46,15 +47,19 @@ def _extract_labels(time_series):
4647

4748
def _extract_value(typed_value):
4849
"""Extract the value from a TypedValue."""
49-
value_type = typed_value.WhichOneof("value")
50-
return typed_value.__getattribute__(value_type)
50+
# There is no equivalent of WhichOneOf in proto-plus
51+
# This may break if the field names have been altered in the
52+
# proto-plus representation
53+
# https://github.com/googleapis/proto-plus-python/issues/137
54+
value_type = monitoring_v3.TypedValue.pb(typed_value).WhichOneof("value")
55+
return getattr(typed_value, value_type)
5156

5257

5358
def _build_dataframe(time_series_iterable, label=None, labels=None): # pragma: NO COVER
5459
"""Build a :mod:`pandas` dataframe out of time series.
5560
5661
:type time_series_iterable:
57-
iterable over :class:`~google.cloud.monitoring_v3.types.TimeSeries`
62+
iterable over :class:`~google.cloud.monitoring_v3.TimeSeries`
5863
:param time_series_iterable:
5964
An iterable (e.g., a query object) yielding time series.
6065
@@ -95,7 +100,8 @@ def _build_dataframe(time_series_iterable, label=None, labels=None): # pragma:
95100
pandas_series = pandas.Series(
96101
data=[_extract_value(point.value) for point in time_series.points],
97102
index=[
98-
point.interval.end_time.ToNanoseconds() for point in time_series.points
103+
point.interval.end_time.timestamp_pb().ToNanoseconds()
104+
for point in time_series.points
99105
],
100106
)
101107
columns.append(pandas_series)

noxfile.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,17 @@
3030
SYSTEM_TEST_PYTHON_VERSIONS = ["3.8"]
3131
UNIT_TEST_PYTHON_VERSIONS = ["3.6", "3.7", "3.8", "3.9"]
3232

33+
# 'docfx' is excluded since it only needs to run in 'docs-presubmit'
34+
nox.options.sessions = [
35+
"unit",
36+
"system",
37+
"cover",
38+
"lint",
39+
"lint_setup_py",
40+
"blacken",
41+
"docs",
42+
]
43+
3344

3445
@nox.session(python=DEFAULT_PYTHON_VERSION)
3546
def lint(session):
@@ -75,12 +86,14 @@ def default(session):
7586
session.install(
7687
"mock", "pytest", "pytest-cov",
7788
)
78-
session.install("-e", ".")
89+
90+
session.install("-e", ".[pandas]")
7991

8092
# Run py.test against the unit tests.
8193
session.run(
8294
"py.test",
8395
"--quiet",
96+
f"--junitxml=unit_{session.python}_sponge_log.xml",
8497
"--cov=google/cloud",
8598
"--cov=tests/unit",
8699
"--cov-append",
@@ -110,6 +123,9 @@ def system(session):
110123
# Sanity check: Only run tests if the environment variable is set.
111124
if not os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", ""):
112125
session.skip("Credentials must be set via environment variable")
126+
# Install pyopenssl for mTLS testing.
127+
if os.environ.get("GOOGLE_API_USE_CLIENT_CERTIFICATE", "false") == "true":
128+
session.install("pyopenssl")
113129

114130
system_test_exists = os.path.exists(system_test_path)
115131
system_test_folder_exists = os.path.exists(system_test_folder_path)
@@ -125,13 +141,25 @@ def system(session):
125141
session.install(
126142
"mock", "pytest", "google-cloud-testutils",
127143
)
128-
session.install("-e", ".")
144+
session.install("-e", ".[pandas]")
129145

130146
# Run py.test against the system tests.
131147
if system_test_exists:
132-
session.run("py.test", "--quiet", system_test_path, *session.posargs)
148+
session.run(
149+
"py.test",
150+
"--quiet",
151+
f"--junitxml=system_{session.python}_sponge_log.xml",
152+
system_test_path,
153+
*session.posargs,
154+
)
133155
if system_test_folder_exists:
134-
session.run("py.test", "--quiet", system_test_folder_path, *session.posargs)
156+
session.run(
157+
"py.test",
158+
"--quiet",
159+
f"--junitxml=system_{session.python}_sponge_log.xml",
160+
system_test_folder_path,
161+
*session.posargs,
162+
)
135163

136164

137165
@nox.session(python=DEFAULT_PYTHON_VERSION)

samples/snippets/v3/cloud-client/snippets.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
import time
1919
import uuid
2020

21-
from google.api import metric_pb2 as ga_metric
2221
from google.api import label_pb2 as ga_label
22+
from google.api import metric_pb2 as ga_metric
2323
from google.cloud import monitoring_v3
2424

2525

@@ -35,13 +35,13 @@ def create_metric_descriptor(project_id):
3535
descriptor.metric_kind = ga_metric.MetricDescriptor.MetricKind.GAUGE
3636
descriptor.value_type = ga_metric.MetricDescriptor.ValueType.DOUBLE
3737
descriptor.description = "This is a simple example of a custom metric."
38-
38+
3939
labels = ga_label.LabelDescriptor()
4040
labels.key = "TestLabel"
4141
labels.value_type = ga_label.LabelDescriptor.ValueType.STRING
4242
labels.description = "This is a test label"
4343
descriptor.labels.append(labels)
44-
44+
4545
descriptor = client.create_metric_descriptor(
4646
name=project_name, metric_descriptor=descriptor
4747
)

synth.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,19 @@
9393
templated_files = common.py_library(
9494
samples=True, # set to True only if there are samples
9595
microgenerator=True,
96+
unit_test_extras=["pandas"],
97+
system_test_extras=["pandas"],
9698
cov_level=99
9799
)
98100
s.move(templated_files, excludes=[".coveragerc"]) # microgenerator has a good .coveragerc file
99101

102+
# Don't treat docs (sphinx) warnings as errors.
103+
s.replace("noxfile.py", '[\"\']-W[\"\']', '# "-W"')
104+
100105
# ----------------------------------------------------------------------------
101106
# Samples templates
102107
# ----------------------------------------------------------------------------
103108
python.py_samples(skip_readmes=True)
104109

105-
# Don't treat warnings as errors.
106-
s.replace("noxfile.py", '[\"\']-W[\"\']', '# "-W"')
107110

108111
s.shell.run(["nox", "-s", "blacken"], hide_output=False)

tests/unit/test__dataframe.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,16 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
try:
16-
import pandas
17-
except ImportError:
18-
HAVE_PANDAS = False
19-
else:
20-
HAVE_PANDAS = True # pragma: NO COVER
2115

16+
import pandas
2217
import unittest
2318

19+
from google.api import metric_pb2
20+
from google.api import monitored_resource_pb2
21+
from google.api_core import datetime_helpers
22+
from google.cloud import monitoring_v3
23+
from google.cloud.monitoring_v3 import _dataframe
24+
2425

2526
PROJECT = "my-project"
2627

@@ -58,20 +59,22 @@ def parse_timestamps():
5859

5960

6061
def generate_query_results():
61-
from google.cloud.monitoring_v3 import types
62-
6362
def P(timestamp, value):
64-
interval = types.TimeInterval()
65-
interval.start_time.FromJsonString(timestamp)
66-
interval.end_time.FromJsonString(timestamp)
67-
return types.Point(interval=interval, value={"double_value": value})
63+
interval = monitoring_v3.TimeInterval()
64+
interval.start_time = datetime_helpers.from_rfc3339(timestamp).replace(
65+
tzinfo=None
66+
)
67+
interval.end_time = datetime_helpers.from_rfc3339(timestamp).replace(
68+
tzinfo=None
69+
)
70+
return monitoring_v3.Point(interval=interval, value={"double_value": value})
6871

6972
for metric_labels, resource_labels, value in zip(
7073
METRIC_LABELS, RESOURCE_LABELS, VALUES
7174
):
72-
yield types.TimeSeries(
73-
metric=types.Metric(type=METRIC_TYPE, labels=metric_labels),
74-
resource=types.MonitoredResource(
75+
yield monitoring_v3.TimeSeries(
76+
metric=metric_pb2.Metric(type=METRIC_TYPE, labels=metric_labels),
77+
resource=monitored_resource_pb2.MonitoredResource(
7578
type=RESOURCE_TYPE, labels=resource_labels
7679
),
7780
metric_kind=METRIC_KIND,
@@ -80,12 +83,9 @@ def P(timestamp, value):
8083
)
8184

8285

83-
@unittest.skipUnless(HAVE_PANDAS, "No pandas")
8486
class Test__build_dataframe(unittest.TestCase):
8587
def _call_fut(self, *args, **kwargs):
86-
from google.cloud.monitoring_v3._dataframe import _build_dataframe
87-
88-
return _build_dataframe(*args, **kwargs)
88+
return _dataframe._build_dataframe(*args, **kwargs)
8989

9090
def test_both_label_and_labels_illegal(self):
9191
with self.assertRaises(ValueError):

0 commit comments

Comments
 (0)