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

PR: Remember which water level and weather datasets were last opened when opening a new project #267

Merged
merged 10 commits into from
Feb 12, 2019
19 changes: 15 additions & 4 deletions gwhat/projet/manager_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
import gwhat.common.widgets as myqt
from gwhat.hydrograph4 import LatLong2Dist
import gwhat.projet.reader_waterlvl as wlrd
from gwhat.projet.reader_projet import INVALID_CHARS, is_dsetname_valid
from gwhat.projet.reader_projet import (INVALID_CHARS, is_dsetname_valid,
make_dsetname_valid, ProjetReader)
import gwhat.meteo.weather_reader as wxrd
from gwhat.widgets.buttons import ToolBarWidget
from gwhat.widgets.spinboxes import StrSpinBox
Expand Down Expand Up @@ -181,9 +182,9 @@ def projet(self):
def set_projet(self, projet):
"""Set the namespace for the projet hdf5 file."""
self._projet = projet
if projet is not None:
self.update_wldsets()
self.update_wxdsets()
if isinstance(projet, ProjetReader):
self.update_wldsets(projet.get_last_opened_wldset())
self.update_wxdsets(projet.get_last_opened_wxdset())

self.update_wldset_info()
self.update_wxdset_info()
Expand Down Expand Up @@ -294,6 +295,15 @@ def get_current_wldset(self):
else:
return self.projet.get_wldset(self.wldsets_cbox.currentText())

def set_current_wldset(self, name):
"""Set the current water level from its name."""
self.wldsets_cbox.blockSignals(True)
self.wldsets_cbox.setCurrentIndex(self.wldsets_cbox.findText(name))
self.wldsets_cbox.blockSignals(False)

self.update_wldset_info()
self.wldset_changed()

def del_current_wldset(self):
"""Delete the currently selected water level dataset."""
if self.wldsets_cbox.count() > 0:
Expand Down Expand Up @@ -402,6 +412,7 @@ def get_current_wxdset(self):
return self.projet.get_wxdset(self.wxdsets_cbox.currentText())

def set_current_wxdset(self, name):
"""Set the current weather dataset from its name."""
self.wxdsets_cbox.blockSignals(True)
self.wxdsets_cbox.setCurrentIndex(self.wxdsets_cbox.findText(name))
self.wxdsets_cbox.blockSignals(False)
Expand Down
28 changes: 28 additions & 0 deletions gwhat/projet/reader_projet.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def load_projet(self, filename):
for key in ['wldsets', 'wxdsets']:
if key not in list(self.db.keys()):
self.db.create_group(key)
if 'last_opened' not in list(self.db[key].attrs.keys()):
# Added in version 0.4.0 (see PR #267)
self.db[key].attrs['last_opened'] = 'None'

def close_projet(self):
"""Close the project hdf5 file."""
Expand Down Expand Up @@ -188,11 +191,20 @@ def wldsets(self):
"""
return list(self.db['wldsets'].keys())

def get_last_opened_wldset(self):
"""
Return the name of the last opened water level dataset in the project
if any.
"""
name = self.db['wldsets'].attrs['last_opened']
return None if name == 'None' else name

def get_wldset(self, name):
"""
Return the water level dataset corresponding to the provided name.
"""
if name in self.wldsets:
self.db['wldsets'].attrs['last_opened'] = name
return WLDataFrameHDF5(self.db['wldsets/%s' % name])
else:
return None
Expand Down Expand Up @@ -276,11 +288,20 @@ def wxdsets(self):
"""
return list(self.db['wxdsets'].keys())

def get_last_opened_wxdset(self):
"""
Return the name of the last opened weather dataset in the project
if any.
"""
name = self.db['wxdsets'].attrs['last_opened']
return None if name == 'None' else name

def get_wxdset(self, name):
"""
Return the weather dataset corresponding to the provided name.
"""
if name in self.wxdsets:
self.db['wxdsets'].attrs['last_opened'] = name
return WXDataFrameHDF5(self.db['wxdsets/%s' % name])
else:
return None
Expand Down Expand Up @@ -744,6 +765,13 @@ def is_dsetname_valid(dsetname):
not any(char in dsetname for char in INVALID_CHARS))


def make_dsetname_valid(dsetname):
"""Replace all invalid characters in the name by an underscore."""
for char in INVALID_CHARS:
dsetname = dsetname.replace(char, '_')
return dsetname


