Skip to content

Commit eabf4ca

Browse files
feat: database module improvements (#3320)
* feat: adding ip argument * feat: adding port start option * refactor: 'run_as_routine' to make it use more mapdl attributes.\nDeleting 'WithinBeginLevel' context * chore: adding changelog file 3320.miscellaneous.md * fix: test * fix: test * fix: test * feat: creating '_enter_routine' and moving out code. Refactoring * fix: missing import * feat: allowing routines starting with /. --------- Co-authored-by: pyansys-ci-bot <[email protected]>
1 parent 6fbaad3 commit eabf4ca

File tree

5 files changed

+92
-83
lines changed

5 files changed

+92
-83
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
feat: database module improvements

src/ansys/mapdl/core/database/database.py

Lines changed: 52 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from functools import wraps
2626
import os
2727
import time
28+
from typing import Optional
2829
from warnings import warn
2930
import weakref
3031

@@ -38,24 +39,7 @@
3839
MINIMUM_MAPDL_VERSION = "21.1"
3940
FAILING_DATABASE_MAPDL = ["24.1", "24.2"]
4041

41-
42-
class WithinBeginLevel:
43-
"""Context manager to run MAPDL within the being level."""
44-
45-
def __init__(self, mapdl):
46-
"""Initialize this context manager."""
47-
self._mapdl = mapdl
48-
49-
def __enter__(self):
50-
"""Enter the begin level and cache the current routine."""
51-
self._mapdl._cache_routine()
52-
if "BEGIN" not in self._mapdl._cached_routine.upper():
53-
self._mapdl.finish()
54-
55-
def __exit__(self, *args, **kwargs):
56-
"""Exit the begin level and reload the previous routine."""
57-
if "BEGIN" not in self._mapdl._cached_routine.upper():
58-
self._mapdl._resume_routine()
42+
DEFAULT_DB_PORT = 50055
5943

6044

6145
def check_mapdl_db_is_alive(function):
@@ -160,7 +144,7 @@ def _mapdl(self):
160144
"""Return the weakly referenced instance of mapdl."""
161145
return self._mapdl_weakref()
162146

163-
def _start(self) -> int:
147+
def _start(self, port: Optional[int] = None) -> int:
164148
"""
165149
Lower level start of the database server.
166150
@@ -170,38 +154,39 @@ def _start(self) -> int:
170154
Port of the database server.
171155
172156
"""
173-
self._mapdl._log.debug("Starting MAPDL server")
174-
175157
# database server must be run from the "BEGIN" level
158+
self._mapdl._log.debug("Starting MAPDL server")
176159
self._mapdl._cache_routine()
177-
with WithinBeginLevel(self._mapdl):
178-
self._mapdl.run("/DBS,SERVER,START")
160+
with self._mapdl.run_as_routine("Begin level"):
161+
self._mapdl.run(f"/DBS,SERVER,START,{port}")
179162

180-
# Scan the DBServer.info file to get the Port Number
163+
if not port:
164+
# We do not know which port has started with
165+
# Scan the DBServer.info file to get the Port Number
181166

182-
# Default is 50055
183-
# wait for start
184-
tstart = time.time()
185-
timeout = 1
186-
status = self._mapdl._download_as_raw("DBServer.info").decode()
187-
while status == "": # pragma: no cover
167+
self._mapdl._log.debug("Downloading 'DBServer' file.")
168+
tstart = time.time()
169+
timeout = 1
188170
status = self._mapdl._download_as_raw("DBServer.info").decode()
189-
time.sleep(0.05)
190-
if time.time() - tstart > timeout:
191-
raise TimeoutError(
192-
f"Unable to start database server in {timeout} second(s)"
171+
while status == "": # pragma: no cover
172+
status = self._mapdl._download_as_raw("DBServer.info").decode()
173+
time.sleep(0.05)
174+
if time.time() - tstart > timeout:
175+
raise TimeoutError(
176+
f"Unable to start database server in {timeout} second(s). DBServer not received."
177+
)
178+
179+
self._mapdl._log.debug("Downloading 'DBServer' file.")
180+
try:
181+
# expected of the form 'Port : 50055'
182+
port = int(status.split(":")[1])
183+
except Exception as e: # pragma: no cover
184+
self._mapdl._log.error(
185+
"Unable to read port number from '%s' due to\n%s",
186+
status,
187+
str(e),
193188
)
194-
195-
try:
196-
# expected of the form 'Port : 50055'
197-
port = int(status.split(":")[1])
198-
except Exception as e: # pragma: no cover
199-
self._mapdl._log.error(
200-
"Unable to read port number from '%s' due to\n%s",
201-
status,
202-
str(e),
203-
)
204-
port = 50055
189+
port = DEFAULT_DB_PORT
205190

206191
self._mapdl._log.debug("MAPDL database server started on port %d", port)
207192
return port
@@ -211,7 +196,7 @@ def active(self) -> bool:
211196
"""Return if the database server is active."""
212197
return "NOT" not in self._status()
213198

214-
def start(self, timeout=10):
199+
def start(self, port: Optional[int] = None, timeout: int = 10):
215200
"""
216201
Start the gRPC MAPDL database server.
217202
@@ -262,19 +247,27 @@ def start(self, timeout=10):
262247
self._mapdl._log.debug("MAPDL DB server running: %s", str(is_running))
263248
if is_running:
264249
return
265-
db_port = self._start()
266-
267-
self._ip = self._mapdl._ip
268250

269251
# permit overriding db_port via env var for CI
270-
if "PYMAPDL_DB_PORT" in os.environ:
271-
db_port_str = os.environ.get("PYMAPDL_DB_PORT")
272-
try:
273-
db_port = int(db_port_str)
274-
except ValueError: # pragma: no cover
275-
raise ValueError(
276-
f"Invalid port '{db_port_str}' specified in the env var PYMAPDL_DB_PORT"
252+
if not port:
253+
if (
254+
"PYMAPDL_DB_PORT" in os.environ
255+
and os.environ.get("PYMAPDL_DB_PORT").isdigit()
256+
):
257+
db_port_str = int(os.environ.get("PYMAPDL_DB_PORT"))
258+
self._mapdl._log.debug(
259+
f"Setting DB port from 'PYMAPDL_DB_PORT' env var: {db_port_str}"
260+
)
261+
else:
262+
self._mapdl._log.debug(
263+
f"Setting default DB port ('{DEFAULT_DB_PORT}') because no port was input or the env var 'PYMAPDL_DB_PORT' is not correctly set."
277264
)
265+
port = DEFAULT_DB_PORT
266+
267+
db_port = self._start(port=port)
268+
269+
if not self._ip:
270+
self._ip = self._mapdl.ip
278271

279272
self._server = {"ip": self._ip, "port": db_port}
280273
self._channel_str = f"{self._ip}:{db_port}"
@@ -295,13 +288,13 @@ def start(self, timeout=10):
295288

296289
if not self._state._matured: # pragma: no cover
297290
raise MapdlConnectionError(
298-
"Unable to establish connection to MAPDL database server"
291+
f"Unable to establish connection to MAPDL database server {self._channel_str}"
299292
)
300293
self._mapdl._log.debug("Established connection to MAPDL database server")
301294

302295
def _stop(self):
303296
"""Stop the MAPDL database service."""
304-
with WithinBeginLevel(self._mapdl):
297+
with self._mapdl.run_as_routine("Begin level"):
305298
return self._mapdl.run("/DBS,SERVER,STOP")
306299

307300
def stop(self):
@@ -338,7 +331,7 @@ def _status(self):
338331
DB Server is NOT currently running ..
339332
"""
340333
# Need to use the health check here
341-
with WithinBeginLevel(self._mapdl):
334+
with self._mapdl.run_as_routine("Begin level"):
342335
return self._mapdl.run("/DBS,SERVER,STATUS")
343336

344337
def load(self, fname, progress_bar=False):

src/ansys/mapdl/core/mapdl_core.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,29 +1443,27 @@ class _RetainRoutine:
14431443

14441444
def __init__(self, parent, routine):
14451445
self._parent = weakref.ref(parent)
1446-
1447-
# check the routine is valid since we're muting the output
1448-
check_valid_routine(routine)
14491446
self._requested_routine = routine
14501447

14511448
def __enter__(self):
14521449
"""Store the current routine and enter the requested routine."""
1453-
self._cached_routine = self._parent().parameters.routine
1454-
self._parent()._log.debug("Caching routine %s", self._cached_routine)
1455-
if self._requested_routine.lower() != self._cached_routine.lower():
1456-
self._enter_routine(self._requested_routine)
1450+
self._parent()._cache_routine()
1451+
self._parent()._log.debug(f"Caching routine {self._cached_routine}")
1452+
1453+
if (
1454+
self._requested_routine.lower().strip()
1455+
!= self._cached_routine.lower().strip()
1456+
):
1457+
self._parent()._enter_routine(self._requested_routine)
14571458

14581459
def __exit__(self, *args):
14591460
"""Restore the original routine."""
1460-
self._parent()._log.debug("Restoring routine %s", self._cached_routine)
1461-
self._enter_routine(self._cached_routine)
1461+
self._parent()._log.debug(f"Restoring routine '{self._cached_routine}'")
1462+
self._parent()._resume_routine()
14621463

1463-
def _enter_routine(self, routine):
1464-
"""Enter a routine."""
1465-
if routine.lower() == "begin level":
1466-
self._parent().finish(mute=True)
1467-
else:
1468-
self._parent().run(f"/{routine}", mute=True)
1464+
@property
1465+
def _cached_routine(self):
1466+
return self._parent()._cached_routine
14691467

14701468
def run_as_routine(self, routine):
14711469
"""
@@ -1707,17 +1705,26 @@ def open_gui(self, include_result=None, inplace=None): # pragma: no cover
17071705
# restore remove tmp state
17081706
self._remove_tmp = remove_tmp
17091707

1708+
def _enter_routine(self, routine):
1709+
# check the routine is valid since we're muting the output
1710+
check_valid_routine(routine)
1711+
1712+
if routine.lower() in ["begin level", "finish"]:
1713+
self.finish(mute=True)
1714+
else:
1715+
if not routine.startswith("/"):
1716+
routine = f"/{routine}"
1717+
1718+
self.run(f"{routine}", mute=True)
1719+
17101720
def _cache_routine(self):
17111721
"""Cache the current routine."""
17121722
self._cached_routine = self.parameters.routine
17131723

17141724
def _resume_routine(self):
17151725
"""Resume the cached routine."""
17161726
if self._cached_routine is not None:
1717-
if "BEGIN" not in self._cached_routine:
1718-
self.run(f"/{self._cached_routine}", mute=True)
1719-
else:
1720-
self.finish(mute=True)
1727+
self._enter_routine(self._cached_routine)
17211728
self._cached_routine = None
17221729

17231730
def _launch(self, *args, **kwargs): # pragma: no cover

src/ansys/mapdl/core/misc.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ def check_valid_routine(routine):
111111
Raised when a routine is invalid.
112112
113113
"""
114+
if routine.lower().startswith("/"):
115+
routine = routine[1:]
116+
114117
if routine.lower().startswith("begin"):
115118
return True
116119
if not hasattr(ROUTINES, routine.upper()):

tests/test_misc.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -372,12 +372,17 @@ def myotherfun2(self):
372372
assert myclass.myotherfun2 is None
373373

374374

375-
def test_check_valid_routine():
376-
assert check_valid_routine("prep7")
377-
assert check_valid_routine("PREP7")
378-
assert check_valid_routine("begin level")
375+
@pytest.mark.parametrize(
376+
"routine", ["prep7", "PREP7", "/PREP7", "begin level", "BEGIN LEVEL"]
377+
)
378+
def test_check_valid_routine(routine):
379+
assert check_valid_routine(routine)
380+
381+
382+
@pytest.mark.parametrize("routine", ["invalid", "invalid routine", "prep78"])
383+
def test_check_valid_routine_invalid(routine):
379384
with pytest.raises(ValueError, match="Invalid routine"):
380-
check_valid_routine("invalid")
385+
check_valid_routine(routine)
381386

382387

383388
@requires("local")

0 commit comments

Comments
 (0)