Uh oh!
There was an error while loading. Please reload this page.
BigQuery: Get query results as pandas DataFrame - #4354
Conversation
jba
commented
Nov 7, 2017
I don't personally like the idea of an optional dependency. I guess I try to think of Python as a typed language as much as possible (and hopefully someday it will be). Maybe instead of actually returning a pandas DataFrame, you could (a) expose whatever currently hidden information is needed to efficiently create one, and (b) add a different module that depends on this one and pandas, and creates a DataFrame. |
dhermes
commented
Nov 7, 2017
I don't particularly like it too much, but in this case, the (you can name the "extra" anything you like, I just chose |
| return self._client.list_rows(dest_table, selected_fields=schema, | ||
| retry=retry) | ||
| def to_dataframe(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| return pd.DataFrame(rows, columns=column_headers) | ||
| def __iter__(self): | ||
| return iter(self.result()) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| row_tuples = [r.values() for r in iterator] | ||
| self.assertEqual(row_tuples, [(1,)]) | ||
| def test_query_iter(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self.assertEqual(row_tuples, [(1,)]) | ||
| def test_query_to_dataframe(self): | ||
| import pandas as pd |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| def test_to_dataframe(self): | ||
| import pandas as pd | ||
| begun_resource = self._makeResource() |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self.assertIsInstance(df, pd.DataFrame) | ||
| self.assertEqual(len(df), 4) | ||
| self.assertEqual(list(df), ['name', 'age']) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self.assertEqual(len(df), 4) | ||
| self.assertEqual(list(df), ['name', 'age']) | ||
| def test_to_dataframe_w_empty_results(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
7b4d967 to
edecb93Compare| retry=retry) | ||
| def to_dataframe(self): | ||
| import pandas as pd |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| row_tuples = [r.values() for r in iterator] | ||
| self.assertEqual(row_tuples, [(1,)]) | ||
| def test_query_to_dataframe(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| self.assertEqual(req['path'], PATH) | ||
| self._verifyResourceProperties(job, RESOURCE) | ||
| def test_to_dataframe(self): |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
theacodes
commented
Nov 9, 2017
+1 to what @dhermes said. We should provide a helpful message if they use a method that requires pandas (I also doubt the folks who want to use this will install bigquery before pandas), and we should provide the extra for pip. |
| retry=retry) | ||
| def to_dataframe(self): | ||
| import pandas as pd |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| def to_dataframe(self): | ||
| import pandas as pd | ||
| iterator = self.result() |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
edecb93 to
52a5e5fCompare
dhermes
left a comment
There was a problem hiding this comment.
As you can see, nox -s cover will fail unless you:
- Explicitly add a "no cover" pragma around these tests and functions (not my preference)
- Install
pandasinto the text environment (session.install('-e', '.[pandas]'))
| def to_dataframe(self): | ||
| """Create a pandas DataFrame from the query results. | ||
| :rtype: ``pandas.DataFrame`` |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| ] | ||
| EXTRAS_REQUIREMENTS = { | ||
| 'pandas': ['pandas >= 0.3.0'], |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
dhermes
commented
Nov 10, 2017
So @alixhami, after discussion with @jonparrott we have decided it is "preferred" if all new docstrings are in the Google style (vs. traditional Sphinx). I'm happy to help out / chat over hangouts / send you some code snippets. Can you change the newly added docstring to Google style? |
dhermes
commented
Nov 10, 2017
LGTM, but you need to resolve the coverage issues |
| """ | ||
| if pandas is None: | ||
| if pandas is None: # pragma: NO COVER |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
dhermes
commented
Nov 13, 2017
@alixhami This is good to merge once CI goes green, right? |
alixhami
commented
Nov 13, 2017
dhermes
commented
Nov 13, 2017
|
tswast
left a comment
There was a problem hiding this comment.
LGTM, though I think it could be a little more general. I'd love if this was a method of the iterator we return from QueryJob.results() and Client.list_rows().
| retry=retry) | ||
| def to_dataframe(self): | ||
| """Create a pandas DataFrame from the query results. |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
| column_headers = [field.name for field in query_results.schema] | ||
| rows = [row.values() for row in query_results] | ||
| return pandas.DataFrame(rows, columns=column_headers) |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
a00c9da to
1458da6Compare… if it isn't installed
d345624 to
0802ca8Comparetheacodes
commented
Dec 4, 2017
dhermes
commented
Dec 4, 2017
@alixhami This is failing on Python 2.7, distinction being between |
This is a basic implementation of a method converting query results to a pandas DataFrame. I am hoping for comments on how best to implement this. Here is an example of how to use the current implementation:
df = client.query(QUERY).to_dataframe()The intent is that pandas would be an optional dependency, and would not be required unless the DataFrame functionality is used. This is not yet handled in my current implementation, which is why CircleCI will fail. I ran the tests locally with pandas installed and they pass.
The base of this PR is #4350