import os.path
import re
import codecs

def script(path, python_paths=[]):
    output = []
    
    sys_path = [os.path.dirname(path)] + python_paths
    
    with open(path) as script_file:
        _add_shebang(script_file, output)
        _add_prelude(script_file, output)
        _add_body(script_file, output, sys_path)
        print "".join(output)
        return "".join(output)

def _add_shebang(script_file, output):
    output.append(script_file.readline())
    
def _add_prelude(script_file, output):
    prelude_path = os.path.join(os.path.dirname(__file__), "prelude.py")
    with open(prelude_path) as prelude_file:
        output.append(prelude_file.read())

def _add_body(script_file, output, sys_path):
    body_output = []
    for line in script_file:
        body_output.append(_transform(line, sys_path))
        
    output.append("    " + "".join(body_output).replace("\n", "\n    "))

def _transform(line, sys_path):
    import_line = _read_import_line(line)
    if import_line is None or _is_stlib_import(import_line):
        return line
    else:
        return _transform_import(import_line, sys_path)
        
def _read_import_line(line):
    package_pattern = "([^\s.]+(?:\.[^\s.]+)*)"
    result = re.match("^import " + package_pattern + "$", line.strip())
    if result:
        return ImportLine(line, result.group(1).replace(".", "/"), None)
    
    result = re.match("^from " + package_pattern +" import ([^\s.]+)$", line.strip())
    if result:
        return ImportLine(line, result.group(1).replace(".", "/"), result.group(2))
    
    return None

def _transform_import(import_line, sys_path):
    import_targets = _read_possible_import_targets(import_line, sys_path)
    
    output = []
    
    for module_path, module_source in import_targets:
        output.append( "__stickytape_write_module({0}, {1})\n".format(
            _string_escape(module_path),
            _string_escape(module_source)
        ))
    output.append(import_line.original_string)
    return "".join(output)
    
def _read_possible_import_targets(import_line, sys_paths):
    possible_module_paths = [
        import_line.import_path + ".py",
        os.path.join(import_line.import_path, "__init__.py")
    ]
    if import_line.item is not None:
        possible_module_paths += [
            os.path.join(import_line.import_path, import_line.item + ".py"),
            os.path.join(import_line.import_path, import_line.item, "__init__.py")
        ]
    
    import_targets = [
        _find_module(module_path, sys_paths)
        for module_path in possible_module_paths
    ]
    
    valid_import_targets = [target for target in import_targets if target is not None]
    print valid_import_targets
    if len(valid_import_targets) > 0:
        return valid_import_targets
    else:
        raise RuntimeError("Could not find module: " + import_line.import_path)

def _find_module(module_path, sys_paths):
    for sys_path in sys_paths:
        full_module_path = os.path.join(sys_path, module_path)
        if os.path.exists(full_module_path):
            return module_path, _read_file(full_module_path)
    return None

def _read_file(path):
    with open(path) as file:
        return file.read()

def _string_escape(string):
    return "'''{0}'''".format(codecs.getencoder("string_escape")(string)[0])

# TODO: fill out, either by hand or generatively
_stdlib_modules = ["argparse", "hashlib", "os", "sys"]

def _is_stlib_import(import_line):
    return import_line.import_path in _stdlib_modules

class ImportLine(object):
    def __init__(self, original_string, import_path, item):
        self.original_string = original_string
        self.import_path = import_path
        self.item = item
        

@@ -192,20 +192,30 @@
         
-_add
+output.append(
 _shebang
@@ -222,32 +222,25 @@
 (script_file
-, output
+)
 )%0A        _a
@@ -241,54 +241,56 @@
     
-_add_prelude(script_file, output)%0A        _add
+output.append(_prelude())%0A        output.append(
 _bod
@@ -299,32 +299,24 @@
 script_file,
- output,
  sys_path)%0A 
@@ -317,37 +317,8 @@
 ath)
-%0A        print %22%22.join(output
 )%0A  
@@ -351,20 +351,16 @@
 t)%0A%0Adef 
-_add
 _shebang
@@ -375,37 +375,22 @@
 file
-, output):%0A    output.append(
+):%0A    return 
 scri
@@ -407,17 +407,16 @@
 adline()
-)
 %0A    %0Ade
@@ -417,20 +417,16 @@
    %0Adef 
-_add
 _prelude
@@ -426,35 +426,16 @@
 prelude(
-script_file, output
 ):%0A    p
@@ -555,30 +555,23 @@
         
-output.append(
+return 
 prelude_
@@ -585,19 +585,14 @@
 ad()
-)
 %0A%0Adef 
-_add
 _bod
@@ -609,16 +609,8 @@
 ile,
- output,
  sys
@@ -617,24 +617,64 @@
 _path):%0A    
+module_writing_output = %5B%5D%0A    original_
 body_output 
@@ -715,16 +715,25 @@
         
+original_
 body_out
@@ -743,16 +743,46 @@
 .append(
+line)%0A        module_writer = 
 _transfo
@@ -791,33 +791,32 @@
 (line, sys_path)
-)
 %0A        %0A    ou
@@ -808,35 +808,181 @@
         
-%0A    output.append(
+if module_writer is not None:%0A            module_writing_output.extend(module_writer)%0A    %0A    body_output = module_writing_output + original_body_output%0A    return 
 %22    %22 +
@@ -1026,17 +1026,16 @@
 %5Cn    %22)
-)
 %0A%0Adef _t
@@ -1178,18 +1178,18 @@
  return 
-li
+No
 ne%0A    e
@@ -1440,38 +1440,32 @@
 turn ImportLine(
-line, 
 result.group(1).
@@ -1621,22 +1621,16 @@
 ortLine(
-line, 
 result.g
@@ -2064,55 +2064,8 @@
  ))%0A
-    output.append(import_line.original_string)%0A
     
@@ -3638,25 +3638,8 @@
 elf,
- original_string,
  imp
@@ -3659,55 +3659,8 @@
 m):%0A
-        self.original_string = original_string%0A
     

Simplify transforms slightly