{"id":284,"date":"2020-02-27T16:57:22","date_gmt":"2020-02-27T16:57:22","guid":{"rendered":"http:\/\/agilno.local\/?p=146"},"modified":"2022-09-27T09:45:12","modified_gmt":"2022-09-27T07:45:12","slug":"why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism","status":"publish","type":"post","link":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/","title":{"rendered":"Why cyclic dependency errors occur &#8211; a look into the Python import mechanism"},"content":{"rendered":"\r\n<p class=\"wp-block-paragraph\"><em>This article is written with Python 3.7 in mind. If you&#8217;re using an older version, keep in mind that some things discussed in this article might work differently, especially if you&#8217;re using Python2.<\/em><\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">If you&#8217;ve been using Python for more than just simple proof-of-concept apps, you have probably encountered issues due to circular dependencies at some point. While some other languages, like Java, will allow you to get away with this, with Python it&#8217;s not always that simple.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Before we start, I will note that most resources will tell you these kinds of issues hint at a bigger, design-level problem. While I mostly agree with that statement, this will not be the focus of this article. Instead, I will attempt to show you how and why import-related exceptions occur and what you can do in situations where making significant design changes, such as splitting modules into more independent ones, is not an option.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">How do errors caused by circular imports manifest?<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">In simplest terms, a circular import occurs when module A tries to import and use an object from module B, while module B tries to import and use an object from module A.<br \/>You can see it on on an example with simple modules a.py and b.py:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  a.py snippet\r\nprint('First line of a.py')\r\nfrom package.package_b.b import fun_b\r\nprint('Imported fun_b inside a.py')\r\n\r\ndef fun_a():\r\n\u00a0\u00a0\u00a0 print('Executing fun_a')\r\n\u00a0\u00a0\u00a0 fun_b()\r\n\u00a0\u00a0\u00a0 return 'a'\r\n\r\nprint('Last line of a.py')<\/pre>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  b.py snippet\r\nprint('First line of b.py')\r\nfrom package.package_a.a import fun_a\r\nprint('Imported fun_a inside b.py')\r\n\r\ndef fun_b():\r\n\u00a0\u00a0\u00a0 print('Executing fun_b')\r\n\u00a0\u00a0\u00a0 return 'b'\r\n\r\nfun_a()\r\nprint('Last line of b.py')<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">We&#8217;ll run the code from run.py, which just imports a.py.<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  run.py snippet\r\nimport package.package_a.a<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This is the output we get:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  output of run.py\r\n\/home\/petar\/Projects\/python_circular_import_article\/venv\/bin\/python \/home\/petar\/Projects\/python_circular_import_article\/package\/run.py\r\nFirst line of a.py\r\nFirst line of b.py\r\nTraceback (most recent call last):\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/run.py\", line 1, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 import package.package_a.a\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/package_a\/a.py\", line 3, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 from package.package_b.b import fun_b\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/package_b\/b.py\", line 3, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 from package.package_a.a import fun_a\r\nImportError: cannot import name 'fun_a' from 'package.package_a.a' (\/home\/petar\/Projects\/python_circular_import_article\/package\/package_a\/a.py)\r\n\r\nProcess finished with exit code 1<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">As you can see, we get an exception as soon as b.py tries to import a.py. Nothing but the first two printouts from each file get displayed.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Notice how we&#8217;re using the &#8216;from import &#8216; syntax. With this format, Python expects that function to exist within that module and tries to access it in that exact moment. Whenever the module is imported, Python checks if the sys.modules dictionary contains that import. If not, it tries to import that module and add it to the dictionary. The way it does this is it goes over the module line by line.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Let&#8217;s see what happens in detail:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>run.py imports module a &#8211;&gt; module a does not exist in sys.modules, interpreter starts going over the module a lines<\/li>\r\n<li>module a gets to the import fun_b line &#8211;&gt; module b does not exist in sys.modules, interpereter starts going over the module b lines<\/li>\r\n<li>module b tries to import fun_a from\u00a0module a &#8211;&gt; module a <em>exists<\/em> in sys.modules, so there&#8217;s no need to import it again line by line.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This is why &#8216;First line of a.py&#8217; only gets printed once. Since it&#8217;s already imported, Python tries to access fun_a. However, the interpreter did not finish going over every line of module a, it stopped at line 2 (before fun_a could be interpreted). Finally, we get an ImportError.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">The main thing to take away from this is that sys.modules can contain a module without that module being fully imported. So how do we work around this?<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Absolute module imports<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Absolute imports have the import package_a.a format, or alternatively, from package_a import a. This way, we&#8217;re importing the module and not the functions.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">The main difference is that with relative imports, the interpreter will attempt to immediately access the function and potentially raise an exception. This is not the case with absolute imports, because the function is only needed at the exact line it&#8217;s called.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This can help us if the only place we use our functions is inside other functions or classes, because code inside of them doesn&#8217;t get evaluated on import time.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Let&#8217;s try our code with absolute imports:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  a.py snippet\r\nprint('First line of a.py')\r\nfrom package.package_b import b\u00a0 # alternative way of writing import package.package_b.b\r\nprint('Imported module b inside a.py')\r\n\r\ndef fun_a():\r\n\u00a0\u00a0\u00a0 print('Executing fun_a')\r\n\u00a0\u00a0\u00a0 b.fun_b()\r\n\u00a0\u00a0\u00a0 return 'a'\r\n\r\nprint('Last line of a.py')<\/pre>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  b.py snippet\r\nprint('First line of b.py')\r\nfrom package.package_a import a\u00a0 # alternative way of writing import package.package_a.a\r\nprint('Imported module a inside b.py')\r\n\r\ndef fun_b():\r\n\u00a0\u00a0\u00a0 print('Executing fun_b')\r\n\u00a0\u00a0\u00a0 return 'b'\r\n\r\nprint('Executing fun_a from b.py')\r\na.fun_a()\r\nprint('Last line of b.py')<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">\u2026And again, we get an error:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  output of run.py\r\n\/home\/petar\/Projects\/python_circular_import_article\/venv\/bin\/python \/home\/petar\/Projects\/python_circular_import_article\/package\/run.py\r\nTraceback (most recent call last):\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/run.py\", line 1, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 import package.package_a.a\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/package_a\/a.py\", line 3, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 from package.package_b import b\u00a0 # alternative way of writing import package.package_b.b\r\n\u00a0 File \"\/home\/petar\/Projects\/python_circular_import_article\/package\/package_b\/b.py\", line 14, in &lt;module&gt;\r\n\u00a0\u00a0\u00a0 a.fun_a()\r\nAttributeError: module 'package.package_a.a' has no attribute 'fun_a'\r\nFirst line of a.py\r\nFirst line of b.py\r\nImported module a inside b.py\r\nExecuting fun_a from b.py\r\n\r\nProcess finished with exit code 1<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Let&#8217;s see what happened:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>module a starts importing module b<\/li>\r\n<li>module b starts importing module a and does so successfully, importing of module b continues<\/li>\r\n<li>we get to line 14 of module b where we try to call a.fun_a(). Since module a is not fully imported, we get an error.<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This time, we get a different exception &#8211; AttributeError. This happens because fun_a() gets called during import time and the module &#8216;a&#8217; obviously doesn&#8217;t have it since it didn&#8217;t finish importing. The issue is that we&#8217;re calling fun_a() at the top module level and the import mechanism evaluates this line while trying to import.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Before going further, there&#8217;s one more interesting interaction I would like to show you. Instead of running run.py, let&#8217;s call a.py directly:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  output of a.py\r\n\/home\/petar\/Projects\/python_circular_import_article\/venv\/bin\/python \/home\/petar\/Projects\/python_circular_import_article\/package\/package_a\/a.py\r\nFirst line of a.py\r\nFirst line of b.py\r\nFirst line of a.py\r\nImported module b inside a.py\r\nLast line of a.py\r\nImported module a inside b.py\r\nExecuting fun_a from b.py\r\nExecuting fun_a\r\nExecuting fun_b\r\nLast line of b.py\r\nImported module b inside a.py\r\nLast line of a.py\r\n\r\nProcess finished with exit code 0<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">It works?! Let&#8217;s see how exactly this happens.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This is related to a specific behavior that&#8217;s worth keeping in mind. The first module that gets ran, i.e. the entry point of the program, will immediately be loaded into sys.modules, but it will be called &#8216;<strong>main<\/strong>&#8216; instead of its original name. So, this is the execution flow in the case of running a.py first:<\/p>\r\n\r\n\r\n\r\n<ol class=\"wp-block-list\">\r\n<li>interpreter starts evaluating a.py, it&#8217;s loaded into sys.modules by the name <strong>main<\/strong><\/li>\r\n<li>it gets to the import b step, b is not in sys.modules so it has to import it<\/li>\r\n<li>importing of b begins, it gets to the import a step<\/li>\r\n<li>this is the strange part &#8211; a is not in sys.modules yet, because it was loaded under the name <strong>main<\/strong>. This means a has to be imported as well!<\/li>\r\n<li>importing of a starts (from the beginning &#8211; it doesn&#8217;t continue because <strong>main<\/strong> is considered a different module) and is successful<\/li>\r\n<li>importing of b continues after the import a line, it too is successful<\/li>\r\n<li>execution of a continues and the program successfully exits<\/li>\r\n<\/ol>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">With that out of the way, let&#8217;s get back to our issue of making run.py run correctly. The root cause of our problem is calling fun_a() at the top level of module b. In this situation, the only &#8216;quick&#8217; fix we can do is move the call to a function so that it doesn&#8217;t get evaluated at import time:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  b.py\r\nprint('First line of b.py')\r\n\r\nfrom package.package_a import a\u00a0# alternative way of writing import package.package_a.a\r\n\r\nprint('Imported module a inside b.py')\r\n\r\ndef fun_b():\r\n\u00a0\u00a0\u00a0print('Executing fun_b')\r\n\u00a0\u00a0\u00a0return 'b'\r\n\r\nprint('Executing fun_a from b.py')\r\na.fun_a()\r\nprint('Last line of b.py')<\/pre>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  output of run.py\r\n\/home\/petar\/Projects\/python_circular_import_article\/venv\/bin\/python \/home\/petar\/Projects\/python_circular_import_article\/package\/run.py\r\nFirst line of a.py\r\nFirst line of b.py\r\nImported module a inside b.py\r\nLast line of b.py\r\nImported module b inside a.py\r\nLast line of a.py\r\n\r\nProcess finished with exit code 0<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\"><em>Quick note: in this situation, you could actually use the from package_a.a import fun_a syntax, but you would have to put that import inside the function, right before usage. I would advise against relying on this too much: it goes against PEP8 and your IDE\/linter will complain. In addition, any potential errors will be not be detected at &#8216;import time&#8217; and you will encounter exceptions later on when the function is invoked. I think we can agree that it&#8217;s much safer to have your program crash right at startup during imports instead of randomly crashing after a while.<\/em><\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">You might think &#8216;Whatever, I never call functions at the top level anyway!&#8217;. Sure, but there is one more very common case during which this can happen.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">I&#8217;m talking about extending a class that&#8217;s inside of a module with circular dependency.<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#  new file with just a class import snippet\r\nimport package.package_class\r\n\r\nclass B(package_class.class_a):<\/pre>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">This line of code is at the top level of a module and the interpreter will try to evaluate it at import time. At that point, if the relationship between modules is circular just like in the previous example, you have no viable option to avoid this. Your only choice is to either give up on trying to extend the class or refactor your code to avoid the circular import altogether.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Takeaways<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">We&#8217;ve seen a general high-level overview of the import mechanism. So how should you import in real projects?<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">First of all, I suggest using explicit absolute imports whenever you can (e.g. from package_a.a import fun_a), or rather, when there are no circular dependencies preventing you from doing that. They are explicit, result in the most concise code and if there is a problem you will know right away because the error will happen as soon as you try to import.<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">If you do have circular dependencies, you should try your best to avoid that situation altogether by changing your project structure, e.g. splitting modules into multiple smaller ones. In case this is not an option for you, you can try using deferred explicit imports (import right before usage, for example before a function call) or you can use absolute module imports (e.g. import package_a.a).<\/p>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Just be aware that these solutions are not optimal and if you find that the amount of coupling\/tangling in your project is increasing, you should really try to resolve the underlying issue.<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>This article is written with Python 3.7 in mind. If you&#8217;re using an older version, keep in mind that some<\/p>\n","protected":false},"author":6,"featured_media":520,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[18],"tags":[],"class_list":["post-284","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-backend-development"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno\" \/>\n<meta property=\"og:description\" content=\"This article is written with Python 3.7 in mind. If you&#8217;re using an older version, keep in mind that some\" \/>\n<meta property=\"og:url\" content=\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\" \/>\n<meta property=\"og:site_name\" content=\"Agilno\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-27T16:57:22+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-09-27T07:45:12+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"770\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Petar Vukasinovic\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Petar Vukasinovic\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\"},\"author\":{\"name\":\"Petar Vukasinovic\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b\"},\"headline\":\"Why cyclic dependency errors occur &#8211; a look into the Python import mechanism\",\"datePublished\":\"2020-02-27T16:57:22+00:00\",\"dateModified\":\"2022-09-27T07:45:12+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\"},\"wordCount\":1422,\"commentCount\":0,\"image\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg\",\"articleSection\":[\"Backend Development\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\",\"url\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\",\"name\":\"Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno\",\"isPartOf\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg\",\"datePublished\":\"2020-02-27T16:57:22+00:00\",\"dateModified\":\"2022-09-27T07:45:12+00:00\",\"author\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b\"},\"breadcrumb\":{\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage\",\"url\":\"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg\",\"contentUrl\":\"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg\",\"width\":1280,\"height\":770},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/makeit.com.hr\/agilno\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Why cyclic dependency errors occur &#8211; a look into the Python import mechanism\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/#website\",\"url\":\"https:\/\/makeit.com.hr\/agilno\/\",\"name\":\"Agilno\",\"description\":\"We build experiences, products, and businesses that create results\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/makeit.com.hr\/agilno\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b\",\"name\":\"Petar Vukasinovic\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g\",\"caption\":\"Petar Vukasinovic\"},\"url\":\"https:\/\/makeit.com.hr\/agilno\/author\/petar\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/","og_locale":"en_US","og_type":"article","og_title":"Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno","og_description":"This article is written with Python 3.7 in mind. If you&#8217;re using an older version, keep in mind that some","og_url":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/","og_site_name":"Agilno","article_published_time":"2020-02-27T16:57:22+00:00","article_modified_time":"2022-09-27T07:45:12+00:00","og_image":[{"width":1280,"height":770,"url":"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg","type":"image\/jpeg"}],"author":"Petar Vukasinovic","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Petar Vukasinovic","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#article","isPartOf":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/"},"author":{"name":"Petar Vukasinovic","@id":"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b"},"headline":"Why cyclic dependency errors occur &#8211; a look into the Python import mechanism","datePublished":"2020-02-27T16:57:22+00:00","dateModified":"2022-09-27T07:45:12+00:00","mainEntityOfPage":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/"},"wordCount":1422,"commentCount":0,"image":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage"},"thumbnailUrl":"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg","articleSection":["Backend Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/","url":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/","name":"Why cyclic dependency errors occur - a look into the Python import mechanism - Agilno","isPartOf":{"@id":"https:\/\/makeit.com.hr\/agilno\/#website"},"primaryImageOfPage":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage"},"image":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage"},"thumbnailUrl":"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg","datePublished":"2020-02-27T16:57:22+00:00","dateModified":"2022-09-27T07:45:12+00:00","author":{"@id":"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b"},"breadcrumb":{"@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#primaryimage","url":"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg","contentUrl":"https:\/\/makeit.com.hr\/agilno\/wp-content\/uploads\/2020\/02\/import-1280770.jpg","width":1280,"height":770},{"@type":"BreadcrumbList","@id":"https:\/\/makeit.com.hr\/agilno\/blog\/why-cyclic-dependency-errors-occur-a-look-into-the-python-import-mechanism\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/makeit.com.hr\/agilno\/"},{"@type":"ListItem","position":2,"name":"Why cyclic dependency errors occur &#8211; a look into the Python import mechanism"}]},{"@type":"WebSite","@id":"https:\/\/makeit.com.hr\/agilno\/#website","url":"https:\/\/makeit.com.hr\/agilno\/","name":"Agilno","description":"We build experiences, products, and businesses that create results","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/makeit.com.hr\/agilno\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/makeit.com.hr\/agilno\/#\/schema\/person\/443d3d24891bd90f096956d39a9fe70b","name":"Petar Vukasinovic","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2934c42d196fd827352e121fef4abc16d21d5c87a94f31906a04c8b1c9aff13f?s=96&d=mm&r=g","caption":"Petar Vukasinovic"},"url":"https:\/\/makeit.com.hr\/agilno\/author\/petar\/"}]}},"_links":{"self":[{"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/posts\/284","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/comments?post=284"}],"version-history":[{"count":2,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/posts\/284\/revisions"}],"predecessor-version":[{"id":487,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/posts\/284\/revisions\/487"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/media\/520"}],"wp:attachment":[{"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/media?parent=284"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/categories?post=284"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/makeit.com.hr\/agilno\/wp-json\/wp\/v2\/tags?post=284"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}