Skip to content

Conversation

@amw007
Copy link
Contributor

@amw007 amw007 commented Nov 6, 2025

As part of making Pyan useful tool again, migrate the packaging tool to uv from setup tools.

Created a issue for the same: #103

@amw007 amw007 marked this pull request as ready for review November 6, 2025 06:50
@Technologicat
Copy link
Owner

Great, thanks! That was quick :)

Reviewed. Mostly looks good to me.

Just two questions/comments:

  • test-python-versions.sh mentioned in the README update is missing from the commit?

  • It's a Python convention that the the running program knows its own version, for two reasons:

    • To support the --version command-line option, and
    • To have a de facto standard __version__ attribute.

    Pyan doesn't have a --version option, so that doesn't apply here. But it has previously had a __version__ attribute.

    The reason for having the attribute is that any other packages that import this one (to use it as a library) can get the version, e.g. for logging purposes. It's also a common idiom for checking a Python package version to just import it and then look at its .__version__. Or at least it used to be. I use pdm, pip, whatever - but sometimes also just one-liners like python -c 'import numpy; print(numpy.__version__)'.

    This is why I've had the version in __init__.py, and still do in my other projects. PDM, in particular, has a dynamic option for the version field, to automatically parse it from a .py source file, exactly for this use case.

    Googling around, it seems the recommended way nowadays, at least with UV, is the other way around. The single source of truth for the version number is in pyproject.toml, and then the __version__ attribute of the running copy is dynamically populated from the package metadata.

    See here:

    https://slhck.info/software/2025/10/01/dynamic-versioning-uv-projects.html
    https://stackoverflow.com/questions/75100102/get-app-version-from-pyproject-toml-inside-python-code

    So I'd recommend that instead of just removing the __version__ attribute in __init__.py, we could replace it with the following:

    import importlib.metadata
    
    __version__ = importlib.metadata.version("pyan3")

    where "pyan3" is the name of the installed package as set up in the project section in pyproject.toml.

    (The import should obviously go with the other imports at the beginning of the source file.)

    I'm not sure how well this approach works with editable mode, though (during development) - but perhaps not a major concern here.

Otherwise, looks great.

@amw007
Copy link
Contributor Author

amw007 commented Nov 6, 2025

Thanks for the quick review. :)

for the test script, I've forgot to add it, so I've added and updated in latest patch.
And, for the version, I wasn't aware of why its needed in the init.py till now.
For the projects I've worked on, its more are personal or internal team which never gone for a build or distribution. I've added it back as you've mentioned.

Thanks for the valuable insights, appreciating for your time to explaining.

Thanks & Regards,
A M

Copy link
Owner

@Technologicat Technologicat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed.

Two more small things, in the new test script.

Other files already OK.

EDIT: Ah, does uv.lock need to be in version control?

@amw007
Copy link
Contributor Author

amw007 commented Nov 7, 2025

Tests with 3.11

uv run python -m pytest tests -q
============================================================================ test session starts =============================================================================
platform linux -- Python 3.11.4, pytest-8.4.2, pluggy-1.6.0 -- pyan/.venv/bin/python3
cachedir: .cache
rootdir: pyan
configfile: pytest.ini
plugins: cov-7.0.0
collected 6 items

tests/test_analyzer.py::test_resolve_import_as PASSED [ 16%]
tests/test_analyzer.py::test_import_relative PASSED [ 33%]
tests/test_analyzer.py::test_resolve_use_in_class PASSED [ 50%]
tests/test_analyzer.py::test_resolve_use_in_function PASSED [ 66%]
tests/test_analyzer.py::test_resolve_package_without___init__ PASSED [ 83%]
tests/test_analyzer.py::test_resolve_package_with_known_root PASSED [100%]

=============================================================================== tests coverage ===============================================================================
coverage: platform linux, python #3.11.4-final-0

Name Stmts Miss Cover Missing

pyan/init.py 46 33 28% 11-20, 77-119

pyan/main.py 3 3 0% 3-6

pyan/analyzer.py 776 263 66% 100, 125-137, 188, 194, 206, 222-225, 255-268, 286-330, 384-386, 466, 470-475, 498, 500, 502, 512-516, 518-523, 611, 649-652, 657-660, 738, 752, 773-789, 794-809, 819-828, 831, 834-835, 838-839, 842-843, 846-847, 859-885, 894, 899-900, 903-909, 929-934, 939-979, 995, 1001-1005, 1013, 1015, 1082-1086, 1106, 1112-1138, 1141-1153, 1170, 1185-1190, 1204-1219, 1275, 1320-1324, 1342-1344, 1365, 1367, 1381, 1399-1406, 1419, 1421, 1424, 1434, 1468, 1501-1505, 1601, 1604, 1650, 1655-1657, 1691-1693, 1696-1697, 1703-1705, 1708-1709, 1714, 1733-1738, 1741-1742, 1745, 1758-1764

pyan/anutils.py 162 79 51% 13-14, 18-21, 43, 63, 93, 114-122, 125, 128, 131-143, 157-166, 174-200, 244-245, 252-263, 267-287

pyan/main.py 81 72 11% 23-243, 247
pyan/node.py 82 33 60% 11-15, 103-106, 111-117, 122-137, 156-159, 163-172, 179, 186

pyan/sphinx.py 64 64 0% 27-167

pyan/visgraph.py 149 128 14% 23-28, 31-36, 39-43, 46-47, 50-63, 67-72, 81-86, 89-93, 104-107, 110, 115-120, 124-251

pyan/writers.py 233 185 21% 17-21, 24, 27, 30, 33, 36-49, 52-57, 60-63, 66, 69, 72, 75, 78, 81, 84, 87, 92-94, 97-99, 102, 105-106, 111-116, 119-121, 124-131, 134-137, 140-141, 147-153, 156, 162-181, 186-206, 211-214, 217-236, 239-265, 268-272, 275-293, 296-316, 319-322

TOTAL 1596 860 46%
Coverage HTML written to dir htmlcov
============================================================================= 6 passed in 10.28s =============================================================================

@Technologicat Technologicat merged commit 535a2db into Technologicat:master Nov 7, 2025
@Technologicat
Copy link
Owner

Merged. Thanks very much for the build system migration!

The incompleteness of the existing automated tests is a good point. I opened an issue to track it, see #105.

We can discuss improvements to the tests further there - I might have some ideas for what kinds of test cases we need.

@Technologicat
Copy link
Owner

Technologicat commented Nov 7, 2025

One more thing - it's a separate issue, but since I can reach you here - could you add a quick guide (a few lines) for developers who aren't familiar with UV, or a link to an existing quickstart guide somewhere on the internet?

Particular questions I have:

  • Does UV create a venv for the project, or is the developer expected to do this separately (e.g. with the venv stdlib module or with conda)?
  • How to install an editable copy of the package, for easy development / interactive testing?
  • How to run tests - seems to be uv run python -m pytest tests -q, from your coverage report above :)
  • How to build the package - seems to be uv build, as you already documented in makedist.sh
  • Anything else important I'm forgetting right now?

For an example, see the install instructions I wrote for another open-source project that I'm currently building at work.

EDIT: Or maybe even better, the development mode instructions I wrote for mcpyrate.

Doesn't need to be that long - I'm just inefficient at explaining things compactly.

@Technologicat Technologicat mentioned this pull request Nov 7, 2025
@amw007
Copy link
Contributor Author

amw007 commented Nov 7, 2025

Hi,
thank you for merging the PR.

for tests, I agree and will continue on the new issue.
And, for the UV releate questions:

  • Yes, UV will create a self contained python envs in .venv folder, its using the venv package internally for the same. uv sync will install the project deps and current project as a editable dep by default.
  • uv sync - that's it, it'll install the deps and current project also as a editable one.
  • we can use like, uv run python -m pytest tests (this is tests dir) -q or simply uv run pytest tests from the project root.
  • uv build - to build it as a package.
  • I guess these are enough, and one more thing is, to install any new prj dep, we can use uv add <pkg> instead of pip install (as uv's python wont ship with pip default and which is slow) or uv run pip install <pkg> which is faster.

I've created a contribution doc and a simple util to get start with the uv cmds. Please review this PR #106 on your time let me know whether its useful or I can remove it, if its adding a more complexity.

Please let me know, if anything can be improved as well.

Thanks & Regards,
A M

@Technologicat
Copy link
Owner

Looks good. Merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants