vector-inspector 0.2.1__tar.gz → 0.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/PKG-INFO +9 -6
  2. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/README.md +224 -225
  3. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/pyproject.toml +7 -1
  4. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/main_window.py +1 -1
  5. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/tests/test_connections.py +60 -60
  6. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/tests/test_filter_service.py +101 -101
  7. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/tests/test_settings_service.py +101 -101
  8. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/tests/vector_inspector.py +35 -35
  9. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/__init__.py +0 -0
  10. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/__main__.py +0 -0
  11. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/__init__.py +0 -0
  12. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/connections/__init__.py +0 -0
  13. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/connections/base_connection.py +0 -0
  14. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/connections/chroma_connection.py +0 -0
  15. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/connections/qdrant_connection.py +0 -0
  16. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/core/connections/template_connection.py +0 -0
  17. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/main.py +0 -0
  18. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/__init__.py +0 -0
  19. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/backup_restore_service.py +0 -0
  20. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/filter_service.py +0 -0
  21. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/import_export_service.py +0 -0
  22. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/settings_service.py +0 -0
  23. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/services/visualization_service.py +0 -0
  24. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/__init__.py +0 -0
  25. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/components/__init__.py +0 -0
  26. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/components/backup_restore_dialog.py +0 -0
  27. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/components/filter_builder.py +0 -0
  28. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/components/item_dialog.py +0 -0
  29. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/components/loading_dialog.py +0 -0
  30. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/__init__.py +0 -0
  31. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/collection_browser.py +0 -0
  32. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/connection_view.py +0 -0
  33. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/metadata_view.py +0 -0
  34. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/search_view.py +0 -0
  35. {vector_inspector-0.2.1 → vector_inspector-0.2.2}/src/vector_inspector/ui/views/visualization_view.py +0 -0
@@ -1,9 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: vector-inspector
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A comprehensive desktop application for visualizing, querying, and managing vector database data
5
5
  Author-Email: Anthony Dawson <anthonypdawson+github@gmail.com>
6
6
  License: MIT
7
+ Project-URL: Homepage, https://github.com/anthony-dawson/vector-inspector
8
+ Project-URL: Source, https://github.com/anthony-dawson/vector-inspector
9
+ Project-URL: Issues, https://github.com/anthony-dawson/vector-inspector/issues
10
+ Project-URL: Documentation, https://github.com/anthony-dawson/vector-inspector#readme
7
11
  Requires-Python: ==3.12.*
8
12
  Requires-Dist: chromadb>=0.4.22
9
13
  Requires-Dist: qdrant-client>=1.7.0
@@ -26,12 +30,13 @@ A comprehensive desktop application for visualizing, querying, and managing vect
26
30
 
27
31
  ## Overview
28
32
 
33
+ Vector Inspector bridges the gap between vector databases and user-friendly data exploration tools. While vector databases are powerful for semantic search and AI applications, they often lack the intuitive inspection and management tools that traditional SQL databases have. This project aims to provide that missing layer.
34
+
29
35
  ## Table of Contents
30
36
 
