diff --git a/.Rbuildignore b/.Rbuildignore deleted file mode 100644 index 5163d0b5b..000000000 --- a/.Rbuildignore +++ /dev/null @@ -1 +0,0 @@ -^LICENSE\.md$ diff --git a/.github/workflows/R-CMD-check.yml b/.github/workflows/R-CMD-check.yml index c35f2cb8d..6663dcb7c 100644 --- a/.github/workflows/R-CMD-check.yml +++ b/.github/workflows/R-CMD-check.yml @@ -15,13 +15,13 @@ jobs: # website: # uses: rstudio/shiny-workflows/.github/workflows/website.yaml@v1 # with: - # working-directory: ./r-package + # working-directory: ./pkg-r routine: uses: rstudio/shiny-workflows/.github/workflows/routine.yaml@v1 with: format-r-code: true - working-directory: ./r-package + working-directory: ./pkg-r R-CMD-check: uses: rstudio/shiny-workflows/.github/workflows/R-CMD-check.yaml@v1 with: - working-directory: ./r-package + working-directory: ./pkg-r diff --git a/.github/workflows/py-release.yml b/.github/workflows/py-release.yml index 1bb93ed1d..769ca515a 100644 --- a/.github/workflows/py-release.yml +++ b/.github/workflows/py-release.yml @@ -12,7 +12,7 @@ jobs: name: Build and release Python package runs-on: ubuntu-latest - if: startsWith(github.ref, 'refs/tags/py-v') + if: startsWith(github.ref, 'refs/tags/py/v') environment: name: pypi @@ -28,31 +28,26 @@ jobs: uses: astral-sh/setup-uv@v3 - name: ๐Ÿ Set up Python ${{ env.PYTHON_VERSION }} - working-directory: ./python-package run: uv python install ${{ env.PYTHON_VERSION }} - name: ๐Ÿ“ฆ Install the project - working-directory: ./python-package run: uv sync --python ${{ env.PYTHON_VERSION }} --all-extras # - name: ๐Ÿงช Check tests - # working-directory: ./python-package - # run: make check-tests - + # run: make py-check-tests - name: ๐Ÿ“ Check types - working-directory: ./python-package - run: make check-types + working-directory: ./pkg-py + run: make py-check-types - name: ๐Ÿ“ Check formatting - working-directory: ./python-package - run: make check-format - + working-directory: ./pkg-py + run: make py-check-format - name: ๐Ÿงณ Build package - working-directory: ./python-package - run: make build + working-directory: ./pkg-py + run: make py-build # TODO: https://pypi.org/manage/project/querychat/settings/publishing/ - name: ๐Ÿšข Publish release on PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: - packages-dir: ./python-package/dist + packages-dir: ./pkg-py/dist diff --git a/.github/workflows/py-test.yml b/.github/workflows/py-test.yml index 2e9734358..0e534c6ca 100644 --- a/.github/workflows/py-test.yml +++ b/.github/workflows/py-test.yml @@ -32,22 +32,16 @@ jobs: uses: astral-sh/setup-uv@v3 - name: ๐Ÿ Set up Python ${{ matrix.config.python-version }} - working-directory: ./python-package run: uv python install ${{matrix.config.python-version }} - name: ๐Ÿ“ฆ Install the project - working-directory: ./python-package - run: uv sync --python ${{ matrix.config.python-version }} --all-extras + run: uv sync --python ${{matrix.config.python-version }} --all-extras # - name: ๐Ÿงช Check tests - # working-directory: ./python-package - # run: make check-tests + # run: make py-check-tests - name: ๐Ÿ“ Check types - # if: ${{ matrix.config.python-version != '3.9' }} - working-directory: ./python-package - run: make check-types + run: make py-check-types - name: ๐Ÿ“ Check formatting - working-directory: ./python-package - run: make check-format + run: make py-check-format diff --git a/.gitignore b/.gitignore index 8229dee08..f64bb8d69 100644 --- a/.gitignore +++ b/.gitignore @@ -244,3 +244,6 @@ po/*~ # RStudio Connect folder rsconnect/ + +uv.lock +_dev diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c5e9d63c..228a0e991 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "python.autoComplete.extraPaths": ["${workspaceFolder}/python-package"], + "python.autoComplete.extraPaths": ["${workspaceFolder}/pkg-py"], "[python]": { "editor.formatOnSave": true, "editor.codeActionsOnSave": { diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..aaa021f20 --- /dev/null +++ b/Makefile @@ -0,0 +1,237 @@ +# Inspired by https://github.com/posit-dev/shinychat/blob/main/Makefile + +# Use qvm to manage quarto +QUARTO_VERSION ?= 1.7.31 +QUARTO_PATH = ~/.local/share/qvm/versions/v${QUARTO_VERSION}/bin/quarto +PATH_PKG_R := pkg-r +PATH_PKG_PY := pkg-py +PATH_PKG_JS := js + +# .PHONY: install-quarto +# install-quarto: +# @echo "๐Ÿ”ต Installing quarto" +# @if ! [ -z $(command -v qvm)]; then \ +# @echo "Error: qvm is not installed. Please visit https://github.com/dpastoor/qvm/releases/ to install it." >&2 \ +# exit 1; \ +# fi +# qvm install v${QUARTO_VERSION} +# @echo "๐Ÿ”น Updating .vscode/settings.json" +# @awk -v path="${QUARTO_PATH}" '/"quarto.path":/ {gsub(/"quarto.path": ".*"/, "\"quarto.path\": \"" path "\"")} 1' .vscode/settings.json > .vscode/settings.json.tmp && mv .vscode/settings.json.tmp .vscode/settings.json +# @echo "๐Ÿ”น Updating .github/workflows/quartodoc.yaml" +# @awk -v ver="${QUARTO_VERSION}" '/QUARTO_VERSION:/ {gsub(/QUARTO_VERSION: .*/, "QUARTO_VERSION: " ver)} 1' .github/workflows/quartodoc.yaml > .github/workflows/quartodoc.yaml.tmp && mv .github/workflows/quartodoc.yaml.tmp .github/workflows/quartodoc.yaml + +# .PHONY: docs +# docs: r-docs-render py-docs-render ## [docs] Build the documentation + +# .PHONY: docs-preview +# docs-preview: ## [docs] Preview the documentation +# @npx http-server docs -p 8080 + +# .PHONY: js-setup +# js-setup: ## [js] Install JS dependencies +# @echo "๐Ÿ†™ Setup JS dependencies" +# cd $(PATH_PKG_JS) && npm install + +# .PHONY: js-setup-ci +# js-setup-ci: ## [js] Install JS dependencies as CI +# @echo "๐Ÿ†™ Setup JS dependencies" +# cd $(PATH_PKG_JS) && npm ci + +# .PHONY: js-lint +# js-lint: ## [js] Lint JS code +# @echo "๐Ÿ“ Linting JS code" +# cd $(PATH_PKG_JS) && npm run lint + +# .PHONY: js-build +# js-build: ## [js] Build JS code +# @echo "๐Ÿงณ Building JS code" +# cd $(PATH_PKG_JS) && npm run build + +# .PHONY: js-build-watch +# js-build-watch: ## [js] Build JS code in watch mode +# @echo "๐Ÿงณ Building JS code in watch mode" +# cd $(PATH_PKG_JS) && npm run watch + +.PHONY: r-setup +r-setup: ## [r] Install R dependencies + @echo "๐Ÿ†™ Updating R dependencies" + cd $(PATH_PKG_R) && Rscript -e "pak::local_install_dev_deps()" + +.PHONY: r-check +r-check: r-check-format r-check-tests r-check-package ## [r] All R checks + +.PHONY: r-document +r-document: ## [r] Document package + @echo "๐Ÿ“œ Documenting R package" + cd $(PATH_PKG_R) && Rscript -e "devtools::document()" + +.PHONY: r-format +r-format: ## [r] Format R code + air format $(PATH_PKG_R)/ + +.PHONY: r-check-package +r-check-package: ## [r] Check package + @echo "" + @echo "๐Ÿ”„ Running R CMD Check" + cd $(PATH_PKG_R) && Rscript -e "devtools::check(document = FALSE)" + +.PHONY: r-check-tests +r-check-tests: ## [r] Check tests + @echo "" + @echo "๐Ÿงช Running R tests" + cd $(PATH_PKG_R) && Rscript -e "devtools::test()" + +.PHONY: r-check-format +r-check-format: ## [r] Check format + @echo "" + @echo "๐Ÿ“ Checking R format" + air format --check $(PATH_PKG_R)/ + +# .PHONY: r-update-dist +# r-update-dist: ## [r] Update shinychat web assets +# @echo "" +# @echo "๐Ÿ”„ Updating shinychat web assets" +# if [ -d $(PATH_PKG_R)/inst/lib/shiny ]; then \ +# rm -rf $(PATH_PKG_R)/inst/lib/shiny; \ +# fi +# mkdir -p $(PATH_PKG_R)/inst/lib/shiny +# cp -r $(PATH_PKG_JS)/dist/chat $(PATH_PKG_R)/inst/lib/shiny/ +# cp -r $(PATH_PKG_JS)/dist/markdown-stream $(PATH_PKG_R)/inst/lib/shiny/ +# (git rev-parse HEAD) > "$(PATH_PKG_R)/inst/lib/shiny/GIT_VERSION" + +.PHONY: r-docs +r-docs: ## [r] Build R docs + @echo "๐Ÿ“– Rendering R docs with pkgdown" + cd $(PATH_PKG_R) && Rscript -e "pkgdown::build_site()" + +.PHONY: r-docs-preview +r-docs-preview: ## [r] Build R docs + @echo "๐Ÿ“– Rendering R docs with pkgdown" + cd $(PATH_PKG_R) && Rscript -e "pkgdown::preview_site()" + +.PHONY: py-setup +py-setup: ## [py] Setup python environment + uv sync --all-extras + +.PHONY: py-check +# py-check: py-check-format py-check-types py-check-tests ## [py] Run python checks +py-check: py-check-format py-check-types ## [py] Run python checks + +.PHONY: py-check-tox +py-check-tox: ## [py] Run python 3.9 - 3.12 checks with tox + @echo "" + @echo "๐Ÿ”„ Running tests and type checking with tox for Python 3.9--3.12" + uv run tox run-parallel + +# .PHONY: py-check-tests +# py-check-tests: ## [py] Run python tests +# @echo "" +# @echo "๐Ÿงช Running tests with pytest" +# uv run playwright install +# uv run pytest + +.PHONY: py-check-types +py-check-types: ## [py] Run python type checks + @echo "" + @echo "๐Ÿ“ Checking types with pyright" + uv run pyright + +.PHONY: py-check-format +py-check-format: + @echo "" + @echo "๐Ÿ“ Checking format with ruff" + uv run ruff check pkg-py --config pyproject.toml + +.PHONY: py-format +py-format: ## [py] Format python code + uv run ruff check --fix pkg-py --config pyproject.toml + uv run ruff format pkg-py --config pyproject.toml + +# .PHONY: py-coverage +# py-coverage: ## [py] Generate coverage report +# @echo "๐Ÿ“” Generating coverage report" +# uv run coverage run -m pytest +# uv run coverage report + +# .PHONY: py-coverage-report +# py-coverage-report: py-coverage ## [py] Generate coverage report and open it in browser +# uv run coverage html +# @echo "" +# @echo "๐Ÿ“ก Serving coverage report at http://localhost:8081/" +# @npx http-server htmlcov --silent -p 8081 + +# .PHONY: py-update-snaps +# py-update-snaps: ## [py] Update python test snapshots +# @echo "๐Ÿ“ธ Updating pytest snapshots" +# uv run pytest --snapshot-update + +# .PHONY: py-docs +# py-docs: py-docs-api py-docs-render ## [py] Build python docs + +# .PHONY: py-docs-render +# py-docs-render: ## [py] Render python docs +# @echo "๐Ÿ“– Rendering python docs with quarto" +# @$(eval export IN_QUARTODOC=true) +# ${QUARTO_PATH} render pkg-py/docs + +# .PHONY: py-docs-preview +# py-docs-preview: ## [py] Preview python docs +# @echo "๐Ÿ“– Rendering python docs with quarto" +# @$(eval export IN_QUARTODOC=true) +# ${QUARTO_PATH} preview pkg-py/docs + +# .PHONY: py-docs-api +# py-docs-api: ## [py] Update python API docs +# @echo "๐Ÿ“– Generating python docs with quartodoc" +# @$(eval export IN_QUARTODOC=true) +# cd pkg-py/docs && uv run quartodoc build +# cd pkg-py/docs && uv run quartodoc interlinks + +# .PHONY: py-docs-api-watch +# py-docs-api-watch: ## [py] Update python docs +# @echo "๐Ÿ“– Generating python docs with quartodoc" +# @$(eval export IN_QUARTODOC=true) +# uv run quartodoc build --config pkg-py/docs/_quarto.yml --watch + +# .PHONY: py-docs-clean +# py-docs-clean: ## [py] Clean python docs +# @echo "๐Ÿงน Cleaning python docs" +# rm -r pkg-py/docs/api +# find pkg-py/docs/py -name '*.quarto_ipynb' -delete + +.PHONY: py-build +py-build: ## [py] Build python package + @echo "๐Ÿงณ Building python package" + @[ -d dist ] && rm -r dist || true + uv build + +.PHONY: py-update-dist +py-update-dist: ## [py] Update shinychat web assets + @echo "" + @echo "๐Ÿ”„ Updating shinychat web assets" + if [ -d $(PATH_PKG_PY)/src/shinychat/www ]; then \ + rm -rf $(PATH_PKG_PY)/src/shinychat/www; \ + fi + mkdir -p $(PATH_PKG_PY)/src/shinychat/www + cp -r $(PATH_PKG_JS)/dist/chat $(PATH_PKG_PY)/src/shinychat/www/ + cp -r $(PATH_PKG_JS)/dist/markdown-stream $(PATH_PKG_PY)/src/shinychat/www/ + (git rev-parse HEAD) > "$(PATH_PKG_PY)/src/shinychat/www/GIT_VERSION" + +.PHONY: help +help: ## Show help messages for make targets + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; { \ + printf "\033[32m%-18s\033[0m", $$1; \ + if ($$2 ~ /^\[docs\]/) { \ + printf "\033[37m[docs]\033[0m%s\n", substr($$2, 7); \ + } else if ($$2 ~ /^\[py\]/) { \ + printf " \033[31m[py]\033[0m%s\n", substr($$2, 5); \ + } else if ($$2 ~ /^\[r\]/) { \ + printf " \033[34m[r]\033[0m%s\n", substr($$2, 4); \ + } else if ($$2 ~ /^\[js\]/) { \ + printf " \033[33m[js]\033[0m%s\n", substr($$2, 5); \ + } else { \ + printf " %s\n", $$2; \ + } \ + }' + +.DEFAULT_GOAL := help diff --git a/README.md b/README.md index 45fbc4604..4a07aa781 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ querychat is a multilingual package that allows you to chat with your data using natural language queries. It's available for: -- [R - Shiny](r-package/README.md) -- [Python - Shiny for Python](python-package/README.md) +- [R - Shiny](pkg-r/README.md) +- [Python - Shiny for Python](pkg-py/README.md) ## Overview @@ -42,5 +42,5 @@ Currently, querychat uses DuckDB for its SQL engine. It's extremely fast and has For detailed information on how to use querychat in your preferred language, see the language-specific READMEs: -- [R Documentation](r-package/README.md) -- [Python Documentation](python-package/README.md) +- [R Documentation](pkg-r/README.md) +- [Python Documentation](pkg-py/README.md) diff --git a/python-package/LICENSE b/pkg-py/LICENSE similarity index 100% rename from python-package/LICENSE rename to pkg-py/LICENSE diff --git a/python-package/README.md b/pkg-py/README.md similarity index 99% rename from python-package/README.md rename to pkg-py/README.md index 9b29fb193..81401feb8 100644 --- a/python-package/README.md +++ b/pkg-py/README.md @@ -13,7 +13,7 @@ querychat is a drop-in component for Shiny that allows users to query a data fra ## Installation ```bash -pip install "querychat @ git+https://github.com/posit-dev/querychat#subdirectory=python-package" +pip install "querychat @ git+https://github.com/posit-dev/querychat#subdirectory=pkg-py" ``` ## How to use diff --git a/python-package/examples/app-database.py b/pkg-py/examples/app-database.py similarity index 100% rename from python-package/examples/app-database.py rename to pkg-py/examples/app-database.py diff --git a/python-package/examples/app-dataframe.py b/pkg-py/examples/app-dataframe.py similarity index 100% rename from python-package/examples/app-dataframe.py rename to pkg-py/examples/app-dataframe.py diff --git a/python-package/examples/data_description.md b/pkg-py/examples/data_description.md similarity index 100% rename from python-package/examples/data_description.md rename to pkg-py/examples/data_description.md diff --git a/python-package/examples/greeting.md b/pkg-py/examples/greeting.md similarity index 100% rename from python-package/examples/greeting.md rename to pkg-py/examples/greeting.md diff --git a/python-package/src/querychat/__init__.py b/pkg-py/src/querychat/__init__.py similarity index 100% rename from python-package/src/querychat/__init__.py rename to pkg-py/src/querychat/__init__.py diff --git a/python-package/src/querychat/datasource.py b/pkg-py/src/querychat/datasource.py similarity index 96% rename from python-package/src/querychat/datasource.py rename to pkg-py/src/querychat/datasource.py index d9322ff49..24c3a30fa 100644 --- a/python-package/src/querychat/datasource.py +++ b/pkg-py/src/querychat/datasource.py @@ -1,14 +1,16 @@ from __future__ import annotations -from typing import ClassVar, Protocol +from typing import TYPE_CHECKING, ClassVar, Protocol import duckdb import narwhals as nw import pandas as pd from sqlalchemy import inspect, text -from sqlalchemy.engine import Connection, Engine from sqlalchemy.sql import sqltypes +if TYPE_CHECKING: + from sqlalchemy.engine import Connection, Engine + class DataSource(Protocol): db_engine: ClassVar[str] @@ -217,8 +219,8 @@ def get_schema(self, *, categorical_threshold: int) -> str: result = conn.execute(query).fetchone() if result and result[0] is not None and result[1] is not None: column_info.append(f" Range: {result[0]} to {result[1]}") - except Exception: - pass # Skip range info if query fails + except Exception: # noqa: S110 + pass # Silently skip range info if query fails # For string/text columns, check if categorical elif isinstance( @@ -242,8 +244,8 @@ def get_schema(self, *, categorical_threshold: int) -> str: ] values_str = ", ".join([f"'{v}'" for v in values]) column_info.append(f" Categorical values: {values_str}") - except Exception: - pass # Skip categorical info if query fails + except Exception: # noqa: S110 + pass # Silently skip categorical info if query fails schema.extend(column_info) @@ -273,7 +275,7 @@ def get_data(self) -> pd.DataFrame: """ return self.execute_query(f"SELECT * FROM {self._table_name}") - def _get_sql_type_name(self, type_: sqltypes.TypeEngine) -> str: + def _get_sql_type_name(self, type_: sqltypes.TypeEngine) -> str: # noqa: PLR0911 """Convert SQLAlchemy type to SQL type name.""" if isinstance(type_, sqltypes.Integer): return "INTEGER" diff --git a/python-package/src/querychat/prompt/prompt.md b/pkg-py/src/querychat/prompt/prompt.md similarity index 100% rename from python-package/src/querychat/prompt/prompt.md rename to pkg-py/src/querychat/prompt/prompt.md diff --git a/python-package/src/querychat/querychat.py b/pkg-py/src/querychat/querychat.py similarity index 98% rename from python-package/src/querychat/querychat.py rename to pkg-py/src/querychat/querychat.py index 5e6936590..9eba2c474 100644 --- a/python-package/src/querychat/querychat.py +++ b/pkg-py/src/querychat/querychat.py @@ -18,7 +18,6 @@ import pandas as pd from narwhals.typing import IntoFrame - from .datasource import DataFrameSource, DataSource, SQLAlchemySource @@ -126,7 +125,7 @@ def __getitem__(self, key: str) -> Any: backwards compatibility only; new code should use the attributes directly instead. """ - if key == "chat": + if key == "chat": # noqa: SIM116 return self.chat elif key == "sql": return self.sql @@ -135,6 +134,11 @@ def __getitem__(self, key: str) -> Any: elif key == "df": return self.df + raise KeyError( + f"`QueryChat` does not have a key `'{key}'`. " + "Use the attributes `chat`, `sql`, `title`, or `df` instead.", + ) + def system_prompt( data_source: DataSource, diff --git a/python-package/src/querychat/static/css/styles.css b/pkg-py/src/querychat/static/css/styles.css similarity index 100% rename from python-package/src/querychat/static/css/styles.css rename to pkg-py/src/querychat/static/css/styles.css diff --git a/r-package/DESCRIPTION b/pkg-r/DESCRIPTION similarity index 100% rename from r-package/DESCRIPTION rename to pkg-r/DESCRIPTION diff --git a/r-package/LICENSE b/pkg-r/LICENSE similarity index 100% rename from r-package/LICENSE rename to pkg-r/LICENSE diff --git a/r-package/NAMESPACE b/pkg-r/NAMESPACE similarity index 100% rename from r-package/NAMESPACE rename to pkg-r/NAMESPACE diff --git a/r-package/R/prompt.R b/pkg-r/R/prompt.R similarity index 100% rename from r-package/R/prompt.R rename to pkg-r/R/prompt.R diff --git a/r-package/R/querychat.R b/pkg-r/R/querychat.R similarity index 100% rename from r-package/R/querychat.R rename to pkg-r/R/querychat.R diff --git a/r-package/README.md b/pkg-r/README.md similarity index 99% rename from r-package/README.md rename to pkg-r/README.md index 8c2badbf0..03b5802ad 100644 --- a/r-package/README.md +++ b/pkg-r/README.md @@ -13,7 +13,7 @@ querychat is a drop-in component for Shiny that allows users to query a data fra ## Installation ```r -pak::pak("posit-dev/querychat/r-package") +pak::pak("posit-dev/querychat/pkg-r") ``` ## How to use diff --git a/r-package/inst/prompt/prompt.md b/pkg-r/inst/prompt/prompt.md similarity index 100% rename from r-package/inst/prompt/prompt.md rename to pkg-r/inst/prompt/prompt.md diff --git a/r-package/inst/www/styles.css b/pkg-r/inst/www/styles.css similarity index 100% rename from r-package/inst/www/styles.css rename to pkg-r/inst/www/styles.css diff --git a/r-package/man/querychat_init.Rd b/pkg-r/man/querychat_init.Rd similarity index 100% rename from r-package/man/querychat_init.Rd rename to pkg-r/man/querychat_init.Rd diff --git a/r-package/man/querychat_server.Rd b/pkg-r/man/querychat_server.Rd similarity index 100% rename from r-package/man/querychat_server.Rd rename to pkg-r/man/querychat_server.Rd diff --git a/r-package/man/querychat_system_prompt.Rd b/pkg-r/man/querychat_system_prompt.Rd similarity index 100% rename from r-package/man/querychat_system_prompt.Rd rename to pkg-r/man/querychat_system_prompt.Rd diff --git a/r-package/man/querychat_ui.Rd b/pkg-r/man/querychat_ui.Rd similarity index 100% rename from r-package/man/querychat_ui.Rd rename to pkg-r/man/querychat_ui.Rd diff --git a/python-package/pyproject.toml b/pyproject.toml similarity index 91% rename from python-package/pyproject.toml rename to pyproject.toml index 1ac303bb0..3ce33dc45 100644 --- a/python-package/pyproject.toml +++ b/pyproject.toml @@ -6,9 +6,9 @@ build-backend = "hatchling.build" name = "querychat" version = "0.1.0" description = "Chat with your data using natural language" -readme = "README.md" +readme = "pkg-py/README.md" requires-python = ">=3.9" -license = { file = "LICENSE" } +license = { file = "pkg-py/LICENSE" } authors = [{ name = "Posit", email = "info@posit.co" }] dependencies = [ "duckdb", @@ -32,21 +32,22 @@ classifiers = [ ] [project.urls] -Homepage = "https://github.com/posit-dev/querychat" +Homepage = "https://github.com/posit-dev/querychat" # TODO update when we have docs +Repository = "https://github.com/posit-dev/querychat" Issues = "https://github.com/posit-dev/querychat/issues" -Source = "https://github.com/posit-dev/querychat/tree/main/python-package" +Source = "https://github.com/posit-dev/querychat/tree/main/pkg-py" [tool.hatch.build.targets.wheel] -packages = ["src/querychat"] +packages = ["pkg-py/src/querychat"] [tool.hatch.build.targets.sdist] -include = ["src/querychat", "LICENSE", "README.md"] +include = ["pkg-py/src/querychat", "pkg-py/LICENSE", "pkg-py/README.md"] [tool.uv] dev-dependencies = ["ruff>=0.6.5", "pyright>=1.1.401", "tox-uv>=1.11.4"] [tool.ruff] -src = ["src/querychat"] +src = ["pkg-py/src/querychat"] exclude = [ ".bzr", ".direnv", @@ -74,7 +75,7 @@ exclude = [ "node_modules", "site-packages", "venv", - "app.py", # ignore examples for now + "app-*.py", # ignore example apps for now ] line-length = 88 @@ -82,8 +83,6 @@ indent-width = 4 target-version = "py39" -# [tool.ruff.lint] -# select = ['E', 'F', 'W', 'A', 'PLC', 'PLE', 'PLW', 'I'] [tool.ruff.lint] extend-ignore = [ "A002", # Shadowing a built-in @@ -100,6 +99,8 @@ extend-ignore = [ "RET504", # Unnecessary assignment to `{name}` before `return` statement "RET505", # Unnecessary branch after `return` statement "UP007", # Use `X | Y` for type annotations (or Optional[X]) + # This package trusts the user + "S608", # Possible SQL injection vector through string-based query construction # TODO: Remove in the future, when we have docstrings. "D100", # Missing docstring in public module "D101", # Missing docstring in public class @@ -165,7 +166,7 @@ docstring-code-format = true docstring-code-line-length = "dynamic" [tool.pyright] -include = ["src/querychat"] +include = ["pkg-py/src/querychat"] # For more tox testing usage (in addition to typing), see: diff --git a/python-package/.gitignore b/python-package/.gitignore deleted file mode 100644 index 07df930ad..000000000 --- a/python-package/.gitignore +++ /dev/null @@ -1 +0,0 @@ -uv.lock diff --git a/python-package/Makefile b/python-package/Makefile deleted file mode 100644 index a9e243429..000000000 --- a/python-package/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# Inspired by https://github.com/posit-dev/chatlas/blob/main/Makefile - -.PHONY: setup -setup: ## [py] Setup python environment - uv sync --all-extras - -.PHONY: build -build: ## [py] Build python package - @echo "๐Ÿงณ Building python package" - @[ -d dist ] && rm -r dist || true - uv build - -.PHONY: publish -publish: - hatch publish - -.PHONY: check -check: check-format check-types ## [py] Run python checks - -.PHONY: check-types -check-types: ## [py] Run python type checks - @echo "" - @echo "๐Ÿ“ Checking types with pyright" - uv run --with pyright pyright - -.PHONY: check-format -check-format: - @echo "" - @echo "๐Ÿ“ Checking format with ruff" - uv run --with ruff ruff check src/querychat --config pyproject.toml - -.PHONY: format -format: ## [py] Format python code - uv run --with ruff ruff check --fix src/querychat --config pyproject.toml - uv run --with ruff ruff format src/querychat --config pyproject.toml - -.PHONY: check-tox -check-tox: ## [py] Run python 3.9 - 3.12 checks with tox - @echo "" - @echo "๐Ÿ”„ Running tests and type checking with tox for Python 3.9--3.12" - uv run tox run-parallel - -.PHONY: help -help: ## Show help messages for make targets - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; { \ - printf "\033[32m%-18s\033[0m", $$1; \ - if ($$2 ~ /^\[docs\]/) { \ - printf "\033[34m[docs]\033[0m%s\n", substr($$2, 7); \ - } else if ($$2 ~ /^\[py\]/) { \ - printf " \033[33m[py]\033[0m%s\n", substr($$2, 5); \ - } else if ($$2 ~ /^\[r\]/) { \ - printf " \033[31m[r]\033[0m%s\n", substr($$2, 4); \ - } else { \ - printf " %s\n", $$2; \ - } \ - }' - -.DEFAULT_GOAL := help