Repository: cython/cython

Issue:
[BUG] cythonize crashes when an include directory contains files with extra . characters
### Describe the bug

When cythonize is passed an `include_path` that contains a directory with the following files, it crashes in the following way

simon@tek-top /var/tmp/build-root/openSUSE_Tumbleweed-x86_64/home/abuild/rpmbuild/BUILD/python-efl-1.26.0/include ➤   ls
efl.c_eo.pxd               efl.ecore_input.pxd      efl.edje.pxd              efl.eo.pxd             efl.utils.conversions.pxd
efl.c_ethumb.pxd           efl.ecore.pxd            efl.eina.pxd              efl.ethumb_client.pxd  efl.utils.deprecated.pxd
efl.ecore_con.enums.pxd    efl.ecore_x.pxd          efl.elementary.enums.pxd  efl.ethumb.enums.pxd   efl.utils.logger.pxd
efl.ecore_con.pxd          efl.edje_edit.enums.pxd  efl.elementary.pxd        efl.ethumb.pxd
efl.ecore.enums.pxd        efl.edje_edit.pxd        efl.emotion.enums.pxd     efl.evas.enums.pxd
efl.ecore_input.enums.pxd  efl.edje.enums.pxd       efl.emotion.pxd           efl.evas.pxd


[    5s]   File "/home/abuild/rpmbuild/BUILD/python-efl-1.26.0/setup.py", line 304, in <module>
[    5s]     ext_modules = cythonize(
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 985, in cythonize
[    5s]     module_list, module_metadata = create_extension_list(
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 834, in create_extension_list
[    5s]     kwds = deps.distutils_info(file, aliases, base).values
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 687, in distutils_info
[    5s]     return (self.transitive_merge(filename, self.distutils_info0, DistutilsInfo.merge)
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 696, in transitive_merge
[    5s]     return self.transitive_merge_helper(
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 708, in transitive_merge_helper
[    5s]     for next in outgoing(node):
[    5s]   File "Cython/Utils.py", line 129, in Cython.Utils.cached_method.wrapper
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 609, in cimported_files
[    5s]     pxd_file = self.find_pxd(module, filename)
[    5s]   File "Cython/Utils.py", line 129, in Cython.Utils.cached_method.wrapper
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Build/Dependencies.py", line 590, in find_pxd
[    5s]     pxd = self.context.find_pxd_file(relative, source_file_path=filename)
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Compiler/Main.py", line 245, in find_pxd_file
[    5s]     pxd = self.search_include_directories(
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Compiler/Main.py", line 273, in search_include_directories
[    5s]     return search_include_directories(
[    5s]   File "Cython/Utils.py", line 90, in Cython.Utils.cached_function.wrapper
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Compiler/Main.py", line 669, in search_include_directories
[    5s]     warning(pos, "Dotted filenames ('%s') are deprecated."
[    5s]   File "/usr/lib64/python3.10/site-packages/Cython/Compiler/Errors.py", line 215, in warning
[    5s]     listing_file = threadlocal.cython_errors_listing_file
[    5s] AttributeError: '_thread._local' object has no attribute 'cython_errors_listing_file'

A full copy of the setup.py can be found at http://git.enlightenment.org/enlightenment/python-efl/src/branch/master/setup.py and a build log for openSUSE Tumbleweed can be found at https://build.opensuse.org/package/live_build_log/home:simotek:branches:X11:Enlightenment:Factory/python-efl/openSUSE_Tumbleweed/x86_64

### Code to reproduce the behaviour:

As above

### Expected behaviour

The code to comple correctly as it did with python3.8

### OS

Linux

### Python version

3.9,3.10,3.11

### Cython version

3.0.0a11

### Additional context

_No response_


Discussion:

Resolving patch:
diff --git a/Cython/Compiler/Main.py b/Cython/Compiler/Main.py
--- a/Cython/Compiler/Main.py
+++ b/Cython/Compiler/Main.py
@@ -168,6 +168,15 @@ def _split_qualified_name(self, qualified_name):
     def _is_init_file(path):
         return os.path.basename(path) in ('__init__.pyx', '__init__.py', '__init__.pxd') if path else False
 
+    @staticmethod
+    def _check_pxd_filename(pos, pxd_pathname, qualified_name):
+        if not pxd_pathname:
+            return
+        pxd_filename = os.path.basename(pxd_pathname)
+        if '.' in qualified_name and qualified_name == os.path.splitext(pxd_filename)[0]:
+            warning(pos, "Dotted filenames ('%s') are deprecated."
+                    " Please use the normal Python package directory layout." % pxd_filename, level=1)
+
     def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1,
                     absolute_fallback=True):
         # Finds and returns the module scope corresponding to
@@ -206,6 +215,7 @@ def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1,
             scope = relative_to.lookup_submodule(module_name)
             if not scope:
                 pxd_pathname = self.find_pxd_file(qualified_name, pos)
+                self._check_pxd_filename(pos, pxd_pathname, qualified_name)
                 if pxd_pathname:
                     is_package = self._is_init_file(pxd_pathname)
                     scope = relative_to.find_submodule(module_name, as_package=is_package)
@@ -228,6 +238,7 @@ def find_module(self, module_name, relative_to=None, pos=None, need_pxd=1,
                 # Only look in sys.path if we are explicitly looking
                 # for a .pxd file.
                 pxd_pathname = self.find_pxd_file(qualified_name, pos, sys_path=need_pxd)
+                self._check_pxd_filename(pos, pxd_pathname, qualified_name)
                 if debug_find_module:
                     print("......found %s" % pxd_pathname)
                 if not pxd_pathname and need_pxd:
@@ -690,9 +701,6 @@ def search_include_directories(dirs, qualified_name, suffix="", pos=None, includ
     for dirname in dirs:
         path = os.path.join(dirname, dotted_filename)
         if os.path.exists(path):
-            if not include and '.' in qualified_name and '.' in os.path.splitext(dotted_filename)[0]:
-                warning(pos, "Dotted filenames ('%s') are deprecated."
-                             " Please use the normal Python package directory layout." % dotted_filename, level=1)
             return path
 
     # search for filename in package structure e.g. <dir>/foo/bar.pxd or <dir>/foo/bar/__init__.pxd


Test patch:
diff --git a/tests/errors/dotted.module.pxd b/tests/errors/dotted.module.pxd
new file mode 100644
--- /dev/null
+++ b/tests/errors/dotted.module.pxd
@@ -0,0 +1,2 @@
+cdef inline int bar():
+    return 5
diff --git a/tests/errors/dotted_filenames.pyx b/tests/errors/dotted_filenames.pyx
new file mode 100644
--- /dev/null
+++ b/tests/errors/dotted_filenames.pyx
@@ -0,0 +1,8 @@
+# mode: compile
+# tag: warnings
+from dotted.module cimport bar
+
+
+_WARNINGS = """
+3:0: Dotted filenames ('dotted.module.pxd') are deprecated. Please use the normal Python package directory layout.
+"""
diff --git a/tests/run/dotted_filenames.srctree b/tests/run/dotted_filenames.srctree
new file mode 100644
--- /dev/null
+++ b/tests/run/dotted_filenames.srctree
@@ -0,0 +1,23 @@
+PYTHON setup.py build_ext --inplace
+PYTHON -c "import a; assert a.a == 5"
+
+######## setup.py ########
+
+from setuptools import setup
+from Cython.Build import cythonize
+
+setup(
+    name="My hello app",
+    ext_modules=cythonize("a.pyx", include_path=['include']),
+)
+
+######## a.pyx ########
+
+from test.ext cimport bar
+
+a = bar()
+
+######## include/test.ext.pxd ########
+
+cdef inline int bar():
+    return 5