mcm-cli 1.7.5__tar.gz → 1.8.0__tar.gz
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.
- {mcm_cli-1.7.5/mcm_cli.egg-info → mcm-cli-1.8.0}/PKG-INFO +4 -12
- {mcm_cli-1.7.5 → mcm-cli-1.8.0/mcm_cli.egg-info}/PKG-INFO +4 -12
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcm_cli.egg-info/SOURCES.txt +2 -2
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcm_cli.egg-info/entry_points.txt +1 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/__main__.py +1 -1
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/admin.py +11 -3
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/decision.py +6 -3
- mcm-cli-1.8.0/mcmcli/command/userevent.py +96 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/logging.py +1 -1
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/setup.py +1 -1
- mcm_cli-1.7.5/tests/test_config.py +0 -16
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/LICENSE +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/NOTICE +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/README.md +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcm_cli.egg-info/dependency_links.txt +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcm_cli.egg-info/requires.txt +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcm_cli.egg-info/top_level.txt +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/__init__.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/account.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/auth.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/campaign.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/config.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/report.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/command/wallet.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/account.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/account_user.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/campaign.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/decision.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/error.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/item.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/item_blocking_result.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/platform_user.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/report.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/seller.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/token.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/user_join_request.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/data/wallet.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/mcmcli/requests.py +0 -0
- {mcm_cli-1.7.5 → mcm-cli-1.8.0}/setup.cfg +0 -0
@@ -1,11 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mcm-cli
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.8.0
|
4
4
|
Summary: A command-line interface for Moloco Commerde Media
|
5
5
|
Home-page: https://github.com/moloco-mcm/mcm-cli
|
6
6
|
Author: Moloco MCM Team
|
7
7
|
Author-email: mcm-help@moloco.com
|
8
8
|
License: Apache-2.0 license
|
9
|
+
Platform: UNKNOWN
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
10
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
11
12
|
Classifier: Operating System :: OS Independent
|
@@ -13,17 +14,6 @@ Requires-Python: >=3.6
|
|
13
14
|
Description-Content-Type: text/markdown
|
14
15
|
License-File: LICENSE
|
15
16
|
License-File: NOTICE
|
16
|
-
Requires-Dist: colorama
|
17
|
-
Requires-Dist: gitpython
|
18
|
-
Requires-Dist: pydantic
|
19
|
-
Requires-Dist: pygithub
|
20
|
-
Requires-Dist: python-terraform
|
21
|
-
Requires-Dist: requests
|
22
|
-
Requires-Dist: rich
|
23
|
-
Requires-Dist: setuptools
|
24
|
-
Requires-Dist: shortuuid
|
25
|
-
Requires-Dist: toml
|
26
|
-
Requires-Dist: typer
|
27
17
|
|
28
18
|
# Moloco Commerce Media (MCM) CLI utility
|
29
19
|
|
@@ -93,3 +83,5 @@ $
|
|
93
83
|
```
|
94
84
|
|
95
85
|
© Moloco, Inc. 2023 All rights reserved. Released under Apache 2.0 License
|
86
|
+
|
87
|
+
|
@@ -1,11 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mcm-cli
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.8.0
|
4
4
|
Summary: A command-line interface for Moloco Commerde Media
|
5
5
|
Home-page: https://github.com/moloco-mcm/mcm-cli
|
6
6
|
Author: Moloco MCM Team
|
7
7
|
Author-email: mcm-help@moloco.com
|
8
8
|
License: Apache-2.0 license
|
9
|
+
Platform: UNKNOWN
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
10
11
|
Classifier: License :: OSI Approved :: Apache Software License
|
11
12
|
Classifier: Operating System :: OS Independent
|
@@ -13,17 +14,6 @@ Requires-Python: >=3.6
|
|
13
14
|
Description-Content-Type: text/markdown
|
14
15
|
License-File: LICENSE
|
15
16
|
License-File: NOTICE
|
16
|
-
Requires-Dist: colorama
|
17
|
-
Requires-Dist: gitpython
|
18
|
-
Requires-Dist: pydantic
|
19
|
-
Requires-Dist: pygithub
|
20
|
-
Requires-Dist: python-terraform
|
21
|
-
Requires-Dist: requests
|
22
|
-
Requires-Dist: rich
|
23
|
-
Requires-Dist: setuptools
|
24
|
-
Requires-Dist: shortuuid
|
25
|
-
Requires-Dist: toml
|
26
|
-
Requires-Dist: typer
|
27
17
|
|
28
18
|
# Moloco Commerce Media (MCM) CLI utility
|
29
19
|
|
@@ -93,3 +83,5 @@ $
|
|
93
83
|
```
|
94
84
|
|
95
85
|
© Moloco, Inc. 2023 All rights reserved. Released under Apache 2.0 License
|
86
|
+
|
87
|
+
|
@@ -19,6 +19,7 @@ mcmcli/command/campaign.py
|
|
19
19
|
mcmcli/command/config.py
|
20
20
|
mcmcli/command/decision.py
|
21
21
|
mcmcli/command/report.py
|
22
|
+
mcmcli/command/userevent.py
|
22
23
|
mcmcli/command/wallet.py
|
23
24
|
mcmcli/data/account.py
|
24
25
|
mcmcli/data/account_user.py
|
@@ -32,5 +33,4 @@ mcmcli/data/report.py
|
|
32
33
|
mcmcli/data/seller.py
|
33
34
|
mcmcli/data/token.py
|
34
35
|
mcmcli/data/user_join_request.py
|
35
|
-
mcmcli/data/wallet.py
|
36
|
-
tests/test_config.py
|
36
|
+
mcmcli/data/wallet.py
|
@@ -37,7 +37,7 @@ def version():
|
|
37
37
|
"""
|
38
38
|
Show the tool version
|
39
39
|
"""
|
40
|
-
typer.echo(f"Version: mcm-cli v1.
|
40
|
+
typer.echo(f"Version: mcm-cli v1.8.0")
|
41
41
|
|
42
42
|
app.add_typer(mcmcli.command.account.app, name="account", help="Ad account management")
|
43
43
|
app.add_typer(mcmcli.command.admin.app, name="admin", help="Platform administration")
|
@@ -28,6 +28,7 @@ import mcmcli.command.auth
|
|
28
28
|
import mcmcli.command.campaign
|
29
29
|
import mcmcli.command.config
|
30
30
|
import mcmcli.command.decision
|
31
|
+
import mcmcli.command.userevent
|
31
32
|
import mcmcli.command.wallet
|
32
33
|
import mcmcli.requests
|
33
34
|
import random
|
@@ -83,8 +84,8 @@ def generate_sample_data(
|
|
83
84
|
profile: str = typer.Option("default", help="Profile Name – The MCM CLI configuration profile to use."),
|
84
85
|
):
|
85
86
|
"""
|
86
|
-
Generate sample impressions and
|
87
|
-
and click trackers to generate sample data in the platform.
|
87
|
+
Generate sample impressions, clicks, and purchase events. This command invokes the Decision APIs, and posts the impression
|
88
|
+
and click trackers to generate sample data in the platform. It also posts the purchase events to the User Event API.
|
88
89
|
"""
|
89
90
|
if warn:
|
90
91
|
typer.confirm("""⚠️ WARNING: This script is strictly for use on the TEST platform.⚠️
|
@@ -105,13 +106,15 @@ Please proceed only if you are certain.""", abort=True)
|
|
105
106
|
|
106
107
|
# Initialize DecisionCommand
|
107
108
|
d = mcmcli.command.decision.DecisionCommand(profile)
|
109
|
+
ue = mcmcli.command.userevent.UserEventCommand(profile)
|
108
110
|
|
109
111
|
print(f"Invoking the Decision API {num_iterations} times to generate sample impressions and clicks...", end='', flush=True)
|
110
112
|
thread, stopper = start_dot_printing()
|
111
113
|
|
112
114
|
for i in range(num_iterations):
|
115
|
+
user_id = f"user-{random.randint(100_000, 999_999)}"
|
113
116
|
# Call Decision API to get trackers
|
114
|
-
_, error, decided_items = d.decide_items(ad_inventory_id, search_query)
|
117
|
+
_, error, decided_items = d.decide_items(ad_inventory_id, user_id, search_query)
|
115
118
|
if error:
|
116
119
|
print_error(f"Error calling Decision API: {error.message}")
|
117
120
|
continue
|
@@ -136,6 +139,11 @@ Please proceed only if you are certain.""", abort=True)
|
|
136
139
|
requests.post(click_url)
|
137
140
|
except requests.RequestException as e:
|
138
141
|
print(f"[{i}] Failed to post imp tracker: {click_url} - Error: {e}")
|
142
|
+
|
143
|
+
# Send Purchase user event with 10% probability
|
144
|
+
if random.random() >= 0.9:
|
145
|
+
continue
|
146
|
+
ue.insert_purchase_event(user_id, item.auction_result.ad_account_id, item.item_id, to_curl=False)
|
139
147
|
|
140
148
|
print('.', end='', flush=True)
|
141
149
|
|
@@ -44,7 +44,9 @@ def decide_items(
|
|
44
44
|
"""
|
45
45
|
d = DecisionCommand(profile)
|
46
46
|
|
47
|
-
|
47
|
+
user_id = f"user-{random.randint(100_000, 999_999)}"
|
48
|
+
|
49
|
+
curl, error, ret = d.decide_items(inventory_id, user_id, search_query, num_items, items, location_filter, to_curl)
|
48
50
|
if to_curl:
|
49
51
|
print(curl)
|
50
52
|
return
|
@@ -141,6 +143,7 @@ class DecisionCommand:
|
|
141
143
|
def decide_items(
|
142
144
|
self,
|
143
145
|
inventory_id,
|
146
|
+
user_id,
|
144
147
|
search_query = None,
|
145
148
|
num_items = 5,
|
146
149
|
items = False,
|
@@ -159,10 +162,10 @@ class DecisionCommand:
|
|
159
162
|
"num_items": num_items
|
160
163
|
},
|
161
164
|
"user": {
|
162
|
-
"user_id":
|
165
|
+
"user_id": user_id
|
163
166
|
},
|
164
167
|
"device": {
|
165
|
-
"persistent_id":
|
168
|
+
"persistent_id": user_id
|
166
169
|
},
|
167
170
|
}
|
168
171
|
if items:
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright 2023 Moloco, Inc
|
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
|
+
from datetime import datetime, timezone
|
15
|
+
from mcmcli.data.error import Error
|
16
|
+
from mcmcli.requests import CurlString, api_request
|
17
|
+
from typing import Optional
|
18
|
+
|
19
|
+
UTC = timezone.utc
|
20
|
+
|
21
|
+
import mcmcli.command.config
|
22
|
+
import sys
|
23
|
+
import typer
|
24
|
+
|
25
|
+
app = typer.Typer(add_completion=False)
|
26
|
+
|
27
|
+
class UserEventCommand:
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
profile,
|
31
|
+
):
|
32
|
+
self.config = mcmcli.command.config.get_config(profile)
|
33
|
+
if (self.config is None):
|
34
|
+
print(f"ERROR: Failed to load the CLI profile", file=sys.stderr, flush=True)
|
35
|
+
sys.exit()
|
36
|
+
|
37
|
+
self.profile = profile
|
38
|
+
|
39
|
+
self.api_base_url = f"{self.config['event_api_hostname']}/rmp/event/v1/platforms/{self.config['platform_id']}/userevents"
|
40
|
+
self.headers = {
|
41
|
+
"accept": "application/json",
|
42
|
+
"content-type": "application/json",
|
43
|
+
"x-api-key": self.config['event_api_key']
|
44
|
+
}
|
45
|
+
|
46
|
+
def insert_purchase_event(
|
47
|
+
self,
|
48
|
+
user_id: str,
|
49
|
+
account_id: str,
|
50
|
+
item_id: str,
|
51
|
+
to_curl: bool,
|
52
|
+
) -> tuple[
|
53
|
+
Optional[CurlString],
|
54
|
+
Optional[Error],
|
55
|
+
]:
|
56
|
+
# Get current timestamp in milliseconds
|
57
|
+
timestamp_ms = int(datetime.now(timezone.utc).timestamp() * 1000)
|
58
|
+
_api_url = self.api_base_url
|
59
|
+
_payload = {
|
60
|
+
"id": f"event-{user_id}",
|
61
|
+
"timestamp":timestamp_ms,
|
62
|
+
"user_id": user_id,
|
63
|
+
"device": {
|
64
|
+
"persistent_id": user_id
|
65
|
+
},
|
66
|
+
"event_type": "PURCHASE",
|
67
|
+
"channel_type": "SITE",
|
68
|
+
"items": [
|
69
|
+
{
|
70
|
+
"id": item_id,
|
71
|
+
"quantity": 1,
|
72
|
+
"seller_id": account_id,
|
73
|
+
"price": {
|
74
|
+
"currency": "USD",
|
75
|
+
"amount": 100
|
76
|
+
}
|
77
|
+
}
|
78
|
+
],
|
79
|
+
"revenue": {
|
80
|
+
"currency": "USD",
|
81
|
+
"amount": 100
|
82
|
+
},
|
83
|
+
"shipping_charge": {
|
84
|
+
"currency": "USD",
|
85
|
+
"amount": 0
|
86
|
+
},
|
87
|
+
}
|
88
|
+
|
89
|
+
curl, error, json_obj = api_request('POST', to_curl, _api_url, self.headers, _payload)
|
90
|
+
if curl:
|
91
|
+
return curl, None
|
92
|
+
if error:
|
93
|
+
return None, error
|
94
|
+
|
95
|
+
return None, None
|
96
|
+
|
@@ -17,7 +17,7 @@ import threading
|
|
17
17
|
import time
|
18
18
|
import typer
|
19
19
|
|
20
|
-
def print_error(
|
20
|
+
def print_error(message, api_url="Unknown"):
|
21
21
|
# Something's wrong. Print error and exit.
|
22
22
|
|
23
23
|
_msg = typer.style(f"\nERROR: {message}", fg=typer.colors.RED, bold=True)
|
@@ -18,7 +18,7 @@ from setuptools import setup, find_packages
|
|
18
18
|
|
19
19
|
setup(
|
20
20
|
name='mcm-cli',
|
21
|
-
version='1.
|
21
|
+
version='1.8.0',
|
22
22
|
description='A command-line interface for Moloco Commerde Media',
|
23
23
|
long_description=open('README.md').read(),
|
24
24
|
long_description_content_type='text/markdown',
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# Copyright 2023 Moloco, Inc
|
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
|
-
def test_hello():
|
16
|
-
assert 1 == 1
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|