Skip to content

Commit aabd282

Browse files
Merge pull request #40 from glassflow/release/v2.1.0
Release/v2.1.0
2 parents 959d063 + cdc9035 commit aabd282

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1910
-2351
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ dist/
1212
build
1313
.env
1414
tests/reports
15-
.coverage
15+
.coverage
16+
.idea/

docs/reference.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
::: src.glassflow.client
22
::: src.glassflow.pipeline
33
::: src.glassflow.pipeline_data
4+
::: src.glassflow.secret
45
::: src.glassflow.space
56
::: src.glassflow.config
67
::: src.glassflow.models.errors
7-
::: src.glassflow.models.operations
8+
::: src.glassflow.models.responses

makefile

+12-10
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,7 @@ add-noqa: generate-api-data-models
99
echo "Add noqa comment ..."
1010
sed -i '' -e '1s/^/# ruff: noqa\n/' $(API_DATA_MODELS)
1111

12-
13-
add-dataclass-json-decorators: add-noqa
14-
echo "Import dataclass_json ..."
15-
sed -i '' -e '/^from __future__ import annotations/a\'$$'\n''from dataclasses_json import dataclass_json' $(API_DATA_MODELS)
16-
17-
18-
echo "Add dataclass_json decorators ..."
19-
sed -i '' -e '/@dataclass/ i\'$$'\n''@dataclass_json\''' $(API_DATA_MODELS)
20-
21-
generate: add-dataclass-json-decorators
12+
generate: add-noqa
2213

2314
include .env
2415
export
@@ -32,3 +23,14 @@ lint:
3223

3324
formatter:
3425
ruff format --check .
26+
27+
fix-format:
28+
ruff format .
29+
30+
fix-lint:
31+
ruff check --fix .
32+
33+
fix: fix-format fix-lint
34+
35+
serve-docs-locally:
36+
mkdocs serve

mkdocs.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ plugins:
4343
handlers:
4444
python:
4545
import:
46-
- url: https://docs.python-requests.org/en/master/objects.inv
46+
- url: https://docs.python.org/3/objects.inv # Add Python's objects.inv
47+
domains: [ std, py ]
48+
- url: https://docs.python-requests.org/en/master/objects.inv # Add requests objects.inv
49+
domains: [ std, py ]
50+
- url: https://docs.pydantic.dev/latest/objects.inv # Add Pydantic's objects.inv
4751
domains: [ std, py ]
4852
options:
4953
members_order: source

pyproject.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,12 @@ convention = "google"
4040
field-constraints = true
4141
snake-case-field = true
4242
strip-default-none = false
43-
target-python-version = "3.7"
43+
target-python-version = "3.8"
4444
use-title-as-name = true
4545
disable-timestamp = true
4646
enable-version-header = true
4747
use-double-quotes = true
4848
use-subclass-enum=true
49+
use-standard-collections=true
4950
input-file-type = "openapi"
50-
output-model-type = "dataclasses.dataclass"
51+
output-model-type = "pydantic_v2.BaseModel"

setup.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setuptools.setup(
1010
name="glassflow",
11-
version="2.0.8",
11+
version="2.1.0",
1212
author="glassflow",
1313
description="GlassFlow Python Client SDK",
1414
url="https://www.glassflow.dev/docs",
@@ -22,7 +22,7 @@
2222
"urllib3==1.26.15",
2323
"certifi>=2023.7.22",
2424
"charset-normalizer>=3.2.0",
25-
"dataclasses-json>=0.6.4",
25+
"pydantic>=2.10.6",
2626
"idna>=3.4",
2727
"jsonpath-python>=1.0.6 ",
2828
"marshmallow>=3.19.0",
@@ -34,19 +34,25 @@
3434
"typing-inspect>=0.9.0",
3535
"typing_extensions>=4.7.1",
3636
"python-dotenv==1.0.1",
37+
"eval_type_backport>=0.2.0",
3738
],
3839
extras_require={
3940
"dev": [
40-
"pylint==2.16.2",
41-
"pytest==8.3.2",
42-
"pytest-cov==5.0.0",
43-
"datamodel-code-generator[http]==0.26.0",
44-
"requests-mock==1.12.1",
45-
"isort==5.13.2",
46-
"ruff==0.6.3",
41+
"pylint>=2.16.2",
42+
"pytest>=8.3.2",
43+
"pytest-cov>=5.0.0",
44+
"datamodel-code-generator[http]>=0.27.0",
45+
"requests-mock>=1.12.1",
46+
"isort>=5.13.2",
47+
"ruff>=0.9.0",
4748
]
4849
},
4950
package_dir={"": "src"},
5051
python_requires=">=3.8",
5152
package_data={"glassflow": ["py.typed"]},
53+
entry_points={
54+
"console_scripts": [
55+
"glassflow = cli.cli:glassflow",
56+
],
57+
},
5258
)

src/cli/__init__.py

Whitespace-only changes.

src/cli/cli.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import click
2+
3+
from .commands import get_started
4+
5+
6+
@click.group()
7+
def glassflow():
8+
"""Glassflow CLI - Manage and control Glassflow SDK"""
9+
pass
10+
11+
12+
@click.command()
13+
@click.argument("command", required=False)
14+
def help(command):
15+
"""Displays help information about Glassflow CLI and its commands."""
16+
17+
commands = {
18+
"get-started": "Initialize Glassflow with an access token.\nUsage: "
19+
"glassflow get-started --token YOUR_TOKEN",
20+
"help": "Shows help information.\nUsage: glassflow help [command]",
21+
}
22+
23+
if command:
24+
if command in commands:
25+
click.echo(f"ℹ️ Help for `{command}`:\n{commands[command]}")
26+
else:
27+
click.echo(
28+
f"❌ Unknown command: `{command}`. Run `glassflow help` for a "
29+
f"list of commands."
30+
)
31+
else:
32+
click.echo("📖 Glassflow CLI Help:")
33+
for cmd, desc in commands.items():
34+
click.echo(f" ➜ {cmd}: {desc.splitlines()[0]}")
35+
click.echo("\nRun `glassflow help <command>` for more details.")
36+
37+
38+
# Add commands to CLI group
39+
glassflow.add_command(get_started)
40+
glassflow.add_command(help)
41+
42+
if __name__ == "__main__":
43+
glassflow()

src/cli/commands/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .get_started import get_started as get_started

src/cli/commands/get_started.py

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import os
2+
3+
import click
4+
from dotenv import load_dotenv
5+
6+
7+
@click.command()
8+
@click.option(
9+
"--personal-access-token", "-pat", default=None, help="Personal access token."
10+
)
11+
@click.option(
12+
"--env-file",
13+
"-e",
14+
default=".env",
15+
help="Path to the .env file (default: .env in current directory).",
16+
)
17+
def get_started(personal_access_token, env_file):
18+
"""Displays a welcome message and setup instructions."""
19+
20+
# Load token from .env if not provided in CLI
21+
if personal_access_token is None:
22+
if os.path.exists(env_file):
23+
load_dotenv(env_file) # Load environment variables
24+
personal_access_token = os.getenv("PERSONAL_ACCESS_TOKEN")
25+
else:
26+
click.echo("⚠️ No token provided and .env file not found!", err=True)
27+
return
28+
29+
if not personal_access_token:
30+
click.echo("❌ Error: Personal access token is required.", err=True)
31+
return
32+
33+
click.echo("🚀 Welcome to Glassflow! \n")
34+
click.echo(
35+
f"🔑 Using Personal Access Token: {personal_access_token[:4]}... "
36+
f"(hidden for security)"
37+
)
38+
click.echo("\n📝 In this getting started guide, we will do the following:")
39+
click.echo("1. Define a data transformation function in Python.\n")
40+
click.echo("2. Create a pipeline with the function.\n")
41+
click.echo("3. Send events to the pipeline.\n")
42+
click.echo("4. Consume transformed events in real-time from the pipeline\n")
43+
click.echo("5. Monitor the pipeline and view logs.\n")
44+
45+
filename = create_transformation_function()
46+
pipeline = create_space_pipeline(personal_access_token, filename)
47+
send_consume_events(pipeline)
48+
49+
click.echo(
50+
"\n🎉 Congratulations! You have successfully created a pipeline and sent"
51+
" events to it.\n"
52+
)
53+
click.echo(
54+
"💻 View the logs and monitor the Pipeline in the "
55+
f"Glassflow Web App at https://app.glassflow.dev/pipelines/{pipeline.id}"
56+
)
57+
58+
59+
def create_transformation_function(filename="transform_getting_started.py"):
60+
file_content = """import json
61+
import logging
62+
63+
def handler(data: dict, log: logging.Logger):
64+
log.info("Echo: " + json.dumps(data))
65+
data['transformed_by'] = "glassflow"
66+
67+
return data
68+
"""
69+
with open(filename, "w") as f:
70+
f.write(file_content)
71+
click.echo(f"✅ Transformation function created in {filename}")
72+
click.echo("The transformation function is:\n")
73+
click.echo(file_content)
74+
click.echo("📝 You can modify the transformation function in the file.")
75+
return filename
76+
77+
78+
def create_space_pipeline(personal_access_token, transform_filename):
79+
import glassflow
80+
81+
# create glassflow client to interact with GlassFlow
82+
client = glassflow.GlassFlowClient(personal_access_token=personal_access_token)
83+
example_space = client.create_space(name="getting-started")
84+
pipeline = client.create_pipeline(
85+
name="getting-started-pipeline",
86+
transformation_file=transform_filename,
87+
space_id=example_space.id,
88+
)
89+
click.echo(f"✅ Created a pipeline with pipeline_id {pipeline.id}")
90+
return pipeline
91+
92+
93+
def send_consume_events(pipeline):
94+
click.echo("🔄 Sending some generated events to pipeline .....")
95+
data_source = pipeline.get_source()
96+
for i in range(10):
97+
event = {"data": f"hello GF {i}"}
98+
res = data_source.publish(event)
99+
if res.status_code == 200:
100+
click.echo(f"Sent event: {event}")
101+
102+
click.echo("📡 Consuming transformed events from the pipeline")
103+
data_sink = pipeline.get_sink()
104+
for _ in range(10):
105+
resp = data_sink.consume()
106+
if resp.status_code == 200:
107+
click.echo(f"Consumed event: {resp.event()} ")

src/glassflow/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from .client import GlassFlowClient as GlassFlowClient
22
from .config import GlassFlowConfig as GlassFlowConfig
3+
from .models import api as internal # noqa: F401
34
from .models import errors as errors
5+
from .models import responses as responses
46
from .pipeline import Pipeline as Pipeline
57
from .pipeline_data import PipelineDataSink as PipelineDataSink
68
from .pipeline_data import PipelineDataSource as PipelineDataSource
9+
from .secret import Secret as Secret
710
from .space import Space as Space

0 commit comments

Comments
 (0)