-
Notifications
You must be signed in to change notification settings - Fork 92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: sub module conflict error #295
base: master
Are you sure you want to change the base?
Conversation
Sorry, I can't access my development computer these days. I will review it a few days later. But the test case should be passed before merging. |
That's OK, I'll fix the test cases. |
thriftpy2/parser/parser.py
Outdated
@@ -949,3 +960,8 @@ def _get_ttype(inst, default_ttype=None): | |||
if hasattr(inst, '__dict__') and '_ttype' in inst.__dict__: | |||
return inst.__dict__['_ttype'] | |||
return default_ttype | |||
|
|||
def remove_suffix(s, suffix): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just use s.replace(suffix, "")
is better.
import itertools
from faker import Faker
SUFFIX = "__SOME_SUFFIX_"
class MyFaker(Faker):
def suffix_name(self):
return f"{self.name()}{SUFFIX}"
fake = MyFaker()
data_num = 10000
escape_ratio = 0.5
escape_num = int(data_num * escape_ratio)
suffix_texts = [fake.suffix_name() for _ in range(escape_num)]
normal_texts = [fake.name() for _ in range(data_num - escape_num)]
def test_and_replace():
for text in itertools.chain(suffix_texts, normal_texts):
if text.endswith(SUFFIX):
res = text.replace(SUFFIX, "")
return res
def test_and_replace_with_slie():
for text in itertools.chain(suffix_texts, normal_texts):
if text.endswith(SUFFIX):
res = text[:-len(SUFFIX)]
return res
def just_replace():
for text in itertools.chain(suffix_texts, normal_texts):
res = text.replace(SUFFIX, "")
return res
__benchmarks__ = [
(test_and_replace, just_replace, "just_replace"),
(test_and_replace, test_and_replace_with_slie, "test_and_replace_with_slie")
]
Benchmarks, repeat=5, number=20
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓
┃ Benchmark ┃ Min ┃ Max ┃ Mean ┃ Min (+) ┃ Max (+) ┃ Mean (+) ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩
│ just_replace │ 0.043 │ 0.043 │ 0.043 │ 0.021 (2.0x) │ 0.022 (1.9x) │ 0.022 (2.0x) │
│ test_and_replace_with_slie │ 0.041 │ 0.042 │ 0.042 │ 0.040 (1.0x) │ 0.041 (1.0x) │ 0.040 (1.0x) │
└────────────────────────────┴─────────┴─────────┴─────────┴─────────────────┴─────────────────┴─────────────────┘
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the advice, it seems better indeed.
thriftpy2/parser/__init__.py
Outdated
sub_modules = thrift.__thrift_meta__["sub_modules"][:] | ||
for module in sub_modules: | ||
if module not in sys.modules: | ||
sys.modules[module.__name__] = include_thrift |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sub_modules = thrift.__thrift_meta__["sub_modules"][:] | |
for module in sub_modules: | |
if module not in sys.modules: | |
sys.modules[module.__name__] = include_thrift | |
lost_modules = [ | |
m for m in thrift.__thrift_meta__["sub_modules"] if m not in sys.modules | |
] | |
for module in lost_modules: | |
sys.modules[module.__name__] = include_thrift |
thriftpy2/parser/parser.py
Outdated
child_module_name = str( | ||
child_path).replace(os.sep, | ||
".").replace( | ||
".thrift", "_thrift") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These code's indents are a little bit strange, I think it's better to using something like:
aaa = bbb().ccc()\
.ddd()
Thank you for your work, but I still have a question. Although the included Thrift modules wouldn't overwrite each other when they have the same name but are in different subdirectories after merge this PR, we support loading a Thrift file with a dot in its name, such as I think the expected behavior should be to raise an exception to inform users about the conflict. I believe the current code already has this issue, but the new code might have the potential to address it. |
Okay, I'll raise an exception in this case. |
@aisk All things have done, but there is still a test fail in |
It would be good if you could squash all the commits down to one, just to tidy up the history. |
9193679
to
08b5ac6
Compare
done |
@aisk Can you please take a review, this PR is delayed quite a long time, thank you ! |
I also meet the cause,waiting |
try this from thriftpy2.parser import threadlocal
threadlocal.__dict__.clear() |
Thanks, all tests have passed right now |
thriftpy2/parser/parser.py
Outdated
setattr(thrift, child.__name__, child) | ||
_add_thrift_meta('includes', child) | ||
_add_thrift_meta('sub_modules', types.ModuleType(child_module_name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found that this empty module is only used to check for conflicts in sys.modules
by using it's name. Maybe we can make the code more readable by assigning the attribute __thrift_module_name__
to the module (the variable child
here)?
thriftpy2/parser/__init__.py
Outdated
include_thrift[0].__thrift_meta__["sub_modules"]))) | ||
else: | ||
if registered_thrift.__thrift_file__ != include_thrift[0].__thrift_file__: | ||
raise ThriftParserError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to add a new exception ThriftModuleNameConflict
which inherits ThriftParserError
to make it easier to catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, please review the code again💌
Currently the logic of register sub module to
sys.modules
may cause conflict,That's because of the PR #249 which fix #215
For example:
We have thrift files as follows:
If we call
load('idl/main.thrift', module_name='idl.main_thrift')
, then the following modules will be registered:idl.main_thrift
included1_thrift
included2_thrift
So, if
included1.thrift
is a common module name like platform, which isplatform.thrift
, then moduleplatform
will register tosys.modules
, so it will cause conflict.Now I come up with 2 solutions:
Add an option to
load()
, which will bedef load(path, module_name=None, include_dirs=None, include_dir=None, encoding='utf-8')
, and let the users to register sub modules manually. (not recommended)Optimize sub module name. (recommended)
use absolute path as its module name instead of the base name of the thrift file.
let's take the example before, then the following modules will be registered:
idl.main_thrift
idl.included1_thrift
idl.included2_thrift