Repository: railwayapp/nixpacks
Pull request #597 (2022-10-01 02:47:36)

Python psycopg2 and postgres
This PR installs the `postgresql` Nix package if the python `psycopg2` dependency is detected



Patch:
diff --git a/examples/python-postgres/main.py b/examples/python-postgres/main.py
new file mode 100644
index 0000000..37388de
--- /dev/null
+++ b/examples/python-postgres/main.py
@@ -0,0 +1,3 @@
+import psycopg2 as pg
+
+print(pg)
diff --git a/examples/python-postgres/requirements.txt b/examples/python-postgres/requirements.txt
new file mode 100644
index 0000000..d7661d4
--- /dev/null
+++ b/examples/python-postgres/requirements.txt
@@ -0,0 +1,1 @@
+psycopg2==2.9.3
diff --git a/install.ps1 b/install.ps1
index 5bd1e39..79d91f9 100644
--- a/install.ps1
+++ b/install.ps1
@@ -46,8 +46,12 @@ tar.exe xf $NixpacksZip -C $BinDir
 
 Remove-Item $NixpacksZip
 
-if (($Env:Path -contains "nixpacks")) {
-    $Env:Path += ";$BinDir"
+$User = [EnvironmentVariableTarget]::User
+$Path = [Environment]::GetEnvironmentVariable('Path', $User)
+if (!(";$Path;".ToLower() -like "*;$BinDir;*".ToLower())) {
+  [Environment]::SetEnvironmentVariable('Path', "$Path;$BinDir", $User)
+  $Env:Path += ";$BinDir"
 }
+
 Write-Output "Nixpacks was installed successfully to $NixpacksExe"
 Write-Output "Run 'nixpacks --help' to get started"
\ No newline at end of file
diff --git a/src/providers/python.rs b/src/providers/python.rs
index e2a7c6f..81934df 100644
--- a/src/providers/python.rs
+++ b/src/providers/python.rs
@@ -112,8 +112,8 @@ impl PythonProvider {
 
         pkgs.append(&mut vec![python_base_package]);
 
-        if PythonProvider::is_django(app, env)? && PythonProvider::is_using_postgres(app, env)? {
-            // Django with Postgres requires postgresql and gcc on top of the original python packages
+        if PythonProvider::is_using_postgres(app, env)? {
+            // Postgres requires postgresql and gcc on top of the original python packages
             pkgs.append(&mut vec![Pkg::new("postgresql")]);
         }
 
@@ -220,7 +220,9 @@ impl PythonProvider {
         // Check for the engine database type in settings.py
         let re = Regex::new(r"django.db.backends.postgresql").unwrap();
 
-        app.find_match(&re, "/**/*.py")
+        let uses_pg =
+            app.find_match(&re, "/**/*.py")? || PythonProvider::uses_dep(app, "psycopg2")?;
+        Ok(uses_pg)
     }
 
     fn is_using_mysql(app: &App, _env: &Environment) -> Result<bool> {
@@ -350,7 +352,6 @@ impl PythonProvider {
         ))
     }
 
-    #[allow(dead_code)]
     fn uses_dep(app: &App, dep: &str) -> Result<bool> {
         let requirements_usage = app.includes_file("requirements.txt")
             && app
@@ -443,7 +444,12 @@ mod test {
     }
 
     #[test]
-    fn test_django_postgres_detection() -> Result<()> {
+    fn test_postgres_detection() -> Result<()> {
+        assert!(PythonProvider::is_using_postgres(
+            &App::new("./examples/python-postgres",)?,
+            &Environment::new(BTreeMap::new())
+        )
+        .unwrap());
         assert!(PythonProvider::is_using_postgres(
             &App::new("./examples/python-django",)?,
             &Environment::new(BTreeMap::new())


Test patch:
diff --git a/tests/docker_run_tests.rs b/tests/docker_run_tests.rs
index 4679004..30b9ab6 100644
--- a/tests/docker_run_tests.rs
+++ b/tests/docker_run_tests.rs
@@ -624,6 +624,13 @@ fn test_python_numpy() {
     assert!(output.contains("Hello from Python numpy and pandas"));
 }
 
+#[test]
+fn test_python_postgres() {
+    let name = simple_build("./examples/python-postgres");
+    let output = run_image(&name, None);
+    assert!(output.contains("psycopg2"));
+}
+
 #[test]
 fn test_rust_custom_version() {
     let name = Uuid::new_v4().to_string();
diff --git a/tests/snapshots/generate_plan_tests__python_postgres.snap b/tests/snapshots/generate_plan_tests__python_postgres.snap
new file mode 100644
index 0000000..40da0a0
--- /dev/null
+++ b/tests/snapshots/generate_plan_tests__python_postgres.snap
@@ -0,0 +1,46 @@
+---
+source: tests/generate_plan_tests.rs
+expression: plan
+---
+{
+  "providers": [],
+  "buildImage": "[build_image]",
+  "variables": {
+    "NIXPACKS_METADATA": "python,postgres",
+    "PYTHONUNBUFFERED": "1"
+  },
+  "phases": {
+    "install": {
+      "name": "install",
+      "dependsOn": [
+        "setup"
+      ],
+      "cmds": [
+        "python -m venv /opt/venv && . /opt/venv/bin/activate && pip install -r requirements.txt"
+      ],
+      "cacheDirectories": [
+        "/root/.cache/pip"
+      ],
+      "paths": [
+        "/opt/venv/bin"
+      ]
+    },
+    "setup": {
+      "name": "setup",
+      "nixPkgs": [
+        "python38",
+        "postgresql",
+        "gcc"
+      ],
+      "nixLibs": [
+        "zlib",
+        "stdenv.cc.cc.lib"
+      ],
+      "nixOverlays": [],
+      "nixpkgsArchive": "[archive]"
+    }
+  },
+  "start": {
+    "cmd": "python main.py"
+  }
+}