Skip to content

Commit b3b5f71

Browse files
chore(merchant): restructure package
1 parent 8aa61ee commit b3b5f71

File tree

13 files changed

+283
-107
lines changed

13 files changed

+283
-107
lines changed

libs/community/google/merchant/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717

1818
### Run as a library
1919
```
20-
from garf_merchant_api import report_fetcher
21-
from garf_io import writer
20+
from garf.community.google.merchant import report_fetcher
21+
from garf.io import writer
2222
2323
2424
# Specify query
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Library for fetching reports from Google Merchant API."""
16+
17+
from __future__ import annotations
18+
19+
from garf.community.google.merchant.api_clients import MerchantApiClient
20+
from garf.community.google.merchant.report_fetcher import (
21+
MerchantApiReportFetcher,
22+
)
23+
24+
__all__ = [
25+
'MerchantApiClient',
26+
'MerchantApiReportFetcher',
27+
]
28+
29+
__version__ = '0.0.1'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Creates API client for Merchant API."""
15+
16+
from garf.community.google.merchant import exceptions
17+
from garf.core import api_clients, query_editor
18+
from google.shopping import merchant_reports_v1beta
19+
from typing_extensions import override
20+
21+
22+
class MerchantApiError(exceptions.GarfMerchantApiError):
23+
"""API specific error."""
24+
25+
26+
class MerchantApiClient(api_clients.BaseClient):
27+
def __init__(
28+
self,
29+
**kwargs: str,
30+
) -> None:
31+
"""Initializes MerchantClient."""
32+
self.query_args = kwargs
33+
34+
@override
35+
def get_response(
36+
self, request: query_editor.BaseQueryElements, **kwargs: str
37+
) -> api_clients.GarfApiResponse:
38+
if not (account := kwargs.get('account')):
39+
raise MerchantApiError('Missing account parameter')
40+
client = merchant_reports_v1beta.ReportServiceClient()
41+
merchant_request = merchant_reports_v1beta.SearchRequest(
42+
parent=f'accounts/{account}',
43+
query=request.text,
44+
)
45+
response = client.search(request=merchant_request)
46+
results = []
47+
for page in response:
48+
for rows in page.get('results'):
49+
for _, row in rows.items():
50+
results.append(row)
51+
return api_clients.GarfApiResponse(results=results)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from garf.core import exceptions
16+
17+
18+
class GarfMerchantApiError(exceptions.GarfError):
19+
"""Base class for all library exceptions."""
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Defines MerchantQuery."""
15+
16+
from garf.core import query_editor
17+
from typing_extensions import Self
18+
19+
20+
def _to_camel_case(field: str) -> str:
21+
first, *others = field.split('_')
22+
return ''.join([first.lower(), *map(str.title, others)])
23+
24+
25+
class MerchantApiQuery(query_editor.QuerySpecification):
26+
"""Query to Knowledge Graph Search api."""
27+
28+
def __init__(
29+
self,
30+
text: str,
31+
title: str | None = None,
32+
args: dict[str, str] | None = None,
33+
**kwargs,
34+
) -> None:
35+
"""Initializes MerchantApiQuery."""
36+
super().__init__(text, title, args, **kwargs)
37+
38+
def extract_fields(self) -> Self:
39+
for line in self._extract_query_lines():
40+
line_elements = query_editor.ExtractedLineElements.from_query_line(line)
41+
if field := line_elements.field:
42+
self.query.fields.append(
43+
_to_camel_case(field) if '_' in field else field
44+
)
45+
return self
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Defines report fetcher."""
16+
17+
from garf.community.google.merchant import MerchantApiClient, query_editor
18+
from garf.core import parsers, report_fetcher
19+
20+
21+
class MerchantApiReportFetcher(report_fetcher.ApiReportFetcher):
22+
"""Defines report fetcher."""
23+
24+
def __init__(
25+
self,
26+
api_client: MerchantApiClient = MerchantApiClient(),
27+
parser: parsers.BaseParser = parsers.NumericConverterDictParser,
28+
query_spec: query_editor.MerchantApiQuery = query_editor.MerchantApiQuery,
29+
**kwargs: str,
30+
) -> None:
31+
"""Initializes MerchantApiReportFetcher."""
32+
super().__init__(api_client, parser, query_spec, **kwargs)
Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 Google LLC
1+
# Copyright 2026 Google LLC
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -12,18 +12,13 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
"""Library for fetching reports from Google Merchant API."""
15+
import warnings
1616

17-
from __future__ import annotations
17+
from garf.community.google.merchant import *
1818

19-
from garf_merchant_api.api_clients import MerchantApiClient
20-
from garf_merchant_api.report_fetcher import (
21-
MerchantApiReportFetcher,
19+
warnings.warn(
20+
"The 'garf_merchant_api' namespace is deprecated. "
21+
"Please use 'garf.community.google.merchant' instead.",
22+
DeprecationWarning,
23+
stacklevel=2,
2224
)
23-
24-
__all__ = [
25-
'MerchantApiClient',
26-
'MerchantApiReportFetcher',
27-
]
28-
29-
__version__ = '0.0.1'
Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 Google LLC
1+
# Copyright 2026 Google LLC
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -11,42 +11,14 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
"""Creates API client for Merchant API."""
1514

16-
from garf_core import api_clients, query_editor
17-
from google.shopping import merchant_reports_v1beta
18-
from typing_extensions import override
15+
import warnings
1916

20-
from garf_merchant_api import exceptions
17+
from garf.community.google.merchant.api_clients import *
2118

22-
23-
class MerchantApiError(exceptions.GarfMerchantApiError):
24-
"""API specific error."""
25-
26-
27-
class MerchantApiClient(api_clients.BaseClient):
28-
def __init__(
29-
self,
30-
**kwargs: str,
31-
) -> None:
32-
"""Initializes MerchantClient."""
33-
self.query_args = kwargs
34-
35-
@override
36-
def get_response(
37-
self, request: query_editor.BaseQueryElements, **kwargs: str
38-
) -> api_clients.GarfApiResponse:
39-
if not (account := kwargs.get('account')):
40-
raise MerchantApiError('Missing account parameter')
41-
client = merchant_reports_v1beta.ReportServiceClient()
42-
merchant_request = merchant_reports_v1beta.SearchRequest(
43-
parent=f'accounts/{account}',
44-
query=request.text,
45-
)
46-
response = client.search(request=merchant_request)
47-
results = []
48-
for page in response:
49-
for rows in page.get('results'):
50-
for _, row in rows.items():
51-
results.append(row)
52-
return api_clients.GarfApiResponse(results=results)
19+
warnings.warn(
20+
"The 'garf_merchant_api' namespace is deprecated. "
21+
"Please use 'garf.community.google.merchant' instead.",
22+
DeprecationWarning,
23+
stacklevel=2,
24+
)

libs/community/google/merchant/garf_merchant_api/exceptions.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 Google LLC
1+
# Copyright 2026 Google LLC
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -12,8 +12,13 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from garf_core import exceptions
15+
import warnings
1616

17+
from garf.community.google.merchant.exceptions import *
1718

18-
class GarfMerchantApiError(exceptions.GarfError):
19-
"""Base class for all library exceptions."""
19+
warnings.warn(
20+
"The 'garf_merchant_api' namespace is deprecated. "
21+
"Please use 'garf.community.google.merchant' instead.",
22+
DeprecationWarning,
23+
stacklevel=2,
24+
)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"results": [
3+
{
4+
"productView": {
5+
"id": "online~en~US~id0"
6+
"offerId": "id0",
7+
"feedLabel": "US",
8+
"aggregatedReportingContextStatus": "NOT_ELIGIBLE_OR_DISAPPROVED",
9+
"itemIssues": [
10+
{
11+
"type": {
12+
"code": "invalid_string_value",
13+
"canonicalAttribute": "n:product_code"
14+
},
15+
"severity": {
16+
"severityPerReportingContext": [
17+
{
18+
"reportingContext": "SHOPPING_ADS",
19+
"disapprovedCountries": [
20+
"US"
21+
]
22+
},
23+
{
24+
"reportingContext": "FREE_LISTINGS",
25+
"disapprovedCountries": [
26+
"US"
27+
]
28+
}
29+
],
30+
"aggregatedSeverity": "DISAPPROVED"
31+
},
32+
"resolution": "MERCHANT_ACTION"
33+
},
34+
{
35+
"type": {
36+
"code": "apparel_missing_brand",
37+
"canonicalAttribute": "n:brand"
38+
},
39+
"severity": {
40+
"severityPerReportingContext": [
41+
{
42+
"reportingContext": "SHOPPING_ADS",
43+
"disapprovedCountries": [
44+
"US"
45+
]
46+
}
47+
],
48+
"aggregatedSeverity": "DEMOTED"
49+
},
50+
"resolution": "MERCHANT_ACTION"
51+
}
52+
]
53+
}
54+
}
55+
]
56+
}

0 commit comments

Comments
 (0)