LINUX.ORG.RU

Вытащить import'ы из .py файла

 ,


0

1

Например есть такой файл:

"""Some util classes"""

from math import sqrt


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def get_dist_to_point(self, point):
        return sqrt((self.x - point.x) ** 2 + (self.y - point.y) ** 2)


class Pair:
    def __init__(self, first, second):
        self.first = first
        self.second = second

    def swap(self):
        temp = self.first
        self.first = self.second
        self.second = temp

Необходимо вытащить список импортируемых модулей (в данном случае только math) и путь до него.

Можно ли как-либо это сделать?

Пробовал через modulefinder, так он ещё кучу всего пишет, что мне не нужно. Судя по всему, тащит ещё внутренние импорты, что мне не нужно.

Deleted

Последнее исправление: merhalak (всего исправлений: 1)

Ответ на: комментарий от Deleted

Да, наверно.

Просто делаешь

# smth.py
import re, itertools

Прогоняешь по нему modulefinder и получаешь в морду:

__main__
re
enum
sys
types
functools
_functools
abc
_weakrefset
_weakref
collections
_collections_abc
operator
builtins
_operator
keyword
heapq
_heapq
doctest
__future__
argparse
copy
weakref
itertools
atexit
gc
copyreg
os
errno
stat
_stat
posixpath
genericpath
nt
ntpath
warnings
_warnings
linecache
tokenize
codecs
_codecs
encodings
encodings.aliases
_bootlocale
_locale
locale
encodings.mbcs
io
_io
token
tracemalloc
fnmatch
pickle
struct
_struct
_compat_pickle
_pickle
pprint
time
_tracemalloc
string
_string
subprocess
signal
_signal
threading
_thread
traceback
_collections
_threading_local
contextlib
msvcrt
_winapi
select
selectors
math
dummy_threading
_dummy_thread
textwrap
gettext
difflib
inspect
ast
_ast
dis
opcode
_opcode
collections.abc
importlib
_imp
importlib._bootstrap
importlib._bootstrap_external
importlib.machinery
pdb
cmd
bdb
reprlib
code
codeop
glob
shlex
pydoc
importlib.util
importlib.abc
pkgutil
zipimport
marshal
platform
winreg
plistlib
binascii
datetime
_datetime
_strptime
calendar
xml
xml.parsers
xml.parsers.expat
pyexpat
socket
_socket
urllib
urllib.parse
tempfile
shutil
zlib
bz2
_compression
_bz2
lzma
_lzma
tarfile
gzip
zipfile
py_compile
random
hashlib
_hashlib
logging
_sha1
_md5
_sha256
_sha512
_blake2
_sha3
bisect
_bisect
_random
tty
pydoc_data
pydoc_data.topics
http
http.server
email
email.parser
email.feedparser
email.errors
email._policybase
email.header
email.quoprimime
email.base64mime
base64
getopt
email.charset
email.encoders
quopri
email.utils
email._parseaddr
email.message
uu
optparse
email._encoded_words
email.iterators
email.generator
email.policy
email.headerregistry
email._header_value_parser
email.contentmanager
html
html.entities
http.client
ssl
ipaddress
_ssl
mimetypes
socketserver
webbrowser
unittest
unittest.result
unittest.util
unittest.case
unittest.suite
unittest.loader
unittest.main
unittest.runner
unittest.signals
sre_compile
_sre
sre_parse
sre_constants

Deleted
()

В глобальном пространстве текущего модуля? Ну как-то так, например


 def ree():
     import types
     for k, v in globals().items():
         if hasattr(v, '__module__'):
             v = __import__(v.__module__)
         if isinstance(v, types.ModuleType) and hasattr(v, '__file__'):
             yield v.__file__

print(list(ree()))
pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

Нет, необходимо распарсить кодом из питона другой питоновский модуль.

То есть есть в одном проекте main.py, в другом foo.py.

Нужно из main.py выяснить, какие модули импортируются в foo.py и найти до них пути. Без глобальных импортов. Хоть регекспами пиши, что печально.

Deleted
()
Последнее исправление: merhalak (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Пока что решил проблему вот так.

К чему ты клонишь?

from modulefinder import ModuleFinder
from os import getcwd

finder = ModuleFinder()

finder.run_script("tests/util_test.py")

working_dir = getcwd()
for name, module in finder.modules.items():
    module_path = str(module.__file__)
    if module_path.startswith(working_dir) and not 'venv' in module_path:
        print(name)
        print(working_dir, module_path)

Deleted
()
Последнее исправление: merhalak (всего исправлений: 1)
Ответ на: комментарий от Deleted

Для твоего примера будет работать так


# cat main.py
import inspect
import foo

for k, v in foo.__dict__.items():
    v = inspect.getmodule(v)
    if hasattr(v, '__file__'):
        print(v.__file__)

# cat foo.py
from math import sqrt

Но если импорты внутри функций, их не увидит. Можно сделать import hook.

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

Ты сейчас из main'а достаёшь импорты main'а.

А у меня примерно так:

project1/main.py (тот, кто ищет)

project2/abc.py
project2/tests/abc_test.py

Надо main натравить на project2 (аргументами в консоли) и достать импорты abc.py и tests/abs_test.py.

Выше накидал своё решение.

Заранее из кода неизвестно, на какие модули будет натравлен project1/main.py

Deleted
()
Последнее исправление: merhalak (всего исправлений: 1)
Ответ на: комментарий от Deleted

К чему ты клонишь?

К тому, что для поиска импортируемых модулей у тебя есть возможность воспользоваться компилятором: https://docs.python.org/2/library/ast.html Причем, что характерно, он найдет все операторы импорта, даже под if или try.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Спасибо, не знал (питон никогда нормально не изучал), пойду читать.

Deleted
()
Ответ на: комментарий от pawnhearts

Ты в main явно сделал import foo а у меня main ничего про foo заранее не знает, на этапе написания кода main.

Анализатор пишу потихонечку.

Deleted
()
Ответ на: комментарий от Deleted

Ты можешь импортировать foo через __import__, importlib или вообще eval сделать. Но tailgunner предлагает более грамотный вариант.

Ещё один костыльный вариант - сравнить sys.modules до и после импорта foo.

pawnhearts ★★★★★
()
Последнее исправление: pawnhearts (всего исправлений: 1)
Ответ на: комментарий от MikeWortin

Как раз это то я могу сделать.

Мне потом надо понять, из локального ли проекта импорт, и, если да, дать относительный путь до исходника. В общем, мне тут сверху примеров по ast накидали. В идеале вообще поверх antlr4 бы сваять, чтобы не было привязки только к Python, но я уже не успею.

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.