kasm-pkg 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kasm_pkg-0.1.0/LICENSE +21 -0
- kasm_pkg-0.1.0/PKG-INFO +98 -0
- kasm_pkg-0.1.0/README.md +65 -0
- kasm_pkg-0.1.0/pyproject.toml +61 -0
- kasm_pkg-0.1.0/pyproject.toml.orig +52 -0
- kasm_pkg-0.1.0/src/kasm/__init__.py +70 -0
- kasm_pkg-0.1.0/src/kasm/_logging.py +42 -0
- kasm_pkg-0.1.0/src/kasm/api.py +803 -0
- kasm_pkg-0.1.0/src/kasm/covar.py +425 -0
- kasm_pkg-0.1.0/src/kasm/dataset.py +471 -0
- kasm_pkg-0.1.0/src/kasm/enrichment.py +502 -0
- kasm_pkg-0.1.0/src/kasm/fitting.py +1241 -0
- kasm_pkg-0.1.0/src/kasm/fixed_effects.py +741 -0
- kasm_pkg-0.1.0/src/kasm/kernels.py +641 -0
- kasm_pkg-0.1.0/src/kasm/ldm.py +305 -0
- kasm_pkg-0.1.0/src/kasm/model.py +426 -0
- kasm_pkg-0.1.0/src/kasm/random_effects.py +1020 -0
- kasm_pkg-0.1.0/src/kasm/simulation.py +220 -0
- kasm_pkg-0.1.0/src/kasm/suffstats.py +1734 -0
kasm_pkg-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kangcheng Hou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
kasm_pkg-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kasm-pkg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Kernel allelic series model for rare-variant heritability from exome summary statistics.
|
|
5
|
+
Keywords: genetics,heritability,rare variants,exome,summary statistics
|
|
6
|
+
Author: Kangcheng Hou
|
|
7
|
+
Author-email: Kangcheng Hou <kangchenghou@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Operating System :: MacOS
|
|
13
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
19
|
+
Requires-Dist: clarabel>=0.11.1
|
|
20
|
+
Requires-Dist: numpy
|
|
21
|
+
Requires-Dist: polars>=1.30
|
|
22
|
+
Requires-Dist: scipy
|
|
23
|
+
Requires-Dist: pytest ; extra == 'dev'
|
|
24
|
+
Requires-Dist: ruff ; extra == 'dev'
|
|
25
|
+
Requires-Dist: pre-commit ; extra == 'dev'
|
|
26
|
+
Requires-Dist: cvxpy>=1.7.5 ; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest-xdist>=3.8.0 ; extra == 'dev'
|
|
28
|
+
Requires-Python: >=3.12
|
|
29
|
+
Project-URL: Repository, https://github.com/KangchengHou/kasm-pkg
|
|
30
|
+
Project-URL: Documentation, https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# KASM
|
|
35
|
+
|
|
36
|
+
The Kernel Allelic Series Model (KASM) integrates functional annotations to
|
|
37
|
+
form a covariance kernel describing how allelic effects within a gene covary.
|
|
38
|
+
Using data from exome association studies, KASM estimates the heritability of
|
|
39
|
+
rare protein coding variants, its enrichment in structural and functional
|
|
40
|
+
annotations, and the concordance of effects between pairs of variants. Our
|
|
41
|
+
paper describes the methodology and applications in detail.
|
|
42
|
+
|
|
43
|
+
KASM can be installed with `pip install kasm-pkg` or `uv add kasm-pkg`.
|
|
44
|
+
|
|
45
|
+
[Documentation](https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md) · [Quick start](#quick-start) · [Development](#development)
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
Here is an example of using KASM to estimate heritability from exome-wide
|
|
50
|
+
association statistics. KASM takes variant-level association statistics: one
|
|
51
|
+
row per variant, with a canonical `chr:pos:ref:alt` ID, its gene, the effect
|
|
52
|
+
estimate and SE, allele frequency, and annotations used as burden weights.
|
|
53
|
+
Within-gene LD comes from an LD matrix file passed to `Dataset` as `ldm`;
|
|
54
|
+
without one, as in this toy example, KASM assumes no LD between variants.
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import kasm
|
|
58
|
+
import polars as pl
|
|
59
|
+
|
|
60
|
+
variant_df = pl.DataFrame(
|
|
61
|
+
{
|
|
62
|
+
"variant": [f"1:{pos}:A:G" for pos in range(100, 1000, 100)],
|
|
63
|
+
"gene": ["G1"] * 3 + ["G2"] * 3 + ["G3"] * 3,
|
|
64
|
+
"beta": [-0.12, 0.19, -0.15, 0.01, 0.17, -0.05, 0.15, 0.25, 0.22],
|
|
65
|
+
"se": [0.10, 0.12, 0.09, 0.11, 0.10, 0.13, 0.08, 0.10, 0.12],
|
|
66
|
+
"af": [2e-4, 5e-5, 3e-4, 1e-4, 2e-4, 4e-5, 5e-4, 2e-4, 6e-5],
|
|
67
|
+
"constant": 1.0,
|
|
68
|
+
"score1": [0.9, 0.1, 0.0, 0.9, 0.1, 0.0, 0.1, 0.8, 0.9],
|
|
69
|
+
"score2": [0.8, 0.3, 0.1, 0.7, 0.2, 0.0, 0.3, 0.6, 0.9],
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
print(variant_df)
|
|
73
|
+
|
|
74
|
+
dataset = kasm.Dataset(variant_df, beta_col="beta", se_col="se", sample_size=300_000)
|
|
75
|
+
model = kasm.Model(
|
|
76
|
+
dataset,
|
|
77
|
+
kasm.KernelOptions(
|
|
78
|
+
maf_col="af",
|
|
79
|
+
burden_cols=["constant", "score1", "score2"],
|
|
80
|
+
overdispersion_cols=["constant"],
|
|
81
|
+
),
|
|
82
|
+
).compute_suffstats()
|
|
83
|
+
fit = kasm.fit_random_effects(model, exclude_genes=[], n_jk_blocks=3)
|
|
84
|
+
print(f"heritability: {fit.hsq:.2e} (SE {fit.hsq_se:.2e})")
|
|
85
|
+
print(fit.components.select("kernel", "kernel_coef", "kernel_coef_se"))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
See more examples in the [documentation](https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md).
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
Development uses [uv](https://docs.astral.sh/uv/):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv run --extra dev pytest
|
|
96
|
+
uv run --extra dev pytest --full
|
|
97
|
+
uv run --extra dev pre-commit install
|
|
98
|
+
```
|
kasm_pkg-0.1.0/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# KASM
|
|
2
|
+
|
|
3
|
+
The Kernel Allelic Series Model (KASM) integrates functional annotations to
|
|
4
|
+
form a covariance kernel describing how allelic effects within a gene covary.
|
|
5
|
+
Using data from exome association studies, KASM estimates the heritability of
|
|
6
|
+
rare protein coding variants, its enrichment in structural and functional
|
|
7
|
+
annotations, and the concordance of effects between pairs of variants. Our
|
|
8
|
+
paper describes the methodology and applications in detail.
|
|
9
|
+
|
|
10
|
+
KASM can be installed with `pip install kasm-pkg` or `uv add kasm-pkg`.
|
|
11
|
+
|
|
12
|
+
[Documentation](https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md) · [Quick start](#quick-start) · [Development](#development)
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
Here is an example of using KASM to estimate heritability from exome-wide
|
|
17
|
+
association statistics. KASM takes variant-level association statistics: one
|
|
18
|
+
row per variant, with a canonical `chr:pos:ref:alt` ID, its gene, the effect
|
|
19
|
+
estimate and SE, allele frequency, and annotations used as burden weights.
|
|
20
|
+
Within-gene LD comes from an LD matrix file passed to `Dataset` as `ldm`;
|
|
21
|
+
without one, as in this toy example, KASM assumes no LD between variants.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import kasm
|
|
25
|
+
import polars as pl
|
|
26
|
+
|
|
27
|
+
variant_df = pl.DataFrame(
|
|
28
|
+
{
|
|
29
|
+
"variant": [f"1:{pos}:A:G" for pos in range(100, 1000, 100)],
|
|
30
|
+
"gene": ["G1"] * 3 + ["G2"] * 3 + ["G3"] * 3,
|
|
31
|
+
"beta": [-0.12, 0.19, -0.15, 0.01, 0.17, -0.05, 0.15, 0.25, 0.22],
|
|
32
|
+
"se": [0.10, 0.12, 0.09, 0.11, 0.10, 0.13, 0.08, 0.10, 0.12],
|
|
33
|
+
"af": [2e-4, 5e-5, 3e-4, 1e-4, 2e-4, 4e-5, 5e-4, 2e-4, 6e-5],
|
|
34
|
+
"constant": 1.0,
|
|
35
|
+
"score1": [0.9, 0.1, 0.0, 0.9, 0.1, 0.0, 0.1, 0.8, 0.9],
|
|
36
|
+
"score2": [0.8, 0.3, 0.1, 0.7, 0.2, 0.0, 0.3, 0.6, 0.9],
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
print(variant_df)
|
|
40
|
+
|
|
41
|
+
dataset = kasm.Dataset(variant_df, beta_col="beta", se_col="se", sample_size=300_000)
|
|
42
|
+
model = kasm.Model(
|
|
43
|
+
dataset,
|
|
44
|
+
kasm.KernelOptions(
|
|
45
|
+
maf_col="af",
|
|
46
|
+
burden_cols=["constant", "score1", "score2"],
|
|
47
|
+
overdispersion_cols=["constant"],
|
|
48
|
+
),
|
|
49
|
+
).compute_suffstats()
|
|
50
|
+
fit = kasm.fit_random_effects(model, exclude_genes=[], n_jk_blocks=3)
|
|
51
|
+
print(f"heritability: {fit.hsq:.2e} (SE {fit.hsq_se:.2e})")
|
|
52
|
+
print(fit.components.select("kernel", "kernel_coef", "kernel_coef_se"))
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See more examples in the [documentation](https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md).
|
|
56
|
+
|
|
57
|
+
## Development
|
|
58
|
+
|
|
59
|
+
Development uses [uv](https://docs.astral.sh/uv/):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv run --extra dev pytest
|
|
63
|
+
uv run --extra dev pytest --full
|
|
64
|
+
uv run --extra dev pre-commit install
|
|
65
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kasm-pkg"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Kernel allelic series model for rare-variant heritability from exome summary statistics."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
keywords = [
|
|
10
|
+
"genetics",
|
|
11
|
+
"heritability",
|
|
12
|
+
"rare variants",
|
|
13
|
+
"exome",
|
|
14
|
+
"summary statistics",
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
"Operating System :: MacOS",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"clarabel>=0.11.1",
|
|
29
|
+
"numpy",
|
|
30
|
+
"polars>=1.30",
|
|
31
|
+
"scipy",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[[project.authors]]
|
|
35
|
+
name = "Kangcheng Hou"
|
|
36
|
+
email = "kangchenghou@gmail.com"
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest",
|
|
41
|
+
"ruff",
|
|
42
|
+
"pre-commit",
|
|
43
|
+
"cvxpy>=1.7.5",
|
|
44
|
+
"pytest-xdist>=3.8.0",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[project.urls]
|
|
48
|
+
Repository = "https://github.com/KangchengHou/kasm-pkg"
|
|
49
|
+
Documentation = "https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md"
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["uv_build>=0.9.26,<0.10"]
|
|
53
|
+
build-backend = "uv_build"
|
|
54
|
+
|
|
55
|
+
[tool.uv.build-backend]
|
|
56
|
+
module-name = "kasm"
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
pythonpath = ["tests"]
|
|
61
|
+
addopts = "-q --strict-markers -n auto"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kasm-pkg"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Kernel allelic series model for rare-variant heritability from exome summary statistics."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
license-files = ["LICENSE"]
|
|
8
|
+
authors = [{ name = "Kangcheng Hou", email = "kangchenghou@gmail.com" }]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
keywords = ["genetics", "heritability", "rare variants", "exome", "summary statistics"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Intended Audience :: Science/Research",
|
|
14
|
+
"Operating System :: MacOS",
|
|
15
|
+
"Operating System :: POSIX :: Linux",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"clarabel>=0.11.1",
|
|
24
|
+
"numpy",
|
|
25
|
+
"polars>=1.30",
|
|
26
|
+
"scipy",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest",
|
|
32
|
+
"ruff",
|
|
33
|
+
"pre-commit",
|
|
34
|
+
"cvxpy>=1.7.5",
|
|
35
|
+
"pytest-xdist>=3.8.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Repository = "https://github.com/KangchengHou/kasm-pkg"
|
|
40
|
+
Documentation = "https://github.com/KangchengHou/kasm-pkg/blob/main/DOCS.md"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["uv_build>=0.9.26,<0.10"]
|
|
44
|
+
build-backend = "uv_build"
|
|
45
|
+
|
|
46
|
+
[tool.uv.build-backend]
|
|
47
|
+
module-name = "kasm"
|
|
48
|
+
|
|
49
|
+
[tool.pytest.ini_options]
|
|
50
|
+
testpaths = ["tests"]
|
|
51
|
+
pythonpath = ["tests"]
|
|
52
|
+
addopts = "-q --strict-markers -n auto"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""kasm — kernel allelic series model."""
|
|
2
|
+
|
|
3
|
+
from kasm import covar
|
|
4
|
+
from kasm._logging import configure_logging, logger
|
|
5
|
+
from kasm.api import (
|
|
6
|
+
RandomFit,
|
|
7
|
+
combine_mixed_effects,
|
|
8
|
+
combine_random_hsq,
|
|
9
|
+
fit_fixed_effects,
|
|
10
|
+
fit_random_effects,
|
|
11
|
+
)
|
|
12
|
+
from kasm.covar import (
|
|
13
|
+
CovarResult,
|
|
14
|
+
compute_random_covar,
|
|
15
|
+
)
|
|
16
|
+
from kasm.dataset import (
|
|
17
|
+
Dataset,
|
|
18
|
+
parse_variant_ids,
|
|
19
|
+
sort_variant_df,
|
|
20
|
+
)
|
|
21
|
+
from kasm.enrichment import EnrichResult, pool_enrichment
|
|
22
|
+
from kasm.fixed_effects import FixedFit
|
|
23
|
+
from kasm.fitting import jackknife_se
|
|
24
|
+
from kasm.kernels import KernelId, KernelLayout, KernelOptions
|
|
25
|
+
from kasm.ldm import LDM, LDMLoader
|
|
26
|
+
from kasm.model import Model
|
|
27
|
+
from kasm.simulation import (
|
|
28
|
+
simulate_burden_effects,
|
|
29
|
+
simulate_sumstats,
|
|
30
|
+
)
|
|
31
|
+
from kasm.suffstats import (
|
|
32
|
+
ExtraEnrichCols,
|
|
33
|
+
ExtSuffStats,
|
|
34
|
+
JKSuffStats,
|
|
35
|
+
SuffStats,
|
|
36
|
+
compute_jk_suffstats,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"LDM",
|
|
41
|
+
"CovarResult",
|
|
42
|
+
"Dataset",
|
|
43
|
+
"EnrichResult",
|
|
44
|
+
"ExtSuffStats",
|
|
45
|
+
"ExtraEnrichCols",
|
|
46
|
+
"FixedFit",
|
|
47
|
+
"JKSuffStats",
|
|
48
|
+
"KernelId",
|
|
49
|
+
"KernelLayout",
|
|
50
|
+
"KernelOptions",
|
|
51
|
+
"LDMLoader",
|
|
52
|
+
"Model",
|
|
53
|
+
"RandomFit",
|
|
54
|
+
"SuffStats",
|
|
55
|
+
"combine_mixed_effects",
|
|
56
|
+
"combine_random_hsq",
|
|
57
|
+
"covar",
|
|
58
|
+
"configure_logging",
|
|
59
|
+
"compute_jk_suffstats",
|
|
60
|
+
"compute_random_covar",
|
|
61
|
+
"fit_fixed_effects",
|
|
62
|
+
"fit_random_effects",
|
|
63
|
+
"jackknife_se",
|
|
64
|
+
"logger",
|
|
65
|
+
"parse_variant_ids",
|
|
66
|
+
"pool_enrichment",
|
|
67
|
+
"simulate_burden_effects",
|
|
68
|
+
"simulate_sumstats",
|
|
69
|
+
"sort_variant_df",
|
|
70
|
+
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Logging configuration for kasm workflows."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("kasm")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def configure_logging(
|
|
12
|
+
level: int | str = "INFO", *, filename: str | Path | None = None
|
|
13
|
+
) -> None:
|
|
14
|
+
"""Configure console logging, and optionally file logging, for ``kasm.*``.
|
|
15
|
+
|
|
16
|
+
Only handlers previously installed by this function are replaced. This
|
|
17
|
+
leaves application-owned handlers and the root logger untouched.
|
|
18
|
+
"""
|
|
19
|
+
resolved_level = (
|
|
20
|
+
logging._nameToLevel.get(level.upper()) if isinstance(level, str) else level
|
|
21
|
+
)
|
|
22
|
+
if not isinstance(resolved_level, int):
|
|
23
|
+
raise ValueError(f"unknown logging level {level!r}")
|
|
24
|
+
formatter = logging.Formatter(
|
|
25
|
+
"%(asctime)s %(module)s %(levelname)s %(message)s",
|
|
26
|
+
datefmt="%Y-%m-%d %H:%M:%S",
|
|
27
|
+
)
|
|
28
|
+
for handler in tuple(logger.handlers):
|
|
29
|
+
if getattr(handler, "_kasm_managed", False):
|
|
30
|
+
logger.removeHandler(handler)
|
|
31
|
+
handler.close()
|
|
32
|
+
handlers: list[logging.Handler] = [logging.StreamHandler()]
|
|
33
|
+
if filename is not None:
|
|
34
|
+
path = Path(filename)
|
|
35
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
handlers.append(logging.FileHandler(path, mode="a"))
|
|
37
|
+
for handler in handlers:
|
|
38
|
+
handler.setFormatter(formatter)
|
|
39
|
+
handler._kasm_managed = True
|
|
40
|
+
logger.addHandler(handler)
|
|
41
|
+
logger.setLevel(resolved_level)
|
|
42
|
+
logger.propagate = False
|