Giter Site home page Giter Site logo

Make leader mutable? about pymarc HOT 14 CLOSED

edsu avatar edsu commented on June 26, 2024 4
Make leader mutable?

from pymarc.

Comments (14)

souzaluuk avatar souzaluuk commented on June 26, 2024

Maybe go to the list type and use the python getter / setter methods to make it easier.
But I do not know about the compatibility of the idea with the other versions of python.

from pymarc.

edsu avatar edsu commented on June 26, 2024

A list would seem to make more sense. We could consider a new major version of pymarc in order to break backwards compatibility.

from pymarc.

souzaluuk avatar souzaluuk commented on June 26, 2024

I can try, so we can see the best way.
What do you think?

from pymarc.

Wooble avatar Wooble commented on June 26, 2024

I think a list makes it harder to get at the pieces of the leader that use more than 1 character of the string.

I suspect a method would work better, although I don't have a good suggestion for a name or even the API.

MARC::Record solves my particular use case by having $record->encoding('UTF-8') set leader[9] to "a" and $record->encoding('MARC-8') set it to " ", although it's got nothing for changing other things in the leader besides the length/base address.

from pymarc.

herrboyer avatar herrboyer commented on June 26, 2024

Hi, we're facing the same kind of issue right now, not blocking at all, but I was wondering about creating a maybe backward compatible Leader object like this one :

class Leader:
    """Mutable leader.

    Usage:
    leader = Leader("00475cas a2200169 i 4500")
    leader[0:4]  # 00475
    leader.status  # "c"
    leader.status = "a"
    leader[6] = "b"
    leader.record_type  # "b"
    str(leader)  # "00475abs a2200169 i 4500"
    """

    def __init__(self, value: str):
        self.value = value

    def __getitem__(self, item) -> str:
        """leader[:4] == leader.length."""
        if isinstance(item, slice) or isinstance(item, int):
            return self.value[item]
        return getattr(self, item)

    def __setitem__(self, item, val):
        """leader[5] works, leader[0:4] too, as well as leader.status = "a"."""
        if isinstance(item, slice):
            self._update_value(start=item.start - 1, stop=item.stop + 1, val=val)
        elif isinstance(item, int):
            self._update_value(start=item - 1, stop=item + 1, val=val)
        else:
            setattr(self, item, val)

    def __str__(self) -> str:
        return self.value

    def _update_value(self, start: int, stop: int, val: str):
        """Replace the chars between `start` & `stop` to `val` in `self.value`."""
        start = max(0, start)
        stop = min(LEADER_LEN, stop)
        if len(val) != stop - start:
            raise Exception("val length should match the replaced chars")
        self.value = self.value[:start] + val + self.value[stop:]

    @property
    def length(self) -> str:
        return self.value[:4]

    @property
    def status(self) -> str:
        return self.value[5]

    @status.setter
    def status(self, status: str):
        self._update_value(start=4, stop=5, val=status)

    @property
    def record_type(self) -> str:
        return self.value[6]

    @record_type.setter
    def record_type(self, record_type: str):
        self._update_value(start=6, stop=7, val=record_type)

The idea would be to use it in Record self.leader = Leader(leader[0:10] + '22' + leader[12:20] + '4500'). It should be almost backward compatible with the leader as a string and provide helpful getters & setters to manipulate it.

It's a bit too much on the magic side of python with its heavy use of dunders though...

I could keep poking around if you think it could be a good solution to this issue.

from pymarc.

edsu avatar edsu commented on June 26, 2024

I really like this proposal @herrboyer. I'm curious to know what others think. Do you want to prepare a pull request?

from pymarc.

Wooble avatar Wooble commented on June 26, 2024

I sort of feel like just replacing the leader with a bytearray would be cleaner, although either way things are going to break :(

from pymarc.

herrboyer avatar herrboyer commented on June 26, 2024

Thanks for your feedback.

We'll quickly see how things will go as soon as I find some time to make a PR.

from pymarc.

edsu avatar edsu commented on June 26, 2024

@Wooble I actually don't see how much will break with @herrboyer's proposal. Does something pop out at you?

from pymarc.

Wooble avatar Wooble commented on June 26, 2024

My example workaround code in the original message in the issue, for one thing, although that one could be fixed by overriding __add__ and __radd__ on the Leader object. (Also it would be silly to be doing that anymore once the leader is mutable, but legacy code breaking is still annoying even if it's breaking because it's an ugly hack that is no longer necessary.)

Anything that just does a naive record.leader = 'some other leader' will give you a str instead of a Leader, which presumably will need to be handled on serialization or which will also fail. Also anything making the assumption that record.leader is a str object so it doesn't bother calling str() on it won't use __str__, and might break depending on what whoever's making that assumption does with it.

I'd be interested to see what breaks in the existing test suite just by simply dropping in a Leader and not changing anything else that uses record.leader. Probably no one should be doing most of the sorts of things with the leader that pymarc has to do internally, but it might point to any other gotchas.

from pymarc.

edsu avatar edsu commented on June 26, 2024

Good points, thanks @Wooble. So whatever the change it will probably be a major version change if we can't guarantee backwards compatibility.

from pymarc.

herrboyer avatar herrboyer commented on June 26, 2024

As you guessed @Wooble serialization was broken but easily fixed, let me now what you think of the PR.

from pymarc.

herrboyer avatar herrboyer commented on June 26, 2024

record.leader = record.leader[0:9] + 'a' + record.leader[10:] will work as expected, except record.leader would not be a Leader object anymore, but a simple string, which probably won't matter much on legacy code, don't you think @Wooble ?

I tried to do something about it but overriding add/radd won't solve it, as a slice returns a string not the Leader itself.

from pymarc.

Wooble avatar Wooble commented on June 26, 2024

Oh, right, you'd have to make the slicing return a weird partial Leader object for that to work, and that would definitely be going too far...

from pymarc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.