Skip to content

feat: os agnostic file existence check#459

Merged
jenhagg merged 1 commit intodevelopfrom
jon/ls
Apr 22, 2021
Merged

feat: os agnostic file existence check#459
jenhagg merged 1 commit intodevelopfrom
jon/ls

Conversation

@jenhagg
Copy link
Copy Markdown
Collaborator

@jenhagg jenhagg commented Apr 22, 2021

Purpose

Small chunk of work to support windows natively. This one splits the file existence check, (basically an ls command) into one for LocalDataAccess which is os independent, and the one for SSHDataAccess which remains unchanged.

What the code is doing

Split implementation from base class, and some related cleanup.

Testing

Ran through creating and preparing a scenario in a container, so we exercise the base functionality and local implementation. Again, the server use case is not changed.

Time estimate

5 min

@jenhagg jenhagg self-assigned this Apr 22, 2021
@jenhagg jenhagg added this to the Let the Sun Shine milestone Apr 22, 2021
@jenhagg jenhagg requested review from BainanXia and ahurli April 22, 2021 18:08
Comment on lines +59 to +65
def _exists(self, filepath):
"""Return whether the file exists

:param str filepath: the path to the file
:return: (*bool*) -- whether the file exists
"""
raise NotImplementedError
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume the reason we put this down here is for situations in the future, we have other classes that inherit DataAccess without overwriting _exists method?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's pretty much it. I'd say a couple related reasons are 1) make it so that self._exists is defined in the context we're referencing it (make editor diagnostics happy), and 2) it's a form of documentation, so you know what needs to be implemented in a subclass.

result = self._exists(filepath)
compare = operator.ne if should_exist else operator.eq
if compare(len(stderr.readlines()), 0):
if compare(result, True):
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is smart.

Copy link
Copy Markdown
Collaborator

@BainanXia BainanXia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

compare = operator.ne if should_exist else operator.eq
if compare(len(stderr.readlines()), 0):
if compare(result, True):
msg = "not found" if should_exist else "already exists"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jon-hagg I am reviewing some code and checked this if statement. As I understand, I enter the if statement if result == False which returns me the "already exists" error message in case should_exist==False and result== False not sure that is the expected behavior.
Also, why not simplifying this check, I had to bend my head :)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it's a bit head bending.. I figured it's worth it if the usage is clear externally (treating the function as a black box). In your example, if should_exist==False and result==False, then we'd have the compare operator set to == so it becomes if False == True, and we won't enter the if statement.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tested it just to make sure..

In [7]: from powersimdata.data_access.data_access import LocalDataAccess

In [8]: lda = LocalDataAccess()

In [9]: lda.root
Out[9]: '/Users/jonhagg/ScenarioData/'

In [10]: %ls /Users/jonhagg/ScenarioData/
ExecuteList.csv      ScenarioList.csv     old/                 test1.txt
ExecuteList.csv.bak  data/                raw/                 tmp/

In [11]: lda._check_file_exists('test1234.txt', should_exist=False)

In [12]: lda._check_file_exists('test1.txt', should_exist=True)

In [13]: lda._check_file_exists('test1.txt', should_exist=False)
---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
<ipython-input-13-78874ba83f1c> in <module>
----> 1 lda._check_file_exists('test1.txt', should_exist=False)

~/code/PowerSimData/powersimdata/data_access/data_access.py in _check_file_exists(self, path, should_exist)
    148         if compare(result, True):
    149             msg = "not found" if should_exist else "already exists"
--> 150             raise OSError(f"{path} {msg} on {self.description}")
    151
    152     def makedir(self, path):

OSError: test1.txt already exists on local machine

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. I did compare(result, should_exist) instead of compare(result, True) in my head.
Why not using:

        exist = self.fs.exists(path)
        if should_exist and not exist:
            raise OSError(f"{path} not found")
        if exist and not should_exist:
            raise OSError(f"{path} already exists")

It's easier to read.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that looks good, definitely more straightforward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants