Skip to content

Commit 4a6f144

Browse files
authored
Merge pull request #40 from smolvik1/add-px-online-server
Add px online server
2 parents 7268b79 + ff0d184 commit 4a6f144

10 files changed

Lines changed: 841 additions & 36 deletions

File tree

.github/workflows/cd.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ jobs:
1717
uses: actions/checkout@v3
1818

1919
- name: "Set up uv"
20-
uses: astral-sh/setup-uv@v3
20+
uses: astral-sh/setup-uv@v5
2121
with:
22-
python-version: "3.11"
22+
python-version: "3.13"
2323

2424
- name: "Build distributions"
2525
run: |

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ jobs:
2323
uses: actions/checkout@v3
2424

2525
- name: "Set up uv"
26-
uses: astral-sh/setup-uv@v3
26+
uses: astral-sh/setup-uv@v5
2727
with:
28-
python-version: "3.11"
28+
python-version: "3.13"
2929

3030
- name: "Build distribution"
3131
run: |

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ sdist/
1414

1515
# Environment
1616
.venv/
17-
venv/
17+
venv/
18+
19+
# Swagger
20+
swagger.json

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,72 @@ DoCmd('PROSPER.OPENFILE("C:\\well_2.OUT")')
6262
DoSet('PROSPER.SIN.SUM.Comments', 'Testing OpenServer from Python')
6363
```
6464

65+
## Remote OpenServer (PxOnlineServer)
66+
67+
In addition to the local COM client, the package ships a `PxOnlineServer` client
68+
that talks to a Petroleum Experts [PxOnlineServer](https://www.petex.com/products/ipm-suite/openserver/)
69+
instance over its REST API. It runs the *same* `DoCmd`/`DoSet`/`DoGet` commands as
70+
the local client, but against a model hosted on the server - no local IPM install
71+
is required.
72+
73+
`requests` is used for the HTTP calls and is installed automatically.
74+
75+
### Connecting to a session
76+
77+
A remote model lives in a *master session* on the server. On connect, the master
78+
session is copied into a temporary *user session* that your commands run against;
79+
the user session is removed again on disconnect.
80+
81+
```python
82+
from openserver import PxOnlineServer
83+
84+
with PxOnlineServer(
85+
base_url="http://my-pxserver:8056",
86+
master_session="my_master_session", # a master session containing a PROSPER module
87+
module_name="IPM-OS", # the server-side OpenServer module name
88+
) as c:
89+
print(c.DoGet("PROSPER.SIN.SUM.Comments"))
90+
c.DoSet("PROSPER.SIN.SUM.Comments", "Testing remote OpenServer from Python")
91+
```
92+
93+
To attach to an existing user session instead of creating one, pass `guid` and
94+
`session` instead of `master_session`.
95+
96+
### Loading a model from the Model Catalogue
97+
98+
The Model Catalogue is the server's versioned file store. `open_catalogue_file`
99+
is the remote analogue of `PROSPER.OPENFILE`: it loads a catalogue model into the
100+
session so the familiar `DoCmd`/`DoSet`/`DoGet` calls operate on it. There is no
101+
`PROSPER.START()` remotely - the module is already running in the session.
102+
103+
```python
104+
from openserver import PxOnlineServer
105+
106+
with PxOnlineServer(base_url="http://my-pxserver:8056",
107+
master_session="my_master_session",
108+
module_name="IPM-OS") as c:
109+
# Remote equivalent of PROSPER.OPENFILE - give the catalogue host + file path
110+
c.open_catalogue_file(
111+
"Root/Europe/Norway/North Sea/Yggdrasil/ByteAll/ProsperModel/SK1.Out",
112+
host_alias="MyCatalogueHost",
113+
)
114+
115+
# ...then it's the same as the local COM client
116+
c.DoSet("PROSPER.SIN.SUM.Comments", "Testing remote OpenServer from Python")
117+
print(c.DoGet("PROSPER.SIN.SUM.Comments"))
118+
```
119+
120+
`open_catalogue_file` returns the catalogue guid, so you can pass it back in as
121+
`catalogue_guid=...` to open further files without re-initialising the catalogue.
122+
123+
The file is uploaded under the existing main file's name, so the session's
124+
reported `MainFile` label is unchanged - but its contents (and everything
125+
`DoGet`/`DoSet`/`DoCmd` see) are the catalogue file you loaded.
126+
127+
See [examples/px_online_server_basic.py](examples/px_online_server_basic.py) for a
128+
complete, runnable walkthrough.
129+
130+
### Limitations
131+
132+
`PxOnlineServer` currently targets a PxOnlineServer instance that requires no
133+
authentication - it sends no credentials.

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.154
2+
* Added `PxOnlineServer`, a remote OpenServer client for Petroleum Experts PxOnlineServer (REST API)
3+
* Added Model Catalogue support: browse folders/files by path, download files, and load a catalogue file into a running session via `open_catalogue_file`
4+
* Added `requests` as a dependency for the remote client
5+
16
## 1.153
27
* Switched packaging and dependency management from Poetry to uv
38
* Updated CI/CD pipelines to use Python 3.11 and uv

examples/px_online_server_basic.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
"""Basic remote OpenServer usage via PxOnlineServer.
2+
3+
Runs the same DoCmd/DoSet/DoGet calls as the local COM client, but against a
4+
Petroleum Experts PxOnlineServer instance. No local IPM install is required.
5+
6+
The base_url, master_session and module_name below are examples - replace them
7+
with values for your own server. `master_session` is referenced by name and is
8+
copied into a temporary user session on connect; that user session is removed
9+
again on disconnect.
10+
"""
11+
12+
from openserver import PxOnlineServer
13+
14+
BASE_URL: str = "http://my-pxserver:8056"
15+
MASTER_SESSION: str = "my-master-session" # a master session that contains a PROSPER OpenServer module
16+
MODULE_NAME: str = "IPM-OS" # the server-side OpenServer module name
17+
18+
MC_FILE_PATH: str = r'Root/Europe/Norway/prosper-testfile.OUT' # Case-sensitive
19+
MC_HOST_ALIAS: str = "my-mc-alias"
20+
21+
# --- Generic OpenServer usage against a Model Catalogue file ---
22+
with PxOnlineServer(base_url=BASE_URL, master_session=MASTER_SESSION, module_name=MODULE_NAME) as c:
23+
# Open a model from the Model Catalogue
24+
# Perform a simple VLP/IPR calculation
25+
# Return the liquid rate result
26+
c.open_catalogue_file(MC_FILE_PATH, host_alias=MC_HOST_ALIAS)
27+
print(f"Opened {MC_FILE_PATH}")
28+
29+
unit_system = "Norwegian S.I."
30+
c.DoCmd(f"PROSPER.SETUNITSYS(\"{unit_system}\")")
31+
32+
whp: float = 30 # bara
33+
wc: float = 40 # percent water cut
34+
gor_tot: float = 79 # gas-oil ratio total
35+
c.DoSet("PROSPER.ANL.SYS.Pres", whp) # Set top node pressure
36+
c.DoSet("PROSPER.ANL.SYS.WC", wc) # Set water cut
37+
c.DoSet("PROSPER.ANL.SYS.GOR", gor_tot) # Set GOR total
38+
39+
c.DoCmd("PROSPER.ANL.SYS.CALC") # Calculate VLP/IPR
40+
41+
qliq = c.DoGet("PROSPER.OUT.SYS.SOL[0].QLIQ") # Get liquid flow rate
42+
print(f"Liquid flow rate: {qliq}")
43+
44+
45+
with PxOnlineServer(base_url=BASE_URL, master_session=MASTER_SESSION, module_name=MODULE_NAME) as d:
46+
catalogue_guid: str = d.open_catalogue_file(MC_FILE_PATH, host_alias=MC_HOST_ALIAS)
47+
48+
# --- Download a copy of a Model Catalogue file to disk ---
49+
file_bytes = d.mc_download_file(catalogue_guid, MC_FILE_PATH)
50+
local_name = MC_FILE_PATH.rsplit("/", 1)[-1]
51+
with open(local_name, "wb") as f:
52+
f.write(file_bytes)
53+
print(f"Downloaded {len(file_bytes)} bytes to {local_name}")

0 commit comments

Comments
 (0)