News

Aggiornamento del forum in corso, ne leggete qui: http://www.python-it.org/forum/index.php?topic=7051.0.

Topic: Salve a Tutti :) file bash in Django  (Letto 355 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline andromeda979

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Salve a Tutti :) file bash in Django
« il: Settembre 06, 2016, 12:44 »
Salve a tutti, sono nuovo sia del forum sia di python/django,
avrei bisogno di un piccolo aiuto da parte vostra.
Dovrei far creare un file bash a django (versione 1.8.5) e poi salvarlo ho provato in questa maniera ma non mi funziona  ;(

Citazione

inputChar = models.CharField(max_length=100, default="", help_text=_(""))
expected = models.CharField(max_length=100, default="", help_text=_(""))



   def script(self):
        with open('script.sh', 'w', buffering=-1) as f:
            f.write("#!/bin/bash
                    "./program <<< '%s' > out.txt
                    "echo 'Everything fine'. > expected.txt
                    "if ! diff -N -w out.txt expected.txt > /dev/null
                    "then
                    " echo '%s'
                    "cat expected.txt
                    "exit 1
                    "else
                    " echo 'Die Ausgabe sieht gut aus.'
                    "fi>
                    % (self.inputChar, self.expected))
        return f

shell_script = models.FileField(upload_to=script, default="")


« Ultima modifica: Settembre 06, 2016, 14:41 da andromeda979 »

Online RicPol

  • python sapiens sapiens
  • ******
  • Post: 2567
  • Punti reputazione: 9
    • Mostra profilo
Re: Salve a Tutti :) file bash in Django
« Risposta #1 il: Settembre 06, 2016, 14:56 »
uhm, non è chiarissimo in che contesto vorresti eseguire quel codice.
Diciamo che *potrebbe* essere un form, per così dire, "slegato", senza un model dietro... semplicemente l'utente riempie una casella di testo, e quando fa "submit" tu restituisci una view qualsiasi ma intanto dietro le quinte componi il contenuto del tuo file e lo salvi da qualche parte... mah.
Oppure forse intendi dire che effettivamente c'è un model che ha un campo per salvare nel db il contenuto dello script bash... è quasi la stessa cosa, dal punto di vista di django...

Hai letto bene (molto bene) il tutorial di django? C'è anche una parte sui form...

Detto questo, meglio comunque non chiedersi che cosa vuoi fare davvero... script bash "alla cieca"... gulp.

Offline andromeda979

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Re: Salve a Tutti :) file bash in Django
« Risposta #2 il: Settembre 07, 2016, 08:56 »
Ciao icPol,
bhe si francamente scritto cosi non e' molto chiaro.

Da qualche mese mi e' stato affidato un progetto chiamato Praktomat fatto naturalmente in Django (1.8.5), prima di allora (5 mesi fa) non avevo minimamente idea di cosa fosse django, e devo dire la verita sono rimasto piacevolmente colpito, con questo ho risposto alla domanda "Hai letto bene (molto bene) il tutorial di django? " No la sto ancora leggendo con vari altri manuali  8) ansi ne approfitto per chiederti (chiedervi) un consiglio oltre alla guida ufficiale un buon manuale :)

Detto questo il progetto analizza gli studenti universitari dei primi anni, il professore lascia un quesito, lo studente carica la sua soluzione, e tramite appositi script, il professore può testare automaticamente il codice dello studente.

Esempio di script caricato dal professore:
#!/bin/bash

./program <<< "0 6" > out.txt

echo "Everything's fine." > expected.txt

if ! diff -N -w out.txt expected.txt > /dev/null
then
  echo "Die Ausgabe entspricht nicht der Erwartung:"
  cat expected.txt
  exit 1
else
  echo "Die Ausgabe sieht gut aus."
fi


Mi e' stato chiesto di evitare il caricamento dello script ogni volta in quanto molte delle volte fa quasi sempre la stessa cosa, cambiano le variabili richieste, all'inizio mi e' venuta in mente di far generare un file bash inserendo le variabile richieste, ma come ho detto sono nuovo di questo mondo, sicuramente si puo fare in tanti altre maniere... per questo motivo sono qui  :)

