python项目文件内部添加环境变量无效问题

项目场景:

在通过使用 os.environ['PATH'] += ';xxx'或者 sys.path.append('xxx') 添加临时系统环境变量时偶尔失效问题
在这里插入图片描述

例如如下代码:

import sys
sys.path.append('D:\\Program Files\\nodejs')
print(sys.path)
from tkinter import *
import execjs


def get_js(fileNme):
    jscript = execjs.get("Node")
    # jscript = execjs.get()
    print(jscript.name)
    with open(fileNme, 'r', encoding='utf-8')as f:
        content = f.read()
    js = jscript.compile(content)
    return js


def get_data(entry):
    js = get_js("测试.js")
    var.set(str(js.call("getData", "1")))


root = Tk()
button = Button(root, text="点击", command=lambda: get_data(entry))
button.pack()
var = StringVar()
entry = Entry(root, textvariable=var)
entry.pack()
root.mainloop()

问题描述

我的nodejs就放在 D:\\Program Files\\nodejs 中,但是无论如何 print(jscript.name) 的执行结果都是 execjs._exceptions.RuntimeUnavailableError: Node.js (V8) runtime is not available on this system 这个错误,按正常情况在体统环境变量中增加 D:\\Program Files\\nodejs 执行结果应该是 Node.js (V8) 那么问题来了,究竟是什么原因呢?


原因分析:

老规矩,哪里出问题,哪里断点调试,看看究竟是什么在作祟

  • jscript = execjs.get("Node")处断点,单步调试,一直找到execjs_runtimes.py
def _find_runtime_by_name(name):
    for runtime_name, runtime in _runtimes:
        if runtime_name.lower() == name.lower():
            break
    else:
        raise exceptions.RuntimeUnavailableError("{name} runtime is not defined".format(name=name))

    if not runtime.is_available():
        raise exceptions.RuntimeUnavailableError(
            "{name} runtime is not available on this system".format(name=runtime.name))
    return runtime
  • 由以上源代码可知,报错就是在这里报的,关键点在于runtime.is_available()这个函数返回值究竟有没有。
  • 继续跟进,发现这个函数返回值是self._available
    def is_available(self):
        return self._available
  • 在文件中搜索查看self._available在哪里定义的,发现是这个函数所在的类初始化时候定义的
class ExternalRuntime(AbstractRuntime):
    '''Runtime to execute codes with external command.'''
    def __init__(self, name, command, runner_source, encoding='utf8', tempfile=False):
        self._name = name
        if isinstance(command, str):
            command = [command]
        self._command = command
        self._runner_source = runner_source
        self._encoding = encoding
        self._tempfile = tempfile
        self._available = self._binary() is not None
  • self._available = self._binary() is not None打断点,注意这里不能往下调试了,因为这个定义是在我们刚才调试开始的位置之前运行的,所以打上断点后重新开始调试。
  • 根据断点后栈的规则,结果发现这个是在import execjs的时候运行的。而且self._available的值是self._binary()给出的,继续一直往下调试,直到下面这个函数
def _find_executable(prog, pathext=("",)):
    """protected"""
    pathlist = _decode_if_not_text(os.environ.get('PATH', '')).split(os.pathsep)

    for dir in pathlist:
        for ext in pathext:
            filename = os.path.join(dir, prog + ext)
            try:
                st = os.stat(filename)
            except os.error:
                continue
            if stat.S_ISREG(st.st_mode) and (stat.S_IMODE(st.st_mode) & 0o111):
                return filename
    return None
  • 根据上面这个函数知道了在import execjs的时候是从os.environ.get('PATH', '')中读取的系统环境变量而我们一开始是加在了sys.path.append('D:\\Program Files\\nodejs')这里。
  • 到现在为止,已经很明显了,sys.path就是原本的系统环境变量,sys.path.append('D:\\Program Files\\nodejs')这行代码只是给sys.path增加了一个子元素,并不是真正加在了环境变量中,而这时候我们通过os.environ.get('PATH', '')读到的也还是系统的环境变量,并没有增加'D:\\Program Files\\nodejs'。因此会出现错误。

解决方案:

  • 知道了问题的原因,解决就简单了,既然execjs读的是os.environ.get('PATH', ''),那么我加的时候就加在os.environ里就好了。如下
import os
	os.environ['PATH'] += ';D:\\Program Files\\nodejs'
print(os.environ['PATH'])

注意:';D:\\Program Files\\nodejs'最前面一定要有;,要不然在pycharm里可以正常运行,但是在控制台或者直接打开的时候就不能运行了,尤其是win10及以上的系统,究其原因是系统内置的问题,在这里不便展开说了,要想知道自己可以添加环境变量,然后打印结果,分别在pycharm和控制台打印,找找区别就可以了。这里我贴两张图,大家可以自己看下,差别就在一个;上。

  • pycharm中运行结果:
    pycharm中运行结果
  • 控制台运行结果
    在这里插入图片描述

总结

python项目文件内部添加环境变量无效时,

  • 可以直接自己手动在系统环境变量中添加,这样是可以解决问题的。(手动在系统环境变量中添加环境变量的方法上网一搜一大堆,这也不是这篇文章想表达的重点)
  • 可以查看源代码,看哪里需要了环境变量,找到后查看是通过os调用还是通过sys调用的,针对性添加就可以了(主要适用于你的python文件需要打包给其他客户使用,由懒得给他装环境,直接把环境打包进去,文件内部增加环境变量即可)
  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值