Last active
November 8, 2017 21:26
-
-
Save jo-migo/15ec6f33e6232097bba21936931ac5b6 to your computer and use it in GitHub Desktop.
Script to Generate a Generic Fullstack MVT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import os | |
import pprint | |
import requests | |
import sys | |
''' | |
DIRECTIONS: | |
- run `export ACCESS_TOKEN=<insert personal access token>` in the terminal (go to Profile > API Access to generate a PAT if you don't have one already) | |
- run setup_script.sh | |
- If you don't have trailmix installed, you have to run `sudo pip install -i https://localshop.dz.optimizely.com/simple/ --upgrade --ignore-installed trailmix` first!! | |
- Run this script woOooo `python generate_fullstack_mvt.py <project_id>` (where project_id is the ID of a new Python FullStack project) in the same terminal window you ran setup_script.sh in. | |
''' | |
def make_request(method, path, headers, data=None): | |
hrd_host = os.environ.get('HRD_HOST', 'https://app.optimizely.com') | |
req_url = '{}/api/v1/{}'.format(hrd_host, path) | |
response = requests.request(method=method, url=req_url, json=data, headers=headers, verify=False) | |
if response.ok: | |
return response.json() | |
print(response.reason) | |
print(response.text) | |
sys.exit(1) | |
project_id = sys.argv[1] | |
proxy_shared_secret = os.environ['PROXY_SHARED_SECRET'] | |
headers = {'Authorization': 'Bearer {}'.format(os.environ['ACCESS_TOKEN']), 'X-3scale-proxy-secret-token': proxy_shared_secret} | |
custom_event_data = { | |
"category": "other", | |
"description": "User clicks buy", | |
"name": "click_buy", | |
"api_name": "click_buy", | |
"project_id": project_id, | |
"config": {}, | |
"event_type": "custom" | |
} | |
custom_event = make_request('POST', 'projects/{}/events'.format(project_id), headers=headers, data=custom_event_data) | |
feature_flag_data = { | |
"description": "Shopping page optimization feature", | |
"variables": [ | |
{ | |
"default_value": "price", | |
"api_name": "sort_type", | |
"type": "string", | |
}, | |
{ | |
"default_value": "ascending", | |
"api_name": "sort_order", | |
"type": "string", | |
} | |
], | |
"api_name": "shopping_page", | |
"project_id": project_id, | |
} | |
feature_flag = make_request('POST', 'projects/{}/feature_flags'.format(project_id), headers=headers, data=feature_flag_data) | |
# Create layer with multivariate type and full-factorial policy | |
layer_formdata = { | |
'policy': 'multivariate', | |
'multivariate_traffic_policy': 'full_factorial', | |
'name': 'Test MVT Layer', | |
'project_id': project_id, | |
} | |
headers.update({'Content-Type': 'application/json'}) | |
mvt_layer = make_request('POST', 'projects/{}/layers'.format(project_id), headers=headers, data=layer_formdata) | |
experiment_formdata ={ | |
'layer_id': mvt_layer['id'], | |
'api_name': 'python_mvt', | |
"bucketing_strategy": "lifetime", | |
"status": "active", | |
"metrics": [{ | |
"event_type": "custom", | |
"event_id": int(custom_event['id']), | |
"aggregator": "unique", | |
"scope": "visitor", | |
"winning_direction": "increasing" | |
}], | |
'feature_flag_id': feature_flag['id'] | |
} | |
mvt_experiment = make_request('POST', 'projects/{}/layer_experiments'.format(project_id), headers=headers, data=experiment_formdata) | |
# Create group and add the MVT to it | |
group_formdata = { | |
"name": "Shopping Page Group", | |
"policy": "random", | |
"entities": [ | |
{ | |
"kind": "LayerExperiment", | |
"id": mvt_experiment['id'], | |
"weight": 5000, | |
"name": "python_mvt" | |
} | |
], | |
"project_id": project_id, | |
"description": "Exclusion group for shopping page experiments" | |
} | |
exp_group = make_request('POST', 'projects/{}/groups'.format(project_id), headers=headers, data=group_formdata) | |
# Get the feature variables on the feature flag | |
# For each, create a section with one variation (the variation will start with the feature variable and its default value) | |
sections = [] | |
for feature_variable in feature_flag['variables']: | |
print('Generating default section for variable {}'.format(feature_variable['api_name'])) | |
if feature_variable['api_name'] == 'sort_type': | |
section_formdata = { | |
'name': 'Sort Type', | |
'variable_id': feature_variable['id'], | |
'variations': [ | |
{ | |
'api_name': 'sort_by_category', | |
'weight': 5000, | |
'variable_value': 'category' | |
}, | |
{ | |
'api_name': 'sort_by_price', | |
'weight': 5000, | |
'variable_value': 'price' | |
} | |
] | |
} | |
else: | |
section_formdata = { | |
'name': 'Sort Order', | |
'variable_id': feature_variable['id'], | |
'variations': [ | |
{ | |
'api_name': 'sort_ascending', | |
'weight': 5000, | |
'variable_value': 'ascending' | |
}, | |
{ | |
'api_name': 'sort_descending', | |
'weight': 5000, | |
'variable_value': 'descending' | |
} | |
] | |
} | |
section = make_request('POST', 'layer_experiments/{}/experiment_sections'.format(mvt_experiment['id']), headers=headers, data=section_formdata) | |
sections.append(section) | |
mvt_update = {'section_ids': [section['id'] for section in sections], | |
'status': 'running', | |
'metrics': [{ | |
"event_type": "custom", | |
"event_id": int(custom_event['id']), | |
"aggregator": "unique", | |
"scope": "visitor", | |
"winning_direction": "increasing" | |
} | |
]} | |
updated_layer = make_request('PUT', 'layers/{}'.format(mvt_layer['id']), headers=headers, data=mvt_update) | |
ab_layer_formdata = { | |
"holdback": 0, | |
"policy": "single_experiment", | |
"project_id": project_id, | |
'metrics': [{ | |
"event_type": "custom", | |
"event_id": int(custom_event['id']), | |
"aggregator": "unique", | |
"scope": "visitor", | |
"winning_direction": "increasing" | |
}], | |
"name": "make_everything_free", | |
} | |
ab_layer = make_request('POST', 'projects/{}/layers'.format(project_id), headers=headers, data=ab_layer_formdata) | |
ab_experiment_formdata = { | |
"audience_name": "Everyone", | |
"project_id": project_id, | |
"bucketing_strategy": "lifetime", | |
"layer_id": ab_layer['id'], | |
"metrics": [{ | |
"event_type": "custom", | |
"event_id": int(custom_event['id']), | |
"aggregator": "unique", | |
"scope": "visitor", | |
"winning_direction": "increasing" | |
} | |
], | |
"key": "make_everything_free", | |
"variations": [ | |
{ | |
"status": "active", | |
"weight": 5000, | |
"api_name": "original_price", | |
}, | |
{ | |
"status": "active", | |
"weight": 5000, | |
"api_name": "free", | |
} | |
] | |
} | |
ab_experiment = make_request('POST', 'projects/{}/layer_experiments'.format(project_id), headers=headers, data=ab_experiment_formdata) | |
group_entities = { | |
'entities': [ | |
{ | |
"kind": "LayerExperiment", | |
"id": ab_experiment['id'], | |
"weight": 5000, | |
}, | |
{ | |
"kind": "LayerExperiment", | |
"id": mvt_experiment['id'], | |
"weight": 5000, | |
}] | |
} | |
exp_group = make_request('PUT', 'groups/{}'.format(exp_group['id']), headers=headers, data=group_entities) | |
variation_ids = [variation.get('variation_id') for variation in ab_experiment['variations']] | |
ab_experiment_data = { | |
'feature_flag_id': feature_flag['id'], | |
'variable_values': { | |
variation_ids[0]: {'1': 'price', '2': 'ascending'}, | |
variation_ids[1]: {'1': 'price', '2': 'ascending'} | |
} | |
} | |
ab_experiment = make_request('PUT', 'layer_experiments/{}'.format(ab_experiment['id']), headers=headers, data=ab_experiment_data) | |
layer_ids = [mvt_layer['id'], ab_layer['id']] | |
# Publish the layer | |
for layer_id in layer_ids: | |
layer_commit_formdata = { | |
'description': 'I dont know what im doing', | |
'name': '"Campaign published at November 7, 2017 sometime PM"' | |
} | |
layer_commit = make_request('POST', 'layers/{}/commits'.format(layer_id), headers=headers, data=layer_commit_formdata) | |
live_commit_tag_formdata = { | |
'active': True, | |
'commit_id': layer_commit['id'], | |
'project_id': project_id, | |
'tag_name': 'live', | |
'layer_id': layer_id | |
} | |
live_commit_tag = make_request('PUT', 'layers/{}/live'.format(layer_id), headers=headers, data=live_commit_tag_formdata) | |
print('\n MVT LAYER:') | |
pprint.pprint(updated_layer) | |
# Re-fetch sections to avoid race conditions in calculating variable_values | |
sections = make_request('GET', 'layer_experiments/{}/experiment_sections'.format(mvt_experiment['id']), headers=headers) | |
print('\n SECTIONS:') | |
pprint.pprint(sections) | |
mvt_experiment_with_combos = make_request('GET', 'layer_experiments/{}'.format(mvt_experiment['id']), headers=headers) | |
print('\n MVT EXPERIMENT:') | |
pprint.pprint(mvt_experiment_with_combos) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment