Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a7635c8
cya later yucky stuff.
chestm007 Mar 3, 2026
b0c9414
license date, some tests, much tidy
chestm007 Mar 3, 2026
e8bc2ea
eas_client docstrings not updated
chestm007 Mar 3, 2026
2a8cb71
I guess returning fields would be ideal
chestm007 Mar 4, 2026
99b79b0
do you think we should put the fields in the right spot?
chestm007 Mar 4, 2026
b22ad10
add some decorators, and integration tests
chestm007 Mar 4, 2026
73ea959
update readme, make constructing objects not suck by importing the ge…
chestm007 Mar 4, 2026
6262507
allowing args for the client is asking for breaking changes.
chestm007 Mar 4, 2026
77e1173
do some docs
chestm007 Mar 10, 2026
75e8699
narrow import path for some statements
chestm007 Mar 10, 2026
4dfdf65
pass kwargs to client.
chestm007 Mar 10, 2026
c412aaa
remove unnessecary param
chestm007 Mar 16, 2026
572e4b1
convenience method for all fields, opt in for legacy methods, other s…
chestm007 Mar 20, 2026
2c5f7e1
add docs, update pyproject
chestm007 Mar 20, 2026
f1eed7c
switch to actual git release version for ariadne-codegen
chestm007 Mar 23, 2026
bd0c49d
simplify code, fix imports, create stub to show lazy added method
chestm007 Mar 26, 2026
98f64da
Added details on installing code gen for non python people.
charlta Mar 30, 2026
7118afa
Added missing licence headers.
charlta Mar 30, 2026
3cdd4b6
Fixed duplicate licence headers.
charlta Mar 30, 2026
e809895
Added missing deprecation warning
charlta Mar 30, 2026
59fdd56
Swapped to use newer methods for starting asyncio loops
charlta Mar 30, 2026
7f59b12
Disabled integration tests for local debugging.
charlta Mar 30, 2026
5c73dac
Removed unused import
charlta Mar 30, 2026
7c1731f
WIP - GraphQL Query Typing
charlta Mar 30, 2026
e772d0a
code gen via ast ftw
chestm007 Mar 31, 2026
58ca2fd
try that
chestm007 Mar 31, 2026
375a30d
:shrug: anthony said "it is that simple"
chestm007 Apr 1, 2026
ab2a2e3
it works
chestm007 Apr 1, 2026
66b2dbe
move monkey patched code into plugin spec format - depends on PR in c…
chestm007 Apr 1, 2026
4aa0275
stuff
chestm007 Apr 1, 2026
a049bc8
the stuff
chestm007 Apr 1, 2026
5e65d8d
changelog and readme
chestm007 Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 139 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,59 @@
# Evolve App Server Python Client #

This library provides a wrapper to the Evolve App Server's API, allowing users of the evolve SDK to authenticate with
This library provides a wrapper to the Evolve App Server's API, allowing users of the Evolve SDK to authenticate with
the Evolve App Server and upload studies.

# Usage #

```python
from geojson import FeatureCollection
from zepben.eas import EasClient, Study, Result, Section, GeoJsonOverlay
from zepben.eas import EasClient, StudyInput, StudyResultInput, GeoJsonOverlayInput, ResultSectionInput, SectionType, Mutation

eas_client = EasClient(
host="<host>",
port=1234,
access_token="<access_token>",
client_id="<client_id>",
username="<username>",
password="<password>",
client_secret="<client_secret>"
asynchronous=False,
)

eas_client.upload_study(
Study(
name="<study name>",
description="<study description>",
tags=["<tag>", "<tag2>"],
results=[
Result(
name="<result_name>",
geo_json_overlay=GeoJsonOverlay(
data=FeatureCollection( ... ),
styles=["style1"]
),
sections=Section(
type="TABLE",
name="<table name>",
description = "<table description>",
columns=[
{ "key": "<column 1 key>", "name": "<column 1 name>" },
{ "key": "<column 2 key>", "name": "<column 2 name>" },
],
data=[
{ "<column 1 key>": "<column 1 row 1 value>", "<column 2 key>": "<column 2 row 1 value>" },
{ "<column 1 key>": "<column 1 row 2 value>", "<column 2 key>": "<column 2 row 2 value>" }
]
)
eas_client.mutation(
Mutation.add_studies(
[
StudyInput(
name="<study name>",
description="<study description>",
tags=["<tag>", "<tag2>"],
results=[
StudyResultInput(
name="<result_name>",
geoJsonOverlay=GeoJsonOverlayInput(
data=FeatureCollection(...),
styles=["style1"]
),
sections=[
ResultSectionInput(
type=SectionType.TABLE,
name="<table name>",
description="<table description>",
columns=[
{"key": "<column 1 key>", "name": "<column 1 name>"},
{"key": "<column 2 key>", "name": "<column 2 name>"},
],
data=[
{"<column 1 key>": "<column 1 row 1 value>", "<column 2 key>": "<column 2 row 1 value>"},
{"<column 1 key>": "<column 1 row 2 value>", "<column 2 key>": "<column 2 row 2 value>"}
]
)
]
)
],
styles=[
{
"id": "style1",
# other Mapbox GL JS style properties
}
]
)
],
styles=[
{
"id": "style1",
# other Mapbox GL JS style properties
}
]
)
)
Expand All @@ -59,62 +62,119 @@ eas_client.close()
```

