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

QWatson doesn't save its state correctly when stopping the current activity. #52

Closed
jnsebgosselin opened this issue Jul 13, 2018 · 3 comments
Assignees
Labels
severity:2-Major type: bug Something isn't working
Milestone

Comments

@jnsebgosselin
Copy link
Owner

QWatson version 0.3.0

  • Starts an activity in QWatson
  • Then, change the project, tags or comment (so that a watson.save is triggered).
  • Stop and close QWatson.
  • Restart QWatson

QWatson indicates that it was not closed correctly :

image

@jnsebgosselin jnsebgosselin added the type: bug Something isn't working label Jul 13, 2018
@jnsebgosselin jnsebgosselin added this to the 0.3.1 milestone Jul 13, 2018
@jnsebgosselin jnsebgosselin self-assigned this Jul 13, 2018
@jnsebgosselin
Copy link
Owner Author

This bug is caused because the Watson object is built to be used in a CLI, where Watson is continuously reinitialized, and so the private attribute Watson._old_state is continuously reinitialized to None and its value subsequently set to that of the state file every time a command is done in the CLI.

In QWatson, the Watson object is instantiated only once and the Watson instance lives in the event loop as long as QWatson is not closed. Therefore, the Watson._old_state private attribute is never reinitialized to None and is thus never updated. It's value is set only once when starting QWatson to the value of the state file.

Therefore, if when starting QWatson, the state file is empty ({}), the value of the Watson._old_state will be set to {}. When starting an activity and then doing a Watson.save, the state file will be correctly updated because Watson._current != Watson._old_state`.

When stopping the current activity, the Watson._current value will be set to {}. When subsequently calling Watson.save, the state file won't be updated because both Watson._current and Watson._old_state equal {}.

When restarting QWatson, the state file won't be empty and therefore, Watson.is_running will be True even if the activity was actually stopped.

So I think that Watson._old_state must be set to Watson._current every time the state file is saved.

def save(self):
    """
    Save the state in the appropriate files. Create them if necessary.
    """
    try:
        if not os.path.isdir(self._dir):
            os.makedirs(self._dir)

        if self._current is not None and self._old_state != self._current:
            if self.is_started:
                current = {
                    'project': self.current['project'],
                    'start': self._format_date(self.current['start']),
                    'tags': self.current['tags'],
                    'message': self.current.get('message'),
                }
            else:
                current = {}

            safe_save(self.state_file, make_json_writer(lambda: current))
            # self._old_state = current

        if self._frames is not None and self._frames.changed:
            safe_save(self.frames_file,
                      make_json_writer(self.frames.dump))

        if self._config_changed:
            safe_save(self.config_file, self.config.write)

        if self._last_sync is not None:
            safe_save(self.last_sync_file,
                      make_json_writer(self._format_date, self.last_sync))
    except OSError as e:
        raise WatsonError(
            "Impossible to write {}: {}".format(e.filename, e)
        )

@jnsebgosselin
Copy link
Owner Author

jnsebgosselin commented Jul 13, 2018

Here is an example to reproduce the problem:

import os.path as osp
import os
from watson.watson import Watson

watson = Watson()

# We remove the state file if it exists:

if osp.exists(watson.state_file):
    os.remove(watson.state_file)

print('Watson is started =', watson.is_started)
print(watson._old_state, watson._current, end='\n\n')

# When starting Watson, the content of the state file is updated to
# that of Watson._current:

print('Starting Watson.')
watson.start('test')
print("Saving 'sate' file =", watson._old_state != watson._current)
print(watson._old_state, watson._current)
watson.save()
print(watson._load_json_file(watson.state_file), end='\n\n')

# When stopping, the content of the state file is not updated because
# both Watson._old_state and Watson._current equal {}:

print('Stoping Watson.')
watson.stop()
print("Saving 'sate' file =", watson._old_state != watson._current)
print(watson._old_state, watson._current)
watson.save()
print(watson._load_json_file(watson.state_file), end='\n\n')

# So when we re-initialized Watson, the Watson._current is initialized from the
# content of the state file. Therefore Watson.is_started return True, but it should return False:

print('Reinitializing Watson.')
watson = Watson()
print('Watson is started =', watson.is_started)
print(watson._old_state, watson._current)

This results in :

Watson is started = False
{} {}

Starting Watson.
Saving 'sate' file = True
{} {'project': 'test', 'start': <Arrow [2018-07-13T14:50:19.818903-04:00]>, 'tags': [], 'message': None}
{'project': 'test', 'start': 1531507819, 'tags': [], 'message': None}

Stoping Watson.
Saving 'sate' file = False
{} {}
{'project': 'test', 'start': 1531507819, 'tags': [], 'message': None}

Reinitializing Watson.
Watson is started = True
{'project': 'test', 'start': <Arrow [2018-07-13T14:50:19-04:00]>, 'tags': [], 'message': None} {'project': 'test', 'start': <Arrow [2018-07-13T14:50:19-04:00]>, 'tags': [], 'message': None}

@jnsebgosselin
Copy link
Owner Author

Reported this issue upstream in jazzband/Watson#213

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
severity:2-Major type: bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant