Python:利用不同级别模块之间共享的实用函数构建项目

发布于 2025-01-17 06:47:45 字数 1085 浏览 2 评论 0原文

我有一个 python 3.10 项目,它结合使用了抓取网站、数据分析和其他 API。一些实用模块可以由抓取和数据分析模块使用。我从根本上误解了 Python 中导入的工作原理。 例如,在 sl_networking.py 中,我尝试从 result.py 导入 Result 类:

from ...util.result import Result

产生错误:

PS C:\Development\TradeAssist> & c:/Development/TradeAssist/.venv/Scripts/python.exe c:/Development/TradeAssist/libs/scrapers/sl/sl_networking.py
Traceback (most recent call last):
  File "c:\Development\TradeAssist\libs\scrapers\sl\sl_networking.py", line 1, in <module>
    from ...util.result import Result
ImportError: attempted relative import with no known parent package

项目结构 I'我当前使用的是:

TradeAssist
|__libs
|  |__broker_apis
|  |  |__ibapi
|  |__data_analysis
|  |  |__sl
|  |  |__ta
|  |__scrapers
|  |  |__sl
|  |  |  |  sl_auth.py
|  |  |  |__sl_networking.py
|  |  |__ta
|  |__util
|     |__result.py
|__tests
   |__test_sl.py
   |__test_ta.py

如果我有一个公共实用程序函数,我希望在 data_analysisscraper 模块中使用,我应该如何构建我的项目并处理导入?

I have python 3.10 project that uses a combination of scraping websites, data analysis, and additional APIs. Some utility modules may be used by the scraping and data analysis modules. I'm fundamentally misunderstanding something about how imports work in Python.
For example, in sl_networking.py, I try to import the Result class from result.py:

from ...util.result import Result

Producing the error:

PS C:\Development\TradeAssist> & c:/Development/TradeAssist/.venv/Scripts/python.exe c:/Development/TradeAssist/libs/scrapers/sl/sl_networking.py
Traceback (most recent call last):
  File "c:\Development\TradeAssist\libs\scrapers\sl\sl_networking.py", line 1, in <module>
    from ...util.result import Result
ImportError: attempted relative import with no known parent package

The project structure I'm currently using is:

TradeAssist
|__libs
|  |__broker_apis
|  |  |__ibapi
|  |__data_analysis
|  |  |__sl
|  |  |__ta
|  |__scrapers
|  |  |__sl
|  |  |  |  sl_auth.py
|  |  |  |__sl_networking.py
|  |  |__ta
|  |__util
|     |__result.py
|__tests
   |__test_sl.py
   |__test_ta.py

If I have a common utility function that I expect to use within the data_analysis and scraper modules, how should I be structuring my project and handling imports?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感情洁癖 2025-01-24 06:47:45

这不是一个Python问题,而是一个VSCode问题。 VSCode 默认运行 Python 文件的方式有点愚蠢。当您在 test_sl 上单击小三角形“运行 Python 文件”时,VSCode 将运行如下命令:

/usr/local/bin/python3 /path/to/TradeAssist/tests/test_ta.py

Python by defaultinitialises sys.path 包含正在运行的文件所在的目录,以及它自己的库,无论你里面有什么PYTHONPATH 变量。这意味着您的 sys.path 看起来像这样(... 是 Python 的库)

['/path/to/TradeAssist/tests', ...]

但是,这意味着 lib 中的代码无法访问; Python 只能正确找到 tests 内的文件。即开箱即用,VSCode 只能运行根源文件夹中的 Python 文件(例如 src 或直接位于根工作区文件夹中)。

有几种解决方案。

第一个最简单:确定您的 TradeAssist 是源根目录,并将您想要直接执行的任何文件放在那里。他们将能够导入其下的任何文件,并且其下的文件将能够正确使用相对和绝对导入。这有明显的缺点——你会自我限制在一个目录中。

第二种是通过定义 PYTHONPATH 来设置 VSCode 来告诉 Python 你的源根目录在哪里。这是相当复杂

