2015-07-07 21 views
5

Jinja2 şablonunu kullanan bir python betiğiyim ve Pyinstaller kullanarak bir tek klasör dağıtımı oluşturmaya çalışıyorum.Jinja2 Şablonunu Pyinstaller Dağıtımına İçermiyor

Jinja'da, programın şablonların konumunu bir PackageLoader sınıfı kullanarak anlamasına izin veriyorum. Aşağıdaki kod, pycorr Python paketinin altındaki templates klasörüme işaret ettiğini gösterir.

env = Environment(loader=PackageLoader('pycorr', 'templates')) 
template = env.get_template('child_template.html') 

Ve burada gibi benim klasör yapısı görünüyor: Ben Pyinstaller kullanarak tek bir klasöre paket derlemek zaman

pycorr 
| | 
| + templates 
| | 
| + base.html 
| + child.html 

, ben jinja2 ile ilgili herhangi bir uyarı/hata görmüyorum ve ben .exe dosyasını başlatabiliyorum. Program jinja2 şablonuna aramaya başlar Ancak, bunun konsol penceresinde görüntülenen bu hata iletisiyle başarısız olur:

Traceback (most recent call last): 
    ... 
    File "C:\Users\ ... \out00-PYZ.pyz\pycorr.WriterToHTML", line 96, in htmlout_table 
    File "C:\Users\ ... \out00-PYZ.pyz\pycorr.WriterToHTML", line 13, in __init__ 
    File "C:\Users\ ... \out00-PYZ.pyz\pycorr.WriterToHTML", line 48, in __set_template 
    File "C:\Users\ ... \out00-PYZ.pyz\jinja2.environment", line 791, in get_template 
    File "C:\Users\ ... \out00-PYZ.pyz\jinja2.environment", line 765, in _load_template 
    File "C:\Users\ ... \out00-PYZ.pyz\jinja2.loaders", line 113, in load 
    File "C:\Users\ ... \out00-PYZ.pyz\jinja2.loaders", line 224, in get_source 
    File "C:\Users\ ... \dist\OCA_CO~1\eggs\setuptools-14.3-py2.7.egg\pkg_resources\__init__.py", line 1572, in has_resource 
    return self._has(self._fn(self.module_path, resource_name)) 
    File "C:\Users\ ... \dist\OCA_CO~1\eggs\setuptools-14.3-py2.7.egg\pkg_resources\__init__.py", line 1627, in _has 
    "Can't perform this operation for unregistered loader type" 
    NotImplementedError: Can't perform this operation for unregistered loader type 

Gerçekten hata mesajı anlamıyorum ama benim tahminim Pyinstaller bulmalıyız olmasıdır templates klasörü. Bu yüzden bu satırları Pyinstaller .spec dosyasına ekledim:

a.datas += [('BASE', './pycorr/templates/base.html', 'DATA')] 
a.datas += [('TABLE', './pycorr/templates/table_child.html', 'DATA')] 
coll = COLLECT(exe, 
       a.binaries, 
       a.zipfiles, 
       a.datas, 
       strip=None, 
       upx=False, 
       name='OCA_correlation') 

Ancak sorunu çözmüyor gibi görünüyor.

Herkes yardımcı olabilir mi? Pyinstaller kılavuzunu birkaç kez okudum ama anlayamıyorum.

+1

