Repository: beeware/briefcase

Issue:
briefcase dev fails if an application puts it's application module in the project root
If an application places its source code directly in the project root, `briefcase dev` fails to start.

**To Reproduce**
Steps to reproduce the behavior:
1. Run Tutorial 0 in the Toga code repository using `briefcase dev`
2. See error

```
[tutorial] Starting in dev mode...
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 205, in run_module
    mod_name, mod_spec, code = _get_module_details(mod_name)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 140, in _get_module_details
    raise error("No module named %s" % mod_name)
ImportError: No module named tutorial

Unable to start application 'tutorial'
```

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Environment:**
 - Operating System: macOS
 - Python version: 0.3.10
 - Software versions:
   - Briefcase: 0.3.9

**Additional context**

This appears to be an unintended side effect of #803 removing the current working directory from the PYTHONPATH when running briefcase dev

Discussion:

Patch:
diff --git a/changes/863.bugfix.rst b/changes/863.bugfix.rst
new file mode 100644
index 00000000..b790c506
--- /dev/null
+++ b/changes/863.bugfix.rst
@@ -0,0 +1,1 @@
+An issue with running `briefcase dev` on projects that put their application module in the project root has been resolved.
diff --git a/src/briefcase/config.py b/src/briefcase/config.py
index 6dd39666..d0a909ae 100644
--- a/src/briefcase/config.py
+++ b/src/briefcase/config.py
@@ -390,7 +390,7 @@ class AppConfig(BaseConfig):
         """The PYTHONPATH modifications needed to run this app."""
         paths = []
         for source in self.sources:
-            path = source.rsplit("/", 1)[0]
+            path = "/".join(source.rsplit("/", 1)[:-1])
             if path not in paths:
                 paths.append(path)
         return paths


Test patch:
diff --git a/tests/commands/dev/test_get_environment.py b/tests/commands/dev/test_get_environment.py
index 17fd2952..97f0d140 100644
--- a/tests/commands/dev/test_get_environment.py
+++ b/tests/commands/dev/test_get_environment.py
@@ -16,11 +16,11 @@ def test_pythonpath_with_one_source(dev_command, first_app):
 def test_pythonpath_with_two_sources_in_windows(dev_command, third_app):
     """Test get environment with two sources in windows."""
     env = dev_command.get_environment(third_app)
-    assert env[PYTHONPATH] == f"{Path.cwd() / 'src'};{Path.cwd() / 'other'}"
+    assert env[PYTHONPATH] == f"{Path.cwd() / 'src'};{Path.cwd()}"
 
 
 @pytest.mark.skipif(sys.platform == "win32", reason="Relevant only for non-windows")
 def test_pythonpath_with_two_sources_in_linux(dev_command, third_app):
     """Test get environment with two sources in linux."""
     env = dev_command.get_environment(third_app)
-    assert env[PYTHONPATH] == f"{Path.cwd() / 'src'}:{Path.cwd() / 'other'}"
+    assert env[PYTHONPATH] == f"{Path.cwd() / 'src'}:{Path.cwd()}"
diff --git a/tests/config/test_AppConfig.py b/tests/config/test_AppConfig.py
index 6731df71..eeb2c55f 100644
--- a/tests/config/test_AppConfig.py
+++ b/tests/config/test_AppConfig.py
@@ -11,7 +11,7 @@ def test_minimal_AppConfig():
         version="1.2.3",
         bundle="org.beeware",
         description="A simple app",
-        sources=["src/myapp", "somewhere/else/interesting"],
+        sources=["src/myapp", "somewhere/else/interesting", "local_app"],
     )
 
     # The basic properties have been set.
@@ -30,7 +30,7 @@ def test_minimal_AppConfig():
     assert config.splash is None
 
     # The PYTHONPATH is derived correctly
-    assert config.PYTHONPATH == ["src", "somewhere/else"]
+    assert config.PYTHONPATH == ["src", "somewhere/else", ""]
 
     # The object has a meaningful REPL
     assert repr(config) == "<org.beeware.myapp v1.2.3 AppConfig>"