第三种是最简单的,也可能是正确的情况:使用 VSCode 的 测试 功能。 配置测试框架(大概使用unittesttest_*.py 测试文件模式),然后只需 运行测试。如果您认为 TradeAssist 是您的源根,它将正常工作(即 import libs.scrapers.sl.sl_networking 将在您的测试中正常工作,并且 from ...util.result import Result 将在您的 sl_networking.py 中正常工作)。测试功能将以正确的方式为您运行测试。

但是,如果您想将 libs 视为您的源根目录(即您希望import scrapers.sl.sl_networking),或者如果您希望能够运行任意文件,而不仅仅是测试,那么你必须回退到方法#2:搞乱PYTHONPATH

tl;dr: 不要手动运行测试文件,让 VSCode 通过正确设置测试来为您完成此操作。

This is not a Python question, but rather a VSCode question. The way VSCode runs Python files by default is a little bit dumb. When you click the little triangle to "Run Python File" on test_sl, VSCode will run a command such as this:

/usr/local/bin/python3 /path/to/TradeAssist/tests/test_ta.py

Python by default initialises sys.path to contain the directory containing the file being run, in addition to its own libraries, and whatever is in your PYTHONPATH variable. This means your sys.path looks something like this (with ... being Python's libraries)

['/path/to/TradeAssist/tests', ...]

However, this means code in lib is not reachable; only files inside tests will be correctly found by Python. I.e. out of the box, VSCode is only able to run Python files that are in your root source folder (e.g. src, or directly in the root workspace folder).

There are several solutions.

The first one is simplest: decide that your TradeAssist is the source root, and put any files you want to execute directly there. They will be able to import any files under them, and the files under them will be able to use both relative and absolute imports correctly. This has obvious disadvantages — you would be self-limiting yourself to one directory.

The second is to set up VSCode to tell Python where your source root(s) are, by defining PYTHONPATH. This is fairly complex.

The third is the simplest, and likely the correct case here: use VSCode's testing functionality. Configure the testing framework (presumably using unittest and test_*.py test file pattern), then just run the tests. If you consider TradeAssist to be your source root, it will work correctly (i.e. import libs.scrapers.sl.sl_networking will work correctly inside your tests, and from ...util.result import Result will work correctly inside your sl_networking.py). The testing function will take care of running the tests for you in a correct fashion.

However, if you want to consider libs to be your source root (i.e. you would like to do import scrapers.sl.sl_networking), or if you want to be able to run arbitrary files, not just tests, then you have to fall back to method #2: messing with PYTHONPATH.

tl;dr: Don't run test files manually, let VSCode do it for you by setting up tests correctly.

一张白纸 2025-01-24 06:47:45

相对导入仅在从最外层父根执行代码时才起作用。目前场景下,只能执行libs目录及以上的代码。

python -m scrapers.sl.sl_networking

如果您在 libs 目录中运行

应该可以正常工作。一旦项目构建完成,就可以使用 -m 标志轻松地从顶级父目录运行各个脚本,因为不需要重构。如果必须从脚本父目录执行代码,则必须执行以下操作:

  1. 使用绝对导入而不是相对导入。
  2. 将目录添加到 python 搜索导入的路径中。这可以通过多种方式完成。将其添加到 PYTHONPATH 环境变量或使用任何 sys.path.appendsys.path.insert 黑客,这可以很容易成立。

Relative imports only work when the code is executed from the outermost parent root. In the current scenario, you can only execute the code at or above libs directory.

python -m scrapers.sl.sl_networking

should work fine if you are running this at libs directory.

Once the project is structured, it is easy to run the individual scripts from the top parent directory using -m flag, as no refactoring will be required. If the code has to be executed from the script parent directory, the following has to be done:

  1. Use absolute imports instead of relative imports.
  2. Add the directory to the path python searches for imports. This can be done in several ways. Add it to the PYTHONPATH env variable or use any of the sys.path.append or sys.path.insert hacks, which can be easily found.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文