<jupyter_start><jupyter_text>Upgrade RuntimeThis cell ensures the runtime supports `asyncio` async/await, and is needed on Google Colab. If the runtime is upgraded, you will be prompted to restart it, which you should do before continuing execution.<jupyter_code>!pip install "ipython>=7"<jupyter_output><empty_output><jupyter_text>Set Up Environment  Import required libraries<jupyter_code>!pip install -q canopy
import canopy
import logging
import nest_asyncio

logging.basicConfig(level=logging.INFO)
nest_asyncio.apply()<jupyter_output><empty_output><jupyter_text>Authenticate<jupyter_code>authentication_data = canopy.prompt_for_authentication()
session = canopy.Session(authentication_data)<jupyter_output><empty_output><jupyter_text>Example: Encrypting config components  Encrypting arbitrary data

The API exposes endpoints for encrypting and decrypting any JSON structure.

We can access these endpoints using the OpenAPI generated wrappers in the Canopy Python library.

In the example below we encrypt some arbitrary data:<jupyter_code># Created the OpenAPI generated wrapper for the config APIs.
config_api = canopy.openapi.ConfigApi(session.async_client)

# Create some arbitrary data.
initial_data = { 'hello': 'world' }

# Encrypt the data using the API.
encrypted_data = await config_api.config_encrypt(initial_data)

print(f'Encrypted: {encrypted_data}')<jupyter_output>Encrypted: {'name': 'encrypted', 'metadata': 'jLFfe44JHJrf940B6LBjpwj5xI/LD3eCjtx90uGxgJj0zHN8PRNQkpKZhUNvuSdF7nnKqn9YXOb8xpn5c6JqdjrdAegC8i8r0eIEYpr6UtVNvYxwyk6RTabQZCqezR0y8Pxrxg6x72aLaAnXO8G9Zlp1xo9H7vthBo9Hxxl4BbCtt6IA2V3XI98GxxDlY8EWRgeVguiIxV9DE4/EcPJ6dA==', 'data': '4kMsTCxgbZFAPKFKRHWVA4tu0KtCztnnNxfezlrECdBvlfIn0s47sSNi+uC0I0A+'}<jupyter_text>We can then decrypt it:<jupyter_code>decrypted_data = await config_api.config_decrypt(encrypted_data)

print(f'Decrypted: {decrypted_data}')<jupyter_output>Decrypted: {'hello': 'world'}<jupyter_text>**Encrypted data can only be decrypted by users within the same Canopy tenant (users who enter the same "company" name when logging in to the Canopy platform).**

Users in other tenants can use the encrypted data in their configs, but cannot decrypt it themselves.

This makes it a secure way to share car components with other Canopy tenants for simulation, without them being able to see the parameters. We can also hide sensitive output channels when certain areas of the car are encrypted.  Encrypting part of a config

Only certain parts of a config can be encrypted, as the encrypted version must still conform to the schema. You can contact Canopy to discuss your encryption requirements.

In this example we will encrypt the electric motors of a car, which is an area that has already been enabled for encryption. First we will fetch a default car and output its `electricMotors` section.<jupyter_code>default_car = await canopy.load_default_config(session, 'car', 'Canopy F1 Car 2019')

print(default_car.data.powertrain.electric.electricMotors)<jupyter_output>[Munch({'name': 'ERSMotor', 'deployment': Munch({'name': 'eMotor with Constant Power', 'PMotorMax': 120000, 'eMotor': 0.95, 'PHarvestRegulatoryLimit': 120000}), 'torqueApplicationPosition': [Munch({'position': 'Rear crankshaft', 'rApplication': 1})], 'transmissionConnection': 'Primary', 'harvestIndependence': Munch({'name': 'Achieve Target Brake Balance'}), 'motorController': 'Rear axle', 'IMotor': 0, 'PPartThrottleHarvest': 30000, 'rPartThrottleChargeOn': 0.2, 'rPartThrottleChargeOff': 0.65, 'rElectricMotorPowerFactor': 1, 'PElectricMotorPowerOffset': 0, 'PMotorMeasurementPosition': 'Motor output shaft'})]<jupyter_text>Next we will encrypt the `electricMotors` section.<jupyter_code>encryption_result = await config_api.config_encrypt(default_car.data.powertrain.electric.electricMotors)

print(encryption_result)<jupyter_output>{'name': 'encrypted', 'metadata': 'Eoy8pF<KEY>', 'data': '<KEY>...]<jupyter_text>Next we will replace the `electricMotors` section of the car with the encrypted version and save the car to the platform.<jupyter_code>default_car.data.powertrain.electric.electricMotors = encryption_result

user_car_id = await canopy.create_config(
    session,
    'car',
    'Python Example - Car with encrypted electric motors',
    default_car.raw_data)

print(user_car_id)<jupyter_output>468842a9200542aaa21223817954a5f2<jupyter_text>And finally we will load the car again and output the `electricMotors` section, to show that it has been saved encrypted.<jupyter_code>user_car = await canopy.load_config(session, user_car_id)

print(user_car.data.powertrain.electric.electricMotors)<jupyter_output>Munch({'name': 'encrypted', 'metadata': '<KEY>', 'data': '<KEY>[...]
{'fraction_non_alphanumeric': 0.09058201058201058, 'fraction_numerical': 0.023915343915343914, 'mean_word_length': 7.424242424242424, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 36, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '42895', 'license': 'MIT', 'n_tokens_mistral': 1663, 'n_tokens_neox': 1533, 'n_words': 424, 'path': 'encrypting_config_components.ipynb', 'repo_name': 'CanopySimulations/canopy-python-examples', 'size': '6600'}