garf-core 0.0.5__py3-none-any.whl → 0.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
garf_core/__init__.py CHANGED
@@ -12,4 +12,4 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- __version__ = '0.0.5'
15
+ __version__ = '0.0.7'
garf_core/api_clients.py CHANGED
@@ -19,6 +19,7 @@ import abc
19
19
  import dataclasses
20
20
  from collections.abc import Sequence
21
21
 
22
+ import requests
22
23
  from typing_extensions import override
23
24
 
24
25
 
@@ -34,16 +35,40 @@ class GarfApiResponse:
34
35
  results: list
35
36
 
36
37
 
38
+ class GarfApiError(Exception):
39
+ """API specific exception."""
40
+
41
+
37
42
  class BaseClient(abc.ABC):
38
43
  """Base API client class."""
39
44
 
40
45
  @abc.abstractmethod
41
46
  def get_response(
42
- self, request: GarfApiRequest = GarfApiRequest()
47
+ self, request: GarfApiRequest = GarfApiRequest(), **kwargs: str
43
48
  ) -> GarfApiResponse:
44
49
  """Method for getting response."""
45
50
 
46
51
 
52
+ class RestApiClient(BaseClient):
53
+ """Specifies REST client."""
54
+
55
+ OK = 200
56
+
57
+ def __init__(self, endpoint: str, **kwargs: str) -> None:
58
+ """Initializes RestApiClient."""
59
+ self.endpoint = endpoint
60
+ self.query_args = kwargs
61
+
62
+ @override
63
+ def get_response(
64
+ self, request: GarfApiRequest = GarfApiRequest(), **kwargs: str
65
+ ) -> GarfApiResponse:
66
+ response = requests.get(f'{self.endpoint}/{request.resource_name}')
67
+ if response.status_code == self.OK:
68
+ return GarfApiResponse(response.json())
69
+ raise GarfApiError('Failed to get data from API')
70
+
71
+
47
72
  class FakeApiClient(BaseClient):
48
73
  """Fake class for specifying API client."""
49
74
 
garf_core/report.py CHANGED
@@ -183,6 +183,18 @@ class GarfReport:
183
183
  output[key] = value
184
184
  return output
185
185
 
186
+ def to_polars(self) -> 'pl.DataFrame':
187
+ try:
188
+ import polars as pl
189
+ except ImportError as e:
190
+ raise ImportError(
191
+ 'Please install garf-io with Polars support '
192
+ '- `pip install garf-io[polars]`'
193
+ ) from e
194
+ return pl.DataFrame(
195
+ data=self.results, schema=self.column_names, orient='row'
196
+ )
197
+
186
198
  def to_pandas(self) -> 'pd.DataFrame':
187
199
  """Converts report to Pandas dataframe.
188
200
 
@@ -196,8 +208,8 @@ class GarfReport:
196
208
  import pandas as pd
197
209
  except ImportError as e:
198
210
  raise ImportError(
199
- 'Please install google-ads-api-report-fetcher with Pandas support '
200
- '- `pip install google-ads-api-report-fetcher[pandas]`'
211
+ 'Please install garf-io with Pandas support '
212
+ '- `pip install garf-io[pandas]`'
201
213
  ) from e
202
214
  return pd.DataFrame(data=self.results, columns=self.column_names)
203
215
 
@@ -385,6 +397,30 @@ class GarfReport:
385
397
  and other.results_placeholder,
386
398
  )
387
399
 
400
+ @classmethod
401
+ def from_polars(cls, df: 'pl.DataFrame') -> GarfReport:
402
+ """Builds GarfReport from polars dataframe.
403
+
404
+ Args:
405
+ df: Polars dataframe to build report from.
406
+
407
+ Returns:
408
+ Report build from dataframe data and columns.
409
+
410
+ Raises:
411
+ ImportError: If polars library not installed.
412
+ """
413
+ try:
414
+ import polars as pl
415
+ except ImportError as e:
416
+ raise ImportError(
417
+ 'Please install garf-io with Polars support '
418
+ '- `pip install garf-io[polars]`'
419
+ ) from e
420
+ return cls(
421
+ results=df.to_numpy().tolist(), column_names=list(df.schema.keys())
422
+ )
423
+
388
424
  @classmethod
389
425
  def from_pandas(cls, df: 'pd.DataFrame') -> GarfReport:
390
426
  """Builds GarfReport from pandas dataframe.