questo e' il codice del modulo esistente che mi da modo di fare l'upload dello script:
# -*- coding: utf-8 -*-

import os, re

from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.html import escape
from django.utils.encoding import force_unicode
from checker.basemodels import Checker, CheckerFileField, truncated_log
from utilities.safeexec import execute_arglist
from utilities.file_operations import *

class ScriptChecker(Checker):

   name = models.CharField(max_length=100, default="Externen Tutor ausführen", help_text=_("Name to be displayed on the solution detail page."))
   shell_script = CheckerFileField(help_text=_("A script (e.g. a shell script) to run. Its output will be displayed to the user (if public), the checker will succeed if it returns an exit code of 0. The environment will contain the variables JAVA and PROGRAM."))
   remove = models.CharField(max_length=5000, blank=True, help_text=_("Regular expression describing passages to be removed from the output."))
   returns_html = models.BooleanField(default= False, help_text=_("If the script doesn't return HTML it will be enclosed in &lt; pre &gt; tags."))

   
   def title(self):
      """ Returns the title for this checker category. """
      return self.name
   
   @staticmethod
   def description():
      """ Returns a description for this Checker. """
      return u"Diese Prüfung wird bestanden, wenn das externe Programm keinen Fehlercode liefert."
   

   def run(self, env):
      """ Runs tests in a special environment. Here's the actual work.
      This runs the check in the environment ENV, returning a CheckerResult. """

      # Setup
      copy_file(self.shell_script.path, env.tmpdir(), to_is_directory=True)
      os.chmod(env.tmpdir()+'/'+os.path.basename(self.shell_script.name),0750)
      
      # Run the tests -- execute dumped shell script 'script.sh'

      filenames = [name for (name,content) in env.sources()]
      args = [env.tmpdir()+'/'+os.path.basename(self.shell_script.name)] + filenames

      environ = {}
      environ['USER'] = str(env.user().id)
      environ['HOME'] = env.tmpdir()
      environ['JAVA'] = settings.JVM
      environ['JAVA_SECURE'] = settings.JVM_SECURE
      environ['POLICY'] = settings.JVM_POLICY
      environ['PROGRAM'] = env.program() or ''

      script_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)),'scripts')

      [output, error, exitcode,timed_out, oom_ed] = execute_arglist(
                            args,
                            working_directory=env.tmpdir(),
                            environment_variables=environ,
                            timeout=settings.TEST_TIMEOUT,
                            maxmem=settings.TEST_MAXMEM,
                            fileseeklimit=settings.TEST_MAXFILESIZE,
                            extradirs = [script_dir],
                            )
      output = force_unicode(output, errors='replace')

      result = self.create_result(env)
      (output,truncated) = truncated_log(output)

      if self.remove:
         output = re.sub(self.remove, "", output)
      if not self.returns_html or truncated or timed_out or oom_ed:
         output = '<pre>' + escape(output) + '</pre>'

      result.set_log(output,timed_out=timed_out,truncated=truncated,oom_ed=oom_ed)
      result.set_passed(not exitcode and not timed_out and not oom_ed and not truncated)
      
      return result
   
from checker.admin import   CheckerInline
from django import forms
from django.contrib import messages
from django.contrib import admin

