We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
race conditions in profile directory creation
Hi- I've been using IPython cluster for a bit now and have recently run into some race conditions when I start up multiple engines at once on a new machine. Specifically, in `IPython.core.profiledir.ProfileDir`, all the `check_*_dir` functions first check if the directory exists then create them if not. This will throw an exception if two engines are running the same code at once and try to create the directory after they both see that it doesn't exist.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `IPython/core/profiledir.py`
Content:
```
1 # encoding: utf-8
2 """
3 An object for managing IPython profile directories.
4 
5 Authors:
6 
7 * Brian Granger
8 * Fernando Perez
9 * Min RK
10 
11 """
12 
13 #-----------------------------------------------------------------------------
14 #  Copyright (C) 2008-2011  The IPython Development Team
15 #
16 #  Distributed under the terms of the BSD License.  The full license is in
17 #  the file COPYING, distributed as part of this software.
18 #-----------------------------------------------------------------------------
19 
20 #-----------------------------------------------------------------------------
21 # Imports
22 #-----------------------------------------------------------------------------
23 
24 import os
25 import shutil
26 
27 from IPython.config.configurable import LoggingConfigurable
28 from IPython.utils.path import get_ipython_package_dir, expand_path
29 from IPython.utils.traitlets import Unicode, Bool
30 
31 #-----------------------------------------------------------------------------
32 # Classes and functions
33 #-----------------------------------------------------------------------------
34 
35 
36 #-----------------------------------------------------------------------------
37 # Module errors
38 #-----------------------------------------------------------------------------
39 
40 class ProfileDirError(Exception):
41     pass
42 
43 
44 #-----------------------------------------------------------------------------
45 # Class for managing profile directories
46 #-----------------------------------------------------------------------------
47 
48 class ProfileDir(LoggingConfigurable):
49     """An object to manage the profile directory and its resources.
50 
51     The profile directory is used by all IPython applications, to manage
52     configuration, logging and security.
53 
54     This object knows how to find, create and manage these directories. This
55     should be used by any code that wants to handle profiles.
56     """
57 
58     security_dir_name = Unicode('security')
59     log_dir_name = Unicode('log')
60     startup_dir_name = Unicode('startup')
61     pid_dir_name = Unicode('pid')
62     security_dir = Unicode(u'')
63     log_dir = Unicode(u'')
64     startup_dir = Unicode(u'')
65     pid_dir = Unicode(u'')
66 
67     location = Unicode(u'', config=True,
68         help="""Set the profile location directly. This overrides the logic used by the
69         `profile` option.""",
70         )
71 
72     _location_isset = Bool(False) # flag for detecting multiply set location
73 
74     def _location_changed(self, name, old, new):
75         if self._location_isset:
76             raise RuntimeError("Cannot set profile location more than once.")
77         self._location_isset = True
78         if not os.path.isdir(new):
79             os.makedirs(new)
80         
81         # ensure config files exist:
82         self.security_dir = os.path.join(new, self.security_dir_name)
83         self.log_dir = os.path.join(new, self.log_dir_name)
84         self.startup_dir = os.path.join(new, self.startup_dir_name)
85         self.pid_dir = os.path.join(new, self.pid_dir_name)
86         self.check_dirs()
87 
88     def _log_dir_changed(self, name, old, new):
89         self.check_log_dir()
90 
91     def check_log_dir(self):
92         if not os.path.isdir(self.log_dir):
93             os.mkdir(self.log_dir)
94 
95     def _startup_dir_changed(self, name, old, new):
96         self.check_startup_dir()
97 
98     def check_startup_dir(self):
99         if not os.path.isdir(self.startup_dir):
100             os.mkdir(self.startup_dir)
101         readme = os.path.join(self.startup_dir, 'README')
102         src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
103 
104         if not os.path.exists(src):
105             self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist." % src)
106 
107         if os.path.exists(src) and not os.path.exists(readme):
108             shutil.copy(src, readme)
109 
110     def _security_dir_changed(self, name, old, new):
111         self.check_security_dir()
112 
113     def check_security_dir(self):
114         if not os.path.isdir(self.security_dir):
115             os.mkdir(self.security_dir, 0o700)
116         else:
117             try:
118                 os.chmod(self.security_dir, 0o700)
119             except OSError:
120                 self.log.warn("Could not set security dir permissions to private.")
121 
122     def _pid_dir_changed(self, name, old, new):
123         self.check_pid_dir()
124 
125     def check_pid_dir(self):
126         if not os.path.isdir(self.pid_dir):
127             os.mkdir(self.pid_dir, 0o700)
128         else:
129             try:
130                 os.chmod(self.pid_dir, 0o700)
131             except OSError:
132                 self.log.warn("Could not set pid dir permissions to private.")
133 
134     def check_dirs(self):
135         self.check_security_dir()
136         self.check_log_dir()
137         self.check_pid_dir()
138         self.check_startup_dir()
139 
140     def copy_config_file(self, config_file, path=None, overwrite=False):
141         """Copy a default config file into the active profile directory.
142 
143         Default configuration files are kept in :mod:`IPython.config.default`.
144         This function moves these from that location to the working profile
145         directory.
146         """
147         dst = os.path.join(self.location, config_file)
148         if os.path.isfile(dst) and not overwrite:
149             return False
150         if path is None:
151             path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
152         src = os.path.join(path, config_file)
153         shutil.copy(src, dst)
154         return True
155 
156     @classmethod
157     def create_profile_dir(cls, profile_dir, config=None):
158         """Create a new profile directory given a full path.
159 
160         Parameters
161         ----------
162         profile_dir : str
163             The full path to the profile directory.  If it does exist, it will
164             be used.  If not, it will be created.
165         """
166         return cls(location=profile_dir, config=config)
167 
168     @classmethod
169     def create_profile_dir_by_name(cls, path, name=u'default', config=None):
170         """Create a profile dir by profile name and path.
171 
172         Parameters
173         ----------
174         path : unicode
175             The path (directory) to put the profile directory in.
176         name : unicode
177             The name of the profile.  The name of the profile directory will
178             be "profile_<profile>".
179         """
180         if not os.path.isdir(path):
181             raise ProfileDirError('Directory not found: %s' % path)
182         profile_dir = os.path.join(path, u'profile_' + name)
183         return cls(location=profile_dir, config=config)
184 
185     @classmethod
186     def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
187         """Find an existing profile dir by profile name, return its ProfileDir.
188 
189         This searches through a sequence of paths for a profile dir.  If it
190         is not found, a :class:`ProfileDirError` exception will be raised.
191 
192         The search path algorithm is:
193         1. ``os.getcwdu()``
194         2. ``ipython_dir``
195 
196         Parameters
197         ----------
198         ipython_dir : unicode or str
199             The IPython directory to use.
200         name : unicode or str
201             The name of the profile.  The name of the profile directory
202             will be "profile_<profile>".
203         """
204         dirname = u'profile_' + name
205         paths = [os.getcwdu(), ipython_dir]
206         for p in paths:
207             profile_dir = os.path.join(p, dirname)
208             if os.path.isdir(profile_dir):
209                 return cls(location=profile_dir, config=config)
210         else:
211             raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
212 
213     @classmethod
214     def find_profile_dir(cls, profile_dir, config=None):
215         """Find/create a profile dir and return its ProfileDir.
216 
217         This will create the profile directory if it doesn't exist.
218 
219         Parameters
220         ----------
221         profile_dir : unicode or str
222             The path of the profile directory.  This is expanded using
223             :func:`IPython.utils.genutils.expand_path`.
224         """
225         profile_dir = expand_path(profile_dir)
226         if not os.path.isdir(profile_dir):
227             raise ProfileDirError('Profile directory not found: %s' % profile_dir)
228         return cls(location=profile_dir, config=config)
229 
230 
231
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py
--- a/IPython/core/profiledir.py
+++ b/IPython/core/profiledir.py
@@ -87,22 +87,55 @@
 
     def _log_dir_changed(self, name, old, new):
         self.check_log_dir()
+    
+    def _mkdir(self, path, mode=None):
+        """ensure a directory exists at a given path
+        
+        This is a version of os.mkdir, with the following differences:
+        
+        - returns True if it created the directory, False otherwise
+        - ignores EEXIST, protecting against race conditions where
+          the dir may have been created in between the check and
+          the creation
+        - sets permissions if requested and the dir already exists
+        """
+        if os.path.exists(path):
+            if mode and os.stat(path).st_mode != mode:
+                try:
+                    os.chmod(path, mode)
+                except OSError:
+                    self.log.warn(
+                        "Could not set permissions on %s",
+                        path
+                    )
+            return False
+        try:
+            if mode:
+                os.mkdir(path, mode)
+            else:
+                os.mkdir(path)
+        except OSError as e:
+            if e.errno == errno.EEXIST:
+                return False
+            else:
+                raise
+        
+        return True
 
     def check_log_dir(self):
-        if not os.path.isdir(self.log_dir):
-            os.mkdir(self.log_dir)
+        self._mkdir(self.log_dir)
 
     def _startup_dir_changed(self, name, old, new):
         self.check_startup_dir()
 
     def check_startup_dir(self):
-        if not os.path.isdir(self.startup_dir):
-            os.mkdir(self.startup_dir)
+        self._mkdir(self.startup_dir)
+
         readme = os.path.join(self.startup_dir, 'README')
         src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
 
         if not os.path.exists(src):
-            self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist." % src)
+            self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
 
         if os.path.exists(src) and not os.path.exists(readme):
             shutil.copy(src, readme)
@@ -111,25 +144,13 @@
         self.check_security_dir()
 
     def check_security_dir(self):
-        if not os.path.isdir(self.security_dir):
-            os.mkdir(self.security_dir, 0o700)
-        else:
-            try:
-                os.chmod(self.security_dir, 0o700)
-            except OSError:
-                self.log.warn("Could not set security dir permissions to private.")
+        self._mkdir(self.security_dir, 0o40700)
 
     def _pid_dir_changed(self, name, old, new):
         self.check_pid_dir()
 
     def check_pid_dir(self):
-        if not os.path.isdir(self.pid_dir):
-            os.mkdir(self.pid_dir, 0o700)
-        else:
-            try:
-                os.chmod(self.pid_dir, 0o700)
-            except OSError:
-                self.log.warn("Could not set pid dir permissions to private.")
+        self._mkdir(self.pid_dir, 0o40700)
 
     def check_dirs(self):
         self.check_security_dir()

{"golden_diff": "diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py\n--- a/IPython/core/profiledir.py\n+++ b/IPython/core/profiledir.py\n@@ -87,22 +87,55 @@\n \n     def _log_dir_changed(self, name, old, new):\n         self.check_log_dir()\n+    \n+    def _mkdir(self, path, mode=None):\n+        \"\"\"ensure a directory exists at a given path\n+        \n+        This is a version of os.mkdir, with the following differences:\n+        \n+        - returns True if it created the directory, False otherwise\n+        - ignores EEXIST, protecting against race conditions where\n+          the dir may have been created in between the check and\n+          the creation\n+        - sets permissions if requested and the dir already exists\n+        \"\"\"\n+        if os.path.exists(path):\n+            if mode and os.stat(path).st_mode != mode:\n+                try:\n+                    os.chmod(path, mode)\n+                except OSError:\n+                    self.log.warn(\n+                        \"Could not set permissions on %s\",\n+                        path\n+                    )\n+            return False\n+        try:\n+            if mode:\n+                os.mkdir(path, mode)\n+            else:\n+                os.mkdir(path)\n+        except OSError as e:\n+            if e.errno == errno.EEXIST:\n+                return False\n+            else:\n+                raise\n+        \n+        return True\n \n     def check_log_dir(self):\n-        if not os.path.isdir(self.log_dir):\n-            os.mkdir(self.log_dir)\n+        self._mkdir(self.log_dir)\n \n     def _startup_dir_changed(self, name, old, new):\n         self.check_startup_dir()\n \n     def check_startup_dir(self):\n-        if not os.path.isdir(self.startup_dir):\n-            os.mkdir(self.startup_dir)\n+        self._mkdir(self.startup_dir)\n+\n         readme = os.path.join(self.startup_dir, 'README')\n         src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')\n \n         if not os.path.exists(src):\n-            self.log.warn(\"Could not copy README_STARTUP to startup dir. Source file %s does not exist.\" % src)\n+            self.log.warn(\"Could not copy README_STARTUP to startup dir. Source file %s does not exist.\", src)\n \n         if os.path.exists(src) and not os.path.exists(readme):\n             shutil.copy(src, readme)\n@@ -111,25 +144,13 @@\n         self.check_security_dir()\n \n     def check_security_dir(self):\n-        if not os.path.isdir(self.security_dir):\n-            os.mkdir(self.security_dir, 0o700)\n-        else:\n-            try:\n-                os.chmod(self.security_dir, 0o700)\n-            except OSError:\n-                self.log.warn(\"Could not set security dir permissions to private.\")\n+        self._mkdir(self.security_dir, 0o40700)\n \n     def _pid_dir_changed(self, name, old, new):\n         self.check_pid_dir()\n \n     def check_pid_dir(self):\n-        if not os.path.isdir(self.pid_dir):\n-            os.mkdir(self.pid_dir, 0o700)\n-        else:\n-            try:\n-                os.chmod(self.pid_dir, 0o700)\n-            except OSError:\n-                self.log.warn(\"Could not set pid dir permissions to private.\")\n+        self._mkdir(self.pid_dir, 0o40700)\n \n     def check_dirs(self):\n         self.check_security_dir()\n", "issue": "race conditions in profile directory creation\nHi- I've been using IPython cluster for a bit now and have recently run into some race conditions when I start up multiple engines at once on a new machine. Specifically, in `IPython.core.profiledir.ProfileDir`, all the `check_*_dir` functions first check if the directory exists then create them if not. This will throw an exception if two engines are running the same code at once and try to create the directory after they both see that it doesn't exist.\n\n", "before_files": [{"content": "# encoding: utf-8\n\"\"\"\nAn object for managing IPython profile directories.\n\nAuthors:\n\n* Brian Granger\n* Fernando Perez\n* Min RK\n\n\"\"\"\n\n#-----------------------------------------------------------------------------\n#  Copyright (C) 2008-2011  The IPython Development Team\n#\n#  Distributed under the terms of the BSD License.  The full license is in\n#  the file COPYING, distributed as part of this software.\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\nimport os\nimport shutil\n\nfrom IPython.config.configurable import LoggingConfigurable\nfrom IPython.utils.path import get_ipython_package_dir, expand_path\nfrom IPython.utils.traitlets import Unicode, Bool\n\n#-----------------------------------------------------------------------------\n# Classes and functions\n#-----------------------------------------------------------------------------\n\n\n#-----------------------------------------------------------------------------\n# Module errors\n#-----------------------------------------------------------------------------\n\nclass ProfileDirError(Exception):\n    pass\n\n\n#-----------------------------------------------------------------------------\n# Class for managing profile directories\n#-----------------------------------------------------------------------------\n\nclass ProfileDir(LoggingConfigurable):\n    \"\"\"An object to manage the profile directory and its resources.\n\n    The profile directory is used by all IPython applications, to manage\n    configuration, logging and security.\n\n    This object knows how to find, create and manage these directories. This\n    should be used by any code that wants to handle profiles.\n    \"\"\"\n\n    security_dir_name = Unicode('security')\n    log_dir_name = Unicode('log')\n    startup_dir_name = Unicode('startup')\n    pid_dir_name = Unicode('pid')\n    security_dir = Unicode(u'')\n    log_dir = Unicode(u'')\n    startup_dir = Unicode(u'')\n    pid_dir = Unicode(u'')\n\n    location = Unicode(u'', config=True,\n        help=\"\"\"Set the profile location directly. This overrides the logic used by the\n        `profile` option.\"\"\",\n        )\n\n    _location_isset = Bool(False) # flag for detecting multiply set location\n\n    def _location_changed(self, name, old, new):\n        if self._location_isset:\n            raise RuntimeError(\"Cannot set profile location more than once.\")\n        self._location_isset = True\n        if not os.path.isdir(new):\n            os.makedirs(new)\n        \n        # ensure config files exist:\n        self.security_dir = os.path.join(new, self.security_dir_name)\n        self.log_dir = os.path.join(new, self.log_dir_name)\n        self.startup_dir = os.path.join(new, self.startup_dir_name)\n        self.pid_dir = os.path.join(new, self.pid_dir_name)\n        self.check_dirs()\n\n    def _log_dir_changed(self, name, old, new):\n        self.check_log_dir()\n\n    def check_log_dir(self):\n        if not os.path.isdir(self.log_dir):\n            os.mkdir(self.log_dir)\n\n    def _startup_dir_changed(self, name, old, new):\n        self.check_startup_dir()\n\n    def check_startup_dir(self):\n        if not os.path.isdir(self.startup_dir):\n            os.mkdir(self.startup_dir)\n        readme = os.path.join(self.startup_dir, 'README')\n        src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')\n\n        if not os.path.exists(src):\n            self.log.warn(\"Could not copy README_STARTUP to startup dir. Source file %s does not exist.\" % src)\n\n        if os.path.exists(src) and not os.path.exists(readme):\n            shutil.copy(src, readme)\n\n    def _security_dir_changed(self, name, old, new):\n        self.check_security_dir()\n\n    def check_security_dir(self):\n        if not os.path.isdir(self.security_dir):\n            os.mkdir(self.security_dir, 0o700)\n        else:\n            try:\n                os.chmod(self.security_dir, 0o700)\n            except OSError:\n                self.log.warn(\"Could not set security dir permissions to private.\")\n\n    def _pid_dir_changed(self, name, old, new):\n        self.check_pid_dir()\n\n    def check_pid_dir(self):\n        if not os.path.isdir(self.pid_dir):\n            os.mkdir(self.pid_dir, 0o700)\n        else:\n            try:\n                os.chmod(self.pid_dir, 0o700)\n            except OSError:\n                self.log.warn(\"Could not set pid dir permissions to private.\")\n\n    def check_dirs(self):\n        self.check_security_dir()\n        self.check_log_dir()\n        self.check_pid_dir()\n        self.check_startup_dir()\n\n    def copy_config_file(self, config_file, path=None, overwrite=False):\n        \"\"\"Copy a default config file into the active profile directory.\n\n        Default configuration files are kept in :mod:`IPython.config.default`.\n        This function moves these from that location to the working profile\n        directory.\n        \"\"\"\n        dst = os.path.join(self.location, config_file)\n        if os.path.isfile(dst) and not overwrite:\n            return False\n        if path is None:\n            path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')\n        src = os.path.join(path, config_file)\n        shutil.copy(src, dst)\n        return True\n\n    @classmethod\n    def create_profile_dir(cls, profile_dir, config=None):\n        \"\"\"Create a new profile directory given a full path.\n\n        Parameters\n        ----------\n        profile_dir : str\n            The full path to the profile directory.  If it does exist, it will\n            be used.  If not, it will be created.\n        \"\"\"\n        return cls(location=profile_dir, config=config)\n\n    @classmethod\n    def create_profile_dir_by_name(cls, path, name=u'default', config=None):\n        \"\"\"Create a profile dir by profile name and path.\n\n        Parameters\n        ----------\n        path : unicode\n            The path (directory) to put the profile directory in.\n        name : unicode\n            The name of the profile.  The name of the profile directory will\n            be \"profile_<profile>\".\n        \"\"\"\n        if not os.path.isdir(path):\n            raise ProfileDirError('Directory not found: %s' % path)\n        profile_dir = os.path.join(path, u'profile_' + name)\n        return cls(location=profile_dir, config=config)\n\n    @classmethod\n    def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):\n        \"\"\"Find an existing profile dir by profile name, return its ProfileDir.\n\n        This searches through a sequence of paths for a profile dir.  If it\n        is not found, a :class:`ProfileDirError` exception will be raised.\n\n        The search path algorithm is:\n        1. ``os.getcwdu()``\n        2. ``ipython_dir``\n\n        Parameters\n        ----------\n        ipython_dir : unicode or str\n            The IPython directory to use.\n        name : unicode or str\n            The name of the profile.  The name of the profile directory\n            will be \"profile_<profile>\".\n        \"\"\"\n        dirname = u'profile_' + name\n        paths = [os.getcwdu(), ipython_dir]\n        for p in paths:\n            profile_dir = os.path.join(p, dirname)\n            if os.path.isdir(profile_dir):\n                return cls(location=profile_dir, config=config)\n        else:\n            raise ProfileDirError('Profile directory not found in paths: %s' % dirname)\n\n    @classmethod\n    def find_profile_dir(cls, profile_dir, config=None):\n        \"\"\"Find/create a profile dir and return its ProfileDir.\n\n        This will create the profile directory if it doesn't exist.\n\n        Parameters\n        ----------\n        profile_dir : unicode or str\n            The path of the profile directory.  This is expanded using\n            :func:`IPython.utils.genutils.expand_path`.\n        \"\"\"\n        profile_dir = expand_path(profile_dir)\n        if not os.path.isdir(profile_dir):\n            raise ProfileDirError('Profile directory not found: %s' % profile_dir)\n        return cls(location=profile_dir, config=config)\n\n\n", "path": "IPython/core/profiledir.py"}], "after_files": [{"content": "# encoding: utf-8\n\"\"\"\nAn object for managing IPython profile directories.\n\nAuthors:\n\n* Brian Granger\n* Fernando Perez\n* Min RK\n\n\"\"\"\n\n#-----------------------------------------------------------------------------\n#  Copyright (C) 2008-2011  The IPython Development Team\n#\n#  Distributed under the terms of the BSD License.  The full license is in\n#  the file COPYING, distributed as part of this software.\n#-----------------------------------------------------------------------------\n\n#-----------------------------------------------------------------------------\n# Imports\n#-----------------------------------------------------------------------------\n\nimport os\nimport shutil\n\nfrom IPython.config.configurable import LoggingConfigurable\nfrom IPython.utils.path import get_ipython_package_dir, expand_path\nfrom IPython.utils.traitlets import Unicode, Bool\n\n#-----------------------------------------------------------------------------\n# Classes and functions\n#-----------------------------------------------------------------------------\n\n\n#-----------------------------------------------------------------------------\n# Module errors\n#-----------------------------------------------------------------------------\n\nclass ProfileDirError(Exception):\n    pass\n\n\n#-----------------------------------------------------------------------------\n# Class for managing profile directories\n#-----------------------------------------------------------------------------\n\nclass ProfileDir(LoggingConfigurable):\n    \"\"\"An object to manage the profile directory and its resources.\n\n    The profile directory is used by all IPython applications, to manage\n    configuration, logging and security.\n\n    This object knows how to find, create and manage these directories. This\n    should be used by any code that wants to handle profiles.\n    \"\"\"\n\n    security_dir_name = Unicode('security')\n    log_dir_name = Unicode('log')\n    startup_dir_name = Unicode('startup')\n    pid_dir_name = Unicode('pid')\n    security_dir = Unicode(u'')\n    log_dir = Unicode(u'')\n    startup_dir = Unicode(u'')\n    pid_dir = Unicode(u'')\n\n    location = Unicode(u'', config=True,\n        help=\"\"\"Set the profile location directly. This overrides the logic used by the\n        `profile` option.\"\"\",\n        )\n\n    _location_isset = Bool(False) # flag for detecting multiply set location\n\n    def _location_changed(self, name, old, new):\n        if self._location_isset:\n            raise RuntimeError(\"Cannot set profile location more than once.\")\n        self._location_isset = True\n        if not os.path.isdir(new):\n            os.makedirs(new)\n        \n        # ensure config files exist:\n        self.security_dir = os.path.join(new, self.security_dir_name)\n        self.log_dir = os.path.join(new, self.log_dir_name)\n        self.startup_dir = os.path.join(new, self.startup_dir_name)\n        self.pid_dir = os.path.join(new, self.pid_dir_name)\n        self.check_dirs()\n\n    def _log_dir_changed(self, name, old, new):\n        self.check_log_dir()\n    \n    def _mkdir(self, path, mode=None):\n        \"\"\"ensure a directory exists at a given path\n        \n        This is a version of os.mkdir, with the following differences:\n        \n        - returns True if it created the directory, False otherwise\n        - ignores EEXIST, protecting against race conditions where\n          the dir may have been created in between the check and\n          the creation\n        - sets permissions if requested and the dir already exists\n        \"\"\"\n        if os.path.exists(path):\n            if mode and os.stat(path).st_mode != mode:\n                try:\n                    os.chmod(path, mode)\n                except OSError:\n                    self.log.warn(\n                        \"Could not set permissions on %s\",\n                        path\n                    )\n            return False\n        try:\n            if mode:\n                os.mkdir(path, mode)\n            else:\n                os.mkdir(path)\n        except OSError as e:\n            if e.errno == errno.EEXIST:\n                return False\n            else:\n                raise\n        \n        return True\n\n    def check_log_dir(self):\n        self._mkdir(self.log_dir)\n\n    def _startup_dir_changed(self, name, old, new):\n        self.check_startup_dir()\n\n    def check_startup_dir(self):\n        self._mkdir(self.startup_dir)\n\n        readme = os.path.join(self.startup_dir, 'README')\n        src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')\n\n        if not os.path.exists(src):\n            self.log.warn(\"Could not copy README_STARTUP to startup dir. Source file %s does not exist.\", src)\n\n        if os.path.exists(src) and not os.path.exists(readme):\n            shutil.copy(src, readme)\n\n    def _security_dir_changed(self, name, old, new):\n        self.check_security_dir()\n\n    def check_security_dir(self):\n        self._mkdir(self.security_dir, 0o40700)\n\n    def _pid_dir_changed(self, name, old, new):\n        self.check_pid_dir()\n\n    def check_pid_dir(self):\n        self._mkdir(self.pid_dir, 0o40700)\n\n    def check_dirs(self):\n        self.check_security_dir()\n        self.check_log_dir()\n        self.check_pid_dir()\n        self.check_startup_dir()\n\n    def copy_config_file(self, config_file, path=None, overwrite=False):\n        \"\"\"Copy a default config file into the active profile directory.\n\n        Default configuration files are kept in :mod:`IPython.config.default`.\n        This function moves these from that location to the working profile\n        directory.\n        \"\"\"\n        dst = os.path.join(self.location, config_file)\n        if os.path.isfile(dst) and not overwrite:\n            return False\n        if path is None:\n            path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')\n        src = os.path.join(path, config_file)\n        shutil.copy(src, dst)\n        return True\n\n    @classmethod\n    def create_profile_dir(cls, profile_dir, config=None):\n        \"\"\"Create a new profile directory given a full path.\n\n        Parameters\n        ----------\n        profile_dir : str\n            The full path to the profile directory.  If it does exist, it will\n            be used.  If not, it will be created.\n        \"\"\"\n        return cls(location=profile_dir, config=config)\n\n    @classmethod\n    def create_profile_dir_by_name(cls, path, name=u'default', config=None):\n        \"\"\"Create a profile dir by profile name and path.\n\n        Parameters\n        ----------\n        path : unicode\n            The path (directory) to put the profile directory in.\n        name : unicode\n            The name of the profile.  The name of the profile directory will\n            be \"profile_<profile>\".\n        \"\"\"\n        if not os.path.isdir(path):\n            raise ProfileDirError('Directory not found: %s' % path)\n        profile_dir = os.path.join(path, u'profile_' + name)\n        return cls(location=profile_dir, config=config)\n\n    @classmethod\n    def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):\n        \"\"\"Find an existing profile dir by profile name, return its ProfileDir.\n\n        This searches through a sequence of paths for a profile dir.  If it\n        is not found, a :class:`ProfileDirError` exception will be raised.\n\n        The search path algorithm is:\n        1. ``os.getcwdu()``\n        2. ``ipython_dir``\n\n        Parameters\n        ----------\n        ipython_dir : unicode or str\n            The IPython directory to use.\n        name : unicode or str\n            The name of the profile.  The name of the profile directory\n            will be \"profile_<profile>\".\n        \"\"\"\n        dirname = u'profile_' + name\n        paths = [os.getcwdu(), ipython_dir]\n        for p in paths:\n            profile_dir = os.path.join(p, dirname)\n            if os.path.isdir(profile_dir):\n                return cls(location=profile_dir, config=config)\n        else:\n            raise ProfileDirError('Profile directory not found in paths: %s' % dirname)\n\n    @classmethod\n    def find_profile_dir(cls, profile_dir, config=None):\n        \"\"\"Find/create a profile dir and return its ProfileDir.\n\n        This will create the profile directory if it doesn't exist.\n\n        Parameters\n        ----------\n        profile_dir : unicode or str\n            The path of the profile directory.  This is expanded using\n            :func:`IPython.utils.genutils.expand_path`.\n        \"\"\"\n        profile_dir = expand_path(profile_dir)\n        if not os.path.isdir(profile_dir):\n            raise ProfileDirError('Profile directory not found: %s' % profile_dir)\n        return cls(location=profile_dir, config=config)\n\n\n", "path": "IPython/core/profiledir.py"}]}