@@ -402,8 +438,8 @@ class GarfReport:
402
438
  import pandas as pd
403
439
  except ImportError as e:
404
440
  raise ImportError(
405
- 'Please install google-ads-api-report-fetcher with Pandas support '
406
- '- `pip install google-ads-api-report-fetcher[pandas]`'
441
+ 'Please install garf-io with Pandas support '
442
+ '- `pip install garf-io[pandas]`'
407
443
  ) from e
408
444
  return cls(results=df.values.tolist(), column_names=list(df.columns.values))
409
445
 
@@ -11,9 +11,9 @@
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
- """Module for getting data from Ads API based on a query.
14
+ """Module for getting data from API based on a query.
15
15
 
16
- AdsReportFetcher performs fetching data from Ads API, parsing it
16
+ ApiReportFetcher performs fetching data from API, parsing it
17
17
  and returning GarfReport.
18
18
  """
19
19
  # pylint: disable=C0330, g-bad-import-order, g-multiple-import
@@ -34,25 +34,27 @@ logger = logging.getLogger(__name__)
34
34
 
35
35
 
36
36
  class ApiReportFetcher:
37
- """Class responsible for getting data from Ads API.
37
+ """Class responsible for getting data from report API.
38
38
 
39
39
  Attributes:
40
- api_client: a client used for connecting to Ads API.
40
+ api_client: a client used for connecting to API.
41
41
  """
42
42
 
43
43
  def __init__(
44
44
  self,
45
45
  api_client: api_clients.BaseApiClient,
46
46
  parser: parsers.BaseParser = parsers.ListParser,
47
+ **kwargs: str,
47
48
  ) -> None:
48
- """Instantiates AdsReportFetcher based on provided api client.
49
+ """Instantiates ApiReportFetcher based on provided api client.
49
50
 
50
51
  Args:
51
- api_client: Instantiated GoogleAdsClient or GoogleAdsApiClient.
52
- parser: Parser.
52
+ api_client: Instantiated api client.
53
+ parser: Type of parser to convert API response.
53
54
  """
54
55
  self.api_client = api_client
55
56
  self.parser = parser()
57
+ self.query_args = kwargs
56
58
 
57
59
  async def afetch(
58
60
  self,
@@ -60,10 +62,10 @@ class ApiReportFetcher:
60
62
  args: dict[str, Any] | None = None,
61
63
  **kwargs: str,
62
64
  ) -> report.GarfReport:
63
- """Asynchronously fetches data from Ads API based on query_specification.
65
+ """Asynchronously fetches data from API based on query_specification.
64
66
 
65
67
  Args:
66
- query_specification: Query text that will be passed to Ads API
68
+ query_specification: Query text that will be passed to API
67
69
  alongside column_names, customizers and virtual columns.
68
70
  args: Arguments that need to be passed to the query.
69
71
 
@@ -78,10 +80,10 @@ class ApiReportFetcher:
78
80
  args: dict[str, Any] | None = None,
79
81
  **kwargs: str,
80
82
  ) -> report.GarfReport:
81
- """Fetches data from Ads API based on query_specification.
83
+ """Fetches data from API based on query_specification.
82
84
 
83
85
  Args:
84
- query_specification: Query text that will be passed to Ads API
86
+ query_specification: Query text that will be passed to API
85
87
  alongside column_names, customizers and virtual columns.
86
88
  args: Arguments that need to be passed to the query.
87
89
 
@@ -90,7 +92,7 @@ class ApiReportFetcher:
90
92
 
91
93
  Raises:
92
94
  GarfExecutorException:
93
- When customer_ids are not provided or Ads API returned error.
95
+ When customer_ids are not provided or API returned error.
94
96
  """
95
97
  if not isinstance(query_specification, query_editor.QuerySpecification):
