diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml deleted file mode 100644 index 789b3ac..0000000 --- a/.github/workflows/codacy.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow checks out code, performs a Codacy security scan -# and integrates the results with the -# GitHub Advanced Security code scanning feature. For more information on -# the Codacy security scan action usage and parameters, see -# https://github.com/codacy/codacy-analysis-cli-action. -# For more information on Codacy Analysis CLI in general, see -# https://github.com/codacy/codacy-analysis-cli. - -name: Codacy Security Scan - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - schedule: - - cron: '38 20 * * 2' - -permissions: - contents: read - -jobs: - codacy-security-scan: - permissions: - contents: read # for actions/checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - name: Codacy Security Scan - runs-on: ubuntu-latest - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout code - uses: actions/checkout@v6 - - # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - - name: Run Codacy Analysis CLI - uses: codacy/codacy-analysis-cli-action@562ee3e92b8e92df8b67e0a5ff8aa8e261919c08 # v4.4.7 - with: - # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository - # You can also omit the token and run the tools that support default configurations - project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} - verbose: true - output: results.sarif - format: sarif - # Adjust severity of non-security issues - gh-code-scanning-compat: true - # Force 0 exit code to allow SARIF file generation - # This will handover control about PR rejection to the GitHub side - max-allowed-issues: 2147483647 - - # Upload the SARIF file generated in the previous step - - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: results.sarif diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..58efb6c --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,37 @@ +name: Lint + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + lint: + name: ruff + black + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install uv + uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + with: + enable-cache: true + + - name: Set up Python + run: uv python install 3.12 + + - name: Install dependencies + run: uv sync --extra dev + + # --output-format=github renders findings as inline PR annotations, + # which is the part of the Codacy integration worth keeping. + - name: Run ruff + run: uv run ruff check --output-format=github src tests + + - name: Run black + run: uv run black --check --diff src tests diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..d81b501 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,41 @@ +# Keep ruff and black revs in step with the versions in the dev extra of +# pyproject.toml. Drift between them produces the "passes locally, fails in +# CI" failure mode. +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.11 + hooks: + - id: ruff-check + # No --fix: this package uses deliberate registration-only imports + # (e.g. models/proposal.py's `partner # noqa: F401`) that F401's + # autofix would silently delete. Report-only also matches the + # check-only Lint workflow. + # Match the Lint workflow, which checks src and tests only. + # alembic/ migrations are historical and deliberately unlinted. + files: ^(src|tests)/ + + - repo: https://github.com/psf/black + rev: 25.12.0 + hooks: + - id: black + files: ^(src|tests)/ + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + # Vendored Bokeh-generated HTML fixtures; rewriting them on every + # regeneration produces a phantom whitespace-only diff. + exclude: ^examples/data/uploader/ + - id: end-of-file-fixer + # Same vendored fixtures as trailing-whitespace above. + exclude: ^examples/data/uploader/ + - id: check-yaml + # mkdocs-material's config uses !!python/name: tags, which + # yaml.safe_load cannot construct. + exclude: ^mkdocs\.yml$ + - id: check-toml + - id: check-added-large-files + # Uploader example fixtures (e.g. ppp_figure_*.html) legitimately + # exceed the default 500kb limit and are committed on purpose. + exclude: ^examples/data/uploader/ diff --git a/README.md b/README.md index 6a2abf4..9ac634e 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,17 @@ If you want to install the package under the Python library directory, you can e The installation process will install some command-line tools under the directory where your Python executable is located. +### Development setup + +If you are going to contribute, install the development dependencies and enable the pre-commit hooks: + +```console +python3 -m pip install -e ".[dev]" +pre-commit install +``` + +The hooks run `ruff` and `black` on the files you stage, plus whitespace and syntax checks. CI runs `ruff` and `black` over all of `src` and `tests`; run `pre-commit run --all-files` to check the whole tree the way CI does. + ## Usage Examples diff --git a/alembic/local_test/alembic/README b/alembic/local_test/alembic/README index 98e4f9c..2500aa1 100644 --- a/alembic/local_test/alembic/README +++ b/alembic/local_test/alembic/README @@ -1 +1 @@ -Generic single-database configuration. \ No newline at end of file +Generic single-database configuration. diff --git a/alembic/local_test/alembic/versions/6407841f5938_baseline.py b/alembic/local_test/alembic/versions/6407841f5938_baseline.py index 96e8a4e..002befe 100644 --- a/alembic/local_test/alembic/versions/6407841f5938_baseline.py +++ b/alembic/local_test/alembic/versions/6407841f5938_baseline.py @@ -1,7 +1,7 @@ """baseline Revision ID: 6407841f5938 -Revises: +Revises: Create Date: 2022-05-11 16:21:57.324356 """ diff --git a/alembic/pfsa-db01-gb/alembic/versions/20220512-103708_33e97fab1034_initial_revision.py b/alembic/pfsa-db01-gb/alembic/versions/20220512-103708_33e97fab1034_initial_revision.py index 128d2ed..69b8fd3 100644 --- a/alembic/pfsa-db01-gb/alembic/versions/20220512-103708_33e97fab1034_initial_revision.py +++ b/alembic/pfsa-db01-gb/alembic/versions/20220512-103708_33e97fab1034_initial_revision.py @@ -1,7 +1,7 @@ """initial revision Revision ID: 33e97fab1034 -Revises: +Revises: Create Date: 2022-05-12 10:37:08.039899 """ diff --git a/alembic/pfsa-db01-gb/alembic/versions/20240417-100959_c636e8e2ecc0_add_unique_constraint_on_the_sky_table.py b/alembic/pfsa-db01-gb/alembic/versions/20240417-100959_c636e8e2ecc0_add_unique_constraint_on_the_sky_table.py index 479972d..7cfe4bf 100644 --- a/alembic/pfsa-db01-gb/alembic/versions/20240417-100959_c636e8e2ecc0_add_unique_constraint_on_the_sky_table.py +++ b/alembic/pfsa-db01-gb/alembic/versions/20240417-100959_c636e8e2ecc0_add_unique_constraint_on_the_sky_table.py @@ -4,7 +4,7 @@ Revises: 065b74905fb6 Create Date: 2024-04-17 10:09:59.291914 -Note: +Note: Before upgrading the database, I run the following query to avoid the violation of the unique constaint: ``` UPDATE sky SET obj_id = sky_id WHERE version = '20220915'; diff --git a/alembic/pfsa-db01-gb/alembic/versions/20250801-202638_89865530fdf1_add_index_in_obj_id_input_catalog_id_.py b/alembic/pfsa-db01-gb/alembic/versions/20250801-202638_89865530fdf1_add_index_in_obj_id_input_catalog_id_.py index ea372c2..271a2d4 100644 --- a/alembic/pfsa-db01-gb/alembic/versions/20250801-202638_89865530fdf1_add_index_in_obj_id_input_catalog_id_.py +++ b/alembic/pfsa-db01-gb/alembic/versions/20250801-202638_89865530fdf1_add_index_in_obj_id_input_catalog_id_.py @@ -1,4 +1,4 @@ -"""add index in obj_id, input_catalog_id, and proposal_id for target table +"""add index in obj_id, input_catalog_id, and proposal_id for target table Revision ID: 89865530fdf1 Revises: 3923581e4392 diff --git a/diagrams/erdiagram_targetdb_latest.pdf b/diagrams/erdiagram_targetdb_latest.pdf index d3c01c3..271f109 100644 Binary files a/diagrams/erdiagram_targetdb_latest.pdf and b/diagrams/erdiagram_targetdb_latest.pdf differ diff --git a/docs/examples/index.md b/docs/examples/index.md index 7adaeb5..e66ac16 100644 --- a/docs/examples/index.md +++ b/docs/examples/index.md @@ -6,4 +6,4 @@ Some simple examples to work with `targetdb` are provided as follows. - [Preparation of input data](preparation.md): how to prepare input data for `targetdb`. - [Useful queries](queries.md): useful queries to work with `targetdb`. - [Run `targetdb` in a Docker container](docker.md): how to run `targetdb` in a Docker container. -- [Tutorial on preparing PFS openuse](obsproc.md): Workflow to prepare the database content for PFS openuse observations. \ No newline at end of file +- [Tutorial on preparing PFS openuse](obsproc.md): Workflow to prepare the database content for PFS openuse observations. diff --git a/docs/reference/api.md b/docs/reference/api.md index f54e4d4..31ecea5 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -1,3 +1,3 @@ # API Reference -TBD \ No newline at end of file +TBD diff --git a/docs/tbls/public.fluxstd.md b/docs/tbls/public.fluxstd.md index 4e21f11..8a0e7d2 100644 --- a/docs/tbls/public.fluxstd.md +++ b/docs/tbls/public.fluxstd.md @@ -101,10 +101,10 @@ | ---- | ---------- | | fluxstd_pkey | CREATE UNIQUE INDEX fluxstd_pkey ON public.fluxstd USING btree (fluxstd_id) | | uq_obj_id_input_catalog_id_version | CREATE UNIQUE INDEX uq_obj_id_input_catalog_id_version ON public.fluxstd USING btree (obj_id, input_catalog_id, version) | -| ix_fluxstd_input_catalog_fluxstdid | CREATE INDEX ix_fluxstd_input_catalog_fluxstdid ON public.fluxstd USING btree (input_catalog_id, fluxstd_id) | | ix_fluxstd_version_fluxstdid | CREATE INDEX ix_fluxstd_version_fluxstdid ON public.fluxstd USING btree (version, fluxstd_id) | -| fluxstd_q3c_ang2ipix_idx | CREATE INDEX fluxstd_q3c_ang2ipix_idx ON public.fluxstd USING btree (q3c_ang2ipix(ra, "dec")) | | ix_fluxstd_version | CREATE INDEX ix_fluxstd_version ON public.fluxstd USING btree (version) | +| fluxstd_q3c_ang2ipix_idx | CREATE INDEX fluxstd_q3c_ang2ipix_idx ON public.fluxstd USING btree (q3c_ang2ipix(ra, "dec")) | +| ix_fluxstd_input_catalog_fluxstdid | CREATE INDEX ix_fluxstd_input_catalog_fluxstdid ON public.fluxstd USING btree (input_catalog_id, fluxstd_id) | ## Relations diff --git a/docs/tbls/public.target.md b/docs/tbls/public.target.md index 12ceb5a..22dbed9 100644 --- a/docs/tbls/public.target.md +++ b/docs/tbls/public.target.md @@ -121,11 +121,11 @@ | target_pkey | CREATE UNIQUE INDEX target_pkey ON public.target USING btree (target_id) | | target_propid_obcode_catid_objid_resolution_key | CREATE UNIQUE INDEX target_propid_obcode_catid_objid_resolution_key ON public.target USING btree (proposal_id, ob_code, input_catalog_id, obj_id, is_medium_resolution) | | target_propid_obcode_key | CREATE UNIQUE INDEX target_propid_obcode_key ON public.target USING btree (proposal_id, ob_code) | +| target_q3c_ang2ipix_idx | CREATE INDEX target_q3c_ang2ipix_idx ON public.target USING btree (q3c_ang2ipix(ra, "dec")) | | target_proposal_id_idx | CREATE INDEX target_proposal_id_idx ON public.target USING btree (proposal_id) | | target_obj_id_input_catalog_id_idx | CREATE INDEX target_obj_id_input_catalog_id_idx ON public.target USING btree (obj_id, input_catalog_id) | | target_input_catalog_id_idx | CREATE INDEX target_input_catalog_id_idx ON public.target USING btree (input_catalog_id) | | target_proposal_id_obj_id_idx | CREATE INDEX target_proposal_id_obj_id_idx ON public.target USING btree (proposal_id, obj_id) | -| target_q3c_ang2ipix_idx | CREATE INDEX target_q3c_ang2ipix_idx ON public.target USING btree (q3c_ang2ipix(ra, "dec")) | ## Relations diff --git a/examples/data/filter_names.csv b/examples/data/filter_names.csv index d59330b..e515df6 100644 --- a/examples/data/filter_names.csv +++ b/examples/data/filter_names.csv @@ -18,4 +18,4 @@ u_sdss,SDSS u filter g_sdss,SDSS g filter r_sdss,SDSS r filter i_sdss,SDSS i filter -z_sdss,SDSS z filter \ No newline at end of file +z_sdss,SDSS z filter diff --git a/examples/data/input_catalogs.csv b/examples/data/input_catalogs.csv index deaee9f..c410065 100644 --- a/examples/data/input_catalogs.csv +++ b/examples/data/input_catalogs.csv @@ -15,4 +15,4 @@ input_catalog_id,input_catalog_name,input_catalog_description,upload_id 1001,sky_hscssp_s21a_wide,Sky positions from S21A HSC-SSP (Wide), 1002,sky_s1,Sky positions from PS1, 1003,sky_gaia,Sky positions from Gaia, -1004,sky_nops1,Sky postionns for regions without PS1 data, \ No newline at end of file +1004,sky_nops1,Sky postionns for regions without PS1 data, diff --git a/examples/data/proposals.csv b/examples/data/proposals.csv index 50a03ef..3ecdab6 100644 --- a/examples/data/proposals.csv +++ b/examples/data/proposals.csv @@ -35,4 +35,4 @@ S24B-QT910,o00010,Wanqiu,He,NaN,7.5,B,5307.25,5307.25,0.0,1,subaru,False S24B-QT911,o00011,Mao,Zhiying,NaN,10.0,A,5348.05,5348.05,0.0,1,subaru,False S24B-QT912,o00012,Yuki,Moritani,NaN,9.5,A,350.25,350.25,0.0,1,subaru,False S24B-QT913,o00013,Vera,Passegger,Maria,7.0,B,263.0,263.0,0.0,1,subaru,False -S24B-QT914,o00014,Miho,Ishigaki,NaN,0.0,F,0.0,0.0,0.0,1,subaru,False \ No newline at end of file +S24B-QT914,o00014,Miho,Ishigaki,NaN,0.0,F,0.0,0.0,0.0,1,subaru,False diff --git a/examples/data/targets/example_input_catalogs_current.csv b/examples/data/targets/example_input_catalogs_current.csv index 14a37ca..f833f06 100644 --- a/examples/data/targets/example_input_catalogs_current.csv +++ b/examples/data/targets/example_input_catalogs_current.csv @@ -1,2 +1 @@ input_catalog_name,input_catalog_description,upload_id,proposal_id,is_classical,is_user_pointing - diff --git a/examples/data/uploader/2024/09/20240921-041833-c9d7ad93118243b5/ppp_figure_c9d7ad93118243b5.html b/examples/data/uploader/2024/09/20240921-041833-c9d7ad93118243b5/ppp_figure_c9d7ad93118243b5.html index 9602f02..14966fd 100644 --- a/examples/data/uploader/2024/09/20240921-041833-c9d7ad93118243b5/ppp_figure_c9d7ad93118243b5.html +++ b/examples/data/uploader/2024/09/20240921-041833-c9d7ad93118243b5/ppp_figure_c9d7ad93118243b5.html @@ -699,21 +699,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1417,21 +1417,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1500,21 +1500,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1645,21 +1645,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1768,21 +1768,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -9024,21 +9024,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -9099,19 +9099,19 @@ /* This file was adapted from https://github.com/uber/deck.gl/ the LICENSE below is preserved to comply with the original license. - + Copyright (c) 2015 - 2017 Uber Technologies, Inc. - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -9126,19 +9126,19 @@ "2cc1a33000": function _(e,t,a,r,n){function i(e){let t=null;return e&&(t=function(e){try{return{boundingClientRect:{...e.getBoundingClientRect()}}}catch{return{}}}(e),e.tagName in l&&l[e.tagName].forEach((a=>Object.assign(t,a(e))))),t}r(),a.serializeEvent= /* The MIT License (MIT) - + Copyright (c) 2019 Ryan S. Morshead - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -9213,7 +9213,7 @@
- + @@ -9252,4 +9252,4 @@ })(); - \ No newline at end of file + diff --git a/examples/data/uploader/2025/01/20250128-043634-62efdd6a9000639d/ppp_figure_62efdd6a9000639d.html b/examples/data/uploader/2025/01/20250128-043634-62efdd6a9000639d/ppp_figure_62efdd6a9000639d.html index 4f13016..9e01b04 100644 --- a/examples/data/uploader/2025/01/20250128-043634-62efdd6a9000639d/ppp_figure_62efdd6a9000639d.html +++ b/examples/data/uploader/2025/01/20250128-043634-62efdd6a9000639d/ppp_figure_62efdd6a9000639d.html @@ -694,21 +694,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1426,21 +1426,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1511,21 +1511,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1656,21 +1656,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -1779,21 +1779,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -9044,21 +9044,21 @@ /*! * Copyright (c) Anaconda, Inc., and Bokeh Contributors * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: - * + * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. - * + * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * + * * Neither the name of Anaconda nor the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -9160,19 +9160,19 @@ "2cc1a33000": function _(e,t,a,r,n){function i(e){let t=null;return e&&(t=function(e){try{return{boundingClientRect:{...e.getBoundingClientRect()}}}catch{return{}}}(e),e.tagName in l&&l[e.tagName].forEach((a=>Object.assign(t,a(e))))),t}r(),a.serializeEvent= /* The MIT License (MIT) - + Copyright (c) 2019 Ryan S. Morshead - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -9222,19 +9222,19 @@ /* This file was adapted from https://github.com/uber/deck.gl/ the LICENSE below is preserved to comply with the original license. - + Copyright (c) 2015 - 2017 Uber Technologies, Inc. - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -9316,7 +9316,7 @@
- + @@ -9355,4 +9355,4 @@ })(); - \ No newline at end of file + diff --git a/mkdocs.yml b/mkdocs.yml index eea69e1..a1eabfc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -115,4 +115,4 @@ extra: social: - icon: fontawesome/brands/github link: https://github.com/Subaru-PFS/ets_target_database/ - name: Subaru-PFS/ets_target_database on GitHub \ No newline at end of file + name: Subaru-PFS/ets_target_database on GitHub diff --git a/pyproject.toml b/pyproject.toml index e436c65..96d24ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,15 @@ source = "https://github.com/Subaru-PFS/ets_target_database" pfs-targetdb-cli = "targetdb.cli.cli_main:app" [project.optional-dependencies] -dev = ["ipython", "pytest", "pytest-cov", "black", "ruff", "setuptools-scm>=8.0"] +dev = [ + "ipython", + "pytest", + "pytest-cov", + "black", + "ruff", + "pre-commit", + "setuptools-scm>=8.0", +] doc = ["mkdocs<2", "mkdocs-material[imaging]"] [build-system] @@ -60,6 +68,12 @@ markers = [ [tool.black] line-length = 88 +# Generated by setuptools-scm and gitignored; see the matching ruff +# extend-exclude below for why it's kept out of linting/formatting. +# alembic/ migrations are historical records and are deliberately left +# unformatted -- excluded here too so an editor's black extension with +# format-on-save doesn't rewrite them. +extend-exclude = "(src/targetdb/_version\\.py|alembic/)" [tool.pdm.scripts] serve-doc = { shell = "mkdocs serve", help = "Start the dev server for doc preview" } @@ -78,27 +92,25 @@ gen-requirements = { cmd = [ ], help = "Generate requirements.txt" } [tool.ruff] -target-version = "py312" +# Matches requires-python (">=3.11"). Do not raise this without raising +# requires-python: with UP rules enabled, ruff rewrites code to the target +# version's syntax. +target-version = "py311" line-length = 88 -# line-length = 128 +# Generated by setuptools-scm and gitignored. It exists locally but not in a +# fresh CI checkout, so linting it makes the checked file set environment- +# dependent. +# alembic/ migrations are historical records and are deliberately not +# linted -- excluding it here (not just in the runners' arguments) keeps +# editors and a bare `ruff check .` in agreement with CI. +extend-exclude = ["src/targetdb/_version.py", "alembic"] [tool.ruff.lint] +# C4 is flake8-comprehensions, unrelated to C901 (mccabe), which stays off. +select = ["E", "W", "F", "I", "B", "C4", "UP"] ignore = [ - "F401", # module imported but unused - "F841", # local variable is assigned to but never used - "E501", # line too long, handled by black - "B008", # do not perform function calls in argument defaults - "C901", # too complex + "E501", # line too long -- black owns line length ] -# select = [ -# "E", # pycodestyle errors -# "W", # pycodestyle warnings -# "F", # pyflakes -# "I", # isort -# "B", # flake8-bugbear -# "C4", # flake8-comprehensions -# "UP", # pyupgrade -# ] [tool.setuptools] package-dir = { "" = "src" } diff --git a/src/targetdb/cli/cli_main.py b/src/targetdb/cli/cli_main.py index 3231aa1..f8182bb 100644 --- a/src/targetdb/cli/cli_main.py +++ b/src/targetdb/cli/cli_main.py @@ -3,7 +3,7 @@ import time from enum import Enum from pathlib import Path -from typing import Annotated, List, Optional +from typing import Annotated import rich import typer @@ -197,7 +197,7 @@ def checkdups( typer.Option("--skip-save-merged", help="Do not save the merged DataFrame."), ] = False, additional_columns: Annotated[ - List[str] | None, + list[str] | None, typer.Option( "--additional-columns", help="Additional columns to output for the merged file. (e.g., 'psf_mag_g' 'psf_mag_r'). " @@ -206,12 +206,16 @@ def checkdups( ), ] = None, check_columns: Annotated[ - List[str], + list[str], typer.Option( "--check-columns", help="Columns used to check for duplicates.", ), - ] = ["obj_id", "input_catalog_id", "version"], + ] = [ # noqa: B006 -- Typer option default; Typer does not mutate it + "obj_id", + "input_catalog_id", + "version", + ], file_format: Annotated[ PyArrowFileFormat, typer.Option( @@ -369,7 +373,7 @@ def diagram( ) def mdtable( output_file: Annotated[ - Optional[str], typer.Option("--output-file", "-o", help="Output file.") + str | None, typer.Option("--output-file", "-o", help="Output file.") ] = None, ): generate_schema_markdown(output_file=output_file) diff --git a/src/targetdb/models/proposal.py b/src/targetdb/models/proposal.py index 6fb75e2..1e48e6b 100644 --- a/src/targetdb/models/proposal.py +++ b/src/targetdb/models/proposal.py @@ -16,7 +16,7 @@ Base, comment_created_at, comment_updated_at, - partner, + partner, # noqa: F401 -- defensive: __init__ imports partner first; FK order-safe proposal_category, # proposal_grade, utcnow, diff --git a/src/targetdb/targetdb.py b/src/targetdb/targetdb.py index 154d888..7661431 100644 --- a/src/targetdb/targetdb.py +++ b/src/targetdb/targetdb.py @@ -3,16 +3,15 @@ import io import pandas as pd +from loguru import logger from sqlalchemy import create_engine, select from sqlalchemy.orm import sessionmaker from sqlalchemy.sql import text -from loguru import logger - from . import models -class TargetDB(object): +class TargetDB: # url = "postgresql://pfs@db-ics:5432/opdb" def __init__( diff --git a/src/targetdb/utils.py b/src/targetdb/utils.py index 9b75dce..e361dd6 100644 --- a/src/targetdb/utils.py +++ b/src/targetdb/utils.py @@ -239,7 +239,7 @@ def generate_schema_markdown(output_file=None): for t in Base.metadata.sorted_tables: - out_md += "\n## {:s}\n\n".format(t.name) + out_md += f"\n## {t.name:s}\n\n" df = pd.DataFrame( [], columns=["name", "type", "primary_key", "autoincrement", "comment"] @@ -1540,7 +1540,9 @@ def _check_existing_directory(local_dir, upload_id, force): def _download_zip_from_api(url, headers, verify_ssl, local_dir): """Download ZIP file from Web API.""" - response = requests.get(url, headers=headers, stream=True, timeout=300, verify=verify_ssl) + response = requests.get( + url, headers=headers, stream=True, timeout=300, verify=verify_ssl + ) response.raise_for_status() with tempfile.NamedTemporaryFile( @@ -1567,7 +1569,9 @@ def _extract_and_validate_zip(zip_path, upload_id, local_dir, force): # Validate directory structure pattern = re.compile(r"^pfs_target-\d{8}-\d{6}-" + re.escape(upload_id) + r"$") extracted_dirs = [ - d for d in tmp_extract_path.iterdir() if d.is_dir() and pattern.match(d.name) + d + for d in tmp_extract_path.iterdir() + if d.is_dir() and pattern.match(d.name) ] if len(extracted_dirs) == 0: @@ -1597,7 +1601,9 @@ def _extract_and_validate_zip(zip_path, upload_id, local_dir, force): return 1, "success" -def _process_single_upload(upload_id, webapi_url, headers, verify_ssl, local_dir, force): +def _process_single_upload( + upload_id, webapi_url, headers, verify_ssl, local_dir, force +): """Process a single upload_id download.""" # Skip empty or invalid upload_id if pd.isna(upload_id) or str(upload_id).strip() == "": @@ -1621,7 +1627,9 @@ def _process_single_upload(upload_id, webapi_url, headers, verify_ssl, local_dir try: zip_path = _download_zip_from_api(full_url, headers, verify_ssl, local_dir) try: - n_transfer, status = _extract_and_validate_zip(zip_path, upload_id, local_dir, force) + n_transfer, status = _extract_and_validate_zip( + zip_path, upload_id, local_dir, force + ) return status, n_transfer finally: zip_path.unlink() @@ -1640,7 +1648,9 @@ def _process_single_upload(upload_id, webapi_url, headers, verify_ssl, local_dir logger.error(str(e)) return "FAILED", 0 except Exception as e: - logger.error(f"Unexpected error while transferring data for upload_id: {upload_id}") + logger.error( + f"Unexpected error while transferring data for upload_id: {upload_id}" + ) logger.error(str(e)) return "FAILED", 0 diff --git a/tests/integration/test_catalog_active.py b/tests/integration/test_catalog_active.py index c669f42..2166bb9 100644 --- a/tests/integration/test_catalog_active.py +++ b/tests/integration/test_catalog_active.py @@ -16,9 +16,9 @@ def _read_active_flags(engine): def test_update_catalog_active_only_affects_target_row(engine, master_data, db_config): before = _read_active_flags(engine) - assert TARGET_CATALOG_ID in before, ( - f"expected input_catalog_id={TARGET_CATALOG_ID} from examples/data/input_catalogs.csv" - ) + assert ( + TARGET_CATALOG_ID in before + ), f"expected input_catalog_id={TARGET_CATALOG_ID} from examples/data/input_catalogs.csv" run_cli( "update-catalog-active", diff --git a/tests/integration/test_master_tables.py b/tests/integration/test_master_tables.py index 130d22e..3f142a7 100644 --- a/tests/integration/test_master_tables.py +++ b/tests/integration/test_master_tables.py @@ -10,7 +10,9 @@ # input_catalogs.csv, so it is checked separately below rather than via the # generic 1:1 CSV-to-table comparison. SIMPLE_MASTER_TABLES = [ - (table, filename) for table, filename in MASTER_TABLE_FILES if table != "input_catalog" + (table, filename) + for table, filename in MASTER_TABLE_FILES + if table != "input_catalog" ] diff --git a/tests/integration/test_pointings.py b/tests/integration/test_pointings.py index 84b4e1d..508905d 100644 --- a/tests/integration/test_pointings.py +++ b/tests/integration/test_pointings.py @@ -46,7 +46,9 @@ def test_user_pointing_only_for_flagged_catalogs(engine, pointing_data, target_d assert actual == 0 -def test_user_pointing_total_matches_flagged_catalogs(engine, pointing_data, target_data): +def test_user_pointing_total_matches_flagged_catalogs( + engine, pointing_data, target_data +): catalogs_df = pd.read_csv(INPUT_CATALOGS_CSV) flagged = catalogs_df[catalogs_df["is_user_pointing"]] diff --git a/tests/integration/test_setup.py b/tests/integration/test_setup.py index a38041c..d5b8c33 100644 --- a/tests/integration/test_setup.py +++ b/tests/integration/test_setup.py @@ -8,7 +8,9 @@ def test_q3c_extension_installed(engine, q3c_installed): with engine.connect() as conn: - extnames = {row[0] for row in conn.execute(text("SELECT extname FROM pg_extension"))} + extnames = { + row[0] for row in conn.execute(text("SELECT extname FROM pg_extension")) + } assert "q3c" in extnames diff --git a/tests/integration/test_targets.py b/tests/integration/test_targets.py index bdbbddd..9e3ec89 100644 --- a/tests/integration/test_targets.py +++ b/tests/integration/test_targets.py @@ -37,7 +37,7 @@ def test_input_catalogs_registered_with_upload_id(engine, target_data, catalogs_ "WHERE upload_id IS NOT NULL" ) ).fetchall() - registered = {name: upload_id for name, upload_id in rows} + registered = dict(rows) for _, row in catalogs_df.iterrows(): assert registered.get(row["input_catalog_name"]) == row["upload_id"] diff --git a/tests/test_clustering.py b/tests/test_clustering.py index f7dd077..1c43d9a 100644 --- a/tests/test_clustering.py +++ b/tests/test_clustering.py @@ -24,7 +24,9 @@ def test_run_clustering(): # returned_n_noises = [] for th in threshs: - labels = clustering_targets.run_clustering(ra, dec, distance_threshold=th) # noqa: F821 + labels = clustering_targets.run_clustering( # noqa: F821 + ra, dec, distance_threshold=th + ) print(f"{labels=}") n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0) # n_noise_ = list(labels).count(-1) diff --git a/tests/test_models.py b/tests/test_models.py index 77d8b59..fd254b7 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -3,6 +3,7 @@ # ref: https://github.com/Subaru-PFS/spt_operational_database/blob/master/tests/test_models.py from sqlalchemy.orm import aliased + from targetdb import models diff --git a/uv.lock b/uv.lock index b09118d..34401b5 100644 --- a/uv.lock +++ b/uv.lock @@ -182,6 +182,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, ] +[[package]] +name = "cfgv" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -319,6 +328,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] +[[package]] +name = "distlib" +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, +] + [[package]] name = "et-xmlfile" version = "2.0.0" @@ -351,6 +369,7 @@ dependencies = [ dev = [ { name = "black" }, { name = "ipython" }, + { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-cov" }, { name = "ruff" }, @@ -373,6 +392,7 @@ requires-dist = [ { name = "numpy", specifier = ">=2.0" }, { name = "openpyxl" }, { name = "pandas" }, + { name = "pre-commit", marker = "extra == 'dev'" }, { name = "psycopg2-binary" }, { name = "pyarrow" }, { name = "pytest", marker = "extra == 'dev'" }, @@ -397,6 +417,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] +[[package]] +name = "filelock" +version = "3.32.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/57/3ba6e6cb097f85b855b00163d169f35365f44277df044dcf96d55b8f62a3/filelock-3.32.2.tar.gz", hash = "sha256:c33351e1f49cae33414acbc6d56784e6ecee82514ec90795da1161fc4836b5b8", size = 217172, upload-time = "2026-07-29T22:46:04.895Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/e8/72f8cef9fdfeffe06213fe8508039396ee48daa0e3259457ed766173bfd6/filelock-3.32.2-py3-none-any.whl", hash = "sha256:87dd94cf281e586d135fa51132b8e3d9a598b316e90377a288663c9321036c82", size = 98830, upload-time = "2026-07-29T22:46:03.52Z" }, +] + [[package]] name = "ghp-import" version = "2.1.0" @@ -431,6 +460,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6c/79/3912a94cf27ec503e51ba493692d6db1e3cd8ac7ac52b0b47c8e33d7f4f9/greenlet-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7a34b13d43a6b78abf828a6d0e87d3385680eaf830cd60d20d52f249faabf39", size = 301964, upload-time = "2025-12-04T14:36:58.316Z" }, ] +[[package]] +name = "identify" +version = "2.6.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/63/51723b5f116cc04b061cb6f5a561790abf249d25931d515cd375e063e0f4/identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842", size = 99567, upload-time = "2026-04-17T18:39:50.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a", size = 99397, upload-time = "2026-04-17T18:39:49.221Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -697,6 +735,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + [[package]] name = "numpy" version = "2.4.0" @@ -877,6 +924,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] +[[package]] +name = "pre-commit" +version = "4.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/3a/ddb78f32a0814e66b18a099377a106a2dcdce92d86a034d69d65df9b256e/pre_commit-4.6.1.tar.gz", hash = "sha256:03e809865c7d178b9979d06c761fcbfe6808fdaded8581a745bb110e52050421", size = 198646, upload-time = "2026-07-21T20:56:58.225Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/49/bc925106abcdac498074f2cbe6137e94e09f418dd2b7775df5b577dc0313/pre_commit-4.6.1-py2.py3-none-any.whl", hash = "sha256:0e3b2942510d1fb34eec167a3ec57331bf8442122f1153a9fb8b58f5c49b2717", size = 226186, upload-time = "2026-07-21T20:56:57.064Z" }, +] + [[package]] name = "prompt-toolkit" version = "3.0.52" @@ -1050,6 +1113,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-discovery" +version = "1.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/b7/1581a8103855c43567776aa34135e5ec3c597346c23bfd10c7eb5e0b10a4/python_discovery-1.5.1.tar.gz", hash = "sha256:e2ea8b884cd1701f386eda8cf327b87743f1dc21b7f784470799537d95635384", size = 77200, upload-time = "2026-07-31T22:06:02.48Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/07/a89b539750a159d5101c4eb9fc84e2961f65cefbd5e0b7440b284471c0b0/python_discovery-1.5.1-py3-none-any.whl", hash = "sha256:ac07f44cade589d954e9d6a1e1468539fdddd2cf676beb51da73e0f156b7c932", size = 35752, upload-time = "2026-07-31T22:06:01.116Z" }, +] + [[package]] name = "pytokens" version = "0.3.0" @@ -1352,6 +1427,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] +[[package]] +name = "virtualenv" +version = "21.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/fa/18004e5cb15541ad2a68ff219c755233b012b12d4ec8663d06a258082bec/virtualenv-21.7.1.tar.gz", hash = "sha256:d0dbfaa5483487baea28d7210ef8d24c9d1bd0f10f449eeb215568825a9b334e", size = 5525237, upload-time = "2026-07-30T15:40:36.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/a7/ded126c19495158a05c7202b3389139839d4cf78d622d453867778e0f7a8/virtualenv-21.7.1-py3-none-any.whl", hash = "sha256:6394973f990536e34c05157179146c020284c42fe01da1dfeb0ba16c345280d9", size = 5504576, upload-time = "2026-07-30T15:40:34.512Z" }, +] + [[package]] name = "watchdog" version = "6.0.0"