<div dir="ltr">hi,<br>for the convenience&nbsp; of&nbsp; all&nbsp; separately attaching the diffs <br><br>rgds,<br>jayaraj<br><br><div class="gmail_quote">On Fri, Sep 26, 2008 at 7:08 PM, Jayarajan Jn <span dir="ltr">&lt;<a href="mailto:jayarajan@musmo.com">jayarajan@musmo.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div dir="ltr"><div><div></div><div class="Wj3C7c">On Wed, Sep 24, 2008 at 8:58 PM, Jürgen kartnaller <span dir="ltr">&lt;<a href="mailto:juergen.kartnaller@gmail.com" target="_blank">juergen.kartnaller@gmail.com</a>&gt;</span> wrote:<br>


</div></div><div class="gmail_quote"><div dir="ltr"><div class="gmail_quote"><div><div></div><div class="Wj3C7c"><div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<div dir="ltr"><br><br><div class="gmail_quote"><div>On Wed, Sep 24, 2008 at 9:10 AM, Jayarajan Jn <span dir="ltr">&lt;<a href="mailto:jayarajan@musmo.com" target="_blank">jayarajan@musmo.com</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div dir="ltr">Hi Jürgen,<br><br>First of all thank you for your reply....<br>hmm you are right too... And i am comfortable with the explicit delete. But in my prototype for i have also added webDAV interface for managing extfile.... Then when a user deletes the extfile object through webDAV interface, the file remains there.... coz i don&#39;t know where to put my codes to call delete() in that case... And in my project there wont be more than one extfiles refering to same file! so in my case its ok to go for implicit delete! but its now working!</div>





</blockquote></div><div><br>You can never be sure if a file&nbsp; is only used once. If two user upload the same file only one copy is stored in extfile because both files have the same hash.</div></div></div></blockquote><div>


&nbsp;</div></div></div></div><div><div><div></div><div class="Wj3C7c">

Yea thats right ... we will never know how many extfile objects share the file. But there is enough resources to be able to know it.<br><br>We can add a reference counting&nbsp; functionality to HashDir class. And then we can keep track of this.... see my code bellow.... i have created a ReferenceCounter and it works fine. I can now implicitly delete with out worry. <br>


<br><br>But still when i use it in my zope application the &#39;__del__&#39; itself is *not* being invoked :?<br><br>plz tell me what you think....<br><br>referencecounter.py:-<br>------------------------------------------------------------------------------------<br>


import os<br>from persistent import Persistent<br><br>class ReferenceCounter(Persistent):<br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot; keeps track number of ExtBytesProperties <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; refering to the a file in HashDir&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;<br>


