Skip to content

Instantly share code, notes, and snippets.

@jo-migo
Last active November 8, 2017 21:26
Show Gist options
  • Save jo-migo/15ec6f33e6232097bba21936931ac5b6 to your computer and use it in GitHub Desktop.
Save jo-migo/15ec6f33e6232097bba21936931ac5b6 to your computer and use it in GitHub Desktop.
Script to Generate a Generic Fullstack MVT
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