96
98
  query_specification = query_editor.QuerySpecification(
@@ -103,3 +105,26 @@ class ApiReportFetcher:
103
105
  return report.GarfReport(
104
106
  results=parsed_response, column_names=query.column_names
105
107
  )
108
+
109
+
110
+ class RestApiReportFetcher(ApiReportFetcher):
111
+ """Fetches data from an REST API endpoint.
112
+
113
+ Attributes:
114
+ api_client: Initialized RestApiClient.
115
+ parser: Type of parser to convert API response.
116
+ """
117
+
118
+ def __init__(
119
+ self,
120
+ endpoint: str,
121
+ parser: parsers.BaseParser = parsers.DictParser,
122
+ ) -> None:
123
+ """Instantiates RestApiReportFetcher.
124
+
125
+ Args:
126
+ endpoint: URL of API endpoint.
127
+ parser: Type of parser to convert API response.
128
+ """
129
+ self.api_client = api_clients.RestApiClient(endpoint)
130
+ self.parser = parser()
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.2
2
+ Name: garf-core
3
+ Version: 0.0.7
4
+ Summary: Abstracts fetching data from API based on provided SQL-like query.
5
+ Author-email: "Google Inc. (gTech gPS CSE team)" <no-reply@google.com>
6
+ License: Apache 2.0
7
+ Classifier: Programming Language :: Python :: 3 :: Only
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: License :: OSI Approved :: Apache Software License
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Requires-Dist: python-dateutil
20
+ Requires-Dist: jinja2==3.1.4
21
+ Requires-Dist: typing-extensions
22
+ Provides-Extra: pandas
23
+ Requires-Dist: pandas; extra == "pandas"
24
+ Provides-Extra: polars
25
+ Requires-Dist: polars; extra == "polars"
26
+ Provides-Extra: all
27
+ Requires-Dist: garf-core[pandas,polars]; extra == "all"
28
+
29
+ # garf-core - Unified approach for interacting with reporting APIs.
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/garf-core?logo=pypi&logoColor=white&style=flat-square)](https://pypi.org/project/garf-core)
32
+ [![Downloads PyPI](https://img.shields.io/pypi/dw/garf-core?logo=pypi)](https://pypi.org/project/garf-core/)
33
+
34
+
35
+ `garf-core` contains the base abstractions are used by an implementation for a concrete reporting API.
36
+
37
+ These abstractions are designed to be as modular and simple as possible:
38
+
39
+ * `BaseApiClient` - an interface for connecting to APIs.
40
+ * `BaseQuery` - encapsulates SQL-like request.
41
+ * `QuerySpecification` - parsed SQL-query into various elements.
42
+ * `BaseParser` - an interface to parse results from the API. Have a couple of default implementations:
43
+ * `ListParser` - returns results from API as a raw list.
44
+ * `DictParser` - returns results from API as a formatted dict.
45
+ * `NumericDictParser` - returns results from API as a formatted dict with converted numeric values.
46
+ * `GarfReport` - contains data from API in a format that is easy to write and interact with.
47
+ * `ApiReportFetcher` - responsible for fetching and parsing data from reporting API.
48
+
49
+ ## Installation
50
+
51
+ `pip install garf-core`
@@ -0,0 +1,13 @@
1
+ garf_core/__init__.py,sha256=YXfq75YjkKDgNZM8YGRyE5aGGLa3MUVQasljixjp-70,598
2
+ garf_core/api_clients.py,sha256=FKmwts_QBV_E4aTmrnsZtow0CmSExLibfeSkMSrudU0,2235
3
+ garf_core/base_query.py,sha256=uEhKP56wcFtMiSwYOxoZ0q7OEvURGVOeRdpSYjxWLho,1201
4
+ garf_core/exceptions.py,sha256=4qvNN-8GqbbVsrLKxJwBeX1FUtWpKbhUWyvm7anD3iE,1916
5
+ garf_core/parsers.py,sha256=Y4wwpDXRZky7LBTBklvzk-aDNxgRL5RJg52rSdH5t9Q,2928
6
+ garf_core/query_editor.py,sha256=EzwjFnbje-RcP9VwWQwzCpy8lipt4tph3Kv6q5Lly5o,15994
7
+ garf_core/report.py,sha256=xlkZ44cdT_uGENuNeGwy69h7XLtwjdUjyPw3S1m-zc8,17852
8
+ garf_core/report_fetcher.py,sha256=g2bmqq8m3XxrWh1tDJ7ZO6iCys34mX8Dm55ZaT_36TI,3813
9
+ garf_core-0.0.7.dist-info/METADATA,sha256=gn0SYdh11jDgZKJJW4m1bD6TfYM90mbq-lqOWm7kQR4,2334
10
+ garf_core-0.0.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
11
+ garf_core-0.0.7.dist-info/entry_points.txt,sha256=ODxSZXwWEIXQAjRwBQsBJ6GYw8oPK6DYTo0oDVkKCpo,39
12
+ garf_core-0.0.7.dist-info/top_level.txt,sha256=Gj-Zp7fM2turGut5vTJuo5xEcKfow7cTLX3y3WFfNgA,10
13
+ garf_core-0.0.7.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [garf]
2
+ rest = garf_core.report_fetcher
@@ -1,27 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: garf-core
3
- Version: 0.0.5
4
- Summary: Abstracts fetching data from API based on provided SQL-like query.
5
- Author-email: "Google Inc. (gTech gPS CSE team)" <no-reply@google.com>
6
- License: Apache 2.0
7
- Classifier: Programming Language :: Python :: 3 :: Only
8
- Classifier: Programming Language :: Python :: 3.8
9
- Classifier: Programming Language :: Python :: 3.9
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
- Classifier: Operating System :: OS Independent
16
- Classifier: License :: OSI Approved :: Apache Software License
17
- Requires-Python: >=3.8
18
- Description-Content-Type: text/markdown
19
- Requires-Dist: python-dateutil
20
- Requires-Dist: jinja2==3.1.4
21
- Requires-Dist: typing-extensions
22
- Provides-Extra: pandas
23
- Requires-Dist: pandas; extra == "pandas"
24
- Provides-Extra: all
25
- Requires-Dist: garf-core[pandas]; extra == "all"
26
-
27
- # gaarf-core - Unified approach for interacting with reporting APIs.
@@ -1,12 +0,0 @@
1
- garf_core/__init__.py,sha256=Te0VIlL1MdNgrZ3wJdVePlSHb4Q-0-2KtcuhQp10jOQ,598
2
- garf_core/api_clients.py,sha256=sBiOfPllrSewV6Ul4uaHhdmgTHQ_l5M7sZHW1z4kNik,1568
3
- garf_core/base_query.py,sha256=uEhKP56wcFtMiSwYOxoZ0q7OEvURGVOeRdpSYjxWLho,1201
4
- garf_core/exceptions.py,sha256=4qvNN-8GqbbVsrLKxJwBeX1FUtWpKbhUWyvm7anD3iE,1916
5
- garf_core/parsers.py,sha256=Y4wwpDXRZky7LBTBklvzk-aDNxgRL5RJg52rSdH5t9Q,2928
6
- garf_core/query_editor.py,sha256=EzwjFnbje-RcP9VwWQwzCpy8lipt4tph3Kv6q5Lly5o,15994
7
- garf_core/report.py,sha256=-wz3c4k6Gtxs1jdqC0aSK61ziulxV1cGTl55E8o26bs,16980
8
- garf_core/report_fetcher.py,sha256=RazwzI8n3e4oVhFUEGshzwaGG0EHIYJgHOleuAeNEto,3231
9
- garf_core-0.0.5.dist-info/METADATA,sha256=_stbiUxOKv99mdf9EHHw8r5T-QeFKj9wpfAji2SRwQ0,1115
10
- garf_core-0.0.5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
11
- garf_core-0.0.5.dist-info/top_level.txt,sha256=Gj-Zp7fM2turGut5vTJuo5xEcKfow7cTLX3y3WFfNgA,10
12
- garf_core-0.0.5.dist-info/RECORD,,