Skip to content

Commit 32398f2

Browse files
committed
reuse URL address in publish_app()
1 parent 3447197 commit 32398f2

6 files changed

Lines changed: 64 additions & 10 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ or publish it quickly:
111111
automl.publish_app()
112112
```
113113

114+
`publish_app()` creates an app URL on the first publish and then reuses the last successfully published URL by default.
115+
114116
The generated app can include:
115117
- single prediction dashboard,
116118
- batch prediction from CSV files,

docs/docs/features/apps.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,20 @@ automl.publish_app()
8989
This helper:
9090

9191
- signs in through `platform.mljar.com`
92-
- creates or updates the app URL
92+
- creates a new app URL on the first publish
93+
- reuses the last successfully published app URL on later publishes
9394
- uploads the generated runtime files
9495
- prints progress and friendly error messages
9596
- remembers the last successfully published app URL
9697

97-
If you want to reuse a specific published app URL:
98+
If you want to update a specific published app URL:
9899

99100
```python
100101
automl.publish_app(url="https://your-app.ismvp.org")
101102
```
102103

104+
The remembered URL is stored in `publish_app_state.json` inside the AutoML `results_path`.
105+
103106
## Publish or host manually
104107

105108
Using `platform.mljar.com` is simply the fastest path, but it is not required.

docs/docs/tutorials/app-classification.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ automl.publish_app()
124124
This helper will:
125125

126126
- sign you in through `platform.mljar.com`,
127-
- create the app URL,
127+
- create the app URL on the first publish,
128+
- reuse the last successfully published app URL on later publishes,
128129
- upload the generated app files,
129130
- and print the final app address.
130131

docs/docs/tutorials/app-regression.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ automl.publish_app()
146146
This helper will:
147147

148148
- sign you in through `platform.mljar.com`,
149-
- create the app URL,
149+
- create the app URL on the first publish,
150+
- reuse the last successfully published app URL on later publishes,
150151
- upload the generated files,
151152
- and print the final app address.
152153

supervised/apps/publisher.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,9 @@ def publish_app_from_automl(
437437
verbose=True,
438438
):
439439
try:
440+
previous_url = _load_publish_state(automl).get("last_published_url")
440441
if verbose:
441442
print("Start app publish")
442-
previous_url = _load_publish_state(automl).get("last_published_url")
443443
if previous_url:
444444
print(f"Last published app URL: {previous_url}")
445445
overwrite_output = overwrite or path is None
@@ -458,12 +458,23 @@ def publish_app_from_automl(
458458
token = session.authenticate()
459459
client = PlatformClient(base_url=DEFAULT_PLATFORM_BASE_URL, token=token)
460460

461-
if url:
461+
target_url = url or previous_url
462+
if target_url:
462463
if verbose:
463-
print(f"Checking existing app URL: {url}")
464-
site = client.find_site_by_url(url)
464+
print(f"Checking existing app URL: {target_url}")
465+
site = client.find_site_by_url(target_url)
465466
if site is None:
466-
raise AutoMLException(f"Could not find Mercury app for URL '{url}'.")
467+
if url:
468+
raise AutoMLException(f"Could not find Mercury app for URL '{url}'.")
469+
site_title = _workspace_title(output_path, fallback_title=title)
470+
if verbose:
471+
print(
472+
f"Last published app URL not found on platform: {target_url}"
473+
)
474+
print("Creating app URL")
475+
site = _create_site_with_generated_slug(client, site_title)
476+
if verbose:
477+
print(f"Created app URL: {_site_url(site)}")
467478
else:
468479
site_title = _workspace_title(output_path, fallback_title=title)
469480
if verbose:
@@ -472,7 +483,7 @@ def publish_app_from_automl(
472483
if verbose:
473484
print(f"Created app URL: {_site_url(site)}")
474485

475-
if verbose and url:
486+
if verbose and target_url and site is not None:
476487
print(f"Using app URL: {_site_url(site)}")
477488

478489
_upload_workspace_files(client, site, output_path, verbose=verbose)

tests/tests_automl/test_automl_publish_app.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,48 @@ def test_publish_app_saves_and_prints_last_successful_url(
251251
state = json.load(fin)
252252
self.assertEqual(state.get("last_published_url"), first_url)
253253

254+
FakePublishingClient.sites = [FakePublishingClient.created_site]
255+
FakePublishingClient.created_site = None
256+
254257
second_stdout = io.StringIO()
255258
with patch("sys.stdout", second_stdout):
256259
second_url = model.publish_app(open_browser=False)
257260

258261
self.assertEqual(second_url, first_url)
262+
self.assertIsNone(FakePublishingClient.created_site)
259263
self.assertIn(f"Last published app URL: {first_url}", second_stdout.getvalue())
264+
self.assertIn(f"Checking existing app URL: {first_url}", second_stdout.getvalue())
265+
self.assertIn(f"Using app URL: {first_url}", second_stdout.getvalue())
266+
267+
@patch("supervised.apps.publisher.generate_machine_learning_slug", return_value="feature-lab")
268+
@patch("supervised.apps.publisher.PlatformClient", FakePublishingClient)
269+
@patch("supervised.apps.publisher.BrowserTokenSession.authenticate", return_value="app.jwt.token")
270+
def test_publish_app_creates_new_site_when_last_published_url_is_missing(
271+
self, _mock_authenticate, _mock_slug
272+
):
273+
model = self._trained_model()
274+
275+
first_stdout = io.StringIO()
276+
with patch("sys.stdout", first_stdout):
277+
first_url = model.publish_app(open_browser=False)
278+
279+
self.assertEqual(first_url, "https://feature-lab.ismvp.org")
280+
FakePublishingClient.created_site = None
281+
FakePublishingClient.sites = []
282+
283+
second_stdout = io.StringIO()
284+
with patch("sys.stdout", second_stdout):
285+
second_url = model.publish_app(open_browser=False)
286+
287+
self.assertEqual(second_url, first_url)
288+
self.assertIsNotNone(FakePublishingClient.created_site)
289+
output = second_stdout.getvalue()
290+
self.assertIn(f"Checking existing app URL: {first_url}", output)
291+
self.assertIn(
292+
f"Last published app URL not found on platform: {first_url}",
293+
output,
294+
)
295+
self.assertIn("Creating app URL", output)
260296

261297
@patch("supervised.apps.publisher.PlatformClient", FakePublishingClient)
262298
@patch("supervised.apps.publisher.BrowserTokenSession.authenticate", return_value="app.jwt.token")

0 commit comments

Comments
 (0)