Nieuws:

Welkom, Gast. Alsjeblieft inloggen of registreren.
Heb je de activerings-mail niet ontvangen?

Auteur Topic: [opgelost] Python line completion  (gelezen 1346 keer)

Offline MKe

  • Lid
[opgelost] Python line completion
« Gepost op: 2010/03/09, 11:53:57 »
Hoi,

Ik wil in mijn python scriptje graag een bash-commando kunnen invoeren zoals in de normale terminal die dan uitgevoerd wordt. Nou is dat nog niet zo'n probleem, maar ik zou er ook graag tab-completion bij willen gebruiken die net zo functioneert als in de terminal.

Een voorbeeld van een scriptje:
#!/usr/bin/env python

import os
import readline

def raw_default(prompt, value=''):
   #raw_input vervanging, met mogelijke default waarde en functionerend
   #pijltjes toetsen
   readline.set_startup_hook(lambda:
   readline.insert_text(value))
   try:
      new_value = raw_input(prompt)
   finally:
      readline.set_startup_hook(None)
      return new_value

#hier de interactie met de gebruiker
while True:
   #gebruikt nieuwe bovenstaande functie als raw_input vervanger
   inp=raw_default('geef commando:')
   #Niets invoeren stopt het script
   #anders wordt het uitgevoerd
   if inp=='':
      break
   else:
      os.system(inp) #uitvoeren

print 'end'
de historie werkt hierin, pijl naar boven geeft het vorige ingevoerde commando etc. Maar completion niet. Ik weet dat module readline het wel ondersteund, maar alleen op een al bekende list van gegevens.
Wat ik graag wil is dat het precies zo werkt als in de teminal, dus completering van filenamen en bash commando's, dus die gegevens zouden ergens vandaan gehaald moeten worden. Heeft iemand een idee hoe ik dat kan bewerkstelligen?
« Laatst bewerkt op: 2010/03/21, 20:35:10 door MKe »
Mijn blokkendoos blog: http://mke21.wordpress.com/

Offline MKe

  • Lid
Re: Python line completion
« Reactie #1 Gepost op: 2010/03/09, 12:44:14 »
Ik ben iets verder. Ik heb de functie
readline.parse_and_bind('tab: complete') toegevoegd aan de raw_default functie en nu kan hij wel path-namen aanvullen. Het lukt nog niet met de commando's.

Re: Python line completion
« Reactie #2 Gepost op: 2010/03/09, 17:40:04 »
[Ik] zou er ook graag tab-completion bij willen gebruiken die net zo functioneert als in de terminal.

Mag ik vragen waarom je iets wat in bash al perfect functioneert (nl. tab-completion) wilt namaken, behalve voor leerdoeleinden dan misschien, en voor wat je dat zou willen leren?

Je zal
1) de omgevingsvariabele PATH moeten ophalen
2) deze splitsen in de verschillende mappen (splitsen op ':')
3) in al deze mappen voor uitvoerbare bestanden zoeken en deze in een lijst zetten
4) in deze lijst zoeken voor tab-completion.

- SeySayux
I use a Unix-based system, that means I'll get laid as often as I have to reboot.
LibSylph
SeySayux.net

Offline MKe

  • Lid
Re: Python line completion
« Reactie #3 Gepost op: 2010/03/09, 21:20:03 »
[Ik] zou er ook graag tab-completion bij willen gebruiken die net zo functioneert als in de terminal.

Mag ik vragen waarom je iets wat in bash al perfect functioneert (nl. tab-completion) wilt namaken, behalve voor leerdoeleinden dan misschien, en voor wat je dat zou willen leren?

Je zal
1) de omgevingsvariabele PATH moeten ophalen
2) deze splitsen in de verschillende mappen (splitsen op ':')
3) in al deze mappen voor uitvoerbare bestanden zoeken en deze in een lijst zetten
4) in deze lijst zoeken voor tab-completion.

