Skip to content

Commit ff243ca

Browse files
author
Matthew Elwell
authored
Feature/rewrite for client side eval (#17)
* Update setup.py * Add publish workflow * Add test workflow * Rewrite basic python client functionality * Add analytics processor logic * Add some docstrings and util function * Move to poetry for dependency management and builds * Formatting * Remove duplicate triggers for pytest workflow * Fix pipeline * Only include flagsmith package * Update example app * Add some todos * Change default refresh interval * Add ability to enable / disable analytics * Add defaults * Typehinting updates * Update example app to use defaults * Tidy up example app * Tidy up type hint * Fix environment document url
1 parent ba6535c commit ff243ca

36 files changed

+1622
-521
lines changed

.flake8

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[flake8]
2+
max-line-length = 120
3+
max-complexity = 10
4+
exclude = .git,__pycache__,.venv

.github/workflows/publish.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Publish Pypi Package
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
jobs:
9+
package:
10+
runs-on: ubuntu-latest
11+
name: Publish Pypi Package
12+
13+
steps:
14+
- name: Cloning repo
15+
uses: actions/checkout@v2
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Build and publish to pypi
20+
uses: JRubics/poetry-publish@v1.10
21+
with:
22+
pypi_token: ${{ secrets.PYPI_API_TOKEN }}
23+
ignore_dev_requirements: "yes"
24+
build_format: "sdist"

.github/workflows/pytest.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
name: Pytest and Black formatting
1+
name: Formatting and Tests
22

33
on:
44
- pull_request
5-
- push
65

76
jobs:
87
test:
@@ -12,7 +11,7 @@ jobs:
1211
strategy:
1312
max-parallel: 4
1413
matrix:
15-
python-version: [3.6, 3.7, 3.8, 3.9]
14+
python-version: ["3.7", "3.8", "3.9", "3.10"]
1615

1716
steps:
1817
- name: Cloning repo
@@ -28,11 +27,14 @@ jobs:
2827
- name: Install Dependencies
2928
run: |
3029
python -m pip install --upgrade pip
31-
pip install -r requirements-dev.txt
30+
pip install poetry
31+
poetry install
3232
3333
- name: Check Formatting
34-
run: black --check .
34+
run: |
35+
poetry run black --check .
36+
poetry run flake8 .
37+
poetry run isort --check .
3538
3639
- name: Run Tests
37-
run: |
38-
pytest
40+
run: poetry run pytest

example/.env.template

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FLASK_APP=app
2+
FLAGSMITH_ENVIRONMENT_KEY=<your key>

example/app.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import json
2+
import os
3+
4+
from flask import Flask, render_template, request
5+
6+
from flagsmith import Flagsmith
7+
from flagsmith.models import DefaultFlag
8+
9+
app = Flask(__name__)
10+
11+
flagsmith = Flagsmith(
12+
environment_key=os.environ.get("FLAGSMITH_ENVIRONMENT_KEY"),
13+
defaults=[
14+
# Set a default flag which will be used if the "secret_button"
15+
# feature is not returned by the API
16+
DefaultFlag(
17+
enabled=False,
18+
value=json.dumps({"colour": "#b8b8b8"}),
19+
feature_name="secret_button",
20+
)
21+
],
22+
)
23+
24+
25+
@app.route("/", methods=["GET", "POST"])
26+
def home():
27+
if request.args:
28+
identifier = request.args["identifier"]
29+
30+
trait_key = request.args.get("trait-key")
31+
trait_value = request.args.get("trait-value")
32+
traits = {trait_key: trait_value} if trait_key else None
33+
34+
# Get the flags for an identity, including the provided trait which will be
35+
# persisted to the API for future requests.
36+
identity_flags = flagsmith.get_identity_flags(
37+
identifier=identifier, traits=traits
38+
)
39+
show_button = identity_flags.is_feature_enabled("secret_button")
40+
button_data = json.loads(identity_flags.get_feature_value("secret_button"))
41+
return render_template(
42+
"home.html",
43+
show_button=show_button,
44+
button_colour=button_data["colour"],
45+
identifier=identifier,
46+
)
47+
48+
# Get the default flags for the current environment
49+
flags = flagsmith.get_environment_flags()
50+
show_button = flags.is_feature_enabled("secret_button")
51+
button_data = json.loads(flags.get_feature_value("secret_button"))
52+
53+
return render_template(
54+
"home.html", show_button=show_button, button_colour=button_data["colour"]
55+
)

example/example.py

Lines changed: 0 additions & 58 deletions
This file was deleted.

example/readme.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
# Flagsmith Basic Python Example
22

3-
To use this basic example, you'll need to first configure a project with at least one feature in Flagsmith.
3+
This directory contains a basic Flask application which utilises Flagsmith. To run the example application, you'll
4+
need to go through the following steps:
45

5-
Once you've done this, you'll then need to install the latest version of the Flagsmith package by running:
6+
1. Create an account, organisation and project on [Flagsmith](https://flagsmith.com)
7+
2. Create a feature in the project called "secret_button"
8+
3. Give the feature a value using the json editor as follows:
69

7-
```bash
8-
pip install flagsmith
10+
```json
11+
{"colour": "#ababab"}
912
```
1013

11-
Then you can run:
14+
4. Create a .env file from the template located in this directory with the environment key of one of the environments
15+
in flagsmith (This can be found on the 'settings' page accessed from the menu on the left under the chosen environment.)
16+
5. From a terminal window, export those environment variables (either manually or by using `export $(cat .env)`)
17+
6. Run the app using `flask run`
18+
7. Browse to http://localhost:5000
1219

13-
```bash
14-
python example.py
15-
```
16-
17-
The script will grab some information from you such as the environment key to test with, an identifier and a feature
18-
name. Once you've inputted those, the script will run you through all of the methods available in the Flagsmith
19-
client and print the result.
20+
Now you can play around with the 'secret_button' feature in flagsmith, turn it on to show it and edit the colour in the
21+
json value to edit the colour of the button. You can also identify as a given user and then update the settings for the
22+
secret button feature for that user in the flagsmith interface to see the affect that has too.

example/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
flask==2.0.2
2+
flagsmith>=3.0.0

example/templates/home.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!doctype html>
2+
<head>
3+
<style></style>
4+
</head>
5+
<title>Flagsmith Example</title>
6+
<body>
7+
<p>Hello, {{ identifier or 'World' }}.</p>
8+
{% if show_button %}
9+
<button style="background-color: {{ button_colour }}">A secret button</button>
10+
{% endif %}
11+
12+
<p></p>
13+
14+
<form action="/" method="GET">
15+
<h3>Identify as a user</h3>
16+
<label for="identifier">Identifier: </label><input name="identifier" id="identifier"><br>
17+
18+
<p>... with an optional user trait</p>
19+
<label for="trait-key">Trait key: </label><input name="trait-key" id="trait-key"><br>
20+
<label for="trait-value">Trait value: </label><input name="trait-value" id="trait-value"><br><br>
21+
22+
<button type="submit">Identify!</button>
23+
</form>
24+
25+
</body>

flagsmith/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from .flagsmith import Flagsmith
1+
from .flagsmith import Flagsmith # noqa

0 commit comments

Comments
 (0)