mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Chore: Switch from pipenv to uv (#9251)
This commit is contained in:
		| @@ -76,18 +76,15 @@ RUN set -eux \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet --no-install-recommends ${RUNTIME_PACKAGES} | ||||
|  | ||||
| ARG PYTHON_PACKAGES="\ | ||||
|   python3 \ | ||||
|   python3-pip \ | ||||
|   python3-wheel \ | ||||
|   pipenv \ | ||||
|   ca-certificates" | ||||
| ARG PYTHON_PACKAGES="ca-certificates" | ||||
|  | ||||
| RUN set -eux \ | ||||
|   echo "Installing python packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet ${PYTHON_PACKAGES} | ||||
|  | ||||
| COPY --from=ghcr.io/astral-sh/uv:0.6 /uv /bin/uv | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Installing pre-built updates" \ | ||||
|     && echo "Installing qpdf ${QPDF_VERSION}" \ | ||||
| @@ -131,6 +128,8 @@ RUN set -eux \ | ||||
|   && echo "Configuring ImageMagick" \ | ||||
|     && mv paperless-policy.xml /etc/ImageMagick-6/policy.xml | ||||
|  | ||||
| COPY --from=ghcr.io/astral-sh/uv:0.6 /uv /bin/uv | ||||
|  | ||||
| # Packages needed only for building a few quick Python | ||||
| # dependencies | ||||
| ARG BUILD_PACKAGES="\ | ||||
| @@ -140,11 +139,10 @@ ARG BUILD_PACKAGES="\ | ||||
|   libpq-dev \ | ||||
|   # https://github.com/PyMySQL/mysqlclient#linux | ||||
|   default-libmysqlclient-dev \ | ||||
|   pkg-config \ | ||||
|   pre-commit" | ||||
|   pkg-config" | ||||
|  | ||||
| # hadolint ignore=DL3042 | ||||
| RUN --mount=type=cache,target=/root/.cache/pip/,id=pip-cache \ | ||||
| RUN --mount=type=cache,target=/root/.cache/uv,id=pip-cache \ | ||||
|   set -eux \ | ||||
|   && echo "Installing build system packages" \ | ||||
|     && apt-get update \ | ||||
| @@ -169,9 +167,6 @@ RUN set -eux \ | ||||
|     && mkdir --parents --verbose /usr/src/paperless/paperless-ngx/.venv \ | ||||
|   && echo "Adjusting all permissions" \ | ||||
|     && chown --from root:root --changes --recursive paperless:paperless /usr/src/paperless | ||||
| #  && echo "Collecting static files" \ | ||||
| #    && gosu paperless python3 manage.py collectstatic --clear --no-input --link \ | ||||
| #    && gosu paperless python3 manage.py compilemessages | ||||
|  | ||||
| VOLUME ["/usr/src/paperless/paperless-ngx/data", \ | ||||
|         "/usr/src/paperless/paperless-ngx/media", \ | ||||
|   | ||||
							
								
								
									
										117
									
								
								.devcontainer/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								.devcontainer/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| # Paperless-ngx Development Environment | ||||
|  | ||||
| ## Overview | ||||
|  | ||||
| Welcome to the Paperless-ngx development environment! This setup uses VSCode DevContainers to provide a consistent and seamless development experience. | ||||
|  | ||||
| ### What are DevContainers? | ||||
|  | ||||
| DevContainers are a feature in VSCode that allows you to develop within a Docker container. This ensures that your development environment is consistent across different machines and setups. By defining a containerized environment, you can eliminate the "works on my machine" problem. | ||||
|  | ||||
| ### Advantages of DevContainers | ||||
|  | ||||
| - **Consistency**: Same environment for all developers. | ||||
| - **Isolation**: Separate development environment from your local machine. | ||||
| - **Reproducibility**: Easily recreate the environment on any machine. | ||||
| - **Pre-configured Tools**: Include all necessary tools and dependencies in the container. | ||||
|  | ||||
| ## DevContainer Setup | ||||
|  | ||||
| The DevContainer configuration provides up all the necessary services for Paperless-ngx, including: | ||||
|  | ||||
| - Redis | ||||
| - Gotenberg | ||||
| - Tika | ||||
|  | ||||
| Data is stored using Docker volumes to ensure persistence across container restarts. | ||||
|  | ||||
| ## Configuration Files | ||||
|  | ||||
| The setup includes debugging configurations (`launch.json`) and tasks (`tasks.json`) to help you manage and debug various parts of the project: | ||||
|  | ||||
| - **Backend Debugging:** | ||||
|   - `manage.py runserver` | ||||
|   - `manage.py document-consumer` | ||||
|   - `celery` | ||||
| - **Maintenance Tasks:** | ||||
|   - Create superuser | ||||
|   - Run migrations | ||||
|   - Recreate virtual environment (`.venv` with `uv`) | ||||
|   - Compile frontend assets | ||||
|  | ||||
| ## Getting Started | ||||
|  | ||||
| ### Step 1: Running the DevContainer | ||||
|  | ||||
| To start the DevContainer: | ||||
|  | ||||
| 1. Open VSCode. | ||||
| 2. Open the project folder. | ||||
| 3. Open the command palette: | ||||
|    - **Windows/Linux**: `Ctrl+Shift+P` | ||||
|    - **Mac**: `Cmd+Shift+P` | ||||
| 4. Type and select `Dev Containers: Rebuild and Reopen in Container`. | ||||
|  | ||||
| VSCode will build and start the DevContainer environment. | ||||
|  | ||||
| ### Step 2: Initial Setup | ||||
|  | ||||
| Once the DevContainer is up and running, perform the following steps: | ||||
|  | ||||
| 1. **Compile Frontend Assets**: | ||||
|  | ||||
|    - Open the command palette: | ||||
|      - **Windows/Linux**: `Ctrl+Shift+P` | ||||
|      - **Mac**: `Cmd+Shift+P` | ||||
|    - Select `Tasks: Run Task`. | ||||
|    - Choose `Frontend Compile`. | ||||
|  | ||||
| 2. **Run Database Migrations**: | ||||
|  | ||||
|    - Open the command palette: | ||||
|      - **Windows/Linux**: `Ctrl+Shift+P` | ||||
|      - **Mac**: `Cmd+Shift+P` | ||||
|    - Select `Tasks: Run Task`. | ||||
|    - Choose `Migrate Database`. | ||||
|  | ||||
| 3. **Create Superuser**: | ||||
|    - Open the command palette: | ||||
|      - **Windows/Linux**: `Ctrl+Shift+P` | ||||
|      - **Mac**: `Cmd+Shift+P` | ||||
|    - Select `Tasks: Run Task`. | ||||
|    - Choose `Create Superuser`. | ||||
|  | ||||
| ### Debugging and Running Services | ||||
|  | ||||
| You can start and debug backend services either as debugging sessions via `launch.json` or as tasks. | ||||
|  | ||||
| #### Using `launch.json` | ||||
|  | ||||
| 1. Press `F5` or go to the **Run and Debug** view in VSCode. | ||||
| 2. Select the desired configuration: | ||||
|    - `Runserver` | ||||
|    - `Document Consumer` | ||||
|    - `Celery` | ||||
|  | ||||
| #### Using Tasks | ||||
|  | ||||
| 1. Open the command palette: | ||||
|    - **Windows/Linux**: `Ctrl+Shift+P` | ||||
|    - **Mac**: `Cmd+Shift+P` | ||||
| 2. Select `Tasks: Run Task`. | ||||
| 3. Choose the desired task: | ||||
|    - `Runserver` | ||||
|    - `Document Consumer` | ||||
|    - `Celery` | ||||
|  | ||||
| ### Additional Maintenance Tasks | ||||
|  | ||||
| Additional tasks are available for common maintenance operations: | ||||
|  | ||||
| - **Recreate .venv**: For setting up the virtual environment using `uv`. | ||||
| - **Migrate Database**: To apply database migrations. | ||||
| - **Create Superuser**: To create an admin user for the application. | ||||
|  | ||||
| ## Let's Get Started! | ||||
|  | ||||
| Follow the steps above to get your development environment up and running. Happy coding! | ||||
| @@ -3,7 +3,7 @@ | ||||
|     "dockerComposeFile": "docker-compose.devcontainer.sqlite-tika.yml", | ||||
|     "service": "paperless-development", | ||||
|     "workspaceFolder": "/usr/src/paperless/paperless-ngx", | ||||
|     "postCreateCommand": "pipenv install --dev && pipenv run pre-commit install", | ||||
|     "postCreateCommand": "/bin/bash -c uv sync --dev && uv run pre-commit install", | ||||
|     "customizations": { | ||||
|         "vscode": { | ||||
|           "extensions": [ | ||||
|   | ||||
| @@ -43,7 +43,7 @@ services: | ||||
|     volumes: | ||||
|       - ..:/usr/src/paperless/paperless-ngx:delegated | ||||
|       - ../.devcontainer/vscode:/usr/src/paperless/paperless-ngx/.vscode:delegated # VSCode config files | ||||
|       - pipenv:/usr/src/paperless/paperless-ngx/.venv | ||||
|       - virtualenv:/usr/src/paperless/paperless-ngx/.venv # Virtual environment persisted in volume | ||||
|       - /usr/src/paperless/paperless-ngx/src/documents/static/frontend # Static frontend files exist only in container | ||||
|       - /usr/src/paperless/paperless-ngx/src/.pytest_cache | ||||
|       - /usr/src/paperless/paperless-ngx/.ruff_cache | ||||
| @@ -80,4 +80,7 @@ services: | ||||
|     restart: unless-stopped | ||||
|  | ||||
| volumes: | ||||
|   pipenv: | ||||
|   data: | ||||
|   media: | ||||
|   redisdata: | ||||
|   virtualenv: | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| 			"label": "Start: Celery Worker", | ||||
| 			"description": "Start the Celery Worker which processes background and consume tasks", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run celery --app paperless worker -l DEBUG", | ||||
| 			"command": "uv run celery --app paperless worker -l DEBUG", | ||||
| 			"isBackground": true, | ||||
| 			"options": { | ||||
| 				"cwd": "${workspaceFolder}/src" | ||||
| @@ -61,7 +61,7 @@ | ||||
| 			"label": "Start: Consumer Service (manage.py document_consumer)", | ||||
| 			"description": "Start the Consumer Service which processes files from a directory", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py document_consumer", | ||||
| 			"command": "uv run python manage.py document_consumer", | ||||
| 			"group": "build", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| @@ -80,7 +80,7 @@ | ||||
| 			"label": "Start: Backend Server (manage.py runserver)", | ||||
| 			"description": "Start the Backend Server which serves the Django API and the compiled Angular frontend", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py runserver", | ||||
| 			"command": "uv run python manage.py runserver", | ||||
| 			"group": "build", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| @@ -99,7 +99,7 @@ | ||||
| 			"label": "Maintenance: manage.py migrate", | ||||
| 			"description": "Apply database migrations", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py migrate", | ||||
| 			"command": "uv run python manage.py migrate", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| @@ -118,7 +118,7 @@ | ||||
| 			"label": "Maintenance: Build Documentation", | ||||
| 			"description": "Build the documentation with MkDocs", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run mkdocs build --config-file mkdocs.yml && pipenv run mkdocs serve", | ||||
| 			"command": "uv run mkdocs build --config-file mkdocs.yml && uv run mkdocs serve", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| @@ -137,7 +137,7 @@ | ||||
| 			"label": "Maintenance: manage.py createsuperuser", | ||||
| 			"description": "Create a superuser", | ||||
| 			"type": "shell", | ||||
| 			"command": "pipenv run python manage.py createsuperuser", | ||||
| 			"command": "uv run python manage.py createsuperuser", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
| @@ -156,7 +156,7 @@ | ||||
| 			"label": "Maintenance: recreate .venv", | ||||
| 			"description": "Recreate the python virtual environment and install python dependencies", | ||||
| 			"type": "shell", | ||||
| 			"command": "rm -R -v .venv/* || pipenv install --dev", | ||||
| 			"command": "rm -R -v .venv/* || uv install --dev", | ||||
| 			"group": "none", | ||||
| 			"presentation": { | ||||
| 				"echo": true, | ||||
|   | ||||
| @@ -27,9 +27,6 @@ indent_style = space | ||||
| [*.md] | ||||
| indent_style = space | ||||
|  | ||||
| [Pipfile.lock] | ||||
| indent_style = space | ||||
|  | ||||
| # Tests don't get a line width restriction.  It's still a good idea to follow | ||||
| # the 79 character rule, but in the interests of clarity, tests often need to | ||||
| # violate it. | ||||
|   | ||||
							
								
								
									
										10
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,8 @@ | ||||
| # https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates#package-ecosystem | ||||
|  | ||||
| version: 2 | ||||
| # Required for uv support for now | ||||
| enable-beta-ecosystems: true | ||||
| updates: | ||||
|  | ||||
|   # Enable version updates for npm | ||||
| @@ -34,9 +36,8 @@ updates: | ||||
|           - "eslint" | ||||
|  | ||||
|   # Enable version updates for Python | ||||
|   - package-ecosystem: "pip" | ||||
|   - package-ecosystem: "uv" | ||||
|     target-branch: "dev" | ||||
|     # Look for a `Pipfile` in the `root` directory | ||||
|     directory: "/" | ||||
|     # Check for updates once a week | ||||
|     schedule: | ||||
| @@ -53,6 +54,7 @@ updates: | ||||
|           - "*pytest*" | ||||
|           - "ruff" | ||||
|           - "mkdocs-material" | ||||
|           - "pre-commit*" | ||||
|       django: | ||||
|         patterns: | ||||
|           - "*django*" | ||||
| @@ -63,6 +65,10 @@ updates: | ||||
|         update-types: | ||||
|           - "minor" | ||||
|           - "patch" | ||||
|       pre-built: | ||||
|         patterns: | ||||
|           - psycopg* | ||||
|           - zxing-cpp | ||||
|  | ||||
|   # Enable updates for GitHub Actions | ||||
|   - package-ecosystem: "github-actions" | ||||
|   | ||||
							
								
								
									
										104
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										104
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -14,9 +14,7 @@ on: | ||||
|       - 'translations**' | ||||
|  | ||||
| env: | ||||
|   # This is the version of pipenv all the steps will use | ||||
|   # If changing this, change Dockerfile | ||||
|   DEFAULT_PIP_ENV_VERSION: "2024.4.1" | ||||
|   DEFAULT_UV_VERSION: "0.6.x" | ||||
|   # This is the default version of Python to use in most steps which aren't specific | ||||
|   DEFAULT_PYTHON_VERSION: "3.11" | ||||
|  | ||||
| @@ -59,24 +57,25 @@ jobs: | ||||
|         uses: actions/setup-python@v5 | ||||
|         with: | ||||
|           python-version: ${{ env.DEFAULT_PYTHON_VERSION }} | ||||
|           cache: "pipenv" | ||||
|           cache-dependency-path: 'Pipfile.lock' | ||||
|       - | ||||
|         name: Install pipenv | ||||
|         run: | | ||||
|           pip install --user pipenv==${{ env.DEFAULT_PIP_ENV_VERSION }} | ||||
|         name: Install uv | ||||
|         uses: astral-sh/setup-uv@v5 | ||||
|         with: | ||||
|           version: ${{ env.DEFAULT_UV_VERSION }} | ||||
|           enable-cache: true | ||||
|           python-version: ${{ env.DEFAULT_PYTHON_VERSION }} | ||||
|       - | ||||
|         name: Install dependencies | ||||
|         name: Install Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev | ||||
|       - | ||||
|         name: List installed Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run pip list | ||||
|           uv sync --python ${{ steps.setup-python.outputs.python-version }} --dev --frozen | ||||
|       - | ||||
|         name: Make documentation | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run mkdocs build --config-file ./mkdocs.yml | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             --dev \ | ||||
|             --frozen \ | ||||
|             mkdocs build --config-file ./mkdocs.yml | ||||
|       - | ||||
|         name: Deploy documentation | ||||
|         if: github.event_name == 'push' && github.ref == 'refs/heads/main' | ||||
| @@ -84,7 +83,11 @@ jobs: | ||||
|           echo "docs.paperless-ngx.com" > "${{ github.workspace }}/docs/CNAME" | ||||
|           git config --global user.name "${{ github.actor }}" | ||||
|           git config --global user.email "${{ github.actor }}@users.noreply.github.com" | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run mkdocs gh-deploy --force --no-history | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             --dev \ | ||||
|             --frozen \ | ||||
|             mkdocs gh-deploy --force --no-history | ||||
|       - | ||||
|         name: Upload artifact | ||||
|         uses: actions/upload-artifact@v4 | ||||
| @@ -117,12 +120,13 @@ jobs: | ||||
|         uses: actions/setup-python@v5 | ||||
|         with: | ||||
|           python-version: "${{ matrix.python-version }}" | ||||
|           cache: "pipenv" | ||||
|           cache-dependency-path: 'Pipfile.lock' | ||||
|       - | ||||
|         name: Install pipenv | ||||
|         run: | | ||||
|           pip install --user pipenv==${{ env.DEFAULT_PIP_ENV_VERSION }} | ||||
|         name: Install uv | ||||
|         uses: astral-sh/setup-uv@v5 | ||||
|         with: | ||||
|           version: ${{ env.DEFAULT_UV_VERSION }} | ||||
|           enable-cache: true | ||||
|           python-version: ${{ steps.setup-python.outputs.python-version }} | ||||
|       - | ||||
|         name: Install system dependencies | ||||
|         run: | | ||||
| @@ -135,12 +139,14 @@ jobs: | ||||
|       - | ||||
|         name: Install Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run python --version | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev | ||||
|           uv sync \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             --group testing \ | ||||
|             --frozen | ||||
|       - | ||||
|         name: List installed Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run pip list | ||||
|           uv pip list | ||||
|       - | ||||
|         name: Tests | ||||
|         env: | ||||
| @@ -151,7 +157,11 @@ jobs: | ||||
|           PAPERLESS_MAIL_TEST_PASSWD: ${{ secrets.TEST_MAIL_PASSWD }} | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run pytest -ra | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             --dev \ | ||||
|             --frozen \ | ||||
|             pytest -ra | ||||
|       - | ||||
|         name: Upload coverage | ||||
|         if: ${{ matrix.python-version == env.DEFAULT_PYTHON_VERSION }} | ||||
| @@ -472,16 +482,17 @@ jobs: | ||||
|         uses: actions/setup-python@v5 | ||||
|         with: | ||||
|           python-version: ${{ env.DEFAULT_PYTHON_VERSION }} | ||||
|           cache: "pipenv" | ||||
|           cache-dependency-path: 'Pipfile.lock' | ||||
|       - | ||||
|         name: Install pipenv + tools | ||||
|         run: | | ||||
|           pip install --upgrade --user pipenv==${{ env.DEFAULT_PIP_ENV_VERSION }} setuptools wheel | ||||
|         name: Install uv | ||||
|         uses: astral-sh/setup-uv@v5 | ||||
|         with: | ||||
|           version: ${{ env.DEFAULT_UV_VERSION }} | ||||
|           enable-cache: true | ||||
|           python-version: ${{ steps.setup-python.outputs.python-version }} | ||||
|       - | ||||
|         name: Install Python dependencies | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} sync --dev | ||||
|           uv sync --python ${{ steps.setup-python.outputs.python-version }} --dev --frozen | ||||
|       - | ||||
|         name: Install system dependencies | ||||
|         run: | | ||||
| @@ -502,17 +513,21 @@ jobs: | ||||
|       - | ||||
|         name: Generate requirements file | ||||
|         run: | | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} requirements > requirements.txt | ||||
|            uv export --quiet --no-dev --format requirements-txt --output-file requirements.txt | ||||
|       - | ||||
|         name: Compile messages | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run python3 manage.py compilemessages | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             manage.py compilemessages | ||||
|       - | ||||
|         name: Collect static files | ||||
|         run: | | ||||
|           cd src/ | ||||
|           pipenv --python ${{ steps.setup-python.outputs.python-version }} run python3 manage.py collectstatic --no-input | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             manage.py collectstatic --no-input | ||||
|       - | ||||
|         name: Move files | ||||
|         run: | | ||||
| @@ -528,8 +543,8 @@ jobs: | ||||
|           for file_name in .dockerignore \ | ||||
|                           .env \ | ||||
|                           Dockerfile \ | ||||
|                           Pipfile \ | ||||
|                           Pipfile.lock \ | ||||
|                           pyproject.toml \ | ||||
|                           uv.lock \ | ||||
|                           requirements.txt \ | ||||
|                           LICENSE \ | ||||
|                           README.md \ | ||||
| @@ -631,15 +646,17 @@ jobs: | ||||
|           ref: main | ||||
|       - | ||||
|         name: Set up Python | ||||
|         id: setup-python | ||||
|         uses: actions/setup-python@v5 | ||||
|         with: | ||||
|           python-version: ${{ env.DEFAULT_PYTHON_VERSION }} | ||||
|           cache: "pipenv" | ||||
|           cache-dependency-path: 'Pipfile.lock' | ||||
|       - | ||||
|         name: Install pipenv + tools | ||||
|         run: | | ||||
|           pip install --upgrade --user pipenv==${{ env.DEFAULT_PIP_ENV_VERSION }} setuptools wheel | ||||
|         name: Install uv | ||||
|         uses: astral-sh/setup-uv@v5 | ||||
|         with: | ||||
|           version: ${{ env.DEFAULT_UV_VERSION }} | ||||
|           enable-cache: true | ||||
|           python-version: ${{ env.DEFAULT_PYTHON_VERSION }} | ||||
|       - | ||||
|         name: Append Changelog to docs | ||||
|         id: append-Changelog | ||||
| @@ -655,7 +672,10 @@ jobs: | ||||
|           CURRENT_CHANGELOG=`tail --lines +2 changelog.md` | ||||
|           echo -e "$CURRENT_CHANGELOG" >> changelog-new.md | ||||
|           mv changelog-new.md changelog.md | ||||
|           pipenv run pre-commit run --files changelog.md || true | ||||
|           uv run \ | ||||
|             --python ${{ steps.setup-python.outputs.python-version }} \ | ||||
|             --dev \ | ||||
|             pre-commit run --files changelog.md || true | ||||
|           git config --global user.name "github-actions" | ||||
|           git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||
|           git commit -am "Changelog ${{ needs.publish-release.outputs.version }} - GHA" | ||||
|   | ||||
| @@ -45,7 +45,6 @@ repos: | ||||
|           - javascript | ||||
|           - ts | ||||
|           - markdown | ||||
|         exclude: "(^Pipfile\\.lock$)" | ||||
|         additional_dependencies: | ||||
|           - prettier@3.3.3 | ||||
|           - 'prettier-plugin-organize-imports@4.1.0' | ||||
| @@ -55,6 +54,10 @@ repos: | ||||
|     hooks: | ||||
|       - id: ruff | ||||
|       - id: ruff-format | ||||
|   - repo: https://github.com/tox-dev/pyproject-fmt | ||||
|     rev: "2.0.4" | ||||
|     hooks: | ||||
|       - id: pyproject-fmt | ||||
|   # Dockerfile hooks | ||||
|   - repo: https://github.com/AleksaC/hadolint-py | ||||
|     rev: v2.12.0.3 | ||||
|   | ||||
| @@ -5,5 +5,6 @@ | ||||
| /src-ui/ @paperless-ngx/frontend | ||||
|  | ||||
| /src/ @paperless-ngx/backend | ||||
| Pipfile* @paperless-ngx/backend | ||||
| pyproject.toml @paperless-ngx/backend | ||||
| uv.lock @paperless-ngx/backend | ||||
| *.py @paperless-ngx/backend | ||||
|   | ||||
							
								
								
									
										42
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -26,28 +26,11 @@ esac | ||||
| RUN set -eux \ | ||||
|   && ./node_modules/.bin/ng build --configuration production | ||||
|  | ||||
| # Stage: pipenv-base | ||||
| # Purpose: Generates a requirements.txt file for building | ||||
| # Comments: | ||||
| #  - pipenv dependencies are not left in the final image | ||||
| #  - pipenv can't touch the final image somehow | ||||
| FROM --platform=$BUILDPLATFORM docker.io/python:3.12-alpine AS pipenv-base | ||||
|  | ||||
| WORKDIR /usr/src/pipenv | ||||
|  | ||||
| COPY Pipfile* ./ | ||||
|  | ||||
| RUN set -eux \ | ||||
|   && echo "Installing pipenv" \ | ||||
|     && python3 -m pip install --no-cache-dir --upgrade pipenv==2024.4.1 \ | ||||
|   && echo "Generating requirement.txt" \ | ||||
|     && pipenv requirements > requirements.txt | ||||
|  | ||||
| # Stage: s6-overlay-base | ||||
| # Purpose: Installs s6-overlay and rootfs | ||||
| # Comments: | ||||
| #  - Don't leave anything extra in here either | ||||
| FROM docker.io/python:3.12-slim-bookworm AS s6-overlay-base | ||||
| FROM ghcr.io/astral-sh/uv:0.6.3-python3.12-bookworm-slim AS s6-overlay-base | ||||
|  | ||||
| WORKDIR /usr/src/s6 | ||||
|  | ||||
| @@ -123,9 +106,12 @@ ARG GS_VERSION=10.03.1 | ||||
| # Set Python environment variables | ||||
| ENV PYTHONDONTWRITEBYTECODE=1 \ | ||||
|     PYTHONUNBUFFERED=1 \ | ||||
|     # Ignore warning from Whitenoise | ||||
|     # Ignore warning from Whitenoise about async iterators | ||||
|     PYTHONWARNINGS="ignore:::django.http.response:517" \ | ||||
|     PNGX_CONTAINERIZED=1 | ||||
|     PNGX_CONTAINERIZED=1 \ | ||||
|     # https://docs.astral.sh/uv/reference/settings/#link-mode | ||||
|     UV_LINK_MODE=copy \ | ||||
|     UV_CACHE_DIR=/cache/uv/ | ||||
|  | ||||
| # | ||||
| # Begin installation and configuration | ||||
| @@ -213,7 +199,7 @@ WORKDIR /usr/src/paperless/src/ | ||||
|  | ||||
| # Python dependencies | ||||
| # Change pretty frequently | ||||
| COPY --chown=1000:1000 --from=pipenv-base /usr/src/pipenv/requirements.txt ./ | ||||
| COPY --chown=1000:1000 ["pyproject.toml", "uv.lock", "/usr/src/paperless/src/"] | ||||
|  | ||||
| # Packages needed only for building a few quick Python | ||||
| # dependencies | ||||
| @@ -226,23 +212,15 @@ ARG BUILD_PACKAGES="\ | ||||
|   default-libmysqlclient-dev \ | ||||
|   pkg-config" | ||||
|  | ||||
| ARG ZXING_VERSION=2.3.0 | ||||
| ARG PSYCOPG_VERSION=3.2.4 | ||||
|  | ||||
| # hadolint ignore=DL3042 | ||||
| RUN --mount=type=cache,target=/root/.cache/pip/,id=pip-cache \ | ||||
| RUN --mount=type=cache,target=${UV_CACHE_DIR},id=python-cache \ | ||||
|   set -eux \ | ||||
|   && echo "Installing build system packages" \ | ||||
|     && apt-get update \ | ||||
|     && apt-get install --yes --quiet --no-install-recommends ${BUILD_PACKAGES} \ | ||||
|     && python3 -m pip install --upgrade wheel \ | ||||
|   && echo "Installing Python requirements" \ | ||||
|     && curl --fail --silent --no-progress-meter --show-error --location --remote-name-all --parallel --parallel-max 4 \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/psycopg-${PSYCOPG_VERSION}/psycopg_c-${PSYCOPG_VERSION}-cp312-cp312-linux_x86_64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/psycopg-${PSYCOPG_VERSION}/psycopg_c-${PSYCOPG_VERSION}-cp312-cp312-linux_aarch64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/zxing-${ZXING_VERSION}/zxing_cpp-${ZXING_VERSION}-cp312-cp312-linux_aarch64.whl \ | ||||
|       https://github.com/paperless-ngx/builder/releases/download/zxing-${ZXING_VERSION}/zxing_cpp-${ZXING_VERSION}-cp312-cp312-linux_x86_64.whl \ | ||||
|     && python3 -m pip install --default-timeout=1000 --find-links . --requirement requirements.txt \ | ||||
|     && uv export --quiet --no-dev --format requirements-txt --output-file requirements.txt \ | ||||
|     && uv pip install --system --no-python-downloads --python-preference system --requirements requirements.txt \ | ||||
|   && echo "Installing NLTK data" \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" snowball_data \ | ||||
|     && python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" stopwords \ | ||||
|   | ||||
							
								
								
									
										99
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								Pipfile
									
									
									
									
									
								
							| @@ -1,99 +0,0 @@ | ||||
| [[source]] | ||||
| url = "https://pypi.python.org/simple" | ||||
| verify_ssl = true | ||||
| name = "pypi" | ||||
|  | ||||
| [packages] | ||||
| dateparser = "~=1.2" | ||||
| # WARNING: django does not use semver. | ||||
| #          Only patch versions are guaranteed to not introduce breaking changes. | ||||
| django = "~=5.1.5" | ||||
| django-allauth = {extras = ["mfa", "socialaccount"], version = "*"} | ||||
| django-auditlog = "*" | ||||
| django-celery-results = "*" | ||||
| django-compression-middleware = "*" | ||||
| django-cors-headers = "*" | ||||
| django-extensions = "*" | ||||
| django-filter = "~=25.1" | ||||
| django-guardian = "*" | ||||
| django-multiselectfield = "*" | ||||
| django-soft-delete = "*" | ||||
| djangorestframework = "~=3.15.2" | ||||
| djangorestframework-guardian = "*" | ||||
| drf-spectacular = "*" | ||||
| drf-spectacular-sidecar = "*" | ||||
| drf-writable-nested = "*" | ||||
| bleach = "*" | ||||
| celery = {extras = ["redis"], version = "*"} | ||||
| channels = "~=4.2" | ||||
| channels-redis = "*" | ||||
| concurrent-log-handler = "*" | ||||
| filelock = "*" | ||||
| flower = "*" | ||||
| gotenberg-client = "*" | ||||
| granian = "*" | ||||
| httpx-oauth = "*" | ||||
| imap-tools = "*" | ||||
| inotifyrecursive = "~=0.3" | ||||
| jinja2 = "~=3.1" | ||||
| langdetect = "*" | ||||
| mysqlclient = "*" | ||||
| nltk = "*" | ||||
| ocrmypdf = "~=16.9" | ||||
| pathvalidate = "*" | ||||
| pdf2image = "*" | ||||
| psycopg = {version = "*", extras = ["c"]} | ||||
| python-dateutil = "*" | ||||
| python-dotenv = "*" | ||||
| python-gnupg = "*" | ||||
| python-ipware = "*" | ||||
| python-magic = "*" | ||||
| pyzbar = "*" | ||||
| rapidfuzz = "*" | ||||
| redis = {extras = ["hiredis"], version = "*"} | ||||
| scikit-learn = "~=1.6" | ||||
| setproctitle = "*" | ||||
| tika-client = "*" | ||||
| tqdm = "*" | ||||
| watchdog = "~=6.0" | ||||
| whitenoise = "~=6.9" | ||||
| whoosh = "~=2.7" | ||||
| zxing-cpp = "*" | ||||
|  | ||||
| [dev-packages] | ||||
| # Linting | ||||
| pre-commit = "*" | ||||
| ruff = "*" | ||||
| # Testing | ||||
| factory-boy = "*" | ||||
| pytest = "*" | ||||
| pytest-cov = "*" | ||||
| pytest-django = "*" | ||||
| pytest-httpx = "*" | ||||
| pytest-env = "*" | ||||
| pytest-sugar = "*" | ||||
| pytest-xdist = "*" | ||||
| pytest-mock = "*" | ||||
| pytest-rerunfailures = "*" | ||||
| imagehash = "*" | ||||
| daphne = "*" | ||||
| # Documentation | ||||
| mkdocs-material = "*" | ||||
| mkdocs-glightbox = "*" | ||||
|  | ||||
| [typing-dev] | ||||
| mypy = "*" | ||||
| types-Pillow = "*" | ||||
| django-filter-stubs = "*" | ||||
| types-python-dateutil = "*" | ||||
| djangorestframework-stubs = {extras= ["compatible-mypy"], version="*"} | ||||
| celery-types = "*" | ||||
| django-stubs = {extras= ["compatible-mypy"], version="*"} | ||||
| types-dateparser = "*" | ||||
| types-bleach = "*" | ||||
| types-redis = "*" | ||||
| types-tqdm = "*" | ||||
| types-Markdown = "*" | ||||
| types-Pygments = "*" | ||||
| types-colorama = "*" | ||||
| types-setuptools = "*" | ||||
							
								
								
									
										4812
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4812
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -60,7 +60,7 @@ first-time setup. | ||||
|  | ||||
|       Every command is executed directly from the root folder of the project unless specified otherwise. | ||||
|  | ||||
| 1.  Install prerequisites + pipenv as mentioned in | ||||
| 1.  Install prerequisites + [uv](https://github.com/astral-sh/uv) as mentioned in | ||||
|     [Bare metal route](setup.md#bare_metal). | ||||
|  | ||||
| 2.  Copy `paperless.conf.example` to `paperless.conf` and enable debug | ||||
| @@ -75,17 +75,13 @@ first-time setup. | ||||
| 4.  Install the Python dependencies: | ||||
|  | ||||
|     ```bash | ||||
|     pipenv install --dev | ||||
|     $ uv sync --dev | ||||
|     ``` | ||||
|  | ||||
|     !!! note | ||||
|  | ||||
|         Using a virtual environment is highly recommended. You can spawn one via `pipenv shell`. | ||||
|  | ||||
| 5.  Install pre-commit hooks: | ||||
|  | ||||
|     ```bash | ||||
|     pre-commit install | ||||
|     $ uv run pre-commit install | ||||
|     ``` | ||||
|  | ||||
| 6.  Apply migrations and create a superuser for your development instance: | ||||
| @@ -93,8 +89,8 @@ first-time setup. | ||||
|     ```bash | ||||
|     # src/ | ||||
|  | ||||
|     python3 manage.py migrate | ||||
|     python3 manage.py createsuperuser | ||||
|     $ uv run manage.py migrate | ||||
|     $ uv run manage.py createsuperuser | ||||
|     ``` | ||||
|  | ||||
| 7.  You can now either ... | ||||
| @@ -164,6 +160,19 @@ $ ng build --configuration production | ||||
|       complicated IF cases. Append `# noqa: E501` to disable this check | ||||
|       for certain lines. | ||||
|  | ||||
| ### Package Management | ||||
|  | ||||
| Paperless uses `uv` to manage packages and virtual environments for both development and production. | ||||
| To accomplish some common tasks using `uv`, follow the shortcuts below: | ||||
|  | ||||
| To upgrade all locked packages to the latest allowed versions: `uv lock --upgrade` | ||||
|  | ||||
| To upgrade a single locked package: `uv lock --upgrade-package <package>` | ||||
|  | ||||
| To add a new package: `uv add <package>` | ||||
|  | ||||
| To add a new development package `uv add --dev <package>` | ||||
|  | ||||
| ## Front end development | ||||
|  | ||||
| The front end is built using AngularJS. In order to get started, you need Node.js (version 14.15+) and | ||||
| @@ -332,27 +341,21 @@ LANGUAGES = [ | ||||
| The documentation is built using material-mkdocs, see their [documentation](https://squidfunk.github.io/mkdocs-material/reference/). | ||||
| If you want to build the documentation locally, this is how you do it: | ||||
|  | ||||
| 1.  Have an active pipenv shell (`pipenv shell`) and install Python dependencies: | ||||
| 1.  Build the documentation | ||||
|  | ||||
|     ```bash | ||||
|     pipenv install --dev | ||||
|     ``` | ||||
|  | ||||
| 2.  Build the documentation | ||||
|  | ||||
|     ```bash | ||||
|     mkdocs build --config-file mkdocs.yml | ||||
|     $ uv run mkdocs build --config-file mkdocs.yml | ||||
|     ``` | ||||
|  | ||||
|     _alternatively..._ | ||||
|  | ||||
| 3.  Serve the documentation. This will spin up a | ||||
| 2.  Serve the documentation. This will spin up a | ||||
|     copy of the documentation at http://127.0.0.1:8000 | ||||
|     that will automatically refresh every time you change | ||||
|     something. | ||||
|  | ||||
|     ```bash | ||||
|     mkdocs serve | ||||
|     $ uv run mkdocs serve | ||||
|     ``` | ||||
|  | ||||
| ## Building the Docker image | ||||
|   | ||||
							
								
								
									
										144
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								pyproject.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | ||||
| [project] | ||||
| name = "paperless-ngx" | ||||
| version = "2.14.7" | ||||
| description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents" | ||||
| readme = "README.md" | ||||
| requires-python = ">=3.10" | ||||
| classifiers = [ | ||||
|   "Programming Language :: Python :: 3 :: Only", | ||||
|   "Programming Language :: Python :: 3.10", | ||||
|   "Programming Language :: Python :: 3.11", | ||||
|   "Programming Language :: Python :: 3.12", | ||||
| ] | ||||
| dependencies = [ | ||||
|   "bleach~=6.2.0", | ||||
|   "celery[redis]~=5.4.0", | ||||
|   "channels~=4.2", | ||||
|   "channels-redis~=4.2", | ||||
|   "concurrent-log-handler~=0.9.25", | ||||
|   "dateparser~=1.2", | ||||
|   # WARNING: django does not use semver. | ||||
|   #          Only patch versions are guaranteed to not introduce breaking changes. | ||||
|   "django~=5.1.6", | ||||
|   "django-allauth[socialaccount,mfa]~=65.4.0", | ||||
|   "django-auditlog~=3.0.0", | ||||
|   "django-celery-results~=2.5.1", | ||||
|   "django-compression-middleware~=0.5.0", | ||||
|   "django-cors-headers~=4.7.0", | ||||
|   "django-extensions~=3.2.3", | ||||
|   "django-filter~=25.1", | ||||
|   "django-guardian~=2.4.0", | ||||
|   "django-multiselectfield~=0.1.13", | ||||
|   "django-soft-delete~=1.0.18", | ||||
|   "djangorestframework~=3.15", | ||||
|   "djangorestframework-guardian~=0.3.0", | ||||
|   "drf-spectacular~=0.28", | ||||
|   "drf-spectacular-sidecar~=2025.2.1", | ||||
|   "drf-writable-nested~=0.7.1", | ||||
|   "filelock~=3.17.0", | ||||
|   "flower~=2.0.1", | ||||
|   "gotenberg-client~=0.9.0", | ||||
|   "granian~=1.7.6", | ||||
|   "httpx-oauth~=0.16", | ||||
|   "imap-tools~=1.10.0", | ||||
|   "inotifyrecursive~=0.3", | ||||
|   "jinja2~=3.1.5", | ||||
|   "langdetect~=1.0.9", | ||||
|   "mysqlclient~=2.2.7", | ||||
|   "nltk~=3.9.1", | ||||
|   "ocrmypdf~=16.9.0", | ||||
|   "pathvalidate~=3.2.3", | ||||
|   "pdf2image~=1.17.0", | ||||
|   "psycopg[c]==3.2.4", | ||||
|   # Direct dependency for proper resolution of the pre-build wheels | ||||
|   "psycopg-c==3.2.4", | ||||
|   "python-dateutil~=2.9.0", | ||||
|   "python-dotenv~=1.0.1", | ||||
|   "python-gnupg~=0.5.4", | ||||
|   "python-ipware~=3.0.0", | ||||
|   "python-magic~=0.4.27", | ||||
|   "pyzbar~=0.1.9", | ||||
|   "rapidfuzz~=3.12.1", | ||||
|   "redis[hiredis]~=5.2.1", | ||||
|   "scikit-learn~=1.6.1", | ||||
|   "setproctitle~=1.3.4", | ||||
|   "tika-client~=0.9.0", | ||||
|   "tqdm~=4.67.1", | ||||
|   "watchdog~=6.0", | ||||
|   "whitenoise~=6.9", | ||||
|   "whoosh~=2.7", | ||||
|   "zxing-cpp~=2.3.0", | ||||
| ] | ||||
|  | ||||
| # TODO: Move certain things to groups and then utilize that further | ||||
| # This will allow testing to not install a webserver, mysql, etc | ||||
|  | ||||
| [dependency-groups] | ||||
|  | ||||
| dev = [ | ||||
|   { "include-group" = "docs" }, | ||||
|   { "include-group" = "testing" }, | ||||
|   { "include-group" = "lint" }, | ||||
| ] | ||||
|  | ||||
| testing = [ | ||||
|   "factory-boy~=3.3.1", | ||||
|   "pytest~=8.3.3", | ||||
|   "pytest-cov~=6.0.0", | ||||
|   "pytest-django~=4.10.0", | ||||
|   "pytest-httpx", | ||||
|   "pytest-env", | ||||
|   "pytest-sugar", | ||||
|   "pytest-xdist", | ||||
|   "pytest-mock", | ||||
|   "pytest-rerunfailures", | ||||
|   "imagehash", | ||||
|   "daphne", | ||||
| ] | ||||
|  | ||||
| lint = [ | ||||
|   "pre-commit~=4.1.0", | ||||
|   "pre-commit-uv~=4.1.3", | ||||
|   "ruff~=0.9.9", | ||||
| ] | ||||
|  | ||||
| docs = [ | ||||
|   "mkdocs-material~=9.6.4", | ||||
|   "mkdocs-glightbox~=0.4.0", | ||||
| ] | ||||
|  | ||||
| typing = [ | ||||
|   "mypy", | ||||
|   "django-filter-stubs", | ||||
|   "types-python-dateutil", | ||||
|   "djangorestframework-stubs[compatible-mypy]", | ||||
|   "celery-types", | ||||
|   "django-stubs[compatible-mypy]", | ||||
|   "types-dateparser", | ||||
|   "types-bleach", | ||||
|   "types-redis", | ||||
|   "types-tqdm", | ||||
|   "types-Markdown", | ||||
|   "types-Pygments", | ||||
|   "types-colorama", | ||||
|   "types-setuptools", | ||||
| ] | ||||
|  | ||||
| [tool.uv] | ||||
| required-version = ">=0.5.14" | ||||
| package = false | ||||
| environments = [ | ||||
|   "sys_platform == 'darwin'", | ||||
|   "sys_platform == 'linux'", | ||||
| ] | ||||
|  | ||||
| [tool.uv.sources] | ||||
| # Markers are chosen to select these almost exclusively when building the Docker image | ||||
| psycopg-c = [ | ||||
|   { url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.4/psycopg_c-3.2.4-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.12'" }, | ||||
|   { url = "https://github.com/paperless-ngx/builder/releases/download/psycopg-3.2.4/psycopg_c-3.2.4-cp312-cp312-linux_aarch64.whl", marker = "sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.12'" }, | ||||
| ] | ||||
| zxing-cpp = [ | ||||
|   { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64' and python_version == '3.12'" }, | ||||
|   { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_aarch64.whl", marker = "sys_platform == 'linux' and platform_machine == 'aarch64' and python_version == '3.12'" }, | ||||
| ] | ||||
| @@ -6,7 +6,7 @@ if __name__ == "__main__": | ||||
|  | ||||
|     Granian( | ||||
|         "paperless.asgi:application", | ||||
|         interface=Interfaces.ASGI, | ||||
|         interface=Interfaces.ASGINL, | ||||
|         address=os.getenv("GRANIAN_HOST") or os.getenv("PAPERLESS_BIND_ADDR", "::"), | ||||
|         port=int(os.getenv("GRANIAN_PORT") or os.getenv("PAPERLESS_PORT") or 8000), | ||||
|         workers=int( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Trenton H
					Trenton H