def save_dict_to_h5grp(h5grp, dic):
"""
Save the content of a dictionay recursively in a hdf5.
Expand Down
66 changes: 56 additions & 10 deletions gwhat/projet/tests/test_manager_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,14 @@

# ---- Pytest Fixtures
@pytest.fixture
def project(tmpdir):
def projectpath(tmpdir):
return osp.join(str(tmpdir), "data_manager_test.gwt")


@pytest.fixture
def project(projectpath):
# Create a project and add add the wldset to it.
return ProjetReader(osp.join(str(tmpdir), "data_manager_test.gwt"))
return ProjetReader(projectpath)


@pytest.fixture
Expand All @@ -41,6 +46,7 @@ def datamanager(project, qtbot):
qtbot.addWidget(datamanager)
qtbot.addWidget(datamanager.new_waterlvl_win)
qtbot.addWidget(datamanager.new_weather_win)
datamanager.show()

return datamanager

Expand All @@ -49,7 +55,6 @@ def datamanager(project, qtbot):
def test_import_weather_data(datamanager, mocker, qtbot):
"""Test importing and saving weather data to the project."""
datamanager.new_weather_win.setModal(False)
datamanager.show()

# Mock the file dialog to return the path of the weather datafile.
mocker.patch.object(
Expand All @@ -75,9 +80,9 @@ def test_import_weather_data(datamanager, mocker, qtbot):


def test_delete_weather_data(datamanager, mocker, qtbot):
"""Test deleting weather datasets from the project."""
datamanager.show()

"""
Test deleting weather datasets from the project.
"""
datamanager.new_wxdset_imported('wxdset1', WXDataFrame(WXFILENAME))
datamanager.new_wxdset_imported('wxdset2', WXDataFrame(WXFILENAME))
assert datamanager.wxdataset_count() == 2
Expand Down Expand Up @@ -111,7 +116,6 @@ def test_delete_weather_data(datamanager, mocker, qtbot):
def test_import_waterlevel_data(datamanager, mocker, qtbot):
"""Test importing and saving water level data to the project."""
datamanager.new_weather_win.setModal(False)
datamanager.show()

# Mock the file dialog to return the path of the weather datafile.
mocker.patch.object(
Expand All @@ -138,9 +142,9 @@ def test_import_waterlevel_data(datamanager, mocker, qtbot):


def test_delete_waterlevel_data(datamanager, mocker, qtbot):
"""Test deleting water level datasets from the project."""
datamanager.show()

"""
Test deleting water level datasets from the project.
"""
datamanager.new_wldset_imported(
'wldset1', read_water_level_datafile(WLFILENAME))
datamanager.new_wldset_imported(
Expand Down Expand Up @@ -173,6 +177,48 @@ def test_delete_waterlevel_data(datamanager, mocker, qtbot):
assert mock_exec_.call_count == 2


def test_last_opened_datasets(qtbot, projectpath):
"""
Test that the data manager recall correctly the water level and weather
datasets that were last opened when opening a new project.

Cover the new feature added in PR #267.
"""
datamanager = DataManager(projet=ProjetReader(projectpath))
qtbot.addWidget(datamanager)
datamanager.show()

# Add some water level dataset.
for name in ['wldset1', 'wldset2', 'wldset3']:
datamanager.new_wldset_imported(
name, read_water_level_datafile(WLFILENAME))
assert datamanager.get_current_wldset().name == 'wldset3'

# Add some weather dataset.
for name in ['wxdset1', 'wxdset2', 'wxdset3']:
datamanager.new_wxdset_imported(name, WXDataFrame(WXFILENAME))
assert datamanager.get_current_wxdset().name == 'wxdset3'

# Change the current water level and weather datasets.
datamanager.set_current_wldset('wldset2')
assert datamanager.get_current_wldset().name == 'wldset2'
datamanager.set_current_wxdset('wxdset2')
assert datamanager.get_current_wxdset().name == 'wxdset2'

# Close the datamanager and its project.
datamanager.projet.close_projet()
datamanager.close()

# Create a new datamanager and assert that the last opened water level
# and weather datasets are remembered correctly.
datamanager2 = DataManager(projet=ProjetReader(projectpath))
qtbot.addWidget(datamanager2)
datamanager2.show()

assert datamanager2.get_current_wldset().name == 'wldset2'
assert datamanager2.get_current_wxdset().name == 'wxdset2'


# ---- Tests ExportWeatherButton
def test_export_yearly_monthly_daily(datamanager, mocker, qtbot, tmp_path):
"""
Expand Down