&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def __init__(self, dirpath):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.path = os.path.join(dirpath,&#39;refcount&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.counts={}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if os.path.exists(self.path): # else case? we will deal with it in commit!<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f= open(self.path)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for line in f:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest, count=line.split(&#39;,&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.counts[digest]=int(count)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.close()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def getCount(self,digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.counts.get(digest,0)<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def getTotalFiles(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return len(self.counts)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def addReference(self,digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newCount=self.getCount(digest)+1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.counts[digest]=newCount<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return newCount<br>


&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def removeReference(self,digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newCount=self.getCount(digest)-1<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newCount &gt; 0:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.counts[digest]=newCount<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elif newCount == 0:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.counts[digest]<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return newCount<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def commit(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f=open(self.path,&#39;w&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.write(&#39;\n&#39;.join(&quot;%s,%s&quot; % (digest,count) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for digest,count in self.counts.items()))<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.close()<br>--------------------------------------------------------------------------------<br>hashdir.py<br>--------------------------------------------------------------------------------<br>import sha<br>import os<br>


import stat<br>import tempfile<br>import shutil<br>from types import StringTypes, UnicodeType<br>import interfaces<br>from zope import interface<br>from persistent import Persistent<br>from zope.cachedescriptors.property import Lazy<br>


from referencecounter import ReferenceCounter<br><br>class HashDir(Persistent):<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;a directory holding files named after their sha1 hash&quot;&quot;&quot;<br><br>&nbsp;&nbsp;&nbsp; interface.implements(interfaces.IHashDir)<br>


&nbsp;&nbsp;&nbsp; _path = None<br><br>&nbsp;&nbsp;&nbsp; def __init__(self, path=None):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.path = path<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.refCounter = ReferenceCounter(self.etc)<br><br>&nbsp;&nbsp;&nbsp; def _setPath(self, path):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if path is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._path = os.path.abspath(path)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.tmp = os.path.join(self.path, &#39;tmp&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.var = os.path.join(self.path, &#39;var&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.etc = os.path.join(self.path, &#39;etc&#39;)<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._initPaths()<br><br>&nbsp;&nbsp;&nbsp; def _getPath(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._path<br><br>&nbsp;&nbsp;&nbsp; path = property(_getPath,_setPath)<br><br>&nbsp;&nbsp;&nbsp; def _initPaths(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for path in [self.path,self.var,self.tmp,self.etc]:<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not os.path.exists(path):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.mkdir(path)<br><br>&nbsp;&nbsp;&nbsp; def new(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;returns a new filehandle&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; handle, path = tempfile.mkstemp(prefix=&#39;dirty.&#39;,<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dir=self.tmp)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return WriteFile(self, handle, path)<br><br>&nbsp;&nbsp;&nbsp; def commit(self, f):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;commit a file, this is called by the file&quot;&quot;&quot;<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = f.sha.hexdigest()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; target = os.path.join(self.var, digest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if os.path.exists(target):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # we have that content so just delete the tmp file<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.remove(f.path)<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shutil.move(f.path, target)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.chmod(target, 0440)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.refCounter.addReference(digest)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.refCounter.commit()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return digest<br>


<br>&nbsp;&nbsp;&nbsp; def digests(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;returns all digests stored&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return os.listdir(self.var)<br><br>&nbsp;&nbsp;&nbsp; def getPath(self, digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if type(digest) not in StringTypes or len(digest) != 40:<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise ValueError, repr(digest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if type(self.var) is UnicodeType:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = unicode(digest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path = os.path.join(self.var, digest)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not os.path.isfile(path):<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raise KeyError, digest<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return path<br><br>&nbsp;&nbsp;&nbsp; def getSize(self, digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return os.path.getsize(self.getPath(digest))<br><br>&nbsp;&nbsp;&nbsp; def open(self, digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ReadFile(self.getPath(digest))<div><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def delete(self,digest):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;delete the file&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path=self.getPath(digest)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if os.path.exists(path):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.refCounter.removeReference(digest) is 0:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.remove(path)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.refCounter.commit()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return <br><br><br>class ReadFile(object):<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;A lazy read file implementation&quot;&quot;&quot;<br>


<br>&nbsp;&nbsp;&nbsp; interface.implements(interfaces.IReadFile)<br><br>&nbsp;&nbsp;&nbsp; def __init__(self, name, bufsize=-1):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://self.name" target="_blank">self.name</a> = name<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.digest = str(os.path.split(<a href="http://self.name" target="_blank">self.name</a>)[1])<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.bufsize=bufsize<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_len = None<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_file = None<br><br>&nbsp;&nbsp;&nbsp; @property<br>&nbsp;&nbsp;&nbsp; def _file(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not self.closed:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._v_file<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_file = file(<a href="http://self.name" target="_blank">self.name</a>, &#39;rb&#39;, self.bufsize)<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._v_file<br><br>&nbsp;&nbsp;&nbsp; @Lazy<br>&nbsp;&nbsp;&nbsp; def ctime(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return int(os.stat(<a href="http://self.name" target="_blank">self.name</a>)[stat.ST_CTIME])<br><br>&nbsp;&nbsp;&nbsp; @Lazy<br>&nbsp;&nbsp;&nbsp; def atime(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return int(os.stat(<a href="http://self.name" target="_blank">self.name</a>)[stat.ST_ATIME])<br>


<br>&nbsp;&nbsp;&nbsp; def __len__(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self._v_len is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_len = int(os.stat(<a href="http://self.name" target="_blank">self.name</a>)[stat.ST_SIZE])<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._v_len<br><br>&nbsp;&nbsp;&nbsp; def __repr__(self):<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &quot;&lt;ReadFile named %s&gt;&quot; % repr(self.digest)<br><br>&nbsp;&nbsp;&nbsp; @property<br>&nbsp;&nbsp;&nbsp; def closed(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;like file closed, but lazy&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._v_file is None or self._v_file.closed<br>


<br>&nbsp;&nbsp;&nbsp; def seek(self, offset, whence=0):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;see file.seek&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # we optimize when we have 0, 0 then we do not need to open<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # the file if it is closed, because on the next read we are at<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if offset==0 and whence==0 and self.closed:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._file.seek(offset, whence)<br><br>&nbsp;&nbsp;&nbsp; def tell(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;see file.tell&quot;&quot;&quot;<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.closed:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._file.tell()<br><br>&nbsp;&nbsp;&nbsp; def read(self, size=-1):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;see file.read&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._file.read(size)<br>


<br>&nbsp;&nbsp;&nbsp; def close(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;see file.close&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not self.closed:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_file.close()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._v_file = None<br><br>&nbsp;&nbsp;&nbsp; def fileno(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._file.fileno()<br>


<br>&nbsp;&nbsp;&nbsp; def __iter__(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._file.__iter__()<br><br><br>class WriteFile(object):<br><br>&nbsp;&nbsp;&nbsp; interface.implements(interfaces.IWriteFile)<br><br>&nbsp;&nbsp;&nbsp; def __init__(self, hd, handle, path):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.hd = hd<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.handle = handle<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.path = path<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sha = sha.new()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._pos = 0<br><br>&nbsp;&nbsp;&nbsp; def write(self, s):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.sha.update(s)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.write(self.handle, s)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._pos += len(s)<br>


<br>&nbsp;&nbsp;&nbsp; def commit(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;returns the sha digest and saves the file&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close(self.handle)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.hd.commit(self)<br><br>&nbsp;&nbsp;&nbsp; def tell(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;see file.tell&quot;&quot;&quot;<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self._pos<br><br>&nbsp;&nbsp;&nbsp; def abort(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;abort the write and delete file&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.close(self.handle)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.unlink(self.path)<br>--------------------------------------------------------------------------------------<br>


property.py<br>-------------------------------------------------------------------------------------<br>from zope import component<br>import interfaces<br>from cStringIO import StringIO<br><br>from datamanager import getFile, _storage<br>


<br>_marker = object()<br><br>BLOCK_SIZE = 1024*128<div><br><br>class ExtBytesProperty(object):<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;a property which&#39;s values are stored as external files&quot;&quot;&quot;<br>
<br>&nbsp;&nbsp;&nbsp; def __init__(self, name):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__name = name<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br></div><div><div></div><div>&nbsp;&nbsp;&nbsp; def __delete__(self,inst):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = inst.__dict__[self.__name]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.hd.delete(digest)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; @property<br>
&nbsp;&nbsp;&nbsp; def hd(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return component.getUtility(interfaces.IHashDir)<br><br>&nbsp;&nbsp;&nbsp; def __get__(self, inst, klass):<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if inst is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = inst.__dict__.get(self.__name, _marker)<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if digest is _marker:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return None<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getFile(digest)<br><br>&nbsp;&nbsp;&nbsp; def __set__(self, inst, value):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # ignore if value is None<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if value is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if inst.__dict__.has_key(self.__name):<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del inst.__dict__[self.__name]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Handle case when value is a string<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isinstance(value, unicode):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = value.encode(&#39;UTF-8&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isinstance(value, str):<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = StringIO(value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value.seek(0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = self.hd.new()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while True:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chunk = value.read(BLOCK_SIZE)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not chunk:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newDigest = f.commit()<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oldDigest = inst.__dict__.get(self.__name, _marker)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newDigest == oldDigest:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # we have no change, so we have to seek to zero<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # because this is normal behaviour when setting a<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # new value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if hasattr(_storage, &#39;dataManager&#39;):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newDigest in _storage.dataManager.files:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = _storage.dataManager.files[newDigest]<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.seek(0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst.__dict__[self.__name] = newDigest<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;<br></div></div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 1: oldDigest=newDigets though the object is still refering<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to same file f.comit would have incremented the reference by one.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; So to balance it oldDigest must be deleted.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case 2: object referencing a new file. So old file must be deleted<br>


&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if oldDigest is not _marker:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.hd.delete(oldDigest) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.write(chunk)<br><br>--------------------------------------------------------------------------------------<br>


file/file.py<br>--------------------------------------------------------------------------------------<br>from persistent import&nbsp; Persistent<br>from z3c.extfile.property import ExtBytesProperty<br>from interfaces import IExtFile<br>


from zope import interface<div><br><br>class ExtFile(Persistent):<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;A zope file implementation based on z3c.extfile&quot;&quot;&quot;<br><br>&nbsp;&nbsp;&nbsp; interface.implements(IExtFile)<br>
&nbsp;&nbsp;&nbsp; data = ExtBytesProperty(&#39;data&#39;)<br>
&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def __init__(self, data=&#39;&#39;, contentType=&#39;&#39;):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.data = data<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.contentType = contentType<br>&nbsp;&nbsp;&nbsp; <br></div>&nbsp;&nbsp;&nbsp; def __del__(self):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br><div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.data<br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;deleted data&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; <br></div>&nbsp;&nbsp;&nbsp; def delete(self):</div></div><div><div></div><div><div><div></div><div class="Wj3C7c"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.data<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; print &quot;deleted data via delete()&quot;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def getSize(self):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return len(self.data)<br>
--------------------------------------------------------------------------------------<br><br></div></div>rgds,<br><br>jayaraj<br>
<br><br></div></div></div><div><div></div><div class="Wj3C7c"><div><div></div><div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div dir="ltr">


<div class="gmail_quote"><div><div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div dir="ltr"><br>
<br>But form a general perspective you are correct.... may be HashDir will have to evolve to add reference counting feture just like python do! <br><div><div></div><div><br><div class="gmail_quote">On Wed, Sep 24, 2008 at 11:34 AM, Jürgen kartnaller <span dir="ltr">&lt;<a href="mailto:juergen.kartnaller@gmail.com" target="_blank">juergen.kartnaller@gmail.com</a>&gt;</span> wrote:<br>






<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div dir="ltr">Hi jayaraj,<br>it is definitely not a good idea to implicitily delete files.<br>






<br>What if two ExtFile objects reference the same file ?<br><br>Jürgen<br><br><div class="gmail_quote"><div><div></div><div>On Wed, Sep 24, 2008 at 4:37 AM, Jayarajan Jn <span dir="ltr">&lt;<a href="mailto:jayarajan@musmo.com" target="_blank">jayarajan@musmo.com</a>&gt;</span> wrote:<br>







</div></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div><div></div><div><div dir="ltr">Hi,<br>i am now doing some prototypes for my projects which will be dealing with tones of files. After a little scouting i decided to try z3c.extfile. Every thing works fine. But i found it strange that there is no delete feature in z3c.extfile. ie, even if i can delete a ExtFile object, the file in the hash directory is not getting deleted! and it keeps on accumulating... <br>








<br>So i&nbsp; thought i &#39;ll add a delete feature... but&nbsp; my&nbsp; __del__() approach doesn&#39;t&nbsp; work for me. but i added an additional delete() function too which can be invoked explicitly to delete the file before trying to delete ExtFile object.<br>








<br>i made following&nbsp; changes to the source...<br>inside&nbsp; z3c.extfile.file.file.ExtFile,<br><br>----------------------------------------------------------------------------------------------<br>class ExtFile(Persistent):<br>








<br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;A zope file implementation based on z3c.extfile&quot;&quot;&quot;<br><br>&nbsp;&nbsp;&nbsp; interface.implements(IExtFile)<br>&nbsp;&nbsp;&nbsp; data = ExtBytesProperty(&#39;data&#39;)<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def __init__(self, data=&#39;&#39;, contentType=&#39;&#39;):<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.data = data<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.contentType = contentType<br><br>&nbsp;&nbsp;&nbsp; # added the following lines#<br><br><i>&nbsp;&nbsp;&nbsp; def __del__(self):&nbsp;&nbsp; # &lt;- this is not being invoked when i try to delete an extfile object<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.data<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #print &quot;deleted data via destructor&quot;<br><br>&nbsp;&nbsp;&nbsp; def delete(self):&nbsp;&nbsp;&nbsp;&nbsp; # &lt;- added this to be able to manually able to delete files<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del self.data<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #print &quot;deleted data via delete()&quot;<br>








<br>&nbsp;&nbsp;&nbsp; # # # # # # #&nbsp; # # # # # # #&nbsp; #<br></i>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; def getSize(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return len(self.data)<br><br>----------------------------------------------------------------------------------------------<br><br>







and the &#39;data&#39; is a &#39;property&#39;&nbsp; (ExtBytesProperty)<br>
so i made following changes to z3c.extfile.property.ExtBytesProperty<br><br>----------------------------------------------------------------------------------------------<br>class ExtBytesProperty(object):<br><br>&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;a property which&#39;s values are stored as external files&quot;&quot;&quot;<br>








<br>&nbsp;&nbsp;&nbsp; def __init__(self, name):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.__name = name<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; # added the following lines#<br><br><i>&nbsp;&nbsp;&nbsp; def __delete__(self,inst):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = inst.__dict__[self.__name]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.hd.delete(digest)<br><br></i>&nbsp;&nbsp;&nbsp;  <i># # # # # # #&nbsp; # # # # # # #&nbsp; #<br><br><br><br></i>&nbsp;&nbsp;&nbsp; @property<br>&nbsp;&nbsp;&nbsp; def hd(self):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return component.getUtility(interfaces.IHashDir)<br><br>&nbsp;&nbsp;&nbsp; def __get__(self, inst, klass):<br>








<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if inst is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; digest = inst.__dict__.get(self.__name, _marker)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if digest is _marker:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return None<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getFile(digest)<br><br>&nbsp;&nbsp;&nbsp; def __set__(self, inst, value):<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # ignore if value is None<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if value is None:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if inst.__dict__.has_key(self.__name):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; del inst.__dict__[self.__name]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Handle case when value is a string<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isinstance(value, unicode):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = value.encode(&#39;UTF-8&#39;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if isinstance(value, str):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value = StringIO(value)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; value.seek(0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = self.hd.new()<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while True:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; chunk = value.read(BLOCK_SIZE)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if not chunk:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; newDigest = f.commit()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; oldDigest = inst.__dict__.get(self.__name, _marker)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newDigest == oldDigest:<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # we have no change, so we have to seek to zero<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # because this is normal behaviour when setting a<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # new value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if hasattr(_storage, &#39;dataManager&#39;):<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if newDigest in _storage.dataManager.files:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f = _storage.dataManager.files[newDigest]<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.seek(0)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inst.__dict__[self.__name] = newDigest<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f.write(chunk)<br>----------------------------------------------------------------------------------------------------<br><br>and at last added the real code which delete the file in hash directory too<br>








<br>i added following codes inside z3c.extfile.hashdir.HashDir class<br>---------------------------------------------------<br>def delete(self,digest):<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;&quot;&quot;delete the file&quot;&quot;&quot;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; path=self.getPath(digest)<br>








&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if os.path.exists(path):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os.remove(path)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return <br>----------------------------------------------------<br><br>Now, everything works fine when i try to delete an ExtFile object in ZODB, __del__() is not being invoked!!!!!<br>








<br>can anyone tell me how can i fix this??? <br><br>thanks in advance<br><br>jayaraj<br></div>
<br></div></div>_______________________________________________<br>
Zope-Dev maillist &nbsp;- &nbsp;<a href="mailto:Zope-Dev@zope.org" target="_blank">Zope-Dev@zope.org</a><br>
<a href="http://mail.zope.org/mailman/listinfo/zope-dev" target="_blank">http://mail.zope.org/mailman/listinfo/zope-dev</a><br>
** &nbsp;No cross posts or HTML encoding! &nbsp;**<br>
(Related lists -<br>
&nbsp;<a href="http://mail.zope.org/mailman/listinfo/zope-announce" target="_blank">http://mail.zope.org/mailman/listinfo/zope-announce</a><br>
&nbsp;<a href="http://mail.zope.org/mailman/listinfo/zope" target="_blank">http://mail.zope.org/mailman/listinfo/zope</a> )<br>
<br></blockquote></div><br></div>
</blockquote></div><br></div></div></div>
</blockquote></div></div></div><br></div>
</blockquote></div></div></div></div></div><br></div>
</div><br></div>
</blockquote></div><br></div>