Skip to content

Conversation

@stevenhua0320
Copy link
Contributor

Closes #4 @sbillinge Ready to review

@codecov
Copy link

codecov bot commented Oct 25, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (f454574) to head (03ae177).
⚠️ Report is 18 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##             main       #34       +/-   ##
============================================
+ Coverage   50.00%   100.00%   +50.00%     
============================================
  Files           2         3        +1     
  Lines          18        48       +30     
============================================
+ Hits            9        48       +39     
+ Misses          9         0        -9     
Files with missing lines Coverage Δ
tests/conftest.py 100.00% <100.00%> (+64.28%) ⬆️
tests/test_load_image.py 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

@stevenhua0320 I can't see the tests for this. I guess that you started by writing a test, which is our workflow, right? :)

you can work with @zmx27 to get help with this, but

  1. there is a tif file in docs/examples/data (actually, that is where it should be)
  2. in conftest.py, copy this into the user_filesystem soemwhere
  3. use this fixture in test to try the different scenarios (directory is cwd, directory is absolute path, directory is relative path0

@stevenhua0320
Copy link
Contributor Author

@stevenhua0320 I can't see the tests for this. I guess that you started by writing a test, which is our workflow, right? :)

you can work with @zmx27 to get help with this, but

  1. there is a tif file in docs/examples/data (actually, that is where it should be)
  2. in conftest.py, copy this into the user_filesystem soemwhere
  3. use this fixture in test to try the different scenarios (directory is cwd, directory is absolute path, directory is relative path0

Actually I have tested with these scenarios on my local machine and they generated the correct matrix of that same tif file. But, you are right. It is more rigorous to write a test here.

@sbillinge
Copy link
Contributor

Actually I have tested with these scenarios on my local machine and they generated the correct matrix of that same tif file. But, you are right. It is more rigorous to write a test here.

yes, this is our workflow. Agree on the test. Only then write the function. The test captures the behavior we want (so in this case, three different successful cases). We can also think about how to handle unsuccessful cases. Probably give a helpful error message for FileNotFound or whatever. The error messages all have the form "what happened. What to do to fix it", so here it would be something like f"The file {file_path} cannot be found. Please rerun specifying a valid filename". There may also be an error reading the file, which would fail in a different way and require a different error message. We put "failures" in a different test.

@stevenhua0320
Copy link
Contributor Author

@sbillinge I'm designing for the test, right now it works well

Please rerun specifying a valid filename

Got the idea, in the original function, it has the FileNotFoundError and gives the error message. I'm still working on the good cases and also I have some ideas that how we gonna test the bad case. We probably can specify a file that is nowhere in the system (ex:nonexistent_file.tif) and let the function to find it. The desired matrix it should give is a matrix full of 0 as described in the original function. I'm still working on those test cases.

@sbillinge
Copy link
Contributor

that's the right idea.

We would usually build the desired user-filesystem as a fixture in conftest.py. In this way it can be reused across different tests. Take a look in diffpy.labpdfproc or diffpy.cmi to see examples.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

Se comments

cwd_dir = base_dir / "cwd_dir"
cwd_dir.mkdir(parents=True, exist_ok=True)
test_dir = base_dir / "test_dir"
for d in (input_dir, home_dir, test_dir):
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't use a single letter for the iterator. Always choose to make it more readable... E.g., for dir in (

I am not sure if you used an LLM for help. OK if you did, but try and work hard to bring the code up to group standards before pushing. It is really really tedious reviewing code from chatgpt....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, that is my habit of indexing object when writing for loops. I should stop this formatting and follow more readable format.

def example_tif():
"""Locate the example TIFF file relative to repo root."""
tif_path = Path("../docs/examples/KFe2As2-00838.tif").resolve()
if not tif_path.exists():
Copy link
Contributor

Choose a reason for hiding this comment

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

Ooooh, don't be doing that. We want tests to fail of something is wrong

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will delete this in the next PR.

return LoadImage(cfg)


# ----------------------------------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

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

Please remove all these comment blocks

# LoadImage test setup
# ----------------------------------------------------------------------
@pytest.fixture(scope="module")
def example_tif():
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't need a fixture for htis. Just copy the file over as you build the filesystem above.

return tif_path


@pytest.fixture(scope="module")
Copy link
Contributor

Choose a reason for hiding this comment

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

i am not sure what this is doing but it doesn't seem appropriate to be building a fixture using one of hte functions that we will be testing. Just delete this.

As a heads-up, we don't do any testing in conftest.py we just build fixtures.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, you mean we need to create a new test_loadimage.py and do all the tests there? If yes then I migrate the test to there.

return loader.loadImage(example_tif)


@pytest.fixture
Copy link
Contributor

Choose a reason for hiding this comment

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

see above, this should also be deleted.

# Unified test
# ----------------------------------------------------------------------


Copy link
Contributor

Choose a reason for hiding this comment

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

use pytest.mark.parametrize for the different cases. Please see examples in diffpy.cmi etc.

):
home_dir = user_filesystem["home"]
test_dir = user_filesystem["test"]
monkeypatch.setenv("HOME", str(home_dir))
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't use monkeypatch but we use pytest mock if it is needed.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

please see comments.

@stevenhua0320
Copy link
Contributor Author

stevenhua0320 commented Oct 26, 2025

please see comments.

I have seen it and I'm currently making edits so that it would follow group's standard.
@sbillinge Really sorry professor I found I'm not so familiar with the use of how Pathlib actually works. It takes me a long time to think about the structure of the tree of files. Maybe still I need to refine the test if it is necessary. For the reason I can only make tags in the pytest.mark.parametrize is because in the case of absolute path, it must first go to its parent to mock to create the folder. That's why it cannot cluster the case of relative path and non-existance path together to make the same workflow of testing as far as I learned.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

pls see comments

return image_loader.loadImage(tif_path)


def build_loadimage_path(case_tag, home_dir):
Copy link
Contributor

Choose a reason for hiding this comment

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

your test seems to have logic in it, but we don't really want that. the purpose of the tests is to encode behavior and then test logic in the function. The tests just have to capture behavior. please see below.



load_image_param = load_image_params = [
("abs", PROJECT_ROOT / "docs/examples/KFe2As2-00838.tif"),
Copy link
Contributor

Choose a reason for hiding this comment

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

this is where we capture the behavior. Please see the other projects for examples, but we want first a comment, e.g.

# case 1: just filename of file in current directory. expect function loads tiff file from cwd

then the paramaterize looks something like (input, output). In this case the input would be "KFe2As2-00838.tif" and the output would assert something that assures us that the file was correctly read.

Then similarly for case 2 # case 2: absolute file path to file in another directory. expect file is found and correctly read
and case 3 would be the relative path.

the test would look soething like

@pytest.mark.parametrize("input, expected")
def test_load_image_cases(input, expected, , user_filesystem):
    copy the test tiff to home_dir
    copy the test tiff to test_dir    # these two lines could be done in conftest.py if we want
    cd to home_dir
    actual = load_image(input)
    some asserts that compare actual and expected things.

@stevenhua0320
Copy link
Contributor Author

stevenhua0320 commented Oct 26, 2025

@sbillinge Professor Simon, If there is anything I could modify in the test file please give me more feedback and I would continue to change it.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

the cases captured in the comments are now good, except Case 4 which I think should result in a crash, but the code needs some tlc. Please could you reach out to @zmx27 and work together on the implementation?

@stevenhua0320
Copy link
Contributor Author

stevenhua0320 commented Oct 26, 2025

the cases captured in the comments are now good, except Case 4 which I think should result in a crash, but the code needs some tlc. Please could you reach out to @zmx27 and work together on the implementation?

OK,actually in Case 4 in the implementation it would return the message like "file {filename} not found, please type in correct file name..." something like that and then return nothing. That's why in the test cases I check the datatype of what loadimage would return. I would reach out to Zhiming @zmx27 to see whether the implementation of loadimage needs further update.

@sbillinge
Copy link
Contributor

the cases captured in the comments are now good, except Case 4 which I think should result in a crash, but the code needs some tlc. Please could you reach out to @zmx27 and work together on the implementation?

OK,actually in Case 4 in the implementation it would return the message like "file {filename} not found, please type in correct file name..." something like that and then return nothing. That's why in the test cases I check the datatype of what loadimage would return. I would reach out to Zhiming @zmx27 to see whether the implementation of loadimage needs further update.

yes, I know that was your intent with case 4. I would rather that the users get that message but in a crash. In that case it would be in the test_function_bad. The next step is to make a clean PR from main with just the tests in it and no edits to loadimage. Then we can work on loadimage, but it is safer if we don't use any of the edits that were done in the past before the tests. We don't need to check the datatype of what loadimage returns I think, in this PR. EIther it can read a valid file or it can't and will crash.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

Good progress. Still some things in the wrong direction.

We do not need ‎tests/cwd/example.tiff, ‎tests/home/example.tiff, or ‎tests/test/example.tiff so please delete these. We will make a clean PR later so we don't add and remove these files, but for now, please delete.

)()
loader = LoadImage(cfg)

if expected:
Copy link
Contributor

Choose a reason for hiding this comment

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

don't have logic in your test

@pytest.mark.parametrize("input_path, expected", load_image_param)
def test_load_image_cases(input_path, expected, user_filesystem):
base_dir, home_dir, cwd_dir, test_dir = user_filesystem
test_file_dir = Path(__file__).parent
Copy link
Contributor

Choose a reason for hiding this comment

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

you seem to be working not in tmpdir, so don't be using test_file_dir in the tests. In fact don't even create this directory.

We will create all the directories we need in tmp_dir. Actually, we already have them, they are passed in from user_filesystem.

so we will move to cwd:

os.chdir(cwd_dir)

and we need to move our example file from docs/examples to the different places we will use it. So something like

source_dir = Path(__file__).parent / "docs" / "examples" / "data"
shutil.copy(source_dir / "example.tiff", test_dir) 
shutil.copy(source_dir / "example.tiff", .)

So we have an example tiff in cwd_dir (which is also the current working directory because we cd'd there) and also in ../test_dir.
After this we are fully working in the tempdir that will be built up before every test and removed after every test automatically.

Then we run as

actual_image = load_image(input_path)
assert something_about_actual_image == expected

we can decide different things to assert. That the shape is right, the total integrated intensity, and so on.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Professor, you are right. Now I learned how to deal with the conftest for user_system and now it would not create additional files in the step of copying as it is in a tmp_path. I also edited the testing here to both handle good case and bad case without using logic here. I would commit a new PR not introducing additional example.tiff in directory immediately.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

Still a bit more to go. We are testing relative paths but not absolute. Also, please see comments

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

please see comments.

**Fixed:**

* <news item>
* Fixed `loadimage` function in any directory.
Copy link
Contributor

Choose a reason for hiding this comment

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

load_image() function correctly finds files when passed a relative path

pic = np.array(pic[::-1, :])
return pic

def loadImage(self, filename):
Copy link
Contributor

Choose a reason for hiding this comment

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

let's make the function have a pep8 compliant name. We may as well fix these when we touch the function.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

pls see comments

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

pls see comments

stevenhua0320 and others added 2 commits October 31, 2025 14:41
Updated expected values for image loading tests and corrected the source file path.
Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

I edited the file to show what I had in mind. It is breaking the test now for sure but hopefully this gives you the idea.

@sbillinge
Copy link
Contributor

btw, I would like to get rid of the cfg clause too. We should decide what we want the function to do explicitly and then test that, so we don't want to put logic in the test that makes the function pass.

@stevenhua0320
Copy link
Contributor Author

btw, I would like to get rid of the cfg clause too. We should decide what we want the function to do explicitly and then test that, so we don't want to put logic in the test that makes the function pass.

Got the idea, I would integrate the hard-coded one for the first and last point of example tiff file, change it to the data directory, and try to eliminate the cfg clause and make another PR soon.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

ok, good progress, we are getting there.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

pls see comments

import os
import shutil
from pathlib import Path
from unittest.mock import Mock
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't ever use unittest.mock, we use pytest.mock, but as discussed below, I don't think we should be mocking anything here.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

Few more questions on the function now. Can you suggest how we want it to handle flipping?

image = np.load(filenamefull)
else:
image = open_image(
str(filenamefull)
Copy link
Contributor

Choose a reason for hiding this comment

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

Per the conversation above, didn't we want to remove this str? That was my point actually

except FileNotFoundError:
time.sleep(0.5)

image = self.flip_image(image)
Copy link
Contributor

Choose a reason for hiding this comment

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

Per conversation above, move this or of the function, or allow flipping as optional inputs.

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.

Cant load files not in the running directory

2 participants