Search code examples
pythonbeautifulsoupwxpythonlxmlcx-freeze

What's needed to get BeautifulSoup4+lxml to work with cx_freeze?


Summary:

I have a wxPython/bs4 app that I'm building into an exe with cx_freeze.

There build succeeds with no errors, but trying to run the EXE results a FeatureNotFound error from BeautifulSoup4. It's complaining that I don't have my lxml library installed.

I've since stripped the program down to it's minimal state and still get the error.

Has anyone else had success building a bs4 app with cx_freeze?

Please take a look at the details below and let me know of any ideas you may have.

Thanks,


Details

Full Error Traceback:

I've simplified the app to it's most basic state and still get the error. I also get the same error on Python 3.4.

Traceback (most recent call last):
  File "C:\WinPython27\python-2.6.7\lib\site-packages\cx_Freeze\initscripts\Console.py", line 27, in <module>
    exec(code, m.__dict__)
  File "test.py", line 6, in <module>
  File "C:\WinPython27\python-2.6.7\lib\site-packages\bs4\__init__.py", line 152, in __init__
    % ",".join(feautres))
FeatureNotFound: Couldn't find a tree builder with the features you requested: xml. Do you need to install a parser library?

What I've already tried:

I found some people saying that I need to include lxml and it's dependents in the build script: http://sourceforge.net/p/cx-freeze/mailman/message/27973651/ (sorry for the SF link). I tried this, but still no dice.

Commenting out the line soup = BeautifulSoup("<tag>value</tag>", 'xml') results in no errors.


Versions and Files:

Versions:

  • lxml 3.4.4
  • BeautifulSoup4 4.3.2
  • Python 2.7.6 (32bit) and Python 3.4.3 (64bit)
  • cx_Freeze 4.3.4
  • wxPython 3.0-msw
  • Windows 7 Professional SP1, 64-bit

test.py

This file is the simplified app that still gets the error.

# -*- coding: utf-8 -*-
from __future__ import print_function
from bs4 import BeautifulSoup
import wx

soup = BeautifulSoup("<tag>value</tag>", 'xml')

app = wx.App()
frame = wx.Frame(None, wx.ID_ANY, "test frame")
frame.Show()
app.MainLoop()

build_executables.py

This is the (simplified) build script I am using.

# -*- coding: utf-8 -*-
from cx_Freeze import setup, Executable
build_exe_opts = {"silent": False, }

base = "Win32GUI"

exes_to_build = [Executable("test.py", base=base),
                 ]

setup(
    name="test",
    version="0.0.1",
    description="FTI test program editor and diff tool.",
    options={"build_exe": build_exe_opts},
    executables=exes_to_build,
)

cx_freeze log

I'm not going to include the entire log here, but I did run python build_executables.py build >> C:\temp\build_log.txt so can look for anything that's asked for.

Here are the lines that contain 'lxml' in them:

  Name                      File
  ----                      ----
P bs4                       C:\WinPython27\python-2.7.6\lib\site-packages\bs4\__init__.py
P bs4.builder               C:\WinPython27\python-2.7.6\lib\site-packages\bs4\builder\__init__.py
m bs4.builder._html5lib     C:\WinPython27\python-2.7.6\lib\site-packages\bs4\builder\_html5lib.py
m bs4.builder._htmlparser   C:\WinPython27\python-2.7.6\lib\site-packages\bs4\builder\_htmlparser.py
m bs4.builder._lxml         C:\WinPython27\python-2.7.6\lib\site-packages\bs4\builder\_lxml.py
m bs4.dammit                C:\WinPython27\python-2.7.6\lib\site-packages\bs4\dammit.py
m bs4.element               C:\WinPython27\python-2.7.6\lib\site-packages\bs4\element.py
...
P lxml                      C:\WinPython27\python-2.7.6\lib\site-packages\lxml\__init__.py
m lxml.etree                C:\WinPython27\python-2.7.6\lib\site-packages\lxml\etree.pyd
...
copying C:\WinPython27\python-2.7.6\lib\site-packages\lxml\etree.pyd -> build\exe.win32-2.7\lxml.etree.pyd

The build succeeds with no errors.


Solution

  • After much investigation, going into bs4 and their builders, I finally found that I need to also add gzip.

    So in the end, the cx_freeze script needs, at minimum, these packages added when building an exe with bs4 + lxml: lxml and gzip.

    So your build_executables.py script should look like:

    # -*- coding: utf-8 -*-
    from cx_Freeze import setup, Executable
    build_exe_opts = {"silent": False,
                      "packages": ['lxml', 'gzip'],
                      }
    base = "Win32GUI"
    
    exes_to_build = [Executable("test.py", base=base)]
    
    setup(
        name="test",
        version="0.0.1",
        description="blah blah blah",
        options={"build_exe": build_exe_opts},
        executables=exes_to_build,
    )
    

    and then when you run python build_executables.py build and try the executable, it should work.