importing pyc from memory?

  • Thread starter Derek van Vliet
  • Start date
D

Derek van Vliet

Using the Python/C API, is there a way I can import a pyc file that I
have in memory (as opposed to loading from disk)?

I'm trying to save compiled python code in a proprietary file format to
cut reduce the overhead of compiling all my scripts when my app starts
up.

Derek
 
S

Sybren Stuvel

Derek van Vliet enlightened us with:
I'm trying to save compiled python code in a proprietary file format
to cut reduce the overhead of compiling all my scripts when my app
starts up.

Why is that faster than having the .pyc files ready on your
filesystem? And why do you want it in a proprietary file format?

Sybren
 
R

Robert

Derek van Vliet said:
Using the Python/C API, is there a way I can import a pyc file that I
have in memory (as opposed to loading from disk)?

I'm trying to save compiled python code in a proprietary file format to
cut reduce the overhead of compiling all my scripts when my app starts
up.


you can use a zip file as "proprietary file format"? with .pyc's or .py's in
and add the zippath to sys.path ?

other than that you can load the code object of .pyc's content in a string
like

co = marshal.loads( pyc_s[8:] )
mod=imp.new_module('xy')
exec co in mod.__dict__


Robert
 
D

Derek van Vliet

Up to now, I've had all my python scripts defined in XML elements,
which were compiled when my program started up using Py_CompileString.
This has worked great, but I'm finding that most of the time my app
uses to start up is spent in that Py_CompileString, because of the
large number of scripts that I use.

Unfortunately, storing these scripts as .pyc files on disk is not an
option for me.
 
D

Derek van Vliet

The second method you describe sounds like it is along the lines of
what I need to do. Is there a way to do this using the Python/C API?

For instance, if I have the contents of a pyc file loaded entirely into
memory, and I have a pointer to the beginning of the file and the size
in bytes at my disposal, can I import that by any means?
 
T

Thomas Heller

Derek van Vliet said:
The second method you describe sounds like it is along the lines of
what I need to do. Is there a way to do this using the Python/C API?

For instance, if I have the contents of a pyc file loaded entirely into
memory, and I have a pointer to the beginning of the file and the size
in bytes at my disposal, can I import that by any means?

The .pyc file format is sort of 'documented' in lib/py_compile.py.
IIRC, it is a magic number, a timestamp, plus a marshalled code
object.

Thomas
 
J

Jeff Epler

This stupid code works for modules, but not for packages. It probably has bugs.


import marshal, types

class StringImporter:
def __init__(self, old_import, modules):
self._import = old_import
self._modules = modules

def __call__(self, name, *args):
module = self._modules.get(name, None)
if module is None:
return self._import(name, *args)
code = marshal.loads(module)
mod = types.ModuleType(name)
exec code in mod.__dict__
return mod

def test():
import __builtin__
__builtin__.__import__ = StringImporter(__builtin__.__import__,
{ 'test_importer': open("/usr/lib/python2.3/os.pyc").read()[8:] })

import test_importer
print test_importer.path.join("a", "b")
print test_importer.__doc__

if __name__ == '__main__': test()

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (GNU/Linux)

iD8DBQFCyXlhJd01MZaTXX0RAgTkAJ9YBAd3ms+q1tWcjFe/jOkV0+pY4ACgn/RU
bakTEx933/aaDQa3Byp9204=
=uKAI
-----END PGP SIGNATURE-----
 
B

Bengt Richter

The .pyc file format is sort of 'documented' in lib/py_compile.py.
IIRC, it is a magic number, a timestamp, plus a marshalled code
object.
I'm wondering if what the OP has is really .pyc files "in memory" or code objects.
If he is using Py_CompileString to compile "scripts" extracted from XML,
wouldn't he get code objects? And if so, wouldn't he have to execute them
in a constructed module dict and be careful of normal imports in the "scripts"
etc etc to simulate import? Anyway, it feels like what he wants to do could be done,
but "the devil is in the details," which are missing ;-)

Regards,
Bengt Richter
 
S

Sybren Stuvel

Derek van Vliet enlightened us with:
Up to now, I've had all my python scripts defined in XML elements,
which were compiled when my program started up using
Py_CompileString. This has worked great, but I'm finding that most
of the time my app uses to start up is spent in that
Py_CompileString

It al makes sense now! Thanks for the explanation.

Sybren
 
D

Derek van Vliet

I do have to do everything you describe here in the current
implementation of my system. I realize that importing a pyc file and
compiling a string results in two different things. This is okay though
as I'm fairly sure this will still suit my needs.

As I said, the file format I plan to store these compiled scripts in is
proprietary, but it would be very comparable storing them in XML
elements as CDATA. I'm hoping that this would allow me to import and
run them, thereby removing the need for my app to compile scripts.
 
B

Bengt Richter

--s2ZSL+KKDSLx8OML
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

This stupid code works for modules, but not for packages. It probably has bugs.


import marshal, types

class StringImporter:
def __init__(self, old_import, modules):
self._import = old_import
self._modules = modules

def __call__(self, name, *args):
module = self._modules.get(name, None)
if module is None:
return self._import(name, *args)
code = marshal.loads(module)
mod = types.ModuleType(name)
exec code in mod.__dict__
return mod

def test():
import __builtin__
__builtin__.__import__ = StringImporter(__builtin__.__import__,
{ 'test_importer': open("/usr/lib/python2.3/os.pyc").read()[8:] })

import test_importer
print test_importer.path.join("a", "b")
print test_importer.__doc__

if __name__ == '__main__': test()

I have a feeling that the OP might be looking for a way to convert
source -> source, e.g., (sketch only, not even remotely tested ;-)

# main.py
import some_module
import another

into

# main.py
# prelim
import marshal, sys # builtin
ModuleType = type(__builtins__) # avoid import types
def unscramble_proprietary_format(proprietary_string):
# ... whatever
def extract_code(proprietary_string):
return marshal.loads(unscramble_proprietary_format(proprietary_string))

# replacing each import with
try: some_module = sys.modules['some_module'] # don't re-"import"
except KeyError:
some_module = ModuleType('some_module')
exec extract_code(
"< ... string literal for proprietarily scrambled marshalled module body code"
" generated by source -> source rewrite utility ... >"
) in some_module.__dict__
sys.modules['some_module'] = some_module

try: another = sys.modules['another']
except NameError:
another = ModuleType('another')
exec extract_code('<proprietary marshalled code string for module source another.py>')
sys.modules['another'] = another

# etc

so that his some_module and another scripts can be pre-compiled by the rewrite utility and embedded in
a single source (e.g. main.py) so that he doesn't have to have external .pyc file accesses.

His startup will then still cost the execs, but not the compiles, and if he doesn't "import" stuff
he doesn't need, until he needs it, it should spread the import time load, if so desired.

All the proprietary string literal sources should become efficiently represented as part of the
single main.pyc IWT, assuming at least that one is used. Chasing various forms of import of
non-builtins recursively to eliminate imports in imported modules before they are converted to
marshalled form etc., all to avoid real imports, and statically determining that some imports
don't need to be converted to marshalled string import form because a prior import can be proved,
should be an interesting exercise, which I can't pursue at this point... ;-)

But I may be reading too much between the lines ;-)

Regards,
Bengt Richter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,122
Latest member
VinayKumarNevatia_
Top