Repository: dynaconf/dynaconf

Issue:
[bug] Dynaconf doesn't load configuration file if cwd doesn't exist
**Describe the bug**
When the current workdir directory has been removed, dynaconf refuses to load configuration files.

**To Reproduce**
Steps to reproduce the behavior:

1. Having the following folder structure

<!-- Describe or use the command `$ tree -v` and paste below -->

<details>
<summary> Project structure </summary>

```bash

# /tmp/dyn.yaml
# /home/user/bug_dynaconf/
#             app.py
#             script.sh
```
</details>


2. Having the following config files:

<!-- Please adjust if you are using different files and formats! -->

<details>
<summary> Config files </summary>

**/tmp/dyn.yaml**
```yaml
offset: 24
```
</details>

3. Having the following app code:

<details>
<summary> Code </summary>

**app.py**
```python

from dynaconf import Dynaconf

settings = Dynaconf(
        settings_files=["/tmp/dyn.yaml"]
)

print(settings.offset)

settings.validators.validate()

print(type(settings.offset))

```

</details>

4. Executing under the following environment

<details>
<summary> Execution </summary>

**script.sh**
```bash
#!/bin/bash -x

python3 -m venv venv
source venv/bin/activate
pip install dynaconf==3.1.12
PARENT=$(realpath .)
mkdir nonexistent_dir
cd nonexistent_dir
rm -r ../nonexistent_dir
python $PARENT/app.py
```

</details>

**Expected behavior**
the `app.py` should have printed the type of `offset`, which is an `int`

**Actual behavior**
~~~Python
Traceback (most recent call last):
  File "/home/mtarral/debug_dynaconf/app.py", line 7, in <module>
    print(settings.offset)
  File "/home/mtarral/debug_dynaconf/venv/lib/python3.8/site-packages/dynaconf/base.py", line 138, in __getattr__
    value = getattr(self._wrapped, name)
  File "/home/mtarral/debug_dynaconf/venv/lib/python3.8/site-packages/dynaconf/base.py", line 300, in __getattribute__
    return super().__getattribute__(name)
AttributeError: 'Settings' object has no attribute 'OFFSET'
~~~

**Environment (please complete the following information):**
 - OS: ubuntu 20.04
 - Dynaconf Version 3.1.12

**Additional context**
Following https://github.com/dynaconf/dynaconf/issues/853, I tried to repro with 3.1.12, and found this issue now.

Thanks for dynaconf !

[bug] Dynaconf doesn't load configuration file if cwd doesn't exist
**Describe the bug**
When the current workdir directory has been removed, dynaconf refuses to load configuration files.

**To Reproduce**
Steps to reproduce the behavior:

1. Having the following folder structure

<!-- Describe or use the command `$ tree -v` and paste below -->

<details>
<summary> Project structure </summary>

```bash

# /tmp/dyn.yaml
# /home/user/bug_dynaconf/
#             app.py
#             script.sh
```
</details>


2. Having the following config files:

<!-- Please adjust if you are using different files and formats! -->

<details>
<summary> Config files </summary>

**/tmp/dyn.yaml**
```yaml
offset: 24
```
</details>

3. Having the following app code:

<details>
<summary> Code </summary>

**app.py**
```python

from dynaconf import Dynaconf

settings = Dynaconf(
        settings_files=["/tmp/dyn.yaml"]
)

print(settings.offset)

settings.validators.validate()

print(type(settings.offset))

```

</details>

4. Executing under the following environment

<details>
<summary> Execution </summary>

**script.sh**
```bash
#!/bin/bash -x

python3 -m venv venv
source venv/bin/activate
pip install dynaconf==3.1.12
PARENT=$(realpath .)
mkdir nonexistent_dir
cd nonexistent_dir
rm -r ../nonexistent_dir
python $PARENT/app.py
```

</details>

**Expected behavior**
the `app.py` should have printed the type of `offset`, which is an `int`