- SeySayux
Bedankt, ik zal het in die richting proberen.
Als antwoord op je vraag: het heeft een 2-ledig doel.
1. leren: Ik ben aan het oefenen met python en probeer daarbij meteen wat meer kennis van Linux op te doen
2. Het progje is bedoeld om een omgeving te creëren voor het bouwen van variabele queues. Ik bedoel hierbij een serie van reken-intensieve algoritmes/programma's die op data moeten worden uitgevoerd zonder dat daarvoor scripts geschreven hoeven worden. De inhoud van de queues kan hierbij per data-set aangepast worden. Serieel en/of parallel uitvoeren van de processen wordt door de omgeving geregeld. Tijdens het runnen van de queue moet het mogelijk zijn om commando's uit te proberen alsof je in bash zit en ook stappen aan de queue toe te voegen.

Offline MKe

  • Lid
Re: Python line completion
« Reactie #4 Gepost op: 2010/03/21, 20:34:34 »
Hoi,

Ik heb het inmiddels opgelost en het is best wel wat code geworden. Voor diegene die hierin ook geïnteresseerd zijn heb ik hieronde mijn completer class gezet:
#!/usr/bin/env python
import readline
import glob

n='_' #prefix voor programma-eigen commando's

#class voor readline completion:
class completer():
   def complete(self, text, index):
      '''Geeft de volgende mogelijke aanvulling.
      De functie wordt aangeroepen met index=0,1,2 etc.
      Telkens wordt er een match gereturned met als laatste waarde None
      Dit is het signaal voor readline om te stoppen.
      '''
      if index == 0:              # Alleen uitvoeren bij de eerste aanroep
         self.matches = []
         start = readline.get_begidx(); pos = 0
         #Het eerste woord is altijd een commando (bash of programma-eigen)
         #Dus als cursor in het eerste woord dan
         if start == 0:                     
            findmode = 'ex' #het is een commando
         else:               # Bij event. spaties aan het begin, dan juiste start vinden.
            for i, char in enumerate(readline.get_line_buffer()):
               if char not in [" "]:
                  pos = i; break
            if start == pos:
               findmode = 'ex'
            else:
               findmode = 'file'       # else file mode
         #
         if findmode == 'ex':
            #alle 'eigen' commando's beginnen met  een prefix die is opgeslagen in variabele n
            if text[0]==n: #als beginletter gelijk aan n, dan is het eigen commando               
               self.matches=self.shell(text)
            elif text[0:2]=='./': #uitvoern executable, niet in PATH
               self.matches=self.doc(self,text[2:])
            else: #executable uit PATH
               self.matches=self.bash(text)
         else: # file
            self.matches=self.doc(text)
      try:
         return self.matches[index]
      except IndexError:
         return None
      except Exception, why:
         print '\nps_completer err:', str(why)
         return None
   #eigen commando'a aanvullen
   def shell(self,text):
      global commands
      keys=commands.keys()
      keys.sort()
      matches=[]
      for k in keys:
         if k.startswith(text):
            matches+=[k]
      return matches
   #commando's (eerste positie) aanvullen
   def bash(self,text):
      ret=[]     
      if os.environ.has_key('PATH'):
         for folder in os.environ['PATH'].split(os.pathsep):
            matches =glob.glob(os.path.join(folder, text) + '*')
            #print matches
            for match in matches:
               if os.access(os.path.expanduser(match),os.X_OK):
                  ret += [os.path.basename(match)]
      else:   ret += glob.glob(text + '*')
      return ret
   def doc(self,text):
      #Aanvullen files en directories
      ret=[]
      matches = glob.glob(os.path.expanduser(text) + '*')
      for match in matches:
         if os.path.isdir(match): match = match + '/'
         ret += [match]
      return ret

#Tab completion instellen en
#readline instellen op nieuwe completer
readline.parse_and_bind("tab: complete")
readline.set_completer_delims('\r\n`~!@#$%^&*()-=+[{]}\|;:\'",<>? ')
readline.set_completer(ps_completer().complete)

#hier de interactie met de gebruiker
while True:
   #gebruikt nieuwe bovenstaande functie als raw_input vervanger
   inp=raw_input('geef commando:')
   #Niets invoeren stopt het script
   #anders wordt het uitgevoerd
   if inp=='':
      break
   elif inp[0]=n:
      pass #eigen code om prog-eigen commando's uit te voeren
   else:
      os.system(inp) #uitvoeren van systeem commando
Dit werkt best goed. Ik heb nog niet de moeite genomen om bij ./ alleen uitvoerbare scripts te zoeken, maar dit is voor mij goed genoeg.