[PATCH 1 of 6] largefiles: replace manifestdict.__contains__, don't extend class

Matt Harbison mharbison72 at gmail.com
Thu Mar 12 20:53:42 CDT 2015


On Thu, 12 Mar 2015 00:27:12 -0400, Martin von Zweigbergk  
<martinvonz at google.com> wrote:

> On Wed, Mar 11, 2015 at 6:00 PM Matt Harbison <mharbison72 at gmail.com>  
> wrote:
>
>> On Wed, 11 Mar 2015 00:23:33 -0400, Martin von Zweigbergk
>> <martinvonz at google.com> wrote:
>>
>> > # HG changeset patch
>> > # User Martin von Zweigbergk <martinvonz at google.com>
>> > # Date 1425946402 25200
>> > #      Mon Mar 09 17:13:22 2015 -0700
>> > # Node ID 1c855bc74470ff7f5a7805c085f95c279f0ef590
>> > # Parent  60c279ab7bd3bb08779cd6c74230d6739a63ebea
>> > largefiles: replace manifestdict.__contains__, don't extend class
>> >
>> > We're soon going to add an alternative manifest class
>> > (treemanifest). Rather than extending both those classes by
>> > largesfiles versions, let's replace the method on the manifest
>> > instances.
>> >
>> > diff -r 60c279ab7bd3 -r 1c855bc74470 hgext/largefiles/reposetup.py
>> > --- a/hgext/largefiles/reposetup.py   Fri Mar 06 22:43:47 2015 -0800
>> > +++ b/hgext/largefiles/reposetup.py   Mon Mar 09 17:13:22 2015 -0700
>> > @@ -10,7 +10,7 @@
>> >  import copy
>> >  import os
>> > -from mercurial import error, manifest, match as match_, util
>> > +from mercurial import error, match as match_, util
>> >  from mercurial.i18n import _
>> >  from mercurial import scmutil, localrepo
>> > @@ -38,17 +38,17 @@
>> >          def __getitem__(self, changeid):
>> >              ctx = super(lfilesrepo, self).__getitem__(changeid)
>> >              if self.lfstatus:
>> > -                class lfilesmanifestdict(manifest.manifestdict):
>> > -                    def __contains__(self, filename):
>> > -                        orig = super(lfilesmanifestdict,
>> > self).__contains__
>> > -                        return orig(filename) or
>> > orig(lfutil.standin(filename))
>> >                  class lfilesctx(ctx.__class__):
>> >                      def files(self):
>> >                          filenames = super(lfilesctx, self).files()
>> >                          return [lfutil.splitstandin(f) or f for f in
>> > filenames]
>> >                      def manifest(self):
>> >                          man1 = super(lfilesctx, self).manifest()
>> > -                        man1.__class__ = lfilesmanifestdict
>> > +                        orig = man1.__contains__
>> > +                        def __contains__(self, filename):
>> > +                            return (orig(filename) or
>> > +                                    orig(lfutil.standin(filename)))
>> > +                        man1.__contains__ =  
>> __contains__.__get__(man1)
>> >                          return man1
>> >                      def filectx(self, path, fileid=None,  
>> filelog=None):
>> >                          orig = super(lfilesctx, self).filectx
>>
>> Is this safe to do, given that _manifest is @propertycached in the base
>> class?  IOW, the first time manifest() is called, the original method is
>> replaced by the local method.  The second time it is called, is the
>> original local method now replaced with another local method (which  
>> calls
>> the original)?  If so, the result would still be correct, but it would  
>> get
>> more expensive each time this is called, when the file is not in the
>> manifest.
>>
>
> Good point! I didn't even think of thinking about that.
>
>
>> And just for my python learning, is there a reason you chose this  
>> instead
>> of having one class, call the base class method to get the object, and
>> update __class__?  That's basically what the surrounding code does for  
>> the
>> context object.
>
>
> No good reason; I simply didn't see it. Patch coming up.
>
>> I can't get my mind around how that is correct, given
>> that there are several different context base classes that can be in  
>> play
>> at the same time, but only one lfilescontext class.
>>
>
> It's a separate class for each call, right? It seems like the classes are
> dynamically created with ctx.__class__ as super type.

I have no idea how that works, and don't know where to look to find out.   
It's mind boggling to me that one instance of lfilesctx can have  
workingctx as a base class while another instance can have changectx as a  
base class *at the same time*.

I've seen hashes with a '+' on the end that shouldn't have been there  
(enabling largefiles when running test-hook.t shows one case), and I was  
wondering if it was because the base class wasn't dynamically created for  
each call.  I suppose a lot more would be broken if it didn't work as you  
describe though.

--Matt


More information about the Mercurial-devel mailing list