You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Js2Py在Python中嵌入JavaScript时Pylance报错求助

问题描述

我尝试在Python应用中使用Js2Py库嵌入JavaScript代码,但Pylance持续抛出错误:第34行提示“{未闭合”(实际已正确闭合),第35行的“global”处提示“expected expression”。请问我存在哪些操作错误或遗漏点?

import js2py

# var_stars = js2py.eval_var('var')


    var_stars = [
        [0, 1.39734], 
        [2.6521683, 0],
        [2.5652089, 5.97229],
        [5.6232309, 2.98584],
        [2.1902414, 2.23642]
    ]
    
    # const = js2py.eval_const('const')
    # A4 = js2py.eval_A4('A4')
    # A4Width = js2py.eval_A4Width('A4Width')
    
    
    const_A4Width = 210
    const_A4Height = 297
    A4_measures = const_A4Width * const_A4Height
    const_A4Margin = 5
    
    
    setTimeout = js2py.eval_setTimeout('setTimeout')
    document = js2py.eval_document('document')
    generatePDF = js2py.eval_generatePDF('generatePDF')
    
    # const = js2py.eval_const('const')
    # console = js2py.eval_console('console')
    
    def generatePDF():  
      {
        global jsPDF 
        var doc = new jsPDF();

        const color = document.querySelector('select').value;
        console.log(color);

        
        doc.setFillColor(255, 255, 255);
        doc.setLineWidth(1);
        doc.setDrawColor(0,255,0);
        doc.circle(120, 20, 5, "S"); 
        
    
        var points = generatePoints(200, 10, A4Margin, A4Width-A4Margin-6, A4Margin, A4Height-A4Margin-6);
        for( var i=0; i<points.length; i++ )
        {
          drawEurion(points[i][0], points[i][1], Math.random()*2*Math.PI, color); 
        }
    
        
        for( var i=0; i<points.length; i++ )
        {
          console.log(points[i][0], points[i][1])
          
          for( var j=i+1; j<points.length; j++ )
          {
            var distance = Math.sqrt(Math.pow(points[i][0]-points[j][0],2)+Math.pow(points[i][1]-points[j][1],2))
            if( distance<10 )
              console.log('d', i, j, Math.sqrt(Math.pow(points[i][0]-points[j][0],2)+Math.pow(points[i][1]-points[j][1],2)) )
              
          }
      
        }
        
          
        //doc.save("eurion.pdf")
        //pdf_test_harness_init(pdf, "Open in Reader (or Firefox) to see the PDF outline");
        //doc.output('datauri') //datauri
        document.querySelector('iframe').src=doc.output('datauristring');
    
    
    
        function drawEurion(offsetX, offsetY, angle, color)
        {
          doc.setDrawColor(color);
          doc.setLineWidth(0.24834293);
          const centreX = 2.6;
          const centreY = 3;
    
          for( var i=0; i<stars.length; i++ )
          {
            var x = offsetX + centreX + Math.cos(angle)*(stars[i][0]-centreX) + Math.sin(angle)*(stars[i][1]-centreY)
            var y = offsetY + centreY - Math.sin(angle)*(stars[i][0]-centreX) + Math.cos(angle)*(stars[i][1]-centreY)
            doc.circle(x, y, 0.36089846, "S");
          }
          //doc.setDrawColor(0,255,0);
          //doc.circle(offsetX+centreX, offsetY+centreY, 4.4, "S");
          
        }
    
        function generatePoints(number, distance, minX, maxX, minY, maxY, )
        {
          var points = [];
          var tries = 0;
          while( points.length<number && tries<40 )
          {
            tries = 0;
            var validPoint = false;
            while( tries<40 && validPoint==false )
            {
              tries++;
              var x = minX + Math.random()*(maxX-minX)
              var y = minY + Math.random()*(maxY-minY)
              validPoint = true
              for( var i=0; i<points.length; i++ )
              {
                if( Math.sqrt(Math.pow(points[i][0]-x,2)+Math.pow(points[i][1]-y,2))<distance )
                //if( Math.abs(points[i][0]-x)<distance/2 || Math.abs(points[i][1]-y)<distance/2 )
                {
                  validPoint = false;
                  break;
                }
              }
              if( validPoint )
                points.push([x,y])
            }
          }
          return points
          
        }
      
    
        setTimeout(generatePDF, 10)
        document.querySelector('select').oninput = generatePDF(); 
        document.querySelector('select').onchange = generatePDF();
        document.querySelector('form').onsubmit = (setTimeout(generatePDF()), 10) 
        return False
      }
错误分析

你的代码存在以下核心问题:

  • 语法混淆:把JavaScript语法直接写在Python函数中,Pylance会按照Python语法规则解析代码:
    • Python函数体不需要用{}包裹,而是靠缩进区分代码块,你写的{会被Python解析器视为语法错误。
    • var、const、function是JavaScript关键字,不是Python语法,Pylance会报错“expected expression”。
    • Python的global关键字用于声明Python全局变量,但你用它来标记JS的jsPDF,完全不符合Python语法逻辑。
  • Js2Py使用方式错误:Js2Py的核心是将JS代码作为字符串传入js2py.eval_js()或js2py.compile_js()执行,而不是直接把JS代码混在Python函数里。你尝试的js2py.eval_setTimeout这类写法不存在,Js2Py会自动模拟JS全局环境,直接在JS代码中使用setTimeout、console即可。
  • 变量作用域错误:Python中的var_stars、const_A4Width等变量无法直接在JS代码中使用,需要手动注入到JS环境。
  • Python缩进错误:代码中var_stars、const_A4Width等变量的缩进层级不对,不符合Python的缩进规范。
修正方案

将JavaScript代码抽离为单独的字符串,使用Js2Py执行并注入所需的Python变量,同时修正Python语法问题:

import js2py

# Python端定义的变量
var_stars = [
    [0, 1.39734], 
    [2.6521683, 0],
    [2.5652089, 5.97229],
    [5.6232309, 2.98584],
    [2.1902414, 2.23642]
]

const_A4Width = 210
const_A4Height = 297
const_A4Margin = 5

# 定义JavaScript代码字符串
js_code = """
function generatePDF() {
    var doc = new jsPDF();

    // 注意:这里的document是JS环境模拟对象,实际使用时可能需要替换为对应的模拟实现
    const color = document.querySelector('select').value;
    console.log(color);

    doc.setFillColor(255, 255, 255);
    doc.setLineWidth(1);
    doc.setDrawColor(0,255,0);
    doc.circle(120, 20, 5, "S"); 

    var points = generatePoints(200, 10, A4Margin, A4Width-A4Margin-6, A4Margin, A4Height-A4Margin-6);
    for( var i=0; i<points.length; i++ ) {
        drawEurion(points[i][0], points[i][1], Math.random()*2*Math.PI, color); 
    }

    for( var i=0; i<points.length; i++ ) {
        console.log(points[i][0], points[i][1]);
        
        for( var j=i+1; j<points.length; j++ ) {
            var distance = Math.sqrt(Math.pow(points[i][0]-points[j][0],2)+Math.pow(points[i][1]-points[j][1],2));
            if( distance<10 ) {
                console.log('d', i, j, distance);
            }
        }
    }

    document.querySelector('iframe').src=doc.output('datauristring');

    function drawEurion(offsetX, offsetY, angle, color) {
        doc.setDrawColor(color);
        doc.setLineWidth(0.24834293);
        const centreX = 2.6;
        const centreY = 3;

        for( var i=0; i<stars.length; i++ ) {
            var x = offsetX + centreX + Math.cos(angle)*(stars[i][0]-centreX) + Math.sin(angle)*(stars[i][1]-centreY);
            var y = offsetY + centreY - Math.sin(angle)*(stars[i][0]-centreX) + Math.cos(angle)*(stars[i][1]-centreY);
            doc.circle(x, y, 0.36089846, "S");
        }
    }

    function generatePoints(number, distance, minX, maxX, minY, maxY) {
        var points = [];
        var tries = 0;
        while( points.length<number && tries<40 ) {
            tries = 0;
            var validPoint = false;
            while( tries<40 && validPoint==false ) {
                tries++;
                var x = minX + Math.random()*(maxX-minX);
                var y = minY + Math.random()*(maxY-minY);
                validPoint = true;
                for( var i=0; i<points.length; i++ ) {
                    if( Math.sqrt(Math.pow(points[i][0]-x,2)+Math.pow(points[i][1]-y,2))<distance ) {
                        validPoint = false;
                        break;
                    }
                }
                if( validPoint ) {
                    points.push([x,y]);
                }
            }
        }
        return points;
    }

    setTimeout(generatePDF, 10);
    document.querySelector('select').oninput = generatePDF; 
    document.querySelector('select').onchange = generatePDF;
    document.querySelector('form').onsubmit = function() {
        setTimeout(generatePDF, 10);
        return false;
    };
}

// 执行生成PDF函数
generatePDF();
"""

# 创建JS上下文,注入Python变量
context = js2py.EvalJs()
context.stars = var_stars
context.A4Width = const_A4Width
context.A4Height = const_A4Height
context.A4Margin = const_A4Margin

# 注意:jsPDF需要提前在JS环境中加载,你可以通过context.eval_js()加载jsPDF的CDN代码
# 例如:context.eval_js("""
#     var script = document.createElement('script');
#     script.src = 'https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js';
#     document.head.appendChild(script);
# """)

# 执行JS代码
context.eval_js(js_code)
额外说明
  1. 如果你需要模拟document、window等浏览器环境,Js2Py默认的环境不包含这些对象,需要自己实现或使用额外的模拟逻辑。
  2. jsPDF需要在JS环境中提前加载,你可以通过注入脚本的方式引入其资源。
  3. 修正了JS代码中的语法细节(如多余的逗号、缺少的分号),避免JS执行时出错。

内容的提问来源于stack exchange,提问作者Squirtgun187

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 13:40:10