deb-ryu/ryu/utils.py
Brad Cowie a197d87375 utils.import_module: Prefer filepath than Python module
Currently, ryu.utils.import_module() prefers the Python module path
than the user specified file path, and if the user app name is the
same with the Python module, this function returns the Python module
instead of the user app.

This patch fixes to try to load "file" before finding the loaded
Python module, and fixes this problem.

Note: With this patch, import_module() will reload (override) a module
if the specified module file name is the same.

Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: Brad Cowie <brad@gizmoguy.net.nz>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
2017-05-09 10:48:18 +09:00

159 lines
4.5 KiB
Python

# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
# Copyright (C) 2011 Isaku Yamahata <yamahata at valinux co jp>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import importlib
import logging
import os
import sys
import six
from pip import req as pip_req
from pip.download import PipSession
LOG = logging.getLogger('ryu.utils')
def load_source(name, pathname):
"""
This function provides the backward compatibility for 'imp.load_source'
in Python 2.
:param name: Name used to create or access a module object.
:param pathname: Path pointing to the source file.
:return: Loaded and initialized module.
"""
if six.PY2:
import imp
return imp.load_source(name, pathname)
else:
loader = importlib.machinery.SourceFileLoader(name, pathname)
return loader.load_module(name)
def chop_py_suffix(p):
for suf in ['.py', '.pyc', '.pyo']:
if p.endswith(suf):
return p[:-len(suf)]
return p
def _likely_same(a, b):
try:
# Samefile not availible on windows
if sys.platform == 'win32':
if os.stat(a) == os.stat(b):
return True
else:
if os.path.samefile(a, b):
return True
except OSError:
# m.__file__ is not always accessible. eg. egg
return False
if chop_py_suffix(a) == chop_py_suffix(b):
return True
return False
def _find_loaded_module(modpath):
# copy() to avoid RuntimeError: dictionary changed size during iteration
for k, m in sys.modules.copy().items():
if k == '__main__':
continue
if not hasattr(m, '__file__'):
continue
if _likely_same(m.__file__, modpath):
return m
return None
def _import_module_file(path):
abspath = os.path.abspath(path)
# Backup original sys.path before appending path to file
original_path = list(sys.path)
sys.path.append(os.path.dirname(abspath))
modname = chop_py_suffix(os.path.basename(abspath))
try:
return load_source(modname, abspath)
finally:
# Restore original sys.path
sys.path = original_path
def import_module(modname):
if os.path.exists(modname):
try:
# Try to import module since 'modname' is a valid path to a file
# e.g.) modname = './path/to/module/name.py'
return _import_module_file(modname)
except SyntaxError:
# The file didn't parse as valid Python code, try
# importing module assuming 'modname' is a Python module name
# e.g.) modname = 'path.to.module.name'
return importlib.import_module(modname)
else:
# Import module assuming 'modname' is a Python module name
# e.g.) modname = 'path.to.module.name'
return importlib.import_module(modname)
def round_up(x, y):
return ((x + y - 1) // y) * y
def hex_array(data):
"""
Convert six.binary_type or bytearray into array of hexes to be printed.
"""
# convert data into bytearray explicitly
return ' '.join('0x%02x' % byte for byte in bytearray(data))
def binary_str(data):
"""
Convert six.binary_type or bytearray into str to be printed.
"""
# convert data into bytearray explicitly
return ''.join('\\x%02x' % byte for byte in bytearray(data))
def parse_requirements(requirements_files=None):
"""
Parses requirements files and returns a list of requirements.
Returned list would be like::
['foo', 'bar>=X.X', ...]
:param requirements_files: List of requirements files. The default
is ['requirements.txt', 'tools/pip-requires'].
:return: List of requirements.
"""
requirements_files = requirements_files or [
'requirements.txt',
'tools/pip-requires',
]
requirements = []
for f in requirements_files:
if not os.path.isfile(f):
continue
for r in pip_req.parse_requirements(f, session=PipSession()):
requirements.append(str(r.req))
return requirements