3
$\begingroup$

CONTEXT:

Hello,

I have 2 notebooks, lets call them "Main.nb" and "FileProcessing.nb". In my "Main.nb" I have a Do loop where the iterating parameter goes over 300 .csv files which I want to process. I wrote the code for the processing into the "FileProcessing.nb".

However not every .csv file is in the right format - e.g. sometimes something is missing, hence the file is too short. I wrote tests into the "FileProcessing.nb", so as it is evaluating it can at several moments discover problems (= a test return False). In such case I want to stop evaluating the "FileProcessing.nb" and continue the Do loop in "Main.nb" with next value of the parameter.

QUESTION:

Is there a way, how can I at several points in the "Fileprocessing.nb" decide if I want to proceed or to stop and continue in the Do loop in "Main.nb"?

TOY PROBLEM:

I have the "Main.nb" and "FileProcessing.nb" in the same folder. The "Main.nb" contains

dir = SetDirectory[NotebookDirectory[]]

Table[
 NotebookEvaluate[FileNameJoin[{dir, "FileProcessing.nb"}]],
 {filenumber, 4}
]

and the "FileProcessing.nb" contains

Print["Hello world! ", 100 + filenumber]

Return["Succesfully returned."]

If[
 filenumber < 3,
 Print["Test OK."],
 Print["Too big."]; Return["Stopped."]
 ]

Print["Hallo Welt! ", 100 + filenumber, "\n"]

There is Return on the second line, so rest of the code does not evaluate. It prints fourtimes "Hello world!" with number (101-104) in the "Main.nb" and returns table with fourtimes "Succesfully returned.".

As far, it behaves as I expected. It is "the proof" that Return[] works. However, I want to return only if something "bad" happends (= a test returns False). So if you remove the second line Return["Succesfully returned."], then there is Return inside If. The idea is that if the test filenumber < 3 is false, the rest of the notebook content should not be evaluated. But Return inside If means in fact something different. It does not return from the whole notebook, but only from the If statement and the rest of the code is always executed.

When I realised that, I tried to wrap NotebookEvaluate in Catch and instead of Return use Throw, but it does not work. It gives the following error

Throw::nocatch: Uncaught Throw[Stopped.] returned to top level.

Then I found in "NotebookEvaluate" documentation page that "The cells of the notebook are evaluated in a dialog subsession.", but I have not been able to use this information to my advantage...

PS: I use version 11.3 and at home (where I write this question) I have 12.1.

I would be very grateful for any help and guidance.

$\endgroup$
1
  • $\begingroup$ Is it important for you to have the code in FileProcessing.nb in a notbook? The preferred way to handle such a situation would be to turn the code in FileProcessing.nb into a function, put the definitions for that function into a package file "FileProcessing.m", load that package, call the function from it in the loop instead of NotebookEvaluate. That would make it much more straightforward to achieve what you want... $\endgroup$ Apr 24, 2022 at 19:56

1 Answer 1

2
$\begingroup$

This looks like a good place to use Throw and Catch. Try this FileProcessing.nb :

Print["Hello world! ", 100 + filenumber]

(*Return["Succesfully returned."]*)

Return[Catch[

  If[filenumber < 3,
    Print["Test OK."]; Throw["Success."],
    Print["Too big."]; Throw["Failed."]
   ];

  Print["Hallo Welt! ", 100 + filenumber, "\n"]

 ]]

The result in Main.nb is

Hello world! 101
Test OK.

Hello world! 102
Test OK.

Hello world! 103
Too big.

Hello world! 104
Too big.

{"Success.", "Success.", "Failed.", "Failed."}

Importantly, Throw stops evaluation and returns its argument to the nearest Catch, so you may not want to Throw["Success"] until after all of your If statements.

$\endgroup$
4
  • $\begingroup$ Your answer brings something I have not thought myself, thank you. However it does not solve completely my problem: The If statement should determine if the rest of the code should be evaluated or not. $\endgroup$
    – Ruze11
    Apr 24, 2022 at 11:24
  • $\begingroup$ The last line Print["Hallo Welt! ", 100 + filenumber, "\n"] is currently a placeholder for more code (but with your solution never evaluated) in which I may want to use similar If statement again. $\endgroup$
    – Ruze11
    Apr 24, 2022 at 11:30
  • $\begingroup$ @Ruze11 Yes, in this example the placeholder code is never executed. But, I thought that was addressed in the last paragraph of the answer. You would remove the Throw["Success."] from the first If and put it after all of the similar If statements. Or, am I still missing something? Perhaps I should move the Throw["Success."] to after the "Hallo Welt". Would that be a more complete solution? $\endgroup$
    – LouisB
    Apr 24, 2022 at 16:01
  • $\begingroup$ My problem is that everything has to be enclosed in Return. I don't want to have all code in one cell - the code is quite long and I still want to evaluate individual cells if I need. Basically I want to define "big function" that is not in one cell. $\endgroup$
    – Ruze11
    Apr 25, 2022 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.