class WarningScriptCheckerFormSet(forms.BaseInlineFormSet):
   class Meta:
      model = ScriptChecker
      exclude = []

   def __init__(self, *args, **kwargs):
      self.request = kwargs.pop('request', None)
      super(WarningScriptCheckerFormSet, self).__init__(*args, **kwargs)

   def save(self, *args, **kwargs):
      scriptcheckers = super(WarningScriptCheckerFormSet, self).save(*args, **kwargs)

      for checker in scriptcheckers:
         script = checker.shell_script
         # Workaround that may not be necerssay anymore  in Django > 1.8,
         # see https://code.djangoproject.com/ticket/13809 and https://code.djangoproject.com/ticket/26398
         script.close()
         script.file.close()

         # In Universal Newline mode, python will collect encountered newlines
         script.open(mode="rU")
         # make sure self.newlines is populated
         script.readline()
         script.readline()
         script.readline()

         if (script.newlines is None) or ("
" in script.newlines):
            messages.add_message(self.request, messages.WARNING, "Script File %s does not appear to use UNIX line-endings. Instead it uses: %s" % (script.name, repr(script.newlines)))

         script.close()
      
      return scriptcheckers

class ScriptCheckerInline(CheckerInline):
   model = ScriptChecker

   formset = WarningScriptCheckerFormSet
   def get_formset(self, request, obj=None, **kwargs):
      AdminFormset = super(ScriptCheckerInline, self).get_formset(request, obj, **kwargs)

      class AdminFormsetWithRequest(AdminFormset):
         def __new__(cls, *args, **kwargs):
            kwargs['request'] = request
            return AdminFormset(*args, **kwargs)

      return AdminFormsetWithRequest


Chiedo aiuto  ;(
Grazie tante  ;)

Online RicPol

  • python sapiens sapiens
  • ******
  • Post: 2567
  • Punti reputazione: 9
    • Mostra profilo
Re: Salve a Tutti :) file bash in Django
« Risposta #3 il: Settembre 07, 2016, 12:57 »
Mah. Non ho l'esperienza / non mi è abbastanza chiaro il contesto per capire se questa cosa è davvero così folle come sembra a prima vista. Voglio dire, in sostanza state eseguendo codice arbitrario immesso da utenti. Un gigantesco eval.
Comunque, se va bene così...
Dal punto di vista di django non è un problema ovviamente. L'utente immette del testo in una form, e il testo viene salvato in un database. Fin qui, nessun danno. Il fatto che poi, in sostanza,  quel testo venga eseguito alla cieca da qualche parte, non è certo più un problema di Django.

Ora, tu dici che

> Mi e' stato chiesto di evitare il caricamento dello script ogni volta
> in quanto molte delle volte fa quasi sempre la stessa cosa,
> cambiano le variabili richieste,

e questo non è chiaro. Che cosa vuol dire "la stessa cosa"? Capisco bene, è come se ci fosse una specie di "template" di script-tipo, e gli utenti possono solo cambiare dei punti qua e là? Boh, allora sì, in teoria potresti fare un modello Django che immagazzina solo i "pezzetti" di codice che effettivamente l'utente inserisce, e poi ricomporre lo script solo all'ultimo... questo potrebbe (e dico potrebbe) migliorare anche un po' la sicurezza del tutto... Ma è difficile farlo in modo che non sia fragile (che succede se domani cambia il "template" dello script? etc.). Ma a parte questo, perché darsi il fastidio di fare una cosa del genere? Non è che "caricare lo script ogni volta" sia un'operazione particolarmente costosa in sé. Mi sembra un problema inutile.
E poi, che cosa vuol dire "quasi sempre fa la stessa cosa"? Ogni tanto invece no? E quando invece no? Bisogna tornare al vecchio sistema di salvare tutto lo script e caricarlo tutto? E come facciamo a sapere quando "farà la stessa cosa" e quando no? Mah. Mi sembra una complicazione davvero superflua.

Per il resto. Di libri su Django ne esistono, anche in italiano. Googla un po'... Comunque, il tutorial e la documentazione sono sempre ottimi per cominciare (e non spendi soldi). Certo, se stai cercando di imparare Django mentre ti destreggi a capire la codebase di un progetto già avviato e piuttosto complesso, allora il tuo compito diventa più difficile.

Comunque, prima di modificare una sola riga di codice di un progetto che funziona, mi assicurerei:
- di conoscere B.E.N.E pyhton
- di conoscere abbastanza bene Django
- di conoscere STRAORDINARIAMENTE BENE tutto quello che è legato all'ambiente (di sviluppo e di produzione) in cui vive attualmente questo progetto... per dire, il workflow del version manager (git o altro), la pipeline delle varie release (ambiente di sviluppo, valutazione, produzione)... altrimenti se fai un danno lo fai davvero bello grosso...

