Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ft: Add method to Specfile to Instantiate from string #458

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

p0tat0chip
Copy link

@p0tat0chip p0tat0chip commented Mar 12, 2025

TODO:

  • Write new tests or update the old ones to cover new functionality.
  • Update doc-strings where appropriate.
  • Update or write new documentation in packit/packit.dev.

Fixes

Related to #248

RELEASE NOTES BEGIN

Now supports creating specfile instance from a string.

RELEASE NOTES END

Copy link
Contributor

Copy link
Contributor

Build succeeded.
https://softwarefactory-project.io/zuul/t/packit-service/buildset/d3c72d139e844076807086e50e1a73b2

✔️ pre-commit SUCCESS in 2m 00s
✔️ specfile-tests-rpm-deps SUCCESS in 1m 03s
✔️ specfile-tests-pip-deps SUCCESS in 58s

@p0tat0chip p0tat0chip changed the title ft: Instantiate specfile from string ft: Add method to Specfile to Instantiate from string Mar 13, 2025
@nforro
Copy link
Member

nforro commented Mar 14, 2025

Thank you for the contribution!
However, I think this problem could be handled in a more elegant way, without using temporary files, and together with #206. The idea is to replace the internal Specfile._path attribute with a file-like object that could be either passed directly to the constructor or instantiated from a path using open() or from a string using StringIO.
The implementation would simply replace instances of Specfile._path.read_text() with something like Specfile._stream.read() and instances of Specfile._path.write_text() with something like Specfile._stream.write() if the file-like object is writable. It would also need to handle seeking, truncating, flushing etc. accordingly.

@p0tat0chip
Copy link
Author

p0tat0chip commented Mar 14, 2025

I tried implementing as described and converted even the path to a fileobject (self._stream = self._path.open("r+"))
But two tests were failing:

FAILED tests/integration/test_specfile.py::test_copy - TypeError: cannot pickle 'TextIOWrapper' instances
FAILED tests/integration/test_specfile.py::test_parse_if_necessary - TypeError: cannot pickle 'TextIOWrapper' instances

and this will fail for objects instantiated from string and open() as well. Not really sure how to handle this.

@nforro
Copy link
Member

nforro commented Mar 14, 2025

Right, that will require doing something similar to what is done in SpecParser:

def __deepcopy__(self, memo: Dict[int, Any]) -> "SpecParser":
result = self.__class__.__new__(self.__class__)
memo[self.id()] = result
for k, v in self.__dict__.items():
if k in ["spec", "tainted"]:
continue
setattr(result, k, copy.deepcopy(v, memo))
result.spec = None
result.tainted = False
return result

The _stream attribute will have to be skipped when deepcopying a Specfile instance, but the question is what should the copy get. For Specfile instantiated from a path it could be calling open() again on the same path, for Specfile instantiated from a string it could be creating a new StringIO instance and supplying it with the content of the original StringIO. For Specfile instantiated with a file-like object perhaps we could just disable deepcopying.

Copy link
Contributor

@p0tat0chip
Copy link
Author

p0tat0chip commented Mar 14, 2025

The tests are passing now. Currently:

  • Return a new StringIO instance for the ones instantiated from it.
  • Return a copy for the ones instantiated from path. They are still file-like objects from open().
  • Ignore and return None for file-like objects without path.

will write new tests for them.

Copy link
Contributor

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