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

Allow to read from stdin #3

Open
brendan-rius opened this Issue Apr 19, 2016 · 9 comments

Comments

Projects
None yet
7 participants
@brendan-rius
Owner

brendan-rius commented Apr 19, 2016

So it is possible to use functions like scanf.

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

@sdd3

This comment has been minimized.

sdd3 commented Apr 29, 2016

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.

@ryukinix

This comment has been minimized.

Contributor

ryukinix commented Apr 29, 2016

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

@sdd3

This comment has been minimized.

sdd3 commented Apr 29, 2016

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

@spoorcc

This comment has been minimized.

spoorcc commented Apr 13, 2017

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

This comment has been minimized.

spoorcc commented Apr 14, 2017

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

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)
@matheusmota

This comment has been minimized.

matheusmota commented Jul 12, 2017

Is there any alternative for reading inputs using scanf?

@spoorcc

This comment has been minimized.

spoorcc commented Jul 26, 2017

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

@masterfish2015

This comment has been minimized.

masterfish2015 commented Jun 16, 2018

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;
}
@LucaCerina

This comment has been minimized.

LucaCerina commented Sep 3, 2018

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

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