jupyter-c-kernel icon indicating copy to clipboard operation
jupyter-c-kernel copied to clipboard

Allow to read from stdin

Open brendan-rius opened this issue 8 years ago • 13 comments

So it is possible to use functions like scanf.

Thanks to @ryukinix for letting me know about this enhancement.

brendan-rius avatar Apr 19 '16 02:04 brendan-rius

Could you give an example of scanf? I get an unassigned value. It's a great project, much appreciated. If possible it would be useful to have a more extensive example notebook.

sdd3 avatar Apr 29 '16 13:04 sdd3

Unfortunately that is not implemented yet, @sdd3. Input functions doesn't works yet. The proposal is a behavior for input functions like the default python kernel related behavior, communicating with the jupyter frontend. Like this:

captura de tela de 2016-04-29 10 31 59

ryukinix avatar Apr 29 '16 13:04 ryukinix

Ah, ok. I misunderstood the first post in this thread. Thanks for clearing that up. Any idea when an input function might be incorporated?

sdd3 avatar Apr 29 '16 13:04 sdd3

I'm trying to implement this, but I'm a little stuck: My idea is to override all fgets calls with my_fgets using a macro. This my_fgets in master.c notifies its parent (subprocess.Popen in kernel.py) somehow to send an input_request through stdin_socket. When input_reply is received from the frontend the data is piped to the stdin of subprocess.

I managed to request and receive input from the frontend as such, which works just fine:

 def _raw_input(self, prompt, ident, parent):
          # Flush output before making the request.
          sys.stderr.flush()
          sys.stdout.flush()

          # Send the input request.
          content = dict(prompt=prompt)
          msg = self.session.send(self.stdin_socket, u'input_request', content, parent, ident=ident)

          # Await a response.
          ident,reply = self.session.recv(self.stdin_socket, 0)
          try:
              value = reply['content']['value']
          except:
              self.log.error("Got bad raw_input reply: %s"%Message(parent))
              value = ''
          return value

    def execute_request(self, stream, ident, parent):
        ''' Wrap execture_request function to force input call '''
        value = self._raw_input('Some info:', ident, parent)
        self.log.warn('Value: {}'.format(value))
        super(CKernel, self).execute_request(stream, ident, parent)

Questions

I cannot find or decide on a mechanism to notify from master.c to Python subprocess instance that input is requested:

  • Is there anybody with an opinion or a better suggestion than:
    • Using zmq sockets directly from master.c?
    • Introducing new messaging system between master.c and kernel.py?
    • Piping some predefined message through stderr/stdout?
  • I looked into raising signals SIGTTIN and SIGTTOU (good blog), but they appear to be used from parent-to-child and I want from child to parent.

spoorcc avatar Apr 13 '17 15:04 spoorcc

Ok I'm 1 step further, (for at least a POSIX solution, sorry windows guys :stuck_out_tongue: ).

From master.c I raise SIGTTIN to the parent process as such, and in contrary to the name kill the c process will continue just fine.

kill(getppid(), SIGTTIN); 

I have chosen SIGTTIN because people might want to use SIGUSR1 and SIGUSR2 in notebooks.

From within kernel.py I can catch this as such:

        def sig_forwarder(a,b):
             self.log.warn('Caught SIGTTIN from C')

         signal.signal(signal.SIGTTIN, sig_forwarder)
         p = self.create_jupyter_subprocess([self.master_path, binary_file.name])
         while p.poll() is None:
             p.write_contents()
         p.write_contents()
         signal.signal(signal.SIGTTIN, signal.SIG_DFL)

spoorcc avatar Apr 14 '17 08:04 spoorcc

Is there any alternative for reading inputs using scanf?

matheusmota avatar Jul 12 '17 00:07 matheusmota

I chose fgets to be safe in the implementation I am/was working on.

For reference see: https://stackoverflow.com/a/3302594

Sent from my OnePlus ONEPLUS A5000 using FastHub

spoorcc avatar Jul 26 '17 11:07 spoorcc

It can be done as following:

#include<stdio.h>
#include<string.h>

int max2i(int x, int y);
char *input_string="25,67";  //<-----input value

int main()
{
    int a,b,c;
    printf("input 2 integer numbers:");
    sscanf(input_string, "%d,%d", &a, &b);  //<------use sscanf instead of scanf
    c=max2i(a,b);
    printf("max value of (%d,%d) is %d\n", a,b,c);
    return 0;
}
int max2i(int x,int y)
{
    if(x>y)
        return x;
    else
        return y;
}

masterfish2015 avatar Jun 16 '18 07:06 masterfish2015

The @masterfish2015 solution didn't work for me with Jupyter 4.4.0 and Notebook 5.5.0, neither from Firefox or Chrome.

LucaCerina avatar Sep 03 '18 09:09 LucaCerina

A fork of this project but realize the input from the tab

Just like this Pic1 Pic2

I am happy that I have found a version that can use the scanf and it works fine in jupyter notebook 6.1.5 .

Zoupers avatar Nov 08 '20 13:11 Zoupers

Alse, I have found a repo from a university that can help us using comment to replace the real input.

Here is the repo

Zoupers avatar Nov 08 '20 13:11 Zoupers

That's pretty cool workaround!

Cordialmente, Manoel Vilela.

Em sáb., 12 de ago. de 2023 00:16, つき 滝猫 @.***> escreveu:

The cool thing is, just print the <inputRequest> before trying to input any thing

For example:

int x;printf("<inputRequest"); //It will prompt for a dialogue helping user to get the inputscanf("%d", &x);printf("%d", x);

— Reply to this email directly, view it on GitHub https://github.com/brendan-rius/jupyter-c-kernel/issues/3#issuecomment-1675650848, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB2J57T6RJMP6WNQ7A6T47TXU3YSVANCNFSM4CBJHSIQ . You are receiving this because you were mentioned.Message ID: @.***>

ryukinix avatar Aug 12 '23 14:08 ryukinix

That's pretty cool workaround! Cordialmente, Manoel Vilela. Em sáb., 12 de ago. de 2023 00:16, つき 滝猫 @.> escreveu: The cool thing is, just print the <inputRequest> before trying to input any thing For example: int x;printf("<inputRequest"); //It will prompt for a dialogue helping user to get the inputscanf("%d", &x);printf("%d", x); — Reply to this email directly, view it on GitHub <#3 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AB2J57T6RJMP6WNQ7A6T47TXU3YSVANCNFSM4CBJHSIQ . You are receiving this because you were mentioned.Message ID: @.>

Ah, this was my comment. I had removed because of this problem:

Once you use the <inputRequest>, you'll also know that the HTML tag is unstable, and it can be redefined by the Jupyter developers. Also, it method leaks the input stream. It is very dangerous when you deployed Jupyter Hub for your campus/lab/enterprise. (Recommendation from IBM)

To solve this, write a header file and force #include it into the source .cpp file. But its security effects are considered.

You can see my C++ header file in my C++ kernel for Jupyter project:

https://github.com/takinekotfs/jupyter-cpp-kernel/blob/master/jupyter-cpp-kernel/resources/gcpph.hpp

shiroinekotfs avatar Aug 14 '23 07:08 shiroinekotfs