Esempio n. 1
0
def validate(recipe, no_input):
    # query for fields if they exist
    fields = json_get_fields(recipe)

    # parse fields and constants into parameters
    if fields:
        if no_input:
            raise NameError(
                'Edit the recipie and convert these fields into values:\n  - %s\n'
                % ' \n  - '.join('%s: %s' % (f['name'], f['description'])
                                 for f in fields))
        else:
            parameters = prompt(fields)
            json_set_fields(recipe, parameters)
Esempio n. 2
0
def generate_include(script_file):
    script = get_recipe(script_file)

    # parse fields and constants into parameters
    print('    { "include":{')
    print('      "script":"%s",' % script_file)
    print('      "parameters":{')
    print(',\n'.join([
        '        "%s":{"field":{ "name":"%s", "kind":"%s", "description":"%s" }}'
        % (field['name'], field['name'], field['kind'],
           field.get('description', '')) for field in json_get_fields(script)
    ]))
    print('      }')
    print('    }}')
    print('')
Esempio n. 3
0
 def __init__(self, sequence, script, values, *args, **kwargs):
     self.script = script
     self.values = values
     super(ScriptJsonForm, self).__init__(*args, **kwargs)
     self.fields['script_sequence'].initial = sequence
     x = script.get_tag()
     self.variables = json_get_fields(script.get_tasks())
     for variable in self.variables:
         if variable['name'].startswith('recipe_'):
             continue  # skip inputs that come from recipe constants
         self.fields[variable['name']] = get_field_kind(variable)
         self.fields[variable['name']].initial = values.get(
             variable['name'],
             variable.get('value', variable.get('default', '')))
         self.fields[variable['name']].required = variable.get(
             'required', False)
         self.fields[variable['name']].help_text = variable.get(
             'description', '')
Esempio n. 4
0
def script_to_dag(dag_name,
                  title,
                  description,
                  instructions,
                  script,
                  parameters={}):
  return AIRFLOW_TEMPLATE.format(**{
    'title':title,
    'description':description,
    'instructions':'  - ' + '\n  - '.join(instructions),
    'inputs':fields_to_string(
      json_get_fields(script),
      parameters
    ),
    'recipe':dict_to_string(
      script,
      skip=('fields',)
    ),
    'dag':dag_name
  })
Esempio n. 5
0
def configure_tests(tests, runs, skips, test_run_id):
    """Initialize the starthinker_assets/tests.json variable harness.

  Read all existing tests from tests/scripts/*.json and create a dictionary of
  each script and fields.  Save that dictionary to a test harness file where
  developer can configure tests.

  Then read the test harness and create recipe files to that can be run.  Write
  those files to tests/recipes/*.json for execution in a later step.

  Args:
    test: List of (filename, json) pairs containing all the tests.
    runs: List of test names that will be run, all will run if blank.
    skips: List of tests to skip.
    test_run_id: String added as a field to each test, used for namespacing.

  Returns:
    List of JSON recpies, where all fields have values from the test harness.

  """

    # Get old fields from the config file

    print('UPDATE CONFIG')

    old_fields = {}
    if os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, 'r') as f:
            old_fields = json.load(f)

    # Get new fields from test files and merge in old values
    fields = {}
    for filename, script in tests:
        script_fields = json_get_fields(script)
        script_name = filename.split('.')[0]

        fields.setdefault(script_name, {})
        for field in script_fields:
            if field['name'] == 'test_run_id': continue
            fields[script_name][field['name']] = old_fields.get(
                script_name, {}).get(field['name'], field.get('default', ''))
            fields[script_name][
                '%s_description' % field['name']] = '(%s) %s' % (field.get(
                    'kind',
                    'string'), field.get('description', 'No description.'))

            if field['name'] not in old_fields.get(script_name, {}):
                print('NEW FIELD ADDED', script_name, field['name'])

    # Save field values to config file

    if fields:
        f = open(CONFIG_FILE, 'w')
        f.write(json.dumps(fields, sort_keys=True, indent=2))
        f.close()
    else:
        print('WARNING CONFIGURATION IS EMPTY, CHECK YOUR PATHS!')

    # Inject the test run ID to the list of field values that were read from the
    # test config file. This is done in memory only, so that concrete test run
    # value are replaced every time a test runs.
    if test_run_id:
        for script in fields:
            fields[script]['test_run_id'] = test_run_id

    # Create recipe directory
    print('GENERATE RECIPES')
    os.makedirs(RECIPE_DIRECTORY, exist_ok=True)

    # Create recipes from tests

    recipes = []
    for filename, script in tests:
        name = filename.split('.')[0]
        if runs and name not in runs:
            continue
        if name in skips:
            continue

        # Set config field values into the script
        json_set_fields(script, fields.get(name, {}))

        # Expand all includes to full recipe
        try:
            json_expand_includes(script)

            with open(RECIPE_DIRECTORY + filename, 'w') as f:
                f.write(json.dumps(script, sort_keys=True, indent=2))

            recipes.append(filename)
        except FileNotFoundError as e:
            print('MISSING INLCLUDE')
            print(' - TEST: tests/scripts/%s' % filename)
            print(' - INCLUDE: ', str(e))

    # Create log directory and clear old logs

    os.makedirs(LOG_DIRECTORY, exist_ok=True)

    # Display instructions

    print('')
    print('------')
    print('------------')
    print('------------------------')
    print(
        'Some tests require custom values. Update the necessary fields for the tests you wish to run.'
    )
    print('EDIT: ' + CONFIG_FILE)
    print('------------------------')
    print(
        'Some tests require external assets.  Join the following group to gain access.'
    )
    print('VISIT: https://groups.google.com/forum/#!forum/starthinker-assets')
    print('------------------------')
    print('------------')
    print('------')
    print('')
    sleep(3)

    return recipes
Esempio n. 6
0
def recipe_to_colab(name, description, instructions, tasks, parameters={}, project=None, client_credentials=None, user_credentials=None, service_credentials=None):
  """ Converts a JSON recipe into a Jupyter Notebook for Colabs.

  Sets up multiple steps to execute recipe:
    1. Install starthinker from repository
    2. Get Cloud Project ID.
    3. Get Client Credentials ( optional if User Credentials exist ).
    4. Enter Recipe parameters if fields present.
    5. Execute recipe tasks.

  Args:
    * name: (string) The name of the notebook.
    * description: (string) A description fo the recipe.
    * instructions: (string) Recipe manual instructions, for example connecting datastudios.
    * tasks: (list) The task JSON to execute.
    * parameters: (dict) Values for field parameters in tasks, optional.
    * project: (string) The GCP project id.
    * client_credentials: (string) The GCP Desktop Client Credentials in JSON string.
    * user_credentials: (string) Not used, placeholder.
    * service_credentials: (string) Not used, placeholder.

  Returns:
    * (string) Rendered notebook source code to be written to a ipynb file.
  """

  colab = Colab(name)

  colab.header('1. Install Dependencies')
  colab.paragraph(
      'First install the libraries needed to execute recipes, this only needs to be done once, then click play.'
  )
  colab.code('!pip install git+https://github.com/google/starthinker')

  colab.header('2. Get Cloud Project ID')
  colab.paragraph(
      'To run this recipe [requires a Google Cloud Project](https://github.com/google/starthinker/blob/master/tutorials/cloud_project.md), this only needs to be done once, then click play.'
  )
  #colab.image('Client Project ID', 'https://github.com/google/starthinker/raw/master/tutorials/images/cloud_project.png')
  colab.code('CLOUD_PROJECT = \'%s\'' % (project or 'PASTE PROJECT ID HERE'))
  colab.code('\nprint("Cloud Project Set To: %s" % CLOUD_PROJECT)')

  colab.header('3. Get Client Credentials')
  #colab.image('Client Credentials', 'https://github.com/google/starthinker/raw/master/tutorials/images/cloud_client_installed.png')
  colab.paragraph(
      'To read and write to various endpoints requires [downloading client credentials](https://github.com/google/starthinker/blob/master/tutorials/cloud_client_installed.md), this only needs to be done once, then click play.'
  )
  colab.code('CLIENT_CREDENTIALS = \'%s\'' % (client_credentials or 'PASTE CLIENT CREDENTIALS HERE'))
  colab.code('\nprint("Client Credentials Set To: %s" % CLIENT_CREDENTIALS)')

  fields = json_get_fields(tasks)
  if fields:
    colab.header('4. Enter %s Parameters' % name)
    colab.paragraph(description)
    colab.list(instructions)
    colab.paragraph(
        'Modify the values below for your use case, can be done multiple times, then click play.'
    )
    colab.code('FIELDS = %s' % fields_to_string(fields, parameters))
    colab.code('\nprint("Parameters Set To: %s" % FIELDS)')

  colab.header('%d. Execute %s' % (5 if fields else 4, name))
  colab.paragraph(
      'This does NOT need to be modified unless you are changing the recipe, click play.'
  )

  colab.code('from starthinker.util.configuration import Configuration')
  colab.code('from starthinker.util.configuration import execute')
  colab.code('from starthinker.util.recipe import json_set_fields')
  colab.code('')
  colab.code("USER_CREDENTIALS = '/content/user.json'")
  colab.code('')
  colab.code('TASKS = %s' %
             dict_to_string(json_set_auths(tasks, 'user'), skip=('field',)))
  colab.code('')

  if fields:
    colab.code('json_set_fields(TASKS, FIELDS)')
  colab.code('')

  colab.code('execute(Configuration(project=CLOUD_PROJECT, client=CLIENT_CREDENTIALS, user=USER_CREDENTIALS, verbose=True), TASKS, force=True)')

  return colab.render()