**Actual behavior**
~~~Python
Traceback (most recent call last):
  File "/home/mtarral/debug_dynaconf/app.py", line 7, in <module>
    print(settings.offset)
  File "/home/mtarral/debug_dynaconf/venv/lib/python3.8/site-packages/dynaconf/base.py", line 138, in __getattr__
    value = getattr(self._wrapped, name)
  File "/home/mtarral/debug_dynaconf/venv/lib/python3.8/site-packages/dynaconf/base.py", line 300, in __getattribute__
    return super().__getattribute__(name)
AttributeError: 'Settings' object has no attribute 'OFFSET'
~~~

**Environment (please complete the following information):**
 - OS: ubuntu 20.04
 - Dynaconf Version 3.1.12

**Additional context**
Following https://github.com/dynaconf/dynaconf/issues/853, I tried to repro with 3.1.12, and found this issue now.

Thanks for dynaconf !



Discussion:
That is a very uncommon use case, lets add this reproducer as a functional test in /tests_functional and fix it.
Even if the Python file is empty, Python will raise errors when running on an unexistent cwd
That is a very uncommon use case, lets add this reproducer as a functional test in /tests_functional and fix it.
Even if the Python file is empty, Python will raise errors when running on an unexistent cwd

Resolving patch:
diff --git a/dynaconf/utils/files.py b/dynaconf/utils/files.py
--- a/dynaconf/utils/files.py
+++ b/dynaconf/utils/files.py
@@ -46,6 +46,12 @@ def find_file(filename=".env", project_root=None, skip_files=None, **kwargs):
     For each path in the `search_tree` it will also look for an
     additional `./config` folder.
     """
+    # If filename is an absolute path and exists, just return it
+    # if the absolute path does not exist, return empty string so
+    # that it can be joined and avoid IoError
+    if os.path.isabs(filename):
+        return filename if os.path.exists(filename) else ""
+
     search_tree = []
     try:
         work_dir = os.getcwd()
@@ -53,12 +59,6 @@ def find_file(filename=".env", project_root=None, skip_files=None, **kwargs):
         return ""
     skip_files = skip_files or []
 
-    # If filename is an absolute path and exists, just return it
-    # if the absolute path does not exist, return empty string so
-    # that it can be joined and avoid IoError
-    if os.path.isabs(filename):
-        return filename if os.path.exists(filename) else ""
-
     if project_root is not None:
         search_tree.extend(_walk_to_root(project_root, break_at=work_dir))
 


Test patch:
diff --git a/tests_functional/issues/876_deleted_cwd/app.py b/tests_functional/issues/876_deleted_cwd/app.py
new file mode 100644
--- /dev/null
+++ b/tests_functional/issues/876_deleted_cwd/app.py
@@ -0,0 +1,16 @@
+from __future__ import annotations
+
+import os
+
+from dynaconf import Dynaconf
+
+print(os.getenv("SETTINGS_FILE_FOR_DYNACONF"))
+settings = Dynaconf()
+
+print(settings.offset)
+assert settings.offset == 24
+
+settings.validators.validate()
+
+print(type(settings.offset))
+assert isinstance(settings.offset, int)
diff --git a/tests_functional/issues/876_deleted_cwd/test.sh b/tests_functional/issues/876_deleted_cwd/test.sh
new file mode 100755
--- /dev/null
+++ b/tests_functional/issues/876_deleted_cwd/test.sh
@@ -0,0 +1,11 @@
+#!/bin/bash -x
+export SETTINGS_FILE_FOR_DYNACONF=$(mktemp -t dynaconf.XXXXX.yaml)
+echo "offset: 24" > $SETTINGS_FILE_FOR_DYNACONF
+PARENT=$(readlink -f .)
+mkdir nonexistent_dir
+cd nonexistent_dir
+rm -r ../nonexistent_dir
+ls ../
+python $PARENT/app.py
+cat $SETTINGS_FILE_FOR_DYNACONF
+rm -r $SETTINGS_FILE_FOR_DYNACONF
diff --git a/tests_functional/skipfile.toml b/tests_functional/skipfile.toml
--- a/tests_functional/skipfile.toml
+++ b/tests_functional/skipfile.toml
@@ -19,4 +19,5 @@ nt = [
     "685_disable_dotted_lookup",
     "741_envvars_ignored",
     "missing_pwd",
+    "876_deleted_cwd",
 ]