Metadata-Version: 2.1
Name: growthbook
Version: 0.3.0
Summary: Powerful Feature flagging and A/B testing for Python apps
Home-page: https://github.com/growthbook/growthbook-python
Author: GrowthBook
Author-email: hello@growthbook.io
License: MIT
Description: # GrowthBook Python SDK
        
        Powerful Feature flagging and A/B testing for Python apps.
        
        ![Build Status](https://github.com/growthbook/growthbook-python/workflows/Build/badge.svg)
        
        -  **No external dependencies**
        -  **Lightweight and fast**
        -  **No HTTP requests** everything is defined and evaluated locally
        -  Python 3.6+
        -  100% test coverage
        -  Flexible **targeting**
        -  **Use your existing event tracking** (GA, Segment, Mixpanel, custom)
        -  **Remote configuration** to change feature flags without deploying new code
        
        ## Installation
        
        `pip install growthbook` (recommended) or copy `growthbook.py` into your project
        
        ## Quick Usage
        
        ```python
        import requests
        from growthbook import GrowthBook
        
        
        # We recommend using a db or cache layer in production
        apiResp = requests.get("https://cdn.growthbook.io/api/features/MY_API_KEY")
        features = apiResp.json()["features"]
        
        # User attributes for targeting and experimentation
        attributes = {
          "id": "123",
          "customUserAttribute": "foo"
        }
        
        def on_experiment_viewed(experiment, result):
          # Use whatever event tracking system you want
          analytics.track(attributes["id"], "Experiment Viewed", {
            'experimentId': experiment.key,
            'variationId': result.variationId
          })
        
        # Create a GrowthBook instance
        gb = GrowthBook(
          attributes = attributes,
          features = features,
          trackingCallback = on_experiment_viewed
        )
        
        # Simple on/off feature gating
        if gb.isOn("my-feature"):
          print("My feature is on!")
        
        # Get the value of a feature with a fallback
        color = gb.getFeatureValue("button-color-feature", "blue")
        ```
        
        ## GrowthBook class
        
        The GrowthBook constructor has the following parameters:
        
        -  **enabled** (`bool`) - Flag to globally disable all experiments. Default true.
        -  **attributes** (`dict`) - Dictionary of user attributes that are used for targeting and to assign variations
        -  **url** (`str`) - The URL of the current request (if applicable)
        -  **features** (`dict`) - Feature definitions from the GrowthBook API
        -  **forcedVariations** (`dict`) - Dictionary of forced experiment variations (used for QA)
        -  **qaMode** (`boolean`) - If true, random assignment is disabled and only explicitly forced variations are used.
        -  **trackingCallback** (`callable`) - A function that takes `experiment` and `result` as arguments.
        
        There are also getter and setter methods for features and attributes if you need to update them later in the request:
        
        ```python
        gb.setFeatures(gb.getFeatures())
        gb.setAttributes(gb.getAttributes())
        ```
        
        ### Features
        
        Defines all of the available features plus rules for how to assign values to users. Features are usually fetched from the GrowthBook API and persisted in cache or a database in production.
        
        Feature definitions are defined in a JSON format. You can fetch them directly from the GrowthBook API:
        
        ```python
        import requests
        
        apiResp = requests.get("https://cdn.growthbook.io/api/features/MY_API_KEY")
        features = apiResp.json()["features"]
        ```
        
        Or, you can use a copy stored in your database or cache server instead:
        
        ```python
        import json
        
        json_string = '{"feature-1":{...},"feature-2":{...},...}'
        features = json.loads(json_string)
        ```
        
        We recommend using the db/cache approach for production.
        
        ### Attributes
        
        You can specify attributes about the current user and request. These are used for two things:
        
        1.  Feature targeting (e.g. paid users get one value, free users get another)
        2.  Assigning persistent variations in A/B tests (e.g. user id "123" always gets variation B)
        
        Attributes can be any JSON data type - boolean, integer, float, string, list, or dict.
        
        ```python
        attributes = {
          'id': "123",
          'loggedIn': True,
          'age': 21.5,
          'tags': ["tag1", "tag2"],
          'account': {
            'age': 90
          ]
        }
        ```
        
        ### Tracking Experiments
        
        Any time an experiment is run to determine the value of a feature, you want to track that event in your analytics system.
        
        You can use the `trackingCallback` option to do this:
        
        ```python
        from growthbook import GrowthBook, Experiment, Result
        
        def on_experiment_viewed(experiment: Experiment, result: Result):
          # Use whatever event tracking system you want
          analytics.track(attributes["id"], "Experiment Viewed", {
            'experimentId': experiment.key,
            'variationId': result.variationId
          })
        
        gb = GrowthBook(
          trackingCallback = on_experiment_viewed
        )
        ```
        
        ## Using Features
        
        There are 3 main methods for interacting with features.
        
        - `gb.isOn("feature-key")` returns true if the feature is on
        - `gb.isOff("feature-key")` returns false if the feature is on
        - `gb.getFeatureValue("feature-key", "default")` returns the value of the feature with a fallback
        
        
        In addition, you can use `gb.evalFeature("feature-key")` to get back a `FeatureResult` object with the following properties:
        
        - **value** - The JSON-decoded value of the feature (or `null` if not defined)
        - **on** and **off** - The JSON-decoded value cast to booleans
        - **source** - Why the value was assigned to the user. One of `unknownFeature`, `defaultValue`, `force`, or `experiment`
        - **experiment** - Information about the experiment (if any) which was used to assign the value to the user
        - **experimentResult** - The result of the experiment (if any) which was used to assign the value to the user
        
        
        ## Inline Experiments
        
        Instead of declaring all features up-front and referencing them by ids in your code, you can also just run an experiment directly. This is done with the `gb->run` method:
        
        ```python
        from growthbook import Experiment
        
        exp = Experiment(
          key = "my-experiment", 
          variations = ["red", "blue", "green"]
        )
        
        # Either "red", "blue", or "green"
        print(gb.run(exp).value)
        ```
        
        As you can see, there are 2 required parameters for experiments, a string key, and an array of variations.  Variations can be any data type, not just strings.
        
        There are a number of additional settings to control the experiment behavior:
        
        -  **key** (`str`) - The globally unique tracking key for the experiment
        -  **variations** (`any[]`) - The different variations to choose between
        -  **weights** (`float[]`) - How to weight traffic between variations. Must add to 1.
        -  **coverage** (`float`) - What percent of users should be included in the experiment (between 0 and 1, inclusive)
        - **condition** (`dict`) - Targeting conditions
        -  **force** (`int`) - All users included in the experiment will be forced into the specified variation index
        -  **hashAttribute** (`string`) - What user attribute should be used to assign variations (defaults to "id")
        -  **namespace** (`tuple[str,float,float]`) - Used to run mutually exclusive experiments.
        
        Here's an example that uses all of them:
        
        ```python
        exp = Experiment(
          key="my-test",
          # Variations can be a list of any data type
          variations=[0, 1],
          # Run a 40/60 experiment instead of the default even split (50/50)
          weights=[0.4, 0.6],
          # Only include 20% of users in the experiment
          coverage=0.2,
          # Targeting condition using a MongoDB-like syntax
          condition={
            'country': 'US',
            'browser': {
              '$in': ['chrome', 'firefox']
            }
          },
          # Use an alternate attribute for assigning variations (default is 'id')
          hashAttribute="sessionId",
          # Includes the first 50% of users in the "pricing" namespace
          # Another experiment with a non-overlapping range will be mutually exclusive (e.g. [0.5, 1])
          namespace=("pricing", 0, 0.5),
        )
        ```
        
        ### Inline Experiment Return Value
        
        A call to `run` returns a `Result` object with a few useful properties:
        
        ```python
        result = gb.run(exp)
        
        # If user is part of the experiment
        print(result.inExperiment) # True or False
        
        # The index of the assigned variation
        print(result.variationId) # e.g. 0 or 1
        
        # The value of the assigned variation
        print(result.value) # e.g. "A" or "B"
        
        # If the variation was randomly assigned by hashing user attributes
        print(result.hashUsed) # True or False
        
        # The user attribute used to assign a variation
        print(result.hashAttribute) # "id"
        
        # The value of that attribute
        print(result.hashValue) # e.g. "123"
        ```
        
        The `inExperiment` flag will be false if the user was excluded from being part of the experiment for any reason (e.g. failed targeting conditions).
        
        The `hashUsed` flag will only be true if the user was randomly assigned a variation. If the user was forced into a specific variation instead, this flag will be false.
        
        ### Example Experiments
        
        3-way experiment with uneven variation weights:
        ```python
        gb.run(Experiment(
          key = "3-way-uneven",
          variations = ["A","B","C"],
          weights = [0.5, 0.25, 0.25]
        ))
        ```
        
        Slow rollout (10% of users who match the targeting condition):
        ```python
        # User is marked as being in "qa" and "beta"
        gb = GrowthBook(
          attributes = {
            "id": "123",
            "beta": True,
            "qa": True,
          },
        )
        
        gb.run(Experiment(
          key = "slow-rollout",
          variations = ["A", "B"],
          coverage = 0.1,
          condition = {
            'beta': True
          }
        ))
        ```
        
        Complex variations
        ```python
        result = gb.run(Experiment(
          key = "complex-variations",
          variations = [
            ("blue", "large"),
            ("green", "small")
          ],
        ))
        
        # Either "blue,large" OR "green,small"
        print(result.value[0] + "," + result.value[1])
        ```
        
        Assign variations based on something other than user id
        ```python
        gb = GrowthBook(
          attributes = {
            "id": "123",
            "company": "growthbook"
          }
        )
        
        # Users in the same company will always get the same variation
        gb.run(Experiment(
          key = "by-company-id",
          variations = ["A", "B"],
          hashAttribute = "company"
        ))
        ```
        
        ### Django
        
        For Django (and other web frameworks), we recommend adding a simple middleware where you instantiate the GrowthBook object
        
        ```python
        from growthbook import GrowthBook
        
        def growthbook_middleware(get_response):
            def middleware(request):
                request.gb = GrowthBook(
                  # ...
                )
                response = get_response(request)
        
                request.gb.destroy() # Cleanup
        
                return response
            return middleware
        ```
        
        Then, you can easily evaluate a feature (or run an inline experiment) in any of your views:
        
        ```python
        def index(request):
            featureEnabled = request.gb.isOn("my-feature")
            # ...
        ```
Keywords: growthbook
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.6
Description-Content-Type: text/markdown