Offline andromeda979

  • python unicellularis
  • *
  • Post: 3
  • Punti reputazione: 0
    • Mostra profilo
Re: Salve a Tutti :) file bash in Django
« Risposta #4 il: Settembre 07, 2016, 13:31 »
Ti ringrazio per avermi risposto, e di avermi dato degli ottimi consigli a riguardo.

Si purtroppo devo imparare django/python in corsa e questo come dici tu non e' assolutamente facile...
ho comprato (e letto) "Sviluppare applicazioni web con Django (2009)" ma e' troppo datato (l'unico che ho trovato), utilizza django 1.0 (sicuramente lo conosci il libro), altro in italiano non ho trovato nulla, l'inglese non e' un problema, ma ovviamente preferivo uno in italiano  :) sto guardando vari tutorial e implemento con la documentazione ufficiale, ma e' dura .

Mi rendo conto che visto in questa maniera risulta quasi folle un progetto in questa maniera(codice arbitrario immesso da utenti), ma non lo e', il progetto utilizza i docker e vari livelli di controllo.

Ti sarei grado, se per te non e' un disturbo, un esempio di come potrei integrare un modello per poi alla fine generare lo script  :batti5:

Grazie ancora !

Online RicPol

  • python sapiens sapiens
  • ******
  • Post: 2567
  • Punti reputazione: 9
    • Mostra profilo
Re: Salve a Tutti :) file bash in Django
« Risposta #5 il: Settembre 08, 2016, 09:17 »
Mah, il libro di Beri è molto buono, non importa che non sia aggiornatissimo, l'importante sono i concetti.
In inglese, un libro molto molto bello è questo https://www.amazon.it/Two-Scoops-Django-Best-Practices/dp/0981467342 ma forse è un po' avanzato. Il fatto è che la documentazione di django è davvero ben fatta, e secondo me c'è poco spazio per il libri entry-level.

Per quanto riguarda il tuo problema, boh... "integrare" è complicato e dovrei capire bene il codice esistente. A farlo da zero, non è complicato in linea di principio: fatti un model che mappa il test fatto da uno studente: questo model avrà un riferimento allo studente e un riferimento al quesito-template (che sono chiaramente altri due model che devi farti); poi avrà una decina... ventina... di campi del tipo "snippet_1", "snippet_2", etc., dove lo studente inserisce i suoi pezzetti di codice da integrare nel quesito-template. Abbonda pure con questi campi... ovviamente certi quesiti-template avranno bisogno solo di 4-5 "buchi", altri quesiti avranno bisogno di più o di meno... non importa, quelli che non servono non si riempiono.
Quando lo studente fa il test, gli viene presentato il quesito-template, e lui riempie i buchi con i suoi snippet di codice. Sul database tu salvi solo gli snippet di codice inseriti dallo studente, quindi. Quando il prof vuole valutare il test, tu fai uno script (più o meno come hai già fatto) che integra gli snippet nel quesito-template e salva da qualche parte un file con tutto il codice risultante. A questo punto il file viene (g-u-l-p) eseguito alla cieca, e il prof controlla se il risultato è giusto (o se gli è sparito il database e il sistema operativo, se lo studente è abbastanza bravo).

Tutto questo in linea di principio non è difficile. Salvo il fatto che è inutile, come già detto. Non guadagni proprio nulla in termini di efficienza a fare una cosa del genere, rispetto semplicemente a lasciare che lo studente scriva tutto il codice, e caricare nel database tutto il codice scritto dallo studente, lasciando perdere il sistema snippet/template. E' vero che tutti gli script caricati dagli studenti saranno sempre più o meno uguali, ma che cosa importa?

(poi ci sarebbero molte cose da dire sulla qualità di questo sistema di insegnamento, ovviamente. Ma lasciamo perdere, spero di aver capito male come funziona.)