feat: add get_lockfile() method to ContentItem#444
Conversation
Add support for retrieving Python lockfiles (requirements.txt.lock) from
content items with managed Python environments.
This implements the GET /v1/content/{guid}/lockfile endpoint that was
added in Connect 2025.12.0.
Changes:
- Add ContentItem.get_lockfile() method with @requires(version="2025.12.0")
- Add 3 unit tests for success, version check, and error handling
- Add 2 integration tests for end-to-end validation
- Update integration Makefile to include Connect 2025.12.0
The method returns the Python lockfile as a string, which describes the
exact Python packages installed in Connect's managed environment.
Co-Authored-By: Claude <noreply@anthropic.com>
☂️ Python Coverage
Overall Coverage
New FilesNo new covered files... Modified Files
|
| # that the method exists and is callable on supported versions | ||
| content = self.client.content.create(name="example-version-check") | ||
| path = Path("../../../resources/connect/bundles/example-flask-minimal/bundle.tar.gz") | ||
| path = (Path(__file__).parent / path).resolve() |
There was a problem hiding this comment.
I'd love to see an helper in the test class for this "Path dance" (like self.example_bundle_path('example-flask-minimal'), as it's repeated in every test, but it's definitely out of scope.
src/posit/connect/content.py
Outdated
| """ | ||
| path = f"v1/content/{self['guid']}/lockfile" | ||
| response = self._ctx.client.get(path) | ||
| return response.text |
There was a problem hiding this comment.
I think we might want to return the Generated-By field too , as that contains the Python version for which the lockfile works, which is a necessary information to reuse the lockfile.
There was a problem hiding this comment.
What does the client side workflow look like for this? Maybe that can help inform what this method returns?
There was a problem hiding this comment.
rsconnect-python for example uses that information to create a new local virtual environment compatible with the deployed content, see https://github.com/posit-dev/rsconnect-python/blob/13b63b56a92c713172cfbaa2f19754492efec51a/rsconnect/main.py#L3185-L3204
There was a problem hiding this comment.
@tdstein I think the issue reported on Generated-By is stil pending right?
Is there a reason why we can't simply return a turple from the controller with both response.text and the generated-by value? I think that's more or less all we need in this context.
There was a problem hiding this comment.
Added two commits:
e7b1c84
uses a tuple to return the raw value of generated_by like you suggested
b5fb2e0 iterates further by adding a dataclass which parses out the python version for more convientally access.
Let me know which you prefer. Generally, I try to avoid using tuples in public sdks like this since (imo) they are harder to change without breaking downstream users.
There was a problem hiding this comment.
Regarding dataclass I'm usually not very fond of the idea of polluting the namespace with additional entities that bring no behavior and introduce additional levels of indirection for the data, but I understand that tuples are harder to migrate on long term.
I personally would have used a namedtuple in general, but I think that in this case, as we are also introducing helpers to parse the Generated-By header the Lockfile class implementation is the one that provides most value.
Flagging the PR as reviewed 👍
There was a problem hiding this comment.
Ah, I always forget about namedtuple! I guess that shows when I started programming in Python...
The method now returns (generated_by, lockfile_content) and raises ValueError if the server response is missing the Generated-By header. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Introduces a Lockfile dataclass that provides convenient access to: - generated_by: the raw Generated-By header value - python_version: parsed Python version (e.g., "3.11.4") - text: the lockfile content Also adds a write() method to easily save the lockfile to disk. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
Adds support for retrieving Python lockfiles (
requirements.txt.lock) from content items with managed Python environments.This implements the
GET /v1/content/{guid}/lockfileendpoint that was added in Connect 2025.12.0 (posit-dev/connect#35619).Changes
Implementation
ContentItem.get_lockfile()returns the Python lockfile as a string@requires(version="2025.12.0")enforces minimum Connect versionClientErrorwhen content doesn't have managed Python environmentTests
Usage
Test Coverage
All tests passing:
Related
🤖 Generated with Claude Code