## AsyncIO ##
Asyncio is also supported using aiohttp. A session will be created for you when you create an EasClient if not provided via the `session` parameter to EasClient.

To use the asyncio API use `async_upload_study` like so:
The EasClient can operate in async mode if specified, like so:

```python
from aiohttp import ClientSession
from geojson import FeatureCollection
from zepben.eas import EasClient, Study, Result, Section, GeoJsonOverlay
from zepben.eas import EasClient, StudyInput, StudyResultInput, GeoJsonOverlayInput, ResultSectionInput, SectionType, Mutation


async def upload():
eas_client = EasClient(
host="<host>",
port=1234,
access_token="<access_token>",
client_id="<client_id>",
username="<username>",
password="<password>",
client_secret="<client_secret>",
session=ClientSession(...)
asynchronous=True, # returns all methods as plain async methods
)

await eas_client.async_upload_study(
Study(
name="<study name>",
description="<study description>",
tags=["<tag>", "<tag2>"],
results=[
Result(
name="<result_name>",
geo_json_overlay=GeoJsonOverlay(
data=FeatureCollection( ... ),
styles=["style1"]
),
sections=Section(
type="TABLE",
name="<table name>",
description = "<table description>",
columns=[
{ "key": "<column 1 key>", "name": "<column 1 name>" },
{ "key": "<column 2 key>", "name": "<column 2 name>" },
],
data=[
{ "<column 1 key>": "<column 1 row 1 value>", "<column 2 key>": "<column 2 row 1 value>" },
{ "<column 1 key>": "<column 1 row 2 value>", "<column 2 key>": "<column 2 row 2 value>" }
]
)
await eas_client.mutation(
Mutation.add_studies(
[
StudyInput(
name="<study name>",
description="<study description>",
tags=["<tag>", "<tag2>"],
results=[
StudyResultInput(
name="<result_name>",
geoJsonOverlay=GeoJsonOverlayInput(
data=FeatureCollection(...),
styles=["style1"]
),
sections=[
ResultSectionInput(
type=SectionType.TABLE,
name="<table name>",
description="<table description>",
columns=[
{"key": "<column 1 key>", "name": "<column 1 name>"},
{"key": "<column 2 key>", "name": "<column 2 name>"},
],
data=[
{"<column 1 key>": "<column 1 row 1 value>", "<column 2 key>": "<column 2 row 1 value>"},
{"<column 1 key>": "<column 1 row 2 value>", "<column 2 key>": "<column 2 row 2 value>"}
]
)
]
)
],
styles=[
{
"id": "style1",
# other Mapbox GL JS style properties
}
]
)
]
)
)

await eas_client.close()
```

# I'm used to the old client, what do i do? #

## Migrating existing code ##

Most of the objects passed into requests are similar.
The new EasClient is fully type hinted and self documenting.

For example.

```python
from zepben.eas import EasClient, WorkPackageInput, HcExecutorConfigInput, FeederConfigsInput, FeederConfigInput

client = EasClient(host='host', port=1234)
client.get_work_package_cost_estimation(
WorkPackageInput(
feederConfigs=FeederConfigsInput(
configs=[
FeederConfigInput(
feeder='myFeeder',
years=[2024, 2025],
scenarios=['scenario1']
)
],
styles=[
{
"id": "style1",
# other Mapbox GL JS style properties
}
]
)
)
)
```

Hovering over any kwarg or looking at any class definition will show all possible parameters, and their expected types.

## Enabling legacy convenience methods ##

Legacy convenience methods can be enabled by passing `enable_legacy_methods` to `__init__` of `EasClient`. eg:

```python
from zepben.eas import EasClient

client = EasClient(enable_legacy_methods=True)
```

This will enable all `deprecated` and `opt_in` methods on the class, they are disabled by default.

# Development #

await eas_client.aclose()
```
To regenerate the graphql client you will need to install `zepben.eas` with `eas-codegen` optional dependencies:

```shell
pip install -e ".[eas-codegen]"
```

With these installed and EAS running locally on port 7654, you can then generate the client:

```shell
ariadne-codegen
```
24 changes: 22 additions & 2 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
# EAS Python client
## [0.30.0] - UNRELEASED
### Breaking Changes
* None.
* Deprecated methods in EasClient:
* aclose
* get_work_package_cost_estimation
* run_hosting_capacity_work_package
* cancel_hosting_capacity_work_package
* get_hosting_capacity_work_packages_progress
* run_feeder_load_analysis_report
* get_feeder_load_analysis_report_status
* upload_study
* run_ingestor
* get_ingestor_run
* get_ingestor_run_list
* run_hosting_capacity_calibration
* get_hosting_capacity_calibration_run
* get_hosting_capacity_calibration_sets
* get_transformer_tap_settings
* run_opendss_export
* get_paged_opendss_models
* get_opendss_model
* Most Input object will need to be migrated over to the new data model

### New Features
* None.

### Enhancements
* None.
* EasClient has new `query` and `mutation` methods that will accept `Query` and `Mutation` objects respectively.
* Available queries and mutations can be found as `@classmethods` on `Queries` and `Mutations`.

### Fixes
* None.
Expand Down
30 changes: 23 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2025 Zeppelin Bend Pty Ltd
# Copyright 2026 Zeppelin Bend Pty Ltd
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand All @@ -7,14 +7,13 @@
[build-system]
requires = [
"setuptools",
"wheel",
"build>=1.2.0"
]
build-backend = "setuptools.build_meta"

[project]
name = "zepben.eas"
version = "0.30.0b1"
version = "1.0.0b1"
description = "Python SDK for interacting with the Evolve App Server"
readme = {file = "README.md", content-type = "text/markdown"}
license = "MPL-2.0"
Expand All @@ -25,10 +24,10 @@ authors = [
]
dependencies = [
"geojson==2.5.0",
"requests<3.0.0,>=2.26.0",
"urllib3==2.5.0",
"zepben.ewb==1.1.0",
"aiohttp[speedups]==3.9.0",
"httpx",
"graphql-core==3.2.8",
"pydantic",
"pydantic_core",
]
classifiers = [
"Programming Language :: Python :: 3",
Expand All @@ -50,6 +49,23 @@ test = [
"pytest-httpserver==1.0.8",
"trustme==0.9.0"
]
codegen = [
"ariadne-codegen @ git+https://github.com/chestm007/ariadne-codegen" # This could break a pypi upload. Waiting on https://github.com/mirumee/ariadne-codegen/pull/413 to be merged.
]

[tool.setuptools.packages.find]
where = ["src/"]

[tool.ariadne-codegen]
remote_schema_url = "http://127.0.0.1:7654/api/graphql" # Set to address of Evolve App Server
enable_custom_operations=true
include_comments=false
target_package_path='src/zepben/eas/lib'
target_package_name='generated_graphql_client'
introspection_descriptions=true
introspection_input_value_deprecations=true
plugins=[
"zepben.eas.lib.ariadne_plugins.custom_query_type_hinter.CustomQueryTypeHinterPlugin",
"zepben.eas.lib.ariadne_plugins.missed_import_checker.MissedImportCheckerPlugin",
"zepben.eas.lib.ariadne_plugins.gql_all_fields.GqlAllFieldsPlugin"
]
18 changes: 12 additions & 6 deletions src/zepben/eas/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
# Copyright 2020 Zeppelin Bend Pty Ltd
# Copyright 2026 Zeppelin Bend Pty Ltd
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
#
import warnings

from zepben.eas.client.eas_client import *
from zepben.eas.client.feeder_load_analysis_input import *
from zepben.eas.client.fla_forecast_config import *
from zepben.eas.client.opendss import *
from zepben.eas.client.study import *
from zepben.eas.client.work_package import *

try:
from zepben.eas.lib.generated_graphql_client import *
from zepben.eas.lib.generated_graphql_client.custom_mutations import *
from zepben.eas.lib.generated_graphql_client.custom_queries import *
from zepben.eas.lib.generated_graphql_client.custom_fields import *
except ImportError:
warnings.warn(
"Could not import `zepben.eas.lib.generated_graphql_client`. "
)
2 changes: 1 addition & 1 deletion src/zepben/eas/client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2020 Zeppelin Bend Pty Ltd
# Copyright 2026 Zeppelin Bend Pty Ltd
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
Expand Down
Loading
Loading