linkinpycli 0.0.1__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.
@@ -0,0 +1,39 @@
1
+
2
+ name: CI
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Set up Python
18
+ uses: actions/setup-python@v6
19
+ with:
20
+ python-version-file: ".python-version"
21
+
22
+ - name: Set up uv
23
+ uses: astral-sh/setup-uv@v7
24
+ with:
25
+ version: "0.11.7"
26
+ enable-cache: true
27
+
28
+ - name: Install dependencies
29
+ run: uv sync
30
+
31
+ - name: Lint
32
+ run: uv run ruff check .
33
+
34
+ - name: Test
35
+ run: uv run pytest
36
+
37
+ - name: Build
38
+ run: uv run python -m build
39
+
@@ -0,0 +1,181 @@
1
+ .gitignore
2
+ plan.md
3
+ .DS_Store
4
+ uv.lock
5
+ # Ignore itself
6
+ .gitignore
7
+
8
+ # Byte-compiled / optimized / DLL files
9
+ __pycache__/
10
+ *.py[cod]
11
+ *$py.class
12
+
13
+ # C extensions
14
+ *.so
15
+
16
+ # Distribution / packagin
17
+ .Python
18
+ build/
19
+ develop-eggs/
20
+ dist/
21
+ downloads/
22
+ eggs/
23
+ .eggs/
24
+ lib/
25
+ lib64/
26
+ parts/
27
+ sdist/
28
+ var/
29
+ wheels/
30
+ share/python-wheels/
31
+ *.egg-info/
32
+ .installed.cfg
33
+ *.egg
34
+ MANIFEST
35
+
36
+ # PyInstaller
37
+ # Usually these files are written by a python script from a template
38
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
39
+ *.manifest
40
+ *.spec
41
+
42
+ # Installer logs
43
+ pip-log.txt
44
+ pip-delete-this-directory.txt
45
+
46
+ # Unit test / coverage reports
47
+ htmlcov/
48
+ .tox/
49
+ .nox/
50
+ .coverage
51
+ .coverage.*
52
+ .cache
53
+ nosetests.xml
54
+ coverage.xml
55
+ *.cover
56
+ *.py,cover
57
+ .hypothesis/
58
+ .pytest_cache/
59
+ cover/
60
+
61
+ # Translations
62
+ *.mo
63
+ *.pot
64
+
65
+ # Django stuff:
66
+ *.log
67
+ local_settings.py
68
+ db.sqlite3
69
+ db.sqlite3-journal
70
+
71
+ # Flask stuff:
72
+ instance/
73
+ .webassets-cache
74
+
75
+ # Scrapy stuff:
76
+ .scrapy
77
+
78
+ # Sphinx documentation
79
+ docs/_build/
80
+
81
+ # PyBuilder
82
+ .pybuilder/
83
+ target/
84
+
85
+ # Jupyter Notebook
86
+ .ipynb_checkpoints
87
+
88
+ # IPython
89
+ profile_default/
90
+ ipython_config.py
91
+
92
+ # pyenv
93
+ # For a library or package, you might want to ignore these files since the code is
94
+ # intended to run in multiple environments; otherwise, check them in:
95
+ # .python-version
96
+
97
+ # pipenv
98
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
99
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
100
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
101
+ # install all needed dependencies.
102
+ #Pipfile.lock
103
+
104
+ # UV
105
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ #uv.lock
109
+
110
+ # poetry
111
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
112
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
113
+ # commonly ignored for libraries.
114
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
115
+ #poetry.lock
116
+
117
+ # pdm
118
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
119
+ #pdm.lock
120
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
121
+ # in version control.
122
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
123
+ .pdm.toml
124
+ .pdm-python
125
+ .pdm-build/
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # SageMath parsed files
135
+ *.sage.py
136
+
137
+ # Environments
138
+ .env
139
+ .venv
140
+ env/
141
+ venv/
142
+ ENV/
143
+ env.bak/
144
+ venv.bak/
145
+
146
+ # Spyder project settings
147
+ .spyderproject
148
+ .spyproject
149
+
150
+ # Rope project settings
151
+ .ropeproject
152
+
153
+ # mkdocs documentation
154
+ /site
155
+
156
+ # mypy
157
+ .mypy_cache/
158
+ .dmypy.json
159
+ dmypy.json
160
+
161
+ # Pyre type checker
162
+ .pyre/
163
+
164
+ # pytype static type analyzer
165
+ .pytype/
166
+
167
+ # Cython debug symbols
168
+ cython_debug/
169
+
170
+ # PyCharm
171
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
172
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
173
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
174
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
175
+ #.idea/
176
+
177
+ # PyPI configuration file
178
+ .pypirc
179
+ .gptignore
180
+ .editorconfig
181
+ .python-version
@@ -0,0 +1,16 @@
1
+ repos:
2
+ - repo: https://github.com/pre-commit/pre-commit-hooks
3
+ rev: v5.0.0
4
+ hooks:
5
+ - id: check-merge-conflict
6
+ - id: check-case-conflict
7
+ - id: detect-private-key
8
+ - id: end-of-file-fixer
9
+ - id: trailing-whitespace
10
+
11
+ - repo: https://github.com/astral-sh/ruff-pre-commit
12
+ rev: v0.11.8
13
+ hooks:
14
+ - id: ruff
15
+ args: [--fix]
16
+ - id: ruff-format
@@ -0,0 +1,19 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [v0.0.1] - Date
11
+
12
+ ### Fixed
13
+
14
+
15
+ ### Added
16
+
17
+
18
+ ### Changed
19
+
@@ -0,0 +1,65 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
+
7
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
+
9
+ ## Our Standards
10
+
11
+ Examples of behavior that contributes to a positive environment for our community include:
12
+ - Demonstrating empathy and kindness toward other people
13
+ - Being respectful of differing opinions, viewpoints, and experiences
14
+ - Giving and gracefully accepting constructive feedback
15
+ - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
16
+ - Focusing on what is best not just for us as individuals, but for the overall community
17
+
18
+ Examples of unacceptable behavior include:
19
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
20
+ - Trolling, insulting or derogatory comments, and personal or political attacks
21
+ - Public or private harassment
22
+ - Publishing others’ private information, such as a physical or email address, without their explicit permission
23
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
24
+
25
+ ## Enforcement Responsibilities
26
+
27
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
28
+
29
+ Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
30
+
31
+ ## Scope
32
+
33
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces.
34
+
35
+ ## Enforcement
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [contact email]. All complaints will be reviewed and investigated promptly and fairly.
38
+
39
+ All community leaders are obligated to respect the privacy and security of the reporter of any incident.
40
+
41
+ ## Enforcement Guidelines
42
+
43
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
44
+
45
+ ### 1. Correction
46
+ **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
47
+ **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
48
+
49
+ ### 2. Warning
50
+ **Community Impact**: A violation through a single incident or series of actions.
51
+ **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
52
+
53
+ ### 3. Temporary Ban
54
+ **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
55
+ **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
56
+
57
+ ### 4. Permanent Ban
58
+ **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
59
+ **Consequence**: A permanent ban from any sort of public interaction within the community.
60
+
61
+ ## Attribution
62
+
63
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html)
64
+
65
+ For answers to common questions about this code of conduct, see [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq).
@@ -0,0 +1,79 @@
1
+ # Contributing to linkinpycli
2
+
3
+ Thanks for contributing. This guide keeps the local workflow simple and consistent.
4
+
5
+ ## Development Setup
6
+
7
+ Clone the repository and enter it:
8
+
9
+ ```bash
10
+ git clone https://github.com/YOUR_USERNAME/LinkinPyCLI.git
11
+ cd LinkinPyCLI
12
+ ```
13
+
14
+ Create the development environment:
15
+
16
+ ```bash
17
+ uv sync
18
+ uv run pre-commit install
19
+ ```
20
+
21
+ ## Daily Workflow
22
+
23
+ Create a branch for your work:
24
+
25
+ ```bash
26
+ git checkout -b feature/short-description
27
+ ```
28
+
29
+ Run the main local checks before opening a pull request:
30
+
31
+ ```bash
32
+ uv run pytest
33
+ uv run ruff check .
34
+ uv run ruff format .
35
+ uv run python -m build
36
+ ```
37
+
38
+ Or use the shorter `make` targets:
39
+
40
+ ```bash
41
+ make test
42
+ make lint
43
+ make format
44
+ make build
45
+ ```
46
+
47
+ ## Command Reference
48
+
49
+ - `uv sync`: create or update the local environment from `pyproject.toml`
50
+ - `uv run pytest`: run the test suite
51
+ - `uv run ruff check .`: run lint checks
52
+ - `uv run ruff format .`: format the codebase
53
+ - `uv run python -m build`: verify the package builds correctly
54
+
55
+ The repository also includes a `.python-version` file so local development and CI agree on the interpreter target.
56
+
57
+ ## Pull Requests
58
+
59
+ Before opening a pull request, please make sure:
60
+
61
+ - tests pass locally
62
+ - linting and formatting are clean
63
+ - the package builds successfully
64
+ - docs are updated if the workflow or public API changed
65
+ - notable changes are reflected in `CHANGELOG.md`
66
+
67
+ ## Code Style
68
+
69
+ This project keeps the toolchain intentionally small:
70
+
71
+ - Ruff for linting and formatting
72
+ - Pytest for tests
73
+ - pre-commit for git hook integration
74
+
75
+ Prefer small, focused changes with clear commit messages and matching tests when behavior changes.
76
+
77
+ ## Getting Help
78
+
79
+ Open an issue for bugs or feature requests, or contact the maintainers at bruno.msaraiva2@gmail.com if you need help.
@@ -0,0 +1,74 @@
1
+ # Getting Started
2
+
3
+ This project uses `uv` to manage the local development environment.
4
+
5
+ The `.python-version` file pins the interpreter version expected for local development and CI.
6
+
7
+ ## 1. Create the environment
8
+
9
+ ```bash
10
+ uv sync
11
+ ```
12
+
13
+ What it does:
14
+
15
+ - creates a virtual environment if needed
16
+ - installs the project in editable mode
17
+ - installs the default development and test dependency groups
18
+
19
+ ## 2. Install git hooks
20
+
21
+ ```bash
22
+ uv run pre-commit install
23
+ ```
24
+
25
+ What it does:
26
+
27
+ - enables local checks before each commit
28
+ - runs formatting and lightweight validation automatically
29
+
30
+ ## 3. Run the tests
31
+
32
+ ```bash
33
+ uv run pytest
34
+ ```
35
+
36
+ What it does:
37
+
38
+ - runs the test suite from `tests/`
39
+ - confirms the package imports correctly from the `src/` layout
40
+
41
+ ## 4. Run linting and formatting
42
+
43
+ ```bash
44
+ uv run ruff check .
45
+ uv run ruff format .
46
+ ```
47
+
48
+ What they do:
49
+
50
+ - `ruff check .` finds lint issues
51
+ - `ruff format .` applies consistent formatting
52
+
53
+ ## 5. Build the package
54
+
55
+ ```bash
56
+ uv run python -m build
57
+ ```
58
+
59
+ What it does:
60
+
61
+ - creates distribution artifacts in `dist/`
62
+ - verifies the package metadata and build configuration are valid
63
+
64
+ ## Optional Make Targets
65
+
66
+ If you like `make`, these commands wrap the same workflow:
67
+
68
+ ```bash
69
+ make sync
70
+ make test
71
+ make lint
72
+ make format
73
+ make build
74
+ ```
@@ -0,0 +1,22 @@
1
+
2
+ The MIT License (MIT)
3
+
4
+ Copyright (c) 2026 linkinpycli
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: linkinpycli
3
+ Version: 0.0.1
4
+ Summary: CLI finder for LinkinPy integration
5
+ Project-URL: Homepage, https://github.com/HenriquesLab/LinkinPy
6
+ Project-URL: Repository, https://github.com/HenriquesLab/LinkinPy
7
+ Project-URL: Issues, https://github.com/HenriquesLab/LinkinPy/issues
8
+ Project-URL: Changelog, https://github.com/HenriquesLab/LinkinPy/blob/main/CHANGELOG.md
9
+ Author-email: brunomsaraiva <bruno.msaraiva2@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE.txt
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+
20
+ # linkinpycli
21
+
22
+ CLI finder for LinkinPy integration
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ uv sync
28
+ uv run pytest
29
+ ```
30
+
31
+ The project pins its local development interpreter in `.python-version` and keeps package metadata in `pyproject.toml`.
32
+
33
+ ## Common Commands
34
+
35
+ ```bash
36
+ uv sync # create/update the local environment
37
+ uv run pytest # run the test suite
38
+ uv run ruff check . # lint the codebase
39
+ uv run ruff format . # format the codebase
40
+ uv run python -m build # build the source and wheel distributions
41
+ uv run pre-commit install
42
+ ```
43
+
44
+ If you prefer shorter aliases, the same workflow is available through `make`:
45
+
46
+ ```bash
47
+ make sync
48
+ make test
49
+ make lint
50
+ make format
51
+ make build
52
+ ```
53
+
54
+ ## Project Layout
55
+
56
+ ```text
57
+ src/linkinpycli/
58
+ tests/
59
+ pyproject.toml
60
+ .python-version
61
+ GETTING_STARTED.md
62
+ CONTRIBUTING.md
63
+ ```
64
+
65
+ ## Documentation
66
+
67
+ - Start with [GETTING_STARTED.md](GETTING_STARTED.md) for first-time setup
68
+ - See [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor workflow
69
+ - Track user-facing changes in [CHANGELOG.md](CHANGELOG.md)
@@ -0,0 +1,50 @@
1
+ # linkinpycli
2
+
3
+ CLI finder for LinkinPy integration
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ uv sync
9
+ uv run pytest
10
+ ```
11
+
12
+ The project pins its local development interpreter in `.python-version` and keeps package metadata in `pyproject.toml`.
13
+
14
+ ## Common Commands
15
+
16
+ ```bash
17
+ uv sync # create/update the local environment
18
+ uv run pytest # run the test suite
19
+ uv run ruff check . # lint the codebase
20
+ uv run ruff format . # format the codebase
21
+ uv run python -m build # build the source and wheel distributions
22
+ uv run pre-commit install
23
+ ```
24
+
25
+ If you prefer shorter aliases, the same workflow is available through `make`:
26
+
27
+ ```bash
28
+ make sync
29
+ make test
30
+ make lint
31
+ make format
32
+ make build
33
+ ```
34
+
35
+ ## Project Layout
36
+
37
+ ```text
38
+ src/linkinpycli/
39
+ tests/
40
+ pyproject.toml
41
+ .python-version
42
+ GETTING_STARTED.md
43
+ CONTRIBUTING.md
44
+ ```
45
+
46
+ ## Documentation
47
+
48
+ - Start with [GETTING_STARTED.md](GETTING_STARTED.md) for first-time setup
49
+ - See [CONTRIBUTING.md](CONTRIBUTING.md) for the contributor workflow
50
+ - Track user-facing changes in [CHANGELOG.md](CHANGELOG.md)
@@ -0,0 +1,41 @@
1
+ .PHONY: help sync sync-dev test lint format check build docs
2
+
3
+ help:
4
+ @echo "Available commands:"
5
+ @echo " sync Create/update the local environment with uv"
6
+ @echo " sync-dev Alias for sync"
7
+ @echo " test Run the test suite"
8
+ @echo " lint Run Ruff lint checks"
9
+ @echo " format Format the codebase with Ruff"
10
+ @echo " check Run lint, tests, and build"
11
+ @echo " build Build source and wheel distributions"
12
+ @echo " docs Generate API docs with pdoc"
13
+
14
+ sync:
15
+ uv sync
16
+
17
+ sync-dev:
18
+ uv sync
19
+
20
+ test:
21
+ uv run pytest
22
+
23
+ lint:
24
+ uv run ruff check .
25
+
26
+ format:
27
+ uv run ruff format .
28
+
29
+ check:
30
+ uv run ruff check .
31
+ uv run pytest
32
+ uv run python -m build
33
+
34
+ build:
35
+ uv run python -m build
36
+
37
+ docs:
38
+ rm -rf docs
39
+ uv run pdoc src/linkinpycli -o docs
40
+
41
+ .DEFAULT_GOAL := help
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.26.0"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "linkinpycli"
7
+ version = "0.0.1"
8
+ description = "CLI finder for LinkinPy integration"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE*"]
13
+ authors = [
14
+ { name = "brunomsaraiva", email = "bruno.msaraiva2@gmail.com" }
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Operating System :: OS Independent",
22
+ ]
23
+ dependencies = []
24
+
25
+ [project.scripts]
26
+ linkinpy-parse = "linkinpycli.linkinpycli:parse_linkinpy_scripts"
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/HenriquesLab/LinkinPy"
30
+ Repository = "https://github.com/HenriquesLab/LinkinPy"
31
+ Issues = "https://github.com/HenriquesLab/LinkinPy/issues"
32
+ Changelog = "https://github.com/HenriquesLab/LinkinPy/blob/main/CHANGELOG.md"
33
+
34
+ [dependency-groups]
35
+ dev = [
36
+ "build>=1.2.2",
37
+ "pdoc>=15.0.0",
38
+ "pre-commit>=4.2.0",
39
+ "ruff>=0.11.0",
40
+ ]
41
+ test = [
42
+ "pytest>=8.3.0",
43
+ "pytest-cov>=6.0.0",
44
+ "pytest-xdist>=3.6.1",
45
+ ]
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["src/linkinpycli"]
49
+
50
+ [tool.pytest.ini_options]
51
+ addopts = "-ra"
52
+ testpaths = ["tests"]
53
+
54
+ [tool.coverage.run]
55
+ source = ["linkinpycli"]
56
+ branch = true
57
+
58
+ [tool.coverage.report]
59
+ show_missing = true
60
+ skip_covered = true
61
+
62
+ [tool.uv]
63
+ default-groups = ["dev", "test"]
@@ -0,0 +1,47 @@
1
+ exclude = [
2
+ ".bzr",
3
+ ".direnv",
4
+ ".eggs",
5
+ ".git",
6
+ ".git-rewrite",
7
+ ".hg",
8
+ ".ipynb_checkpoints",
9
+ ".mypy_cache",
10
+ ".nox",
11
+ ".pants.d",
12
+ ".pyenv",
13
+ ".pytest_cache",
14
+ ".pytype",
15
+ ".ruff_cache",
16
+ ".svn",
17
+ ".tox",
18
+ ".venv",
19
+ ".vscode",
20
+ "__pypackages__",
21
+ "_build",
22
+ "buck-out",
23
+ "build",
24
+ "dist",
25
+ "node_modules",
26
+ "site-packages",
27
+ "venv",
28
+ ]
29
+ line-length = 88
30
+ indent-width = 4
31
+ target-version = "py310"
32
+
33
+ [lint]
34
+ fixable = ["ALL"]
35
+ unfixable = []
36
+ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
37
+
38
+ [format]
39
+ quote-style = "double"
40
+ indent-style = "space"
41
+ skip-magic-trailing-comma = false
42
+ line-ending = "auto"
43
+ docstring-code-format = true
44
+ docstring-code-line-length = "dynamic"
45
+
46
+ [lint.pydocstyle]
47
+ convention = "google"
@@ -0,0 +1,83 @@
1
+ {
2
+ "scripts": [
3
+ {
4
+ "name": "linkinpy-esrrf",
5
+ "entry_point": "linkinpynanopyx.linkinpy_nanopyx:cli",
6
+ "arguments": [
7
+ {
8
+ "name": "first",
9
+ "datatype": "str | Path",
10
+ "required": true,
11
+ "default": null
12
+ },
13
+ {
14
+ "name": "second",
15
+ "datatype": "str | Path",
16
+ "required": true,
17
+ "default": null
18
+ },
19
+ {
20
+ "name": "magnification",
21
+ "datatype": "int",
22
+ "required": false,
23
+ "default": 5
24
+ },
25
+ {
26
+ "name": "radius",
27
+ "datatype": "float",
28
+ "required": false,
29
+ "default": 1.5
30
+ },
31
+ {
32
+ "name": "sensitivity",
33
+ "datatype": "float",
34
+ "required": false,
35
+ "default": 1.0
36
+ },
37
+ {
38
+ "name": "frames_per_timepoint",
39
+ "datatype": "int",
40
+ "required": false,
41
+ "default": 0
42
+ },
43
+ {
44
+ "name": "temporal_correlation",
45
+ "datatype": "str",
46
+ "required": false,
47
+ "default": "AVG"
48
+ },
49
+ {
50
+ "name": "use_fht",
51
+ "datatype": "bool",
52
+ "required": false,
53
+ "default": false
54
+ },
55
+ {
56
+ "name": "doIntensityWeighting",
57
+ "datatype": "bool",
58
+ "required": false,
59
+ "default": true
60
+ },
61
+ {
62
+ "name": "macro_pixel_correction",
63
+ "datatype": "bool",
64
+ "required": false,
65
+ "default": true
66
+ },
67
+ {
68
+ "name": "pad_edges",
69
+ "datatype": "bool",
70
+ "required": false,
71
+ "default": false
72
+ },
73
+ {
74
+ "name": "_force_run_type",
75
+ "datatype": "str | None",
76
+ "required": false,
77
+ "default": null
78
+ }
79
+ ],
80
+ "callable": "linkinpynanopyx.linkinpy_nanopyx:linkinpy_esrrf"
81
+ }
82
+ ]
83
+ }
File without changes
@@ -0,0 +1,18 @@
1
+ from importlib.metadata import EntryPoint, entry_points
2
+
3
+ LINKINPY_SCRIPT_PREFIX = "linkinpy"
4
+
5
+
6
+ def find_linkinpy_entry_points() -> list[EntryPoint]:
7
+ """Find all console-script entry points that start with 'linkinpy'."""
8
+ return [
9
+ ep
10
+ for ep in entry_points(group="console_scripts")
11
+ if ep.name.startswith(LINKINPY_SCRIPT_PREFIX)
12
+ and ep.name != "linkinpy-parse"
13
+ ]
14
+
15
+
16
+ def find_linkinpy_scripts() -> list[str]:
17
+ """Find all console scripts that start with 'linkinpy'."""
18
+ return [ep.name for ep in find_linkinpy_entry_points()]
@@ -0,0 +1,117 @@
1
+ from __future__ import annotations
2
+
3
+ import inspect
4
+ import json
5
+ from importlib import import_module
6
+ from importlib.metadata import EntryPoint
7
+ from pathlib import Path
8
+
9
+ from .crawler import find_linkinpy_entry_points
10
+
11
+
12
+ _IGNORED_SIGNATURE_PARAMETERS = {"argv", "args", "kwargs"}
13
+
14
+
15
+ def _format_datatype(annotation: object) -> str:
16
+ if annotation is inspect.Signature.empty:
17
+ return "Any"
18
+ if isinstance(annotation, str):
19
+ return annotation.replace("pathlib.", "")
20
+ if getattr(annotation, "__module__", "") == "builtins":
21
+ return annotation.__name__
22
+ return str(annotation).replace("pathlib.", "")
23
+
24
+
25
+ def _format_default(default: object) -> object:
26
+ if default is inspect.Signature.empty:
27
+ return None
28
+ if isinstance(default, (str, int, float, bool)) or default is None:
29
+ return default
30
+ return repr(default)
31
+
32
+
33
+ def _signature_arguments(callable_object: object) -> list[dict[str, object]]:
34
+ signature = inspect.signature(callable_object)
35
+ arguments = []
36
+ for name, parameter in signature.parameters.items():
37
+ if name in _IGNORED_SIGNATURE_PARAMETERS:
38
+ continue
39
+ if parameter.kind in (
40
+ inspect.Parameter.VAR_POSITIONAL,
41
+ inspect.Parameter.VAR_KEYWORD,
42
+ ):
43
+ continue
44
+ arguments.append(
45
+ {
46
+ "name": name,
47
+ "datatype": _format_datatype(parameter.annotation),
48
+ "required": parameter.default is inspect.Signature.empty,
49
+ "default": _format_default(parameter.default),
50
+ }
51
+ )
52
+ return arguments
53
+
54
+
55
+ def _entry_point_reference(entry_point: EntryPoint) -> str:
56
+ return f"{entry_point.module}:{entry_point.attr}"
57
+
58
+
59
+ def _resolve_callable(entry_point: EntryPoint) -> object:
60
+ module = import_module(entry_point.module)
61
+ entry_callable = entry_point.load()
62
+ entry_arguments = _signature_arguments(entry_callable)
63
+ if entry_arguments:
64
+ return entry_callable
65
+
66
+ expected_name = entry_point.name.replace("-", "_")
67
+ expected_callable = getattr(module, expected_name, None)
68
+ if callable(expected_callable):
69
+ return expected_callable
70
+
71
+ linkinpy_callables = [
72
+ obj
73
+ for name, obj in inspect.getmembers(module, inspect.isfunction)
74
+ if name.startswith("linkinpy") and name not in {"linkinpy_parse"}
75
+ ]
76
+ if len(linkinpy_callables) == 1:
77
+ return linkinpy_callables[0]
78
+
79
+ return entry_callable
80
+
81
+
82
+ def _script_details(entry_point: EntryPoint) -> dict[str, object]:
83
+ details: dict[str, object] = {
84
+ "name": entry_point.name,
85
+ "entry_point": _entry_point_reference(entry_point),
86
+ "arguments": [],
87
+ }
88
+ try:
89
+ callable_object = _resolve_callable(entry_point)
90
+ details["callable"] = (
91
+ f"{callable_object.__module__}:{callable_object.__name__}"
92
+ )
93
+ details["arguments"] = _signature_arguments(callable_object)
94
+ except Exception as exc:
95
+ details["error"] = str(exc)
96
+ return details
97
+
98
+
99
+ def parse_linkinpy_scripts() -> None:
100
+ """Find LinkinPy console scripts and write their argument metadata to scripts.json."""
101
+ scripts = [
102
+ _script_details(entry_point)
103
+ for entry_point in find_linkinpy_entry_points()
104
+ ]
105
+ output_path = Path.cwd() / "scripts.json"
106
+ output_path.write_text(
107
+ json.dumps({"scripts": scripts}, indent=2) + "\n",
108
+ encoding="utf-8",
109
+ )
110
+ print(f"Saved {len(scripts)} scripts to {output_path}")
111
+
112
+
113
+ class LinkinPyCLI:
114
+ """Minimal example class generated by the template."""
115
+
116
+ def run(self) -> int:
117
+ return 1
linkinpycli-0.0.1/t.py ADDED
@@ -0,0 +1,18 @@
1
+ from importlib.metadata import entry_points
2
+
3
+ prefix = "linkinpy"
4
+
5
+ matches = []
6
+
7
+ for ep in entry_points(group="console_scripts"):
8
+ if ep.name.startswith(prefix):
9
+ matches.append(
10
+ {
11
+ "script": ep.name,
12
+ "function": f"{ep.module}:{ep.attr}",
13
+ "callable": ep.load(),
14
+ }
15
+ )
16
+
17
+ for m in matches:
18
+ print(m["script"], "->", m["function"])
@@ -0,0 +1,6 @@
1
+ from linkinpycli.linkinpycli import LinkinPyCLI
2
+
3
+ def test_LinkinPyCLI() -> None:
4
+ my_class = LinkinPyCLI()
5
+ example_output = my_class.run()
6
+ assert example_output == 1