Skip to content

Commit 40c5c84

Browse files
feat: add test and fix python dependencies (#304)
--------- Co-authored-by: Marcus Schiesser <[email protected]>
1 parent 0031e67 commit 40c5c84

File tree

6 files changed

+202
-14
lines changed

6 files changed

+202
-14
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { expect, test } from "@playwright/test";
2+
import { exec } from "child_process";
3+
import fs from "fs";
4+
import path from "path";
5+
import util from "util";
6+
import { TemplateFramework, TemplateVectorDB } from "../helpers/types";
7+
import { createTestDir, runCreateLlama } from "./utils";
8+
9+
const execAsync = util.promisify(exec);
10+
11+
const templateFramework: TemplateFramework = process.env.FRAMEWORK
12+
? (process.env.FRAMEWORK as TemplateFramework)
13+
: "fastapi";
14+
const dataSource: string = process.env.DATASOURCE
15+
? process.env.DATASOURCE
16+
: "--example-file";
17+
18+
if (
19+
templateFramework == "fastapi" && // test is only relevant for fastapi
20+
process.version.startsWith("v20.") && // XXX: Only run for Node.js version 20 (CI matrix will trigger other versions)
21+
dataSource === "--example-file" // XXX: this test provides its own data source - only trigger it on one data source (usually the CI matrix will trigger multiple data sources)
22+
) {
23+
// vectorDBs, tools, and data source combinations to test
24+
const vectorDbs: TemplateVectorDB[] = [
25+
"mongo",
26+
"pg",
27+
"pinecone",
28+
"milvus",
29+
"astra",
30+
"qdrant",
31+
"chroma",
32+
"weaviate",
33+
];
34+
35+
const toolOptions = [
36+
"wikipedia.WikipediaToolSpec",
37+
"google.GoogleSearchToolSpec",
38+
];
39+
40+
const dataSources = [
41+
"--example-file",
42+
"--web-source https://www.example.com",
43+
"--db-source mysql+pymysql://user:pass@localhost:3306/mydb",
44+
];
45+
46+
test.describe("Test resolve python dependencies", () => {
47+
for (const vectorDb of vectorDbs) {
48+
for (const tool of toolOptions) {
49+
for (const dataSource of dataSources) {
50+
const dataSourceType = dataSource.split(" ")[0];
51+
const optionDescription = `vectorDb: ${vectorDb}, tools: ${tool}, dataSource: ${dataSourceType}`;
52+
53+
test(`options: ${optionDescription}`, async () => {
54+
const cwd = await createTestDir();
55+
56+
const result = await runCreateLlama(
57+
cwd,
58+
"streaming",
59+
"fastapi",
60+
dataSource,
61+
vectorDb,
62+
3000, // port
63+
8000, // externalPort
64+
"none", // postInstallAction
65+
undefined, // ui
66+
"--no-frontend", // appType
67+
undefined, // llamaCloudProjectName
68+
undefined, // llamaCloudIndexName
69+
tool,
70+
);
71+
const name = result.projectName;
72+
73+
// Check if the app folder exists
74+
const dirExists = fs.existsSync(path.join(cwd, name));
75+
expect(dirExists).toBeTruthy();
76+
77+
// Check if pyproject.toml exists
78+
const pyprojectPath = path.join(cwd, name, "pyproject.toml");
79+
const pyprojectExists = fs.existsSync(pyprojectPath);
80+
expect(pyprojectExists).toBeTruthy();
81+
82+
// Run poetry lock
83+
try {
84+
const { stdout, stderr } = await execAsync(
85+
"poetry config virtualenvs.in-project true && poetry lock --no-update",
86+
{
87+
cwd: path.join(cwd, name),
88+
},
89+
);
90+
console.log("poetry lock stdout:", stdout);
91+
console.error("poetry lock stderr:", stderr);
92+
} catch (error) {
93+
console.error("Error running poetry lock:", error);
94+
throw error;
95+
}
96+
97+
// Check if poetry.lock file was created
98+
const poetryLockExists = fs.existsSync(
99+
path.join(cwd, name, "poetry.lock"),
100+
);
101+
expect(poetryLockExists).toBeTruthy();
102+
103+
// Verify that specific dependencies are in pyproject.toml
104+
const pyprojectContent = fs.readFileSync(pyprojectPath, "utf-8");
105+
if (vectorDb !== "none") {
106+
if (vectorDb === "pg") {
107+
expect(pyprojectContent).toContain(
108+
"llama-index-vector-stores-postgres",
109+
);
110+
} else {
111+
expect(pyprojectContent).toContain(
112+
`llama-index-vector-stores-${vectorDb}`,
113+
);
114+
}
115+
}
116+
if (tool !== "none") {
117+
if (tool === "wikipedia.WikipediaToolSpec") {
118+
expect(pyprojectContent).toContain("wikipedia");
119+
}
120+
if (tool === "google.GoogleSearchToolSpec") {
121+
expect(pyprojectContent).toContain("google");
122+
}
123+
}
124+
125+
// Check for data source specific dependencies
126+
if (dataSource.includes("--web-source")) {
127+
expect(pyprojectContent).toContain("llama-index-readers-web");
128+
}
129+
if (dataSource.includes("--db-source")) {
130+
expect(pyprojectContent).toContain(
131+
"llama-index-readers-database ",
132+
);
133+
}
134+
});
135+
}
136+
}
137+
}
138+
});
139+
}

e2e/utils.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export async function runCreateLlama(
3232
appType?: AppType,
3333
llamaCloudProjectName?: string,
3434
llamaCloudIndexName?: string,
35+
tools?: string,
3536
): Promise<CreateLlamaResult> {
3637
if (!process.env.OPENAI_API_KEY || !process.env.LLAMA_CLOUD_API_KEY) {
3738
throw new Error(
@@ -41,18 +42,31 @@ export async function runCreateLlama(
4142
const name = [
4243
templateType,
4344
templateFramework,
44-
dataSource,
45+
dataSource.split(" ")[0],
4546
templateUI,
4647
appType,
4748
].join("-");
49+
50+
// Handle different data source types
51+
let dataSourceArgs = [];
52+
if (dataSource.includes("--web-source" || "--db-source")) {
53+
const webSource = dataSource.split(" ")[1];
54+
dataSourceArgs.push("--web-source", webSource);
55+
} else if (dataSource.includes("--db-source")) {
56+
const dbSource = dataSource.split(" ")[1];
57+
dataSourceArgs.push("--db-source", dbSource);
58+
} else {
59+
dataSourceArgs.push(dataSource);
60+
}
61+
4862
const commandArgs = [
4963
"create-llama",
5064
name,
5165
"--template",
5266
templateType,
5367
"--framework",
5468
templateFramework,
55-
dataSource,
69+
...dataSourceArgs,
5670
"--vector-db",
5771
vectorDb,
5872
"--open-ai-key",
@@ -65,7 +79,7 @@ export async function runCreateLlama(
6579
"--post-install-action",
6680
postInstallAction,
6781
"--tools",
68-
"none",
82+
tools ?? "none",
6983
"--no-llama-parse",
7084
"--observability",
7185
"none",

helpers/python.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,28 @@ const getAdditionalDependencies = (
3636
case "mongo": {
3737
dependencies.push({
3838
name: "llama-index-vector-stores-mongodb",
39-
version: "^0.1.3",
39+
version: "^0.3.1",
4040
});
4141
break;
4242
}
4343
case "pg": {
4444
dependencies.push({
4545
name: "llama-index-vector-stores-postgres",
46-
version: "^0.1.1",
46+
version: "^0.2.5",
4747
});
4848
break;
4949
}
5050
case "pinecone": {
5151
dependencies.push({
5252
name: "llama-index-vector-stores-pinecone",
53-
version: "^0.1.3",
53+
version: "^0.2.1",
5454
});
5555
break;
5656
}
5757
case "milvus": {
5858
dependencies.push({
5959
name: "llama-index-vector-stores-milvus",
60-
version: "^0.1.20",
60+
version: "^0.2.0",
6161
});
6262
dependencies.push({
6363
name: "pymilvus",
@@ -68,28 +68,28 @@ const getAdditionalDependencies = (
6868
case "astra": {
6969
dependencies.push({
7070
name: "llama-index-vector-stores-astra-db",
71-
version: "^0.1.5",
71+
version: "^0.2.0",
7272
});
7373
break;
7474
}
7575
case "qdrant": {
7676
dependencies.push({
7777
name: "llama-index-vector-stores-qdrant",
78-
version: "^0.2.8",
78+
version: "^0.3.0",
7979
});
8080
break;
8181
}
8282
case "chroma": {
8383
dependencies.push({
8484
name: "llama-index-vector-stores-chroma",
85-
version: "^0.1.8",
85+
version: "^0.2.0",
8686
});
8787
break;
8888
}
8989
case "weaviate": {
9090
dependencies.push({
9191
name: "llama-index-vector-stores-weaviate",
92-
version: "^1.0.2",
92+
version: "^1.1.1",
9393
});
9494
break;
9595
}
@@ -130,7 +130,7 @@ const getAdditionalDependencies = (
130130
case "llamacloud":
131131
dependencies.push({
132132
name: "llama-index-indices-managed-llama-cloud",
133-
version: "^0.3.0",
133+
version: "^0.3.1",
134134
});
135135
break;
136136
}

index.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ const program = new Commander.Command(packageJson.name)
9090
`
9191
9292
Select to use an example PDF as data source.
93+
`,
94+
)
95+
.option(
96+
"--web-source <url>",
97+
`
98+
99+
Specify a website URL to use as a data source.
100+
`,
101+
)
102+
.option(
103+
"--db-source <connection-string>",
104+
`
105+
106+
Specify a database connection string to use as a data source.
93107
`,
94108
)
95109
.option(
@@ -215,6 +229,27 @@ if (process.argv.includes("--no-files")) {
215229
},
216230
EXAMPLE_FILE,
217231
];
232+
} else if (process.argv.includes("--web-source")) {
233+
program.dataSources = [
234+
{
235+
type: "web",
236+
config: {
237+
baseUrl: program.webSource,
238+
prefix: program.webSource,
239+
depth: 1,
240+
},
241+
},
242+
];
243+
} else if (process.argv.includes("--db-source")) {
244+
program.dataSources = [
245+
{
246+
type: "db",
247+
config: {
248+
uri: program.dbSource,
249+
queries: program.dbQuery || "SELECT * FROM mytable",
250+
},
251+
},
252+
];
218253
}
219254

220255
const packageManager = !!program.useNpm

templates/types/multiagent/fastapi/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ readme = "README.md"
1010
generate = "app.engine.generate:generate_datasource"
1111

1212
[tool.poetry.dependencies]
13-
python = "^3.11"
13+
python = ">=3.11,<3.13"
1414
llama-index-agent-openai = ">=0.3.0,<0.4.0"
1515
llama-index = "0.11.11"
1616
fastapi = "^0.112.2"

templates/types/streaming/fastapi/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ readme = "README.md"
99
generate = "app.engine.generate:generate_datasource"
1010

1111
[tool.poetry.dependencies]
12-
python = "^3.11,<4.0"
12+
python = ">=3.11,<3.13"
1313
fastapi = "^0.109.1"
1414
uvicorn = { extras = ["standard"], version = "^0.23.2" }
1515
python-dotenv = "^1.0.0"

0 commit comments

Comments
 (0)