Bu soruna rağmen oldukça eski ve yazar belki de kendisi tarafından çözülmüş, 'pkg_resources' belirtildiği gibi pyinstaller tarafından desteklenmiyor (https://github.com/pyinstaller/pyinstaller/wiki/FAQ#misc). Bu nedenle Jinja2 Paket Yükleyici kullanılamaz. – jrast

cevap

1

GUI kullanımı pyinstaller oluştururken bu soruna rastladım. Bir rapor oluşturmak için Jinja2'yi kullandım ve şablonlar yüklenmedi, bunun yerine "kayıtsız yükleme türü" hatası aldım. Birçok çözümü online olarak okuma ve test etme Sonunda bir düzeltme yaptık: FileSystemLoader, PackageLoader yerine kullanılmalıdır. Ayrıca FileSystemLoader için bir dosya yolu sağlanmalıdır. Son çözümüm, here ve here arasındaki bilgilerin birleşimidir.

Aşağıdakiler bu çözüm için tam bir örnek sağlar.

import os 
import sys 
from jinja2 import Environment, PackageLoader, FileSystemLoader 


def resource_path(relative_path, file_name): 
    """ Get absolute path to resource, works for both in IDE and for PyInstaller """ 
    # PyInstaller creates a temp folder and stores path in sys._MEIPASS 
    # In IDE, the path is os.path.join(base_path, relative_path, file_name) 
    # Search in Dev path first, then MEIPASS 
    base_path = os.path.abspath(".") 
    dev_file_path = os.path.join(base_path, relative_path, file_name) 
    if os.path.exists(dev_file_path): 
     return dev_file_path 
    else: 
     base_path = sys._MEIPASS 
     file_path = os.path.join(base_path, file_name) 
     if not os.path.exists(file_path): 
      msg = "\nError finding resource in either {} or {}".format(dev_file_path, file_path) 
      print(msg) 
      return None 
     return file_path 

class Report: 

    def main(self, output_html_file): 
     # template_loader = PackageLoader("report", "templates") 
     # --- PackageLoader returns unregistered loader problem, use FileSystemLoader instead 
     template_file_name = 'report.html' 
     template_file_path = resource_path('templates', template_file_name) 
     template_file_directory = os.path.dirname(template_file_path) 
     template_loader = FileSystemLoader(searchpath=template_file_directory) 
     env = Environment(loader=template_loader) # Jinja2 template environment 
     template = env.get_template(template_file_name) 
     report_content_placeholder = "This is my report content placeholder" 
     html = template.render(report_content= report_content_placeholder) 
     with open(output_html_file, 'w') as f: 
      f.write(html) 

if __name__ == "__main__": 
    my_report = Report() 
    my_report.main("output.html") 

bir yöntem resource_path çünkü gereklidir, testreport.py olarak

# -*- mode: python -*- 

block_cipher = None 


a = Analysis(['E:\\testjinja2\\testreport.py'], 
      pathex=['E:\\testjinja2'], 
      binaries=[], 
      datas=[('E:\\testjinja2\\templates\\base.html', '.'), 
        ('E:\\testjinja2\\templates\\report.css', '.'), 
        ('E:\\testjinja2\\templates\\report.html', '.')], 
      hiddenimports=[], 
      hookspath=[], 
      runtime_hooks=[], 
      excludes=[], 
      win_no_prefer_redirects=False, 
      win_private_assemblies=False, 
      cipher=block_cipher) 
pyz = PYZ(a.pure, a.zipped_data, 
      cipher=block_cipher) 
exe = EXE(pyz, 
      a.scripts, 
      a.binaries, 
      a.zipfiles, 
      a.datas, 
      name='testreport', 
      debug=False, 
      strip=False, 
      upx=True, 
     console=True) 

: testreport.spec olarak

testjinja2 
| | 
| + templates 
| | 
| + base.html 
| + report.html 
testreport.py 
testreport.spec 

: Kodum alt dizin şablonlar şablon sayesinde testjinjia2 altında jinja şablonları dosyalarının dosya yolu IDE'mde ve exe dosyasından ayıklanan dosyalar arasında farklıdır.

Ayrıca, bazı basit şablon dosyalarını da denemeniz yeterli.
base.html

<html> 
<head lang="en"> 
    <meta charset="UTF-8"> 
    <title></title> 

    <style> 
     .centered { 
      text-align: center; 
     } 
     .centeredbr { 
      text-align: center; 
      page-break-before:always; 
     } 

     .underlined { 
      text-decoration: underline; 
     } 

    </style> 
</head> 
<body> 
{% block body %}{% endblock %} 
</body> 
</html> 

Raporu html

<!DOCTYPE html> 
{% extends "base.html" %} 

{% block body %} 
<h1 class="centered underlined">Report Title</h1> 

<h2 class="centeredbr">Chaper I</h2> 

<p>{{ report_content }}</p> 

{% endblock %} 

Ben pyinstaller 3.2.1 ve Python 3.5 kullanıyorum.1 Anaconda Özel (64 bit)

0

@Uynix'ten yola çıkarak, cx_freeze kullanarak sorunumun sürümüne ilişkin çözümü uygulamak için birkaç adım daha yapmam gerektiğini buldum. İlk çözüm gönderiim, daha fazla ayrıntı gerekip gerekmediğini bana bildirin.

Özetle

, I C değiştirmek zorunda: \ ProgramData'nın \ Anaconda3 \ pkgs \ boke-0.12.9-py36_0 Lib \ sitesi-paketleri \ boke \ çekirdek \ templates.py

orijinal dosya \ (bokeh 0.12.9): aynı hatayı atma, her nasılsa,

JS_RESOURCES = _env.get_template("js_resources.html") 

keşfettim cx_freeze tarafından doğru bir biçimde hazırlandığına değildi:

''' Provide Jinja2 templates used by Bokeh to embed Bokeh models 
(e.g. plots, widgets, layouts) in various ways. 

.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_JS 
.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_NB_JS 
.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_TAG 
.. bokeh-jinja:: bokeh.core.templates.CSS_RESOURCES 
.. bokeh-jinja:: bokeh.core.templates.DOC_JS 
.. bokeh-jinja:: bokeh.core.templates.FILE 
.. bokeh-jinja:: bokeh.core.templates.JS_RESOURCES 
.. bokeh-jinja:: bokeh.core.templates.NOTEBOOK_LOAD 
.. bokeh-jinja:: bokeh.core.templates.NOTEBOOK_DIV 
.. bokeh-jinja:: bokeh.core.templates.PLOT_DIV 
.. bokeh-jinja:: bokeh.core.templates.SCRIPT_TAG 

''' 
from __future__ import absolute_import 

import json 

from jinja2 import Environment, PackageLoader, Markup 

_env = Environment(loader=PackageLoader('bokeh.core', '_templates')) 
_env.filters['json'] = lambda obj: Markup(json.dumps(obj)) 


JS_RESOURCES = _env.get_template("js_resources.html") 

CSS_RESOURCES = _env.get_template("css_resources.html") 

SCRIPT_TAG = _env.get_template("script_tag.html") 

PLOT_DIV = _env.get_template("plot_div.html") 

DOC_JS = _env.get_template("doc_js.js") 

FILE = _env.get_template("file.html") 

NOTEBOOK_LOAD = _env.get_template("notebook_load.html") 

NOTEBOOK_DIV = _env.get_template("notebook_div.html") 

AUTOLOAD_JS = _env.get_template("autoload_js.js") 

AUTOLOAD_NB_JS = _env.get_template("autoload_nb_js.js") 

AUTOLOAD_TAG = _env.get_template("autoload_tag.html") 

Ben hattına sorunu takip

File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\templates.py", line 27, in <module> 
    JS_RESOURCES = _env.get_template("js_resources.html") 
    File "C:\ProgramData\Anaconda3\lib\site-packages\jinja2\environment.py", line 830, in get_template 
    return self._load_template(name, self.make_globals(globals)) 
    File "C:\ProgramData\Anaconda3\lib\site-packages\jinja2\environment.py", line 804, in _load_template 
    template = self.loader.load(self, name, globals) 
    File "C:\ProgramData\Anaconda3\lib\site-packages\jinja2\loaders.py", line 113, in load 
    source, filename, uptodate = self.get_source(environment, name) 
    File "C:\ProgramData\Anaconda3\lib\site-packages\jinja2\loaders.py", line 234, in get_source 
    if not self.provider.has_resource(p): 
    File "C:\ProgramData\Anaconda3\lib\site-packages\pkg_resources\__init__.py", line 1464, in has_resource 
    return self._has(self._fn(self.module_path, resource_name)) 
    File "C:\ProgramData\Anaconda3\lib\site-packages\pkg_resources\__init__.py", line 1514, in _has 
    "Can't perform this operation for unregistered loader type" 
NotImplementedError: Can't perform this operation for unregistered loader type 

Yeni templates.py dosyası:

''' Provide Jinja2 templates used by Bokeh to embed Bokeh models 
(e.g. plots, widgets, layouts) in various ways. 

.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_JS 
.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_NB_JS 
.. bokeh-jinja:: bokeh.core.templates.AUTOLOAD_TAG 
.. bokeh-jinja:: bokeh.core.templates.CSS_RESOURCES 
.. bokeh-jinja:: bokeh.core.templates.DOC_JS 
.. bokeh-jinja:: bokeh.core.templates.FILE 
.. bokeh-jinja:: bokeh.core.templates.JS_RESOURCES 
.. bokeh-jinja:: bokeh.core.templates.NOTEBOOK_LOAD 
.. bokeh-jinja:: bokeh.core.templates.NOTEBOOK_DIV 
.. bokeh-jinja:: bokeh.core.templates.PLOT_DIV 
.. bokeh-jinja:: bokeh.core.templates.SCRIPT_TAG 

''' 
from __future__ import absolute_import 

import json 
import sys, os 
import bokeh.core 

# from jinja2 import Environment, PackageLoader, Markup 
from jinja2 import Environment, Markup, FileSystemLoader 

# add in from Uynix 
def resource_path(relative_path, file_name): 
    """ Get absolute path to resource, works for both in IDE and for PyInstaller """ 
    # PyInstaller creates a temp folder and stores path in sys._MEIPASS 
    # In IDE, the path is os.path.join(base_path, relative_path, file_name) 
    # Search in Dev path first, then MEIPASS 
    base_path = os.path.abspath(".") 
    dev_file_path = os.path.join(base_path, relative_path, file_name) 
    if os.path.exists(dev_file_path): 
     return dev_file_path 
    else: 
     base_path = sys._MEIPASS 
     file_path = os.path.join(base_path, file_name) 
     if not os.path.exists(file_path): 
      msg = "\nError finding resource in either {} or {}".format(dev_file_path, file_path) 
      print(msg) 
      return None 
     return file_path 



""" my new code here 
""" 
_env = Environment(loader=FileSystemLoader(os.path.dirname(bokeh.core.__file__) +'\\_templates')) 
""" end of my new code 
""" 


_env.filters['json'] = lambda obj: Markup(json.dumps(obj)) 

# this is where the errors start to happen! need to replace get_template! 
JS_RESOURCES = _env.get_template("js_resources.html") 

CSS_RESOURCES = _env.get_template("css_resources.html") 

SCRIPT_TAG = _env.get_template("script_tag.html") 

PLOT_DIV = _env.get_template("plot_div.html") 

DOC_JS = _env.get_template("doc_js.js") 

FILE = _env.get_template("file.html") 

NOTEBOOK_LOAD = _env.get_template("notebook_load.html") 

NOTEBOOK_DIV = _env.get_template("notebook_div.html") 

AUTOLOAD_JS = _env.get_template("autoload_js.js") 

AUTOLOAD_NB_JS = _env.get_template("autoload_nb_js.js") 

AUTOLOAD_TAG = _env.get_template("autoload_tag.html") 

Sonra cx_freeze vb tekrar koştu ve bu sefer bokeh artık çalışıyor!