You are only as good as your tools.

In search of Python

Or, On Progam Storage Minimums

10 Feb 2024

First Draft

Today I'm looking at installing Python. I'm starting with a standalone Python (3.9.?) from a 'nother computer that has a footprint of 77/170 MB (that is Size / Size on disk).

As one must know, much of the computing world is of "program suites" – i.e. they consist of multiple programs and tools, with binaries, libraries, documentation, etc. (Though more often these days documentation is online as mega-pages...)

For basic "Hello World" programming, as I am ever only going to be doing, some amount of that data is not needed by me. (Also, this... essay, has relation to my being stuck with a computer that has little storage space...)

So, how small Python can be? My goal here was to install Python on a PC without Python, by copying Python binaries from a PC with Python installed.

First, I copied the basics:

    C:.
    |   main.py
    |   python.exe
    |   python3.dll
    |   python39.dll
    |
    +---DLLs
            libcrypto-1_1.dll
            libffi-7.dll
            libssl-1_1.dll
            sqlite3.dll
            tcl86t.dll
            tk86t.dll

(Yup. I'm caught. It's Windows. But, I do use Cygwin. :-) "Don't leave Unix without it," Perl. Oh, and actual drive/directory names here are not really relevant.)

After that copy a DIR is like:

    Total Files Listed:
        10 File(s) 8,840,584 bytes

With MAIN.PY just print a string, this happens (as expected):

    C:\>python.exe main.py
    Python path configuration:
      PYTHONHOME = (not set)
      PYTHONPATH = (not set)
      program name = 'python.exe'
      isolated = 0
      environment = 1
      user site = 1
      import site = 1
      sys._base_executable = 'C:\\Python\\python.exe'
      sys.base_prefix = ''
      sys.base_exec_prefix = ''
      sys.platlibdir = 'lib'
      sys.executable = 'C:\\Python\\python.exe'
      sys.prefix = ''
      sys.exec_prefix = ''
      sys.path = [
        'C:\\Python\\python39.zip',
        '.\\DLLs',
        '.\\lib',
        'C:\\Python',
      ]
    Fatal Python error: init_fs_encoding: failed to get the Python codec of the 
    filesystem encoding
    ModuleNotFoundError: No module named 'encodings'

Since this is not the typical Windows Installation a PYVENV.CFG file probably should be created. I thought.

A web search of python "pyvenv.cfg" found a great many pages about the "Creation of [Python] virtual environments".

But most were how to use programs to do so and none provided an example. (Seriously, how complicated can the file format be? Just some Python-like assignments, right?)

A Stackoverflow post was first (of course) and someone had written:

    you can just create yourself a pyvenv.cfg file with following contents:
    
        home = <location-of-python-exe>
        include-system-site-packages = false
        version = <version>

Which is entirely un-adequate... But then I realized that (pursuing) that path was a waste of time because Python has defaults and it'd be running in it's own base directory.

So Python just needs it's basic module requirements. Since this first run failed with not finding OS.PY, I can make this a long process of "one at a time" or a shorter one of "many at a time."

But first, why am I doing this? For S&G mostly. But I just want to see just how small Python can be.

Here is the default LIB size (of a "properly" installed Python):

    56 MB Size
    143 MB Size on disk
    3,500 Files

UGH! Way too big! I want to find the minimum...

So, here we go... With just OS.PY copied over, the error message was the same. Expected. But the process monitor (PROCMON) showed that OS.PY was first directly read and then the LIB directory was queried (no other files found) and Python quit.

What I was hoping was more direct file opens (one at a time) to count the number of libs required. (But that was a reach.) So I'll see if I can find any "encoding" lib and retry... No, wait, I'll just copy all the basic libs (155 files about 4 MB).

Same result. (Hey, this is fun!) Will looking at the PROCMON log help in any way?

Nope. So, it's a subdirectory of libs. (Kind figured that would be the case.) And stupid me there's LIB/ENCODINGS! So I copy that...

Success! I mean... A different result!

    C:\>python.exe main.py
    
    Fatal Python error: init_import_site: Failed to import the site module
    Python runtime state: initialized
    Traceback (most recent call last):
      File "C:\Python\lib\site.py", line 73, in <module>
        import os
      File "C:\Python\lib\os.py", line 29, in <module>
        from _collections_abc import _check_methods
    ModuleNotFoundError: No module named '_collections_abc'

Well, LIB/SITE.PY is there of course, included by OS.PY, but Python did not say what file that collections stuff should be in. Back to the process monitor.

Nope. Loaded all base libs, loaded many encoding libs, but No "NAME NOT FOUND" error caused that error. Gotta open SITE.PY I guess.

Oh. And these files where created:

    Python\Lib\__pycache__
    
         5,335 abc.cpython-39.pyc
        33,885 codecs.cpython-39.pyc
         3,405 io.cpython-39.pyc
        31,643 os.cpython-39.pyc
        16,786 site.cpython-39.pyc
         4,369 stat.cpython-39.pyc
        6 File(s) 95,423 bytes
    
    Python\Lib\encodings\__pycache__
    
        6,327 aliases.cpython-39.pyc
        2,448 cp1252.cpython-39.pyc
        1,892 latin_1.cpython-39.pyc
        1,629 utf_8.cpython-39.pyc
        3,894 __init__.cpython-39.pyc
        5 File(s) 16,190 bytes

Aha! Now, I think that caches can cause headaches (we all know they can), and my simple run "only" added 11 file and 120 KB, but this exercise is about "program storage minimums". (That was in the title, wasn't it?) Maybe there is a way to turn caching off. (I doubt it.) Maybe there is a way to indicate where/which filesystem to put them on. (That'd be nice. But I doubt it.)

But, what is really interesting is that Python just told me which libs were (basically) required just to print a string! (See what I mean by fun?) And if the file sizes of just those that were compiled were added up I bet it'd be small. (Thing for another day.) (Oh. And could Python be considered a Compiling Interpreter? You betcha!)

Back to figuring...

The message:

    ModuleNotFoundError: No module named '_collections_abc'

Is from (pun unfortunately cannot be not made) this line in OS.PY:

    29: from _collections_abc import _check_methods

Because SITE.PY had this:

    73: import os

So, where is this collections thing? Oh, man! It's supposed to be in LIB! I forgot to copy all the (underscore) _*.py libs!

Yay! It works! Woohoo... Python Sez!

    File "C:\bin\Python\main.py", line 1
      print "Hello world!"
            ^
    SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Hello world!")?

Well, blow me down and lift me up! It's a version thing I guess for I (as I had to remind myself what a basic "Hello World" Python would be) had just copied the first one I found. sheesh

Well, anyways, conclusion is, success fully reached!

Python is really quite small. And can be made smaller by a process of elimination (the DLLS as well as the LIBS). No TCL! No INCLUDE! Much/most is not needed for simple console work. Obviously, doing more will require more LIBS. That is to be expected.

Hey? How about an "Install on Demand" feature! Maybe there is as PROCMON shows that Python is looking for a PYTHON39.ZIP file before it looks for DLLS and LIBS.

Later more...

  1. Which most often pollute the environment and system-wide configuration (the Registry).
  2. shits and giggles
  3. Certainly a very slow and tedious process, but I wanted to start with that anyway.
A man's got to know his possibilities.