简体   繁体   中英

Circular dependency - best approach?

I Have two three files: a.py , b.py , c.py .

These three files are in different directories (let us call it a_dir , b_dir , c_dir ). First I only had two files a.py and b.py . b.py had this:

from root_dir.a_dir import a
...
do something
...

Then everything worked. But when I created third file c.py , and I imported it to a.py like this:

from root_dir.c_dir import c
...
do something
... 

I started getting error that pyton can't import a to b.py . So I figured it might be circular dependency? Then I changed how import works in a.py like this:

def method_with_c_import(s):
    from root_dir.c_dir import c
    ...
    do something inside method
    ...

So I used import only in method I needed it (I don't need that import anywhere else and that method is not used in b.py .

But is it best approach or maybe there is better way to solve such problem?

As requested error trace (this happens if I put import I added in a.py outside method at the beginning of the file):

Traceback (most recent call last):
  File "/home/oerp/openerp70/openerp/server/openerp/cli/server.py", line 97, in preload_registry
    db, registry = openerp.pooler.get_db_and_pool(dbname,update_module=update_module)
  File "/home/oerp/openerp70/openerp/server/openerp/pooler.py", line 33, in get_db_and_pool
    registry = RegistryManager.get(db_name, force_demo, status, update_module)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/registry.py", line 203, in get
    update_module)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/registry.py", line 233, in new
    openerp.modules.load_modules(registry.db, force_demo, status, update_module)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 350, in load_modules
    force, status, report, loaded_modules, update_module)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 256, in load_marked_modules
    loaded, processed = load_module_graph(cr, graph, progressdict, report=report, skip_modules=loaded_modules, perform_checks=perform_checks)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/loading.py", line 159, in load_module_graph
    load_openerp_module(package.name)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/module.py", line 415, in load_openerp_module
    getattr(sys.modules['openerp.addons.' + module_name], info['post_load'])()
  File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 628, in wsgi_postload
    openerp.wsgi.register_wsgi_handler(Root())
  File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 517, in __init__
    self.load_addons()
  File "/home/oerp/openerp70/openerp/server/openerp/addons/web/http.py", line 580, in load_addons
    m = __import__('openerp.addons.' + module)
  File "/home/oerp/openerp70/openerp/server/openerp/modules/module.py", line 133, in load_module
    mod = imp.load_module('openerp.addons.' + module_part, f, path, descr)
  File "/home/oerp/openerp70/openerp/addons/ambulance_system/__init__.py", line 24, in <module>
    import report
  File "/home/oerp/openerp70/openerp/addons/ambulance_system/report/__init__.py", line 15, in <module>
    import marketing_clinic_report
  File "/home/oerp/openerp70/openerp/addons/ambulance_system/report/marketing_clinic_report.py", line 6, in <module>
    from ambulance_system.model import new_medical_card as nmc
ImportError: cannot import name new_medical_card

PS This error is for file I named in question b.py (when I changed in a.py as written above before error trace).

Update Priority imports for directories:

import generic #c.py directory
import model #a.py directory
import report #b.py directory

Update2

As requested for example to reproduce the problem ( new_medical_card.py is a.py , marketing_clinic_report.py is b.py , generic.py is c.py ):

Module files and dirs structure :

ambulance_system/:
  - generic/generic.py
  - model/new_medical_card.py
  - report/marketing_clinic_report.py

Imports in all three files:

generic.py :

import math

new_medical_card.py :

from openerp.osv import osv, orm, fields
import tools
from tools.translate import _
import time
from datetime import date, datetime, timedelta
ambulance_system.model.generic import generic as grc #This one produces error

marketing_clinic_report.py :

import time
from report import report_sxw
from ambulance_system.model import new_medical_card as nmc

As requested Update3 init imports:

I already showed main init file (the one in root directory - ambulance_system, but for clarity reasons will post here too:

__init__.py Priority imports for directories:

import generic #c.py directory
import model #a.py directory
import report #b.py directory

__init__.py for generic dir ( c.py ):

import generic

__init__.py for model dir ( a.py ):

import new_medical_card
import medical_card_segment_res
import medical_card
import res_partner
import model_request_access
import new_medical_card_requirement
import medical_card_rule
import hr_department_team

__init__.py for report dir ( b.py ):

import card_field_report
import medical_card_field_report
import medical_card_reject_report
import new_medical_card_reject_report
import new_medical_card_field_report
import old_diagnosis_report
import new_diagnosis_report
import old_form_ambulance_usage_report
import new_form_ambulance_usage_report
import medical_card_history
import new_medical_card_history
import new_medical_card_report
import report1
import report2
import marketing_clinic_report
import print_gsc_data

is it best approach or maybe there is better way to solve such problem?

No, it isn't the best approach! The best approach is:

Get rid of the circular dependency .

Really. It just means you have a design problem in those modules. Circular dependencies shouldn't exist in the first place. In fact a lot of programming languages don't allow them in the first place.

You have several options to do that:

  • Move the definitions among the three modules so that each module doesn't have to import the other two.
  • Move the definitions so that the imports are only "in one direction": eg b imports a and c imports a and b .
  • Remove a module. You have decided to split something that is better to keep together. For example c may not be required and could have been better to avoid splitting a in the first place
  • Split some module (eg c ) to group its definitions by dependency. For example c_a will contain all the definitions of c that rely on a and c_b all those that rely on b and c_a and c_b do not import each other .
  • Completely rewrite the design of what you are doing. (The circular dependency might be a symptom of a deeper problem...)

If, for some evil reason, you do want to keep the circular dependency, you might get rid of the erros by placing the import s that cause the dependency at the end of the file instead of the top.

However this isn't always possible, but it should work if you use the module only inside function definitions.

Also in this way you loose the grouping of import s so that you cannot simply look at the top of the module to understand the dependencies of a module... but this is even worse when imports are inside functions since you also have to look at multiple places in that situation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM