Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: Don't always remove AEDT project files #413

Merged
merged 3 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
46 changes: 27 additions & 19 deletions src/pyedb/dotnet/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,16 @@ class Edb(Database):

def __init__(
self,
edbpath=None,
cellname=None,
isreadonly=False,
edbversion=None,
isaedtowned=False,
edbpath: str = None,
cellname: str = None,
isreadonly: bool = False,
edbversion: str = None,
isaedtowned: bool = False,
oproject=None,
student_version=False,
use_ppe=False,
technology_file=None,
student_version: bool = False,
use_ppe: bool = False,
technology_file: str = None,
remove_existing_aedt: bool = False,
):
edbversion = get_string_version(edbversion)
self._clean_variables()
Expand Down Expand Up @@ -213,17 +214,8 @@ def __init__(
os.path.dirname(edbpath),
"pyedb_" + os.path.splitext(os.path.split(edbpath)[-1])[0] + ".log",
)
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
files = [aedt_file, aedt_file + ".lock"]
for file in files:
if os.path.isfile(file):
try:
shutil.rmtree(file)
self.logger.info(f"Removing {file} to allow loading EDB file.")
except:
self.logger.info(
f"Failed to delete {file} which is located at the same location as the EDB file."
)
if not isreadonly:
self._check_remove_project_files(edbpath, remove_existing_aedt)

if isaedtowned and (inside_desktop or settings.remote_rpc_session):
self.open_edb_inside_aedt()
Expand Down Expand Up @@ -311,6 +303,22 @@ def __setitem__(self, variable_name, variable_value):
if description: # Add the variable description if a two-item list is passed for variable_value.
self.__getitem__(variable_name).description = description

def _check_remove_project_files(self, edbpath: str, remove_existing_aedt: bool) -> None:
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
files = [aedt_file, aedt_file + ".lock"]
for file in files:
if os.path.isfile(file):
if not remove_existing_aedt:
self.logger.warning(
f"AEDT project-related file {file} exists and may need to be deleted before opening the EDB in HFSS 3D Layout." # noqa: E501
)
else:
try:
os.unlink(file)
self.logger.info(f"Deleted AEDT project-related file {file}.")
except:
self.logger.info(f"Failed to delete AEDT project-related file {file}.")

def _clean_variables(self):
"""Initialize internal variables and perform garbage collection."""
self._materials = None
Expand Down
88 changes: 68 additions & 20 deletions tests/legacy/unit/test_edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ def init(self, local_scratch):

def test_create_edb(self):
"""Create EDB."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
assert edb
assert edb.active_layout
edb.close()
Expand All @@ -56,7 +59,10 @@ def test_variables_value(self):
"""Evaluate variables value."""
from pyedb.generic.general_methods import check_numeric_equivalence

edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
edb["var1"] = 0.01
edb["var2"] = "10um"
edb["var3"] = [0.03, "test description"]
Expand All @@ -73,7 +79,10 @@ def test_variables_value(self):

def test_add_design_variable(self):
"""Add a variable value."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
is_added, _ = edb.add_design_variable("ant_length", "1cm")
assert is_added
is_added, _ = edb.add_design_variable("ant_length", "1cm")
Expand All @@ -89,14 +98,20 @@ def test_add_design_variable(self):

def test_add_design_variable_with_setitem(self):
"""Add a variable value."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
edb["ant_length"] = "1cm"
assert edb.variable_exists("ant_length")[0]
assert edb["ant_length"].value == 0.01

def test_change_design_variable_value(self):
"""Change a variable value."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
edb.add_design_variable("ant_length", "1cm")
edb.add_design_variable("my_parameter_default", "1mm", is_parameter=True)
edb.add_design_variable("$my_project_variable", "1mm")
Expand All @@ -114,15 +129,21 @@ def test_change_design_variable_value(self):

def test_change_design_variable_value_with_setitem(self):
"""Change a variable value."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)
edb["ant_length"] = "1cm"
assert edb["ant_length"].value == 0.01
edb["ant_length"] = "2cm"
assert edb["ant_length"].value == 0.02

def test_create_padstack_instance(self):
"""Create padstack instances."""
edb = Edb(os.path.join(self.local_scratch.path, "temp.aedb"), edbversion=desktop_version)
edb = Edb(
os.path.join(self.local_scratch.path, "temp.aedb"),
edbversion=desktop_version,
)

pad_name = edb.padstacks.create(
pad_shape="Rectangle",
Expand Down Expand Up @@ -151,38 +172,65 @@ def test_create_padstack_instance(self):
edb.close()

@patch("os.path.isfile")
@patch("shutil.rmtree")
@patch("pyedb.dotnet.edb_core.dotnet.database.EdbDotNet.logger", new_callable=PropertyMock)
def test_conflict_files_removal_success(self, mock_logger, mock_rmtree, mock_isfile):
@patch("os.unlink")
@patch(
"pyedb.dotnet.edb_core.dotnet.database.EdbDotNet.logger",
new_callable=PropertyMock,
)
def test_conflict_files_removal_success(self, mock_logger, mock_unlink, mock_isfile):
logger_mock = MagicMock()
mock_logger.return_value = logger_mock
mock_isfile.side_effect = lambda file: file.endswith((".aedt", ".aedt.lock"))

edbpath = "file.edb"
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
files = [aedt_file, aedt_file + ".lock"]
_ = Edb(edbpath)
_ = Edb(edbpath, remove_existing_aedt=True)

for file in files:
mock_unlink.assert_any_call(file)
logger_mock.info.assert_any_call(f"Deleted AEDT project-related file {file}.")

@patch("os.path.isfile")
@patch("os.unlink")
@patch(
"pyedb.dotnet.edb_core.dotnet.database.EdbDotNet.logger",
new_callable=PropertyMock,
)
def test_conflict_files_removal_failure(self, mock_logger, mock_unlink, mock_isfile):
logger_mock = MagicMock()
mock_logger.return_value = logger_mock
mock_isfile.side_effect = lambda file: file.endswith((".aedt", ".aedt.lock"))
mock_unlink.side_effect = Exception("Could not delete file")

edbpath = "file.edb"
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
files = [aedt_file, aedt_file + ".lock"]
_ = Edb(edbpath, remove_existing_aedt=True)

for file in files:
mock_rmtree.assert_any_call(file)
logger_mock.info.assert_any_call(f"Removing {file} to allow loading EDB file.")
mock_unlink.assert_any_call(file)
logger_mock.info.assert_any_call(f"Failed to delete AEDT project-related file {file}.")

@patch("os.path.isfile")
@patch("shutil.rmtree")
@patch("pyedb.dotnet.edb_core.dotnet.database.EdbDotNet.logger", new_callable=PropertyMock)
def test_conflict_files_removal_failure(self, mock_logger, mock_rmtree, mock_isfile):
@patch("os.unlink")
@patch(
"pyedb.dotnet.edb_core.dotnet.database.EdbDotNet.logger",
new_callable=PropertyMock,
)
def test_conflict_files_leave_in_place(self, mock_logger, mock_unlink, mock_isfile):
logger_mock = MagicMock()
mock_logger.return_value = logger_mock
mock_isfile.side_effect = lambda file: file.endswith((".aedt", ".aedt.lock"))
mock_rmtree.side_effect = Exception("Could not delete file")
mock_unlink.side_effect = Exception("Could not delete file")

edbpath = "file.edb"
aedt_file = os.path.splitext(edbpath)[0] + ".aedt"
files = [aedt_file, aedt_file + ".lock"]
_ = Edb(edbpath)

mock_unlink.assert_not_called()
for file in files:
mock_rmtree.assert_any_call(file)
logger_mock.info.assert_any_call(
f"Failed to delete {file} which is located at the same location as the EDB file."
logger_mock.warning.assert_any_call(
f"AEDT project-related file {file} exists and may need to be deleted before opening the EDB in HFSS 3D Layout." # noqa: E501
)
Loading