31
37
  - [Overview](#overview)
32
38
  - [Key Features](#key-features)
33
39
  - [Architecture](#architecture)
34
- - [Application Structure](#application-structure)
35
40
  - [Use Cases](#use-cases)
36
41
  - [Feature Access](#feature-access)
37
42
  - [Roadmap](#roadmap)
@@ -42,8 +47,6 @@ A comprehensive desktop application for visualizing, querying, and managing vect
42
47
  - [License](#license)
43
48
  - [Acknowledgments](#acknowledgments)
44
49
 
45
- Vector Inspector bridges the gap between vector databases and user-friendly data exploration tools. While vector databases are powerful for semantic search and AI applications, they often lack the intuitive inspection and management tools that traditional SQL databases have. This project aims to provide that missing layer.
46
-
47
50
  ## Key Features
48
51
 
49
52
  ### 1. **Multi-Provider Support**
@@ -157,8 +160,8 @@ vector-inspector
157
160
 
158
161
  ```bash
159
162
  # Clone the repository
160
- git clone https://github.com/anthonypdawson/vector-viewer.git
161
- cd vector-viewer
163
+ git clone https://github.com/anthonypdawson/vector-inspector.git
164
+ cd vector-inspector
162
165
 
163
166
  # Install dependencies using PDM
164
167
  pdm install
@@ -1,225 +1,224 @@
1
- # Vector Inspector
2
-
3
-
4
- A comprehensive desktop application for visualizing, querying, and managing vector database data. Similar to SQL database viewers, Vector Inspector provides an intuitive GUI for exploring vector embeddings, metadata, and performing similarity searches across multiple vector database providers.
5
-
6
- ## Overview
7
-
8
- ## Table of Contents
9
-
10
- - [Overview](#overview)
11
- - [Key Features](#key-features)
12
- - [Architecture](#architecture)
13
- - [Application Structure](#application-structure)
14
- - [Use Cases](#use-cases)
15
- - [Feature Access](#feature-access)
16
- - [Roadmap](#roadmap)
17
- - [Installation](#installation)
18
- - [Configuration](#configuration)
19
- - [Development Setup](#development-setup)
20
- - [Contributing](#contributing)
21
- - [License](#license)
22
- - [Acknowledgments](#acknowledgments)
23
-
24
- Vector Inspector bridges the gap between vector databases and user-friendly data exploration tools. While vector databases are powerful for semantic search and AI applications, they often lack the intuitive inspection and management tools that traditional SQL databases have. This project aims to provide that missing layer.
25
-
26
- ## Key Features
27
-
28
- ### 1. **Multi-Provider Support**
29
- - Connect to vector databases:
30
- - ChromaDB (persistent local storage)
31
- - Qdrant (remote server or embedded local)
32
- - Unified interface regardless of backend provider
33
- - Automatically saves last connection configuration
34
-
35
- ### 2. **Data Visualization**
36
- - **Metadata Explorer**: Browse and filter vector entries by metadata fields
37
- - **Vector Dimensionality Reduction**: Visualize high-dimensional vectors in 2D/3D using:
38
- - t-SNE
39
- - UMAP
40
- - PCA
41
- - **Cluster Visualization**: Color-code vectors by metadata categories or clustering results
42
- - **Interactive Plots**: Zoom, pan, and select vectors for detailed inspection
43
- - **Data Distribution Charts**: Histograms and statistics for metadata fields
44
-
45
- ### 3. **Search & Query Interface**
46
- - **Similarity Search**:
47
- - Text-to-vector search (with embedding model integration)
48
- - Vector-to-vector search
49
- - Find similar items to selected entries
50
- - Adjustable top-k results and similarity thresholds
51
- - **Metadata Filtering**:
52
- - SQL-like query builder for metadata
53
- - Combine vector similarity with metadata filters
54
- - Advanced filtering: ranges, IN clauses, pattern matching
55
- - **Hybrid Search**: Combine semantic search with keyword search
56
- - **Query History**: Save and reuse frequent queries
57
-
58
- ### 4. **Data Management**
59
- - **Browse Collections/Indexes**: View all available collections with statistics
60
- - **CRUD Operations**:
61
- - View individual vectors and their metadata
62
- - Add new vectors (with auto-embedding options)
63
- - Update metadata fields
64
- - Delete vectors (single or batch)
65
- - **Bulk Import/Export**:
66
- - Import from CSV, JSON, Parquet
67
- - Export query results to various formats
68
- - Backup and restore collections
69
- - **Schema Inspector**: View collection configuration, vector dimensions, metadata schema
70
-
71
- ### 5. **SQL-Like Experience**
72
- - **Query Console**: Write queries in a familiar SQL-like syntax (where supported)
73
- - **Results Grid**:
74
- - Sortable, filterable table view
75
- - Pagination for large result sets
76
- - Column customization
77
- - **Data Inspector**: Click any row to see full details including raw vector
78
- - **Query Execution Plans**: Understand how queries are executed
79
- - **Auto-completion**: Intelligent suggestions for collection names, fields, and operations
80
-
81
- ### 6. **Advanced Features**
82
- - **Embedding Model Integration**:
83
- - Use OpenAI, Cohere, HuggingFace models for text-to-vector conversion
84
- - Local model support (sentence-transformers)
85
- - Custom model integration
86
- - **Vector Analysis**:
87
- - Compute similarity matrices
88
- - Identify outliers and anomalies
89
- - Cluster analysis with k-means, DBSCAN
90
- - **Embedding Inspector**:
91
- - For similar collections or items, automatically identify which vector dimensions (activations) most contribute to the similarity
92
- - Map key activations to interpretable concepts (e.g., 'humor', 'sadness', 'anger') using metadata or labels
93
- - Generate human-readable explanations for why items are similar
94
- - **Performance Monitoring**:
95
- - Query latency tracking
96
- - Index performance metrics
97
- - Connection health monitoring
98
-
99
- ## Architecture
100
-
101
- Vector Inspector is built with PySide6 (Qt for Python) for the GUI, providing a native desktop experience. The backend uses Python with support for multiple vector database providers through a unified interface.
102
-
103
- For detailed architecture information, see [docs/architecture.md](docs/architecture.md).
104
-
105
- ## Use Cases
106
-
107
- 1. **AI/ML Development**: Inspect embeddings generated during model development
108
- 2. **RAG System Debugging**: Verify what documents are being retrieved
109
- 3. **Data Quality Assurance**: Identify poorly embedded or outlier vectors
110
- 4. **Production Monitoring**: Check vector database health and data consistency
111
- 5. **Data Migration**: Transfer data between vector database providers
112
- 6. **Education**: Learn and experiment with vector databases interactively
113
-
114
- ## Feature Access
115
-
116
- Vector Inspector is available in both free (open source) and Pro versions. The free version includes all core features for ChromaDB and basic Qdrant support, while Pro adds advanced analytics and additional providers.
117
-
118
- See [FEATURES.md](FEATURES.md) for a complete feature comparison.
119
-
120
- ## Roadmap
121
-
122
- **Current Status**: ✅ Phase 2 Complete
123
-
124
- See [ROADMAP.md](ROADMAP.md) for the complete development roadmap and planned features.
125
-
126
- ## Installation
127
-
128
- ### From PyPI (Recommended)
129
-
130
- ```bash
131
- pip install vector-inspector
132
- vector-inspector
133
- ```
134
-
135
- ### From Source
136
-
137
- ```bash
138
- # Clone the repository
139
- git clone https://github.com/anthonypdawson/vector-viewer.git
140
- cd vector-viewer
141
-
142
- # Install dependencies using PDM
143
- pdm install
144
-
145
- # Launch application
146
- ./run.sh # Linux/macOS
147
- ./run.bat # Windows
148
- ```
149
-
150
- ## Configuration
151
-
152
- Paths are resolved relative to the project root (where `pyproject.toml` is). For example, entering `./data/chroma_db` will use the absolute path resolved from the project root.
153
-
154
- The application automatically saves your last connection configuration to `~/.vector-viewer/settings.json`. The next time you launch the application, it will attempt to reconnect using the last saved settings.
155
-
156
- Example settings structure:
157
- ```json
158
- {
159
- "last_connection": {
160
- "provider": "chromadb",
161
- "connection_type": "persistent",
162
- "path": "./data/chroma_db"
163
- }
164
- }
165
- ```
166
-
167
- ## Development Setup
168
-
169
- ```bash
170
- # Install PDM if you haven't already
171
- pip install pdm
172
-
173
- # Install dependencies with development tools (PDM will create venv automatically)
174
- pdm install -d
175
-
176
- # Run tests
177
- pdm run pytest
178
-
179
- # Run application in development mode
180
- ./run.sh # Linux/macOS
181
- ./run.bat # Windows
182
-
183
- # Or use Python module directly from src directory:
184
- cd src
185
- pdm run python -m vector_viewer
186
- ```
187
-
188
- ## Contributing
189
-
190
- Contributions are welcome! Areas where help is needed:
191
- - Additional vector database provider integrations
192
- - UI/UX improvements
193
- - Performance optimizations
194
- - Documentation
195
- - Test coverage
196
-
197
- Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
198
-
199
- ## License
200
-
201
- MIT License - See [LICENSE](LICENSE) file for details.
202
-
203
- ## Acknowledgments
204
-
205
- This project draws inspiration from:
206
- - DBeaver (SQL database viewer)
207
- - MongoDB Compass (NoSQL database GUI)
208
- - Pinecone Console
209
- - Various vector database management tools
210
-
211
- ---
212
-
213
- **Status**: ✅ Phase 2 Complete - Advanced Features Implemented!
214
-
215
- **What's New in Phase 2:**
216
- - 🔍 Advanced metadata filtering with customizable filter rules (AND/OR logic)
217
- - ✏️ Double-click to edit items directly in the data browser
218
- - 📥 Import data from CSV, JSON, and Parquet files
219
- - 📤 Export filtered data to CSV, JSON, and Parquet formats
220
- - 💾 Comprehensive backup and restore system for collections
221
- - 🔄 Metadata filters integrated with search for powerful queries
222
-
223
- See [GETTING_STARTED.md](GETTING_STARTED.md) for usage instructions and [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) for technical details.
224
-
225
- **Contact**: Anthony Dawson
1
+ # Vector Inspector
2
+
3
+
4
+ A comprehensive desktop application for visualizing, querying, and managing vector database data. Similar to SQL database viewers, Vector Inspector provides an intuitive GUI for exploring vector embeddings, metadata, and performing similarity searches across multiple vector database providers.
5
+
6
+ ## Overview
7
+
8
+ Vector Inspector bridges the gap between vector databases and user-friendly data exploration tools. While vector databases are powerful for semantic search and AI applications, they often lack the intuitive inspection and management tools that traditional SQL databases have. This project aims to provide that missing layer.
9
+
10
+ ## Table of Contents
11
+
12
+ - [Overview](#overview)
13
+ - [Key Features](#key-features)
14
+ - [Architecture](#architecture)
15
+ - [Use Cases](#use-cases)
16
+ - [Feature Access](#feature-access)
17
+ - [Roadmap](#roadmap)
18
+ - [Installation](#installation)
19
+ - [Configuration](#configuration)
20
+ - [Development Setup](#development-setup)
21
+ - [Contributing](#contributing)
22
+ - [License](#license)
23
+ - [Acknowledgments](#acknowledgments)
24
+
25
+ ## Key Features
26
+
27
+ ### 1. **Multi-Provider Support**
28
+ - Connect to vector databases:
29
+ - ChromaDB (persistent local storage)
30
+ - Qdrant (remote server or embedded local)
31
+ - Unified interface regardless of backend provider
32
+ - Automatically saves last connection configuration
33
+
34
+ ### 2. **Data Visualization**
35
+ - **Metadata Explorer**: Browse and filter vector entries by metadata fields
36
+ - **Vector Dimensionality Reduction**: Visualize high-dimensional vectors in 2D/3D using:
37
+ - t-SNE
38
+ - UMAP
39
+ - PCA
40
+ - **Cluster Visualization**: Color-code vectors by metadata categories or clustering results
41
+ - **Interactive Plots**: Zoom, pan, and select vectors for detailed inspection
42
+ - **Data Distribution Charts**: Histograms and statistics for metadata fields
43
+
44
+ ### 3. **Search & Query Interface**
45
+ - **Similarity Search**:
46
+ - Text-to-vector search (with embedding model integration)
47
+ - Vector-to-vector search
48
+ - Find similar items to selected entries
49
+ - Adjustable top-k results and similarity thresholds
50
+ - **Metadata Filtering**:
51
+ - SQL-like query builder for metadata
52
+ - Combine vector similarity with metadata filters
53
+ - Advanced filtering: ranges, IN clauses, pattern matching
54
+ - **Hybrid Search**: Combine semantic search with keyword search
55
+ - **Query History**: Save and reuse frequent queries
56
+
57
+ ### 4. **Data Management**
58
+ - **Browse Collections/Indexes**: View all available collections with statistics
59
+ - **CRUD Operations**:
60
+ - View individual vectors and their metadata
61
+ - Add new vectors (with auto-embedding options)
62
+ - Update metadata fields
63
+ - Delete vectors (single or batch)
64
+ - **Bulk Import/Export**:
65
+ - Import from CSV, JSON, Parquet
66
+ - Export query results to various formats
67
+ - Backup and restore collections
68
+ - **Schema Inspector**: View collection configuration, vector dimensions, metadata schema
69
+
70
+ ### 5. **SQL-Like Experience**
71
+ - **Query Console**: Write queries in a familiar SQL-like syntax (where supported)
72
+ - **Results Grid**:
73
+ - Sortable, filterable table view
74
+ - Pagination for large result sets
75
+ - Column customization
76
+ - **Data Inspector**: Click any row to see full details including raw vector
77
+ - **Query Execution Plans**: Understand how queries are executed
78
+ - **Auto-completion**: Intelligent suggestions for collection names, fields, and operations
79
+
80
+ ### 6. **Advanced Features**
81
+ - **Embedding Model Integration**:
82
+ - Use OpenAI, Cohere, HuggingFace models for text-to-vector conversion
83
+ - Local model support (sentence-transformers)
84
+ - Custom model integration
85
+ - **Vector Analysis**:
86
+ - Compute similarity matrices
87
+ - Identify outliers and anomalies
88
+ - Cluster analysis with k-means, DBSCAN
89
+ - **Embedding Inspector**:
90
+ - For similar collections or items, automatically identify which vector dimensions (activations) most contribute to the similarity
91
+ - Map key activations to interpretable concepts (e.g., 'humor', 'sadness', 'anger') using metadata or labels
92
+ - Generate human-readable explanations for why items are similar
93
+ - **Performance Monitoring**:
94
+ - Query latency tracking
95
+ - Index performance metrics
96
+ - Connection health monitoring
97
+
98
+ ## Architecture
99
+
100
+ Vector Inspector is built with PySide6 (Qt for Python) for the GUI, providing a native desktop experience. The backend uses Python with support for multiple vector database providers through a unified interface.
101
+
102
+ For detailed architecture information, see [docs/architecture.md](docs/architecture.md).
103
+
104
+ ## Use Cases
105
+
106
+ 1. **AI/ML Development**: Inspect embeddings generated during model development
107
+ 2. **RAG System Debugging**: Verify what documents are being retrieved
108
+ 3. **Data Quality Assurance**: Identify poorly embedded or outlier vectors
109
+ 4. **Production Monitoring**: Check vector database health and data consistency
110
+ 5. **Data Migration**: Transfer data between vector database providers
111
+ 6. **Education**: Learn and experiment with vector databases interactively
112
+
113
+ ## Feature Access
114
+
115
+ Vector Inspector is available in both free (open source) and Pro versions. The free version includes all core features for ChromaDB and basic Qdrant support, while Pro adds advanced analytics and additional providers.
116
+
117
+ See [FEATURES.md](FEATURES.md) for a complete feature comparison.
118
+
119
+ ## Roadmap
120
+
121
+ **Current Status**: ✅ Phase 2 Complete
122
+
123
+ See [ROADMAP.md](ROADMAP.md) for the complete development roadmap and planned features.
124
+
125
+ ## Installation
126
+
127
+ ### From PyPI (Recommended)
128
+
129
+ ```bash
130
+ pip install vector-inspector
131
+ vector-inspector
132
+ ```
133
+
134
+ ### From Source
135
+
136
+ ```bash
137
+ # Clone the repository
138
+ git clone https://github.com/anthonypdawson/vector-inspector.git
139
+ cd vector-inspector
140
+
141
+ # Install dependencies using PDM
142
+ pdm install
143
+
144
+ # Launch application
145
+ ./run.sh # Linux/macOS
146
+ ./run.bat # Windows
147
+ ```
148
+
149
+ ## Configuration
150
+
151
+ Paths are resolved relative to the project root (where `pyproject.toml` is). For example, entering `./data/chroma_db` will use the absolute path resolved from the project root.
152
+
153
+ The application automatically saves your last connection configuration to `~/.vector-viewer/settings.json`. The next time you launch the application, it will attempt to reconnect using the last saved settings.
154
+
155
+ Example settings structure:
156
+ ```json
157
+ {
158
+ "last_connection": {
159
+ "provider": "chromadb",
160
+ "connection_type": "persistent",
161
+ "path": "./data/chroma_db"
162
+ }
163
+ }
164
+ ```
165
+
166
+ ## Development Setup
167
+
168
+ ```bash
169
+ # Install PDM if you haven't already
170
+ pip install pdm
171
+
172
+ # Install dependencies with development tools (PDM will create venv automatically)
173
+ pdm install -d
174
+
175
+ # Run tests
176
+ pdm run pytest
177
+
178
+ # Run application in development mode
179
+ ./run.sh # Linux/macOS
180
+ ./run.bat # Windows
181
+
182
+ # Or use Python module directly from src directory:
183
+ cd src
184
+ pdm run python -m vector_viewer
185
+ ```
186
+
187
+ ## Contributing
188
+
189
+ Contributions are welcome! Areas where help is needed:
190
+ - Additional vector database provider integrations
191
+ - UI/UX improvements
192
+ - Performance optimizations
193
+ - Documentation
194
+ - Test coverage
195
+
196
+ Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
197
+
198
+ ## License
199
+
200
+ MIT License - See [LICENSE](LICENSE) file for details.
201
+
202
+ ## Acknowledgments
203
+
204
+ This project draws inspiration from:
205
+ - DBeaver (SQL database viewer)
206
+ - MongoDB Compass (NoSQL database GUI)
207
+ - Pinecone Console
208
+ - Various vector database management tools
209
+
210
+ ---
211
+
212
+ **Status**: ✅ Phase 2 Complete - Advanced Features Implemented!
213
+
214
+ **What's New in Phase 2:**
215
+ - 🔍 Advanced metadata filtering with customizable filter rules (AND/OR logic)
216
+ - ✏️ Double-click to edit items directly in the data browser
217
+ - 📥 Import data from CSV, JSON, and Parquet files
218
+ - 📤 Export filtered data to CSV, JSON, and Parquet formats
219
+ - 💾 Comprehensive backup and restore system for collections
220
+ - 🔄 Metadata filters integrated with search for powerful queries
221
+
222
+ See [GETTING_STARTED.md](GETTING_STARTED.md) for usage instructions and [IMPLEMENTATION_SUMMARY.md](IMPLEMENTATION_SUMMARY.md) for technical details.
223
+
224
+ **Contact**: Anthony Dawson
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vector-inspector"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "A comprehensive desktop application for visualizing, querying, and managing vector database data"
5
5
  authors = [
6
6
  { name = "Anthony Dawson", email = "anthonypdawson+github@gmail.com" },
@@ -25,6 +25,12 @@ readme = "README.md"
25
25
  [project.license]
26
26
  text = "MIT"
27
27
 
28
+ [project.urls]
29
+ Homepage = "https://github.com/anthony-dawson/vector-inspector"
30
+ Source = "https://github.com/anthony-dawson/vector-inspector"
31
+ Issues = "https://github.com/anthony-dawson/vector-inspector/issues"
32
+ Documentation = "https://github.com/anthony-dawson/vector-inspector#readme"
33
+
28
34
  [project.scripts]
29
35
  vector-inspector = "vector_inspector.main:main"
30
36
 
@@ -282,7 +282,7 @@ class MainWindow(QMainWindow):
282
282
  "<h2>Vector Inspector 0.1.0</h2>"
283
283
  "<p>A comprehensive desktop application for visualizing, "
284
284
  "querying, and managing vector database data.</p>"
285
- '<p><a href="https://github.com/anthonypdawson/vector-viewer" style="color:#2980b9;">GitHub Project Page</a></p>'
285
+ '<p><a href="https://github.com/anthonypdawson/vector-inspector" style="color:#2980b9;">GitHub Project Page</a></p>'
286
286
  "<hr />"
287
287
  "<p>Built with PySide6 and ChromaDB</p>"
288
288
  )
@@ -1,60 +1,60 @@
1
- import pytest
2
- from vector_inspector.core.connections.chroma_connection import ChromaDBConnection
3
- from vector_inspector.core.connections.qdrant_connection import QdrantConnection
4
- import uuid
5
-
6
- @pytest.mark.parametrize("provider", ["chroma", "qdrant"])
7
- def test_provider_integration(provider, tmp_path):
8
- """Test provider connection using standard add_items signature."""
9
- collection_name = f"test_collection_{uuid.uuid4().hex[:8]}"
10
- test_ids = ["id1", "id2"]
11
- test_vectors = [[0.1, 0.2], [0.3, 0.4]]
12
- test_docs = ["hello", "world"]
13
- test_metadata = [{"type": "greeting"}, {"type": "noun"}]
14
-
15
- if provider == "chroma":
16
- conn = ChromaDBConnection()
17
- assert conn.connect()
18
- assert conn.create_collection(collection_name, vector_size=2)
19
- # Use standard signature: collection_name, documents, metadatas, ids, embeddings
20
- success = conn.add_items(
21
- collection_name,
22
- documents=test_docs,
23
- metadatas=test_metadata,
24
- ids=test_ids,
25
- embeddings=test_vectors
26
- )
27
- assert success
28
- assert collection_name in conn.list_collections()
29
- # Verify items inserted
30
- info = conn.get_collection_info(collection_name)
31
- assert info["count"] == 2
32
- res = conn.get_all_items(collection_name, limit=10)
33
- assert len(res["documents"]) == 2
34
- assert conn.delete_collection(collection_name)
35
- assert collection_name not in conn.list_collections()
36
-
37
- elif provider == "qdrant":
38
- db_path = str(tmp_path / "qdrant_test")
39
- conn = QdrantConnection(path=db_path)
40
- assert conn.connect()
41
- assert conn.create_collection(collection_name, vector_size=2, distance="Cosine")
42
- # Use standard signature
43
- success = conn.add_items(
44
- collection_name,
45
- documents=test_docs,
46
- metadatas=test_metadata,
47
- ids=test_ids,
48
- embeddings=test_vectors
49
- )
50
- assert success
51
- assert collection_name in conn.list_collections()
52
- # Verify items inserted
53
- info = conn.get_collection_info(collection_name)
54
- if info["count"] == 0:
55
- pytest.skip("Qdrant local upsert not supported in this environment")
56
- assert info["count"] == 2
57
- res = conn.get_all_items(collection_name, limit=10)
58
- assert len(res["documents"]) == 2
59
- assert conn.delete_collection(collection_name)
60
- assert collection_name not in conn.list_collections()
1
+ import pytest
2
+ from vector_inspector.core.connections.chroma_connection import ChromaDBConnection
3
+ from vector_inspector.core.connections.qdrant_connection import QdrantConnection
4
+ import uuid
5
+
6
+ @pytest.mark.parametrize("provider", ["chroma", "qdrant"])
7
+ def test_provider_integration(provider, tmp_path):
8
+ """Test provider connection using standard add_items signature."""
9
+ collection_name = f"test_collection_{uuid.uuid4().hex[:8]}"
10
+ test_ids = ["id1", "id2"]
11
+ test_vectors = [[0.1, 0.2], [0.3, 0.4]]
12
+ test_docs = ["hello", "world"]
13
+ test_metadata = [{"type": "greeting"}, {"type": "noun"}]
14
+
15
+ if provider == "chroma":
16
+ conn = ChromaDBConnection()
17
+ assert conn.connect()
18
+ assert conn.create_collection(collection_name, vector_size=2)
19
+ # Use standard signature: collection_name, documents, metadatas, ids, embeddings
20
+ success = conn.add_items(
21
+ collection_name,
22
+ documents=test_docs,
23
+ metadatas=test_metadata,
24
+ ids=test_ids,
25
+ embeddings=test_vectors
26
+ )
27
+ assert success
28
+ assert collection_name in conn.list_collections()
29
+ # Verify items inserted
30
+ info = conn.get_collection_info(collection_name)
31
+ assert info["count"] == 2
32
+ res = conn.get_all_items(collection_name, limit=10)
33
+ assert len(res["documents"]) == 2
34
+ assert conn.delete_collection(collection_name)
35
+ assert collection_name not in conn.list_collections()
36
+
37
+ elif provider == "qdrant":
38
+ db_path = str(tmp_path / "qdrant_test")
39
+ conn = QdrantConnection(path=db_path)
40
+ assert conn.connect()
41
+ assert conn.create_collection(collection_name, vector_size=2, distance="Cosine")
42
+ # Use standard signature
43
+ success = conn.add_items(
44
+ collection_name,
45
+ documents=test_docs,
46
+ metadatas=test_metadata,
47
+ ids=test_ids,
48
+ embeddings=test_vectors
49
+ )
50
+ assert success
51
+ assert collection_name in conn.list_collections()
52
+ # Verify items inserted
53
+ info = conn.get_collection_info(collection_name)
54
+ if info["count"] == 0:
55
+ pytest.skip("Qdrant local upsert not supported in this environment")
56
+ assert info["count"] == 2
57
+ res = conn.get_all_items(collection_name, limit=10)
58
+ assert len(res["documents"]) == 2
59
+ assert conn.delete_collection(collection_name)
60
+ assert collection_name not in conn.list_collections()
@@ -1,101 +1,101 @@
1
- import pytest
2
- from vector_inspector.services.filter_service import apply_client_side_filters
3
-
4
- def sample_data():
5
- return {
6
- "ids": [1, 2, 3],
7
- "documents": ["The quick brown fox", "Jumps over the lazy dog", "Hello world!"],
8
- "metadatas": [
9
- {"category": "animal", "author": "A"},
10
- {"category": "animal", "author": "B"},
11
- {"category": "greeting", "author": "C"},
12
- ],
13
- "embeddings": [[0.1], [0.2], [0.3]],
14
- }
15
-
16
- def test_no_filters_returns_all():
17
- data = sample_data()
18
- result = apply_client_side_filters(data, [])
19
- assert result == {
20
- "ids": [1, 2, 3],
21
- "documents": ["The quick brown fox", "Jumps over the lazy dog", "Hello world!"],
22
- "metadatas": [
23
- {"category": "animal", "author": "A"},
24
- {"category": "animal", "author": "B"},
25
- {"category": "greeting", "author": "C"},
26
- ],
27
- "embeddings": [[0.1], [0.2], [0.3]],
28
- }
29
-
30
- def test_contains_document():
31
- data = sample_data()
32
- filters = [{"field": "document", "op": "contains", "value": "fox"}]
33
- result = apply_client_side_filters(data, filters)
34
- assert result["ids"] == [1]
35
- assert result["documents"] == ["The quick brown fox"]
36
- assert result["metadatas"] == [{"category": "animal", "author": "A"}]
37
- assert result["embeddings"] == [[0.1]]
38
-
39
- def test_not_contains_metadata():
40
- data = sample_data()
41
- filters = [{"field": "category", "op": "not_contains", "value": "animal"}]
42
- result = apply_client_side_filters(data, filters)
43
- assert result["ids"] == [3]
44
- assert result["documents"] == ["Hello world!"]
45
- assert result["metadatas"] == [{"category": "greeting", "author": "C"}]
46
- assert result["embeddings"] == [[0.3]]
47
-
48
- def test_multiple_filters():
49
- data = sample_data()
50
- filters = [
51
- {"field": "category", "op": "contains", "value": "animal"},
52
- {"field": "author", "op": "contains", "value": "B"},
53
- ]
54
- result = apply_client_side_filters(data, filters)
55
- assert result["ids"] == [2]
56
- assert result["documents"] == ["Jumps over the lazy dog"]
57
- assert result["metadatas"] == [{"category": "animal", "author": "B"}]
58
- assert result["embeddings"] == [[0.2]]
59
-
60
- def test_empty_data():
61
- result = apply_client_side_filters({}, [])
62
- assert result == {}
63
-
64
- def test_missing_fields():
65
- data = {"ids": [1], "documents": ["foo"]}
66
- filters = [{"field": "category", "op": "contains", "value": "animal"}]
67
- result = apply_client_side_filters(data, filters)
68
- assert result["ids"] == []
69
- assert result["documents"] == []
70
- assert result["metadatas"] == []
71
-
72
- def test_case_sensitivity():
73
- data = {"ids": [1], "documents": ["Hello World"], "metadatas": [{"author": "Alice"}]}
74
- filters = [{"field": "document", "op": "contains", "value": "hello world"}]
75
- result = apply_client_side_filters(data, filters)
76
- assert result["ids"] == [1]
77
-
78
- def test_non_string_metadata_value():
79
- data = {"ids": [1], "documents": ["foo"], "metadatas": [{"num": 123}]}
80
- filters = [{"field": "num", "op": "contains", "value": "123"}]
81
- result = apply_client_side_filters(data, filters)
82
- assert result["ids"] == [1]
83
-
84
- def test_unknown_operator():
85
- data = {"ids": [1], "documents": ["foo"], "metadatas": [{"author": "Bob"}]}
86
- filters = [{"field": "author", "op": "unknown", "value": "Bob"}]
87
- result = apply_client_side_filters(data, filters)
88
- # Unknown op: should not filter out
89
- assert result["ids"] == [1]
90
-
91
- def test_large_input():
92
- data = {
93
- "ids": list(range(1000)),
94
- "documents": ["doc" + str(i) for i in range(1000)],
95
- "metadatas": [{"author": "A" if i % 2 == 0 else "B"} for i in range(1000)],
96
- "embeddings": [[i] for i in range(1000)],
97
- }
98
- filters = [{"field": "author", "op": "contains", "value": "A"}]
99
- result = apply_client_side_filters(data, filters)
100
- assert all(m["author"] == "A" for m in result["metadatas"])
101
- assert len(result["ids"]) == 500
1
+ import pytest
2
+ from vector_inspector.services.filter_service import apply_client_side_filters
3
+
4
+ def sample_data():
5
+ return {
6
+ "ids": [1, 2, 3],
7
+ "documents": ["The quick brown fox", "Jumps over the lazy dog", "Hello world!"],
8
+ "metadatas": [
9
+ {"category": "animal", "author": "A"},
10
+ {"category": "animal", "author": "B"},
11
+ {"category": "greeting", "author": "C"},
12
+ ],
13
+ "embeddings": [[0.1], [0.2], [0.3]],
14
+ }
15
+
16
+ def test_no_filters_returns_all():
17
+ data = sample_data()
18
+ result = apply_client_side_filters(data, [])
19
+ assert result == {
20
+ "ids": [1, 2, 3],
21
+ "documents": ["The quick brown fox", "Jumps over the lazy dog", "Hello world!"],
22
+ "metadatas": [
23
+ {"category": "animal", "author": "A"},
24
+ {"category": "animal", "author": "B"},
25
+ {"category": "greeting", "author": "C"},
26
+ ],
27
+ "embeddings": [[0.1], [0.2], [0.3]],
28
+ }
29
+
30
+ def test_contains_document():
31
+ data = sample_data()
32
+ filters = [{"field": "document", "op": "contains", "value": "fox"}]
33
+ result = apply_client_side_filters(data, filters)
34
+ assert result["ids"] == [1]
35
+ assert result["documents"] == ["The quick brown fox"]
36
+ assert result["metadatas"] == [{"category": "animal", "author": "A"}]
37
+ assert result["embeddings"] == [[0.1]]
38
+
39
+ def test_not_contains_metadata():
40
+ data = sample_data()
41
+ filters = [{"field": "category", "op": "not_contains", "value": "animal"}]
42
+ result = apply_client_side_filters(data, filters)
43
+ assert result["ids"] == [3]
44
+ assert result["documents"] == ["Hello world!"]
45
+ assert result["metadatas"] == [{"category": "greeting", "author": "C"}]
46
+ assert result["embeddings"] == [[0.3]]
47
+
48
+ def test_multiple_filters():
49
+ data = sample_data()
50
+ filters = [
51
+ {"field": "category", "op": "contains", "value": "animal"},
52
+ {"field": "author", "op": "contains", "value": "B"},
53
+ ]
54
+ result = apply_client_side_filters(data, filters)
55
+ assert result["ids"] == [2]
56
+ assert result["documents"] == ["Jumps over the lazy dog"]
57
+ assert result["metadatas"] == [{"category": "animal", "author": "B"}]
58
+ assert result["embeddings"] == [[0.2]]
59
+
60
+ def test_empty_data():
61
+ result = apply_client_side_filters({}, [])
62
+ assert result == {}
63
+
64
+ def test_missing_fields():
65
+ data = {"ids": [1], "documents": ["foo"]}
66
+ filters = [{"field": "category", "op": "contains", "value": "animal"}]
67
+ result = apply_client_side_filters(data, filters)
68
+ assert result["ids"] == []
69
+ assert result["documents"] == []
70
+ assert result["metadatas"] == []
71
+
72
+ def test_case_sensitivity():
73
+ data = {"ids": [1], "documents": ["Hello World"], "metadatas": [{"author": "Alice"}]}
74
+ filters = [{"field": "document", "op": "contains", "value": "hello world"}]
75
+ result = apply_client_side_filters(data, filters)
76
+ assert result["ids"] == [1]
77
+
78
+ def test_non_string_metadata_value():
79
+ data = {"ids": [1], "documents": ["foo"], "metadatas": [{"num": 123}]}
80
+ filters = [{"field": "num", "op": "contains", "value": "123"}]
81
+ result = apply_client_side_filters(data, filters)
82
+ assert result["ids"] == [1]
83
+
84
+ def test_unknown_operator():
85
+ data = {"ids": [1], "documents": ["foo"], "metadatas": [{"author": "Bob"}]}
86
+ filters = [{"field": "author", "op": "unknown", "value": "Bob"}]
87
+ result = apply_client_side_filters(data, filters)
88
+ # Unknown op: should not filter out
89
+ assert result["ids"] == [1]
90
+
91
+ def test_large_input():
92
+ data = {
93
+ "ids": list(range(1000)),
94
+ "documents": ["doc" + str(i) for i in range(1000)],
95
+ "metadatas": [{"author": "A" if i % 2 == 0 else "B"} for i in range(1000)],
96
+ "embeddings": [[i] for i in range(1000)],
97
+ }
98
+ filters = [{"field": "author", "op": "contains", "value": "A"}]
99
+ result = apply_client_side_filters(data, filters)
100
+ assert all(m["author"] == "A" for m in result["metadatas"])
101
+ assert len(result["ids"]) == 500
@@ -1,101 +1,101 @@
1
- import json
2
- from pathlib import Path
3
-
4
- import pytest
5
-
6
- from vector_inspector.services.settings_service import SettingsService
7
-
8
-
9
- @pytest.fixture()
10
- def temp_home(tmp_path):
11
- # Monkeypatch Path.home() to point to a temporary directory for isolation
12
- original_home = Path.home
13
- Path.home = lambda: tmp_path # type: ignore
14
- try:
15
- yield tmp_path
16
- finally:
17
- Path.home = original_home # restore
18
-
19
-
20
- def test_last_connection_roundtrip(temp_home):
21
- svc = SettingsService()
22
- assert svc.get_last_connection() is None
23
-
24
- config = {
25
- "provider": "chromadb",
26
- "connection_type": "persistent",
27
- "path": "./data/chroma_db",
28
- }
29
- svc.save_last_connection(config)
30
-
31
- # Create a new service to ensure it reads from disk
32
- svc2 = SettingsService()
33
- assert svc2.get_last_connection() == config
34
-
35
- # Validate file exists with expected content
36
- settings_file = temp_home / ".vector-viewer" / "settings.json"
37
- assert settings_file.exists()
38
- data = json.loads(settings_file.read_text(encoding="utf-8"))
39
- assert data["last_connection"] == config
40
-
41
-
42
- def test_set_get_and_clear(temp_home):
43
- svc = SettingsService()
44
-
45
- assert svc.get("theme", "light") == "light"
46
- svc.set("theme", "dark")
47
- assert svc.get("theme") == "dark"
48
-
49
- # Ensure persisted
50
- settings_file = temp_home / ".vector-viewer" / "settings.json"
51
- data = json.loads(settings_file.read_text(encoding="utf-8"))
52
- assert data["theme"] == "dark"
53
-
54
- # Clear and verify
55
- svc.clear()
56
- assert svc.get("theme") is None
57
-
58
- # File should reflect cleared settings
59
- data2 = json.loads(settings_file.read_text(encoding="utf-8"))
60
- assert data2 == {}
61
-
62
-
63
- def test_missing_settings_file(temp_home):
64
- svc = SettingsService()
65
- # Remove file if exists
66
- settings_file = temp_home / ".vector-viewer" / "settings.json"
67
- if settings_file.exists():
68
- settings_file.unlink()
69
- svc._load_settings()
70
- assert svc.settings == {}
71
-
72
-
73
- def test_invalid_json_file(temp_home):
74
- settings_file = temp_home / ".vector-viewer" / "settings.json"
75
- settings_file.parent.mkdir(parents=True, exist_ok=True)
76
- settings_file.write_text("{ invalid json }", encoding="utf-8")
77
- svc = SettingsService()
78
- # Should fallback to empty settings
79
- assert svc.settings == {}
80
-
81
-
82
- def test_overwrite_key(temp_home):
83
- svc = SettingsService()
84
- svc.set("theme", "light")
85
- svc.set("theme", "dark")
86
- assert svc.get("theme") == "dark"
87
-
88
-
89
- def test_unicode_and_large_value(temp_home):
90
- svc = SettingsService()
91
- unicode_val = "你好, мир, hello!"
92
- large_val = "x" * 10000
93
- svc.set("greeting", unicode_val)
94
- svc.set("blob", large_val)
95
- assert svc.get("greeting") == unicode_val
96
- assert svc.get("blob") == large_val
97
- # Validate persistence
98
- settings_file = temp_home / ".vector-viewer" / "settings.json"
99
- data = json.loads(settings_file.read_text(encoding="utf-8"))
100
- assert data["greeting"] == unicode_val
101
- assert data["blob"] == large_val
1
+ import json
2
+ from pathlib import Path
3
+
4
+ import pytest
5
+
6
+ from vector_inspector.services.settings_service import SettingsService
7
+
8
+
9
+ @pytest.fixture()
10
+ def temp_home(tmp_path):
11
+ # Monkeypatch Path.home() to point to a temporary directory for isolation
12
+ original_home = Path.home
13
+ Path.home = lambda: tmp_path # type: ignore
14
+ try:
15
+ yield tmp_path
16
+ finally:
17
+ Path.home = original_home # restore
18
+
19
+
20
+ def test_last_connection_roundtrip(temp_home):
21
+ svc = SettingsService()
22
+ assert svc.get_last_connection() is None
23
+
24
+ config = {
25
+ "provider": "chromadb",
26
+ "connection_type": "persistent",
27
+ "path": "./data/chroma_db",
28
+ }
29
+ svc.save_last_connection(config)
30
+
31
+ # Create a new service to ensure it reads from disk
32
+ svc2 = SettingsService()
33
+ assert svc2.get_last_connection() == config
34
+
35
+ # Validate file exists with expected content
36
+ settings_file = temp_home / ".vector-viewer" / "settings.json"
37
+ assert settings_file.exists()
38
+ data = json.loads(settings_file.read_text(encoding="utf-8"))
39
+ assert data["last_connection"] == config
40
+
41
+
42
+ def test_set_get_and_clear(temp_home):
43
+ svc = SettingsService()
44
+
45
+ assert svc.get("theme", "light") == "light"
46
+ svc.set("theme", "dark")
47
+ assert svc.get("theme") == "dark"
48
+
49
+ # Ensure persisted
50
+ settings_file = temp_home / ".vector-viewer" / "settings.json"
51
+ data = json.loads(settings_file.read_text(encoding="utf-8"))
52
+ assert data["theme"] == "dark"
53
+
54
+ # Clear and verify
55
+ svc.clear()
56
+ assert svc.get("theme") is None
57
+
58
+ # File should reflect cleared settings
59
+ data2 = json.loads(settings_file.read_text(encoding="utf-8"))
60
+ assert data2 == {}
61
+
62
+
63
+ def test_missing_settings_file(temp_home):
64
+ svc = SettingsService()
65
+ # Remove file if exists
66
+ settings_file = temp_home / ".vector-viewer" / "settings.json"
67
+ if settings_file.exists():
68
+ settings_file.unlink()
69
+ svc._load_settings()
70
+ assert svc.settings == {}
71
+
72
+
73
+ def test_invalid_json_file(temp_home):
74
+ settings_file = temp_home / ".vector-viewer" / "settings.json"
75
+ settings_file.parent.mkdir(parents=True, exist_ok=True)
76
+ settings_file.write_text("{ invalid json }", encoding="utf-8")
77
+ svc = SettingsService()
78
+ # Should fallback to empty settings
79
+ assert svc.settings == {}
80
+
81
+
82
+ def test_overwrite_key(temp_home):
83
+ svc = SettingsService()
84
+ svc.set("theme", "light")
85
+ svc.set("theme", "dark")
86
+ assert svc.get("theme") == "dark"
87
+
88
+
89
+ def test_unicode_and_large_value(temp_home):
90
+ svc = SettingsService()
91
+ unicode_val = "你好, мир, hello!"
92
+ large_val = "x" * 10000
93
+ svc.set("greeting", unicode_val)
94
+ svc.set("blob", large_val)
95
+ assert svc.get("greeting") == unicode_val
96
+ assert svc.get("blob") == large_val
97
+ # Validate persistence
98
+ settings_file = temp_home / ".vector-viewer" / "settings.json"
99
+ data = json.loads(settings_file.read_text(encoding="utf-8"))
100
+ assert data["greeting"] == unicode_val
101
+ assert data["blob"] == large_val
@@ -1,35 +1,35 @@
1
- import os
2
- import sys
3
- import tempfile
4
- from pathlib import Path
5
-
6
- import pytest
7
-
8
-
9
- def run_tests():
10
- project_path = Path(__file__).parent.parent
11
- os.chdir(project_path)
12
-
13
- # Determine any args to pass to pytest. If there aren't any,
14
- # default to running the whole test suite.
15
- args = sys.argv[1:]
16
- if len(args) == 0:
17
- args = ["tests"]
18
-
19
- returncode = pytest.main(
20
- [
21
- # Turn up verbosity
22
- "-vv",
23
- # Disable color
24
- "--color=no",
25
- # Overwrite the cache directory to somewhere writable
26
- "-o",
27
- f"cache_dir={tempfile.gettempdir()}/.pytest_cache",
28
- ] + args
29
- )
30
-
31
- print(f">>>>>>>>>> EXIT {returncode} <<<<<<<<<<")
32
-
33
-
34
- if __name__ == "__main__":
35
- run_tests()
1
+ import os
2
+ import sys
3
+ import tempfile
4
+ from pathlib import Path
5
+
6
+ import pytest
7
+
8
+
9
+ def run_tests():
10
+ project_path = Path(__file__).parent.parent
11
+ os.chdir(project_path)
12
+
13
+ # Determine any args to pass to pytest. If there aren't any,
14
+ # default to running the whole test suite.
15
+ args = sys.argv[1:]
16
+ if len(args) == 0:
17
+ args = ["tests"]
18
+
19
+ returncode = pytest.main(
20
+ [
21
+ # Turn up verbosity
22
+ "-vv",
23
+ # Disable color
24
+ "--color=no",
25
+ # Overwrite the cache directory to somewhere writable
26
+ "-o",
27
+ f"cache_dir={tempfile.gettempdir()}/.pytest_cache",
28
+ ] + args
29
+ )
30
+
31
+ print(f">>>>>>>>>> EXIT {returncode} <<<<<<<<<<")
32
+
33
+
34
+ if __name__ == "__main__":
35
+ run_tests()