Weird Python error after extending a class

Weird Python error after extending a class

vkr.mobile
Participant Participant
952 Views
4 Replies
Message 1 of 5

Weird Python error after extending a class

vkr.mobile
Participant
Participant

I've asked this question on a Python Discord server, but the people that helped me there were not able to help me with this one. I'm hoping someone here can help me with the extended class of which Fusion Python says cannot access a member of the parent class.

 

The error I get is:

 

File "/Users/user/Library/Application Support/Autodesk/Autodesk Fusion 360/API/Scripts/NewScript1/modules/VKR/order.py", line 86, in __init__
app.log(str(self.__filesWithInfo))
AttributeError: 'PriorityFiles' object has no attribute '_PriorityFiles__filesWithInfo'

 

Since there are no line-numbers in the snippet, I've added a comment of #error in the line that produces the error. As far as I can see, I've correctly extended the FilesWithInfo class with the PriorityFiles class. Yet, the child-class does not seem to have access to the parent's class member self.__filesWithInfo. What am I doing wrong?

 

 

'''
Module to handle checking if there are files to be processed.
'''
import adsk.core, adsk.fusion, adsk.cam, traceback
import os
from ..VKR.options import OPTIONS

app = adsk.core.Application.get()

class OrderFile:
    ''' A file that has been found in the orders directory that needs to be prioritized '''

    def __init__( self, name: str ):
        self.name: str = name
        self._mod_time: int = None
        self._priority_level: int = 0

    
    def mod_time( self ) -> int:
        ''' Modification time '''
        return self._mod_time

    _time.setter
    def mod_time( self, time: int ):
        self._mod_time = time

    
    def priority_level( self ) -> int:
        ''' The priority level of the file '''
        return self._priority_level

    _level.setter
    def priority_level( self, priority: int ):
        self._priority_level = priority




class FilesWithInfo:
    ''' A holder for filenames with information stored about the files '''

    def __init__( self, files: list[ OrderFile ] = [] ):

        self.__filesWithInfo = files

    def add( self, file: OrderFile ):
        ''' Add a file with information to the storage '''

        self.__filesWithInfo.append( file )

    
    def length( self ):
        ''' Return the amount of stored files '''

        return len( self.__filesWithInfo )

    
    def priorities( self ) -> list[ OrderFile ] or None:
        ''' Return only the files that have priority or return None '''

        ret     = list( filter( lambda x: int( x.priority_level ) > 0, self.__filesWithInfo ))
        ret2    = PriorityFiles( ret )

        return ret2 if ret2.length > 0 else None

    
    def oldest( self, files: list[ OrderFile ] ) -> OrderFile:
        ''' Return the oldest file '''

        ret = None

        for x in files:
            if ret and x.mod_time < ret.mod_time:
                ret = x

        return ret




class PriorityFiles( FilesWithInfo ):
    ''' FilesWithInfo, but then for priority files only '''

    def __init__( self, files: list[ OrderFile ] = [] ):
        super().__init__( files )
        app.log(str(self.__filesWithInfo)) #error

    
    def highest( self ) -> OrderFile:
        ''' Return the filename that has the highest priority '''

        highest = None

        for f in self.__filesWithInfo:
            if highest:
                highest = f if f.priority_level > highest.priority_level else highest
            elif not highest:
                highest = f

        return highest
            



class Order:
    ''' Find files to process in the designated directory '''

    def __init__( self, path ):

        self.__currentDirList   = os.listdir()
        self.__currentFileInfo  = FilesWithInfo()
        self.__nextOrder        = ''
        self.__done             = True
        return

    def check( self ) -> OrderFile or None:
        ''' Check if there are orders that need to be processed '''
        
        self.__oldDirList       = self.__currentDirList
        self.__currentDirList   = os.listdir()
        self.__currentFileInfo  = FilesWithInfo( self._getFileInformation( self.__currentDirList ))

        if len( self.__currentDirList ) > 0:
            self.__nextOrder = self._selectOrder( self.__currentFileInfo )
            return self.__nextOrder
        else:
            return None

    def _selectOrder( self, fileInfo: FilesWithInfo ):
        ''' Select an order to be processed next by applying selection priority criteria '''

        
        prio        = fileInfo.priorities if isinstance(fileInfo, FilesWithInfo ) else None
        nextOrder   = None

        if isinstance( prio, PriorityFiles ):
            nextOrder = prio.highest
        elif isinstance( fileInfo, FilesWithInfo ):
            nextOrder = fileInfo.oldest

        return nextOrder

    def _getFileInformation( self, files: [str] ) -> FilesWithInfo:
        ''' Run through all the found files and return a Dictionary of OrderFiles '''
        
        ret = []

        for name in files:
            f_stats                     = os.stat( name )
            newFileInfo                 = OrderFile( name )
            OrderFile.mod_time          = f_stats.st_mtime
            OrderFile.priority_level    = self._getPriorityLevel( name )
            ret.append( OrderFile )
        
        return ret

    def _getPriorityLevel( self, name: str ) -> int:
        ''' Find if a filename has priority or not and if so, return the priority level '''
        
        if 'priority' in name:
            tmp = name.split( '_' )

            locationOfPriority = tmp.index( 'priority' ) + 1

            return tmp[ locationOfPriority ]
        else:
            return 0

 

 

 

 

0 Likes
Accepted solutions (2)
953 Views
4 Replies
Replies (4)
Message 2 of 5

Jorge_Jaramillo
Collaborator
Collaborator
Accepted solution

Hi,

 

It's hard to find the error with the information you provided.

Printing the callstack with traceback module is very handy:

import traceback
....
    try:
        app.log(str(self.__filesWithInfo)) #error
    except:
        app.log(f'Traceback: {traceback.format_exc()}')

 

Nevertheless, if your idea with the PriorityFiles class is to find the item with the highest priority, you can replace it with a lambda's function (see next snip) which could be implemented in a FilesWithInfo's method (that way you get rid out of the class PriorityFiles) :

max(file_list, key=lambda x: x.priority_level)

 

Also notice that it is strange that PriorityFiles being a subclass of FilesWithInfo, you use an instance of it own subclass PriorityFiles.

 

Finally, this is just a Python question, and nothing to be related with Fusion 360 API behavior.

Hope this could help you.

 

Regards,

Jorge

 

0 Likes
Message 3 of 5

vkr.mobile
Participant
Participant
Accepted solution

Apparently, properties with a double underscore are somewhat enforced as 'private' properties so that subclasses don't have easy access to them.

Thanks for the help

0 Likes
Message 4 of 5

Jorge_Jaramillo
Collaborator
Collaborator

Hi @vkr.mobile ,

 

I was referring to this method in FilesWithInfo:

    def priorities( self ) -> list[ OrderFile ] or None:
        ''' Return only the files that have priority or return None '''

        ret     = list( filter( lambda x: int( x.priority_level ) > 0, self.__filesWithInfo ))
        ret2    = PriorityFiles( ret )

        return ret2 if ret2.length > 0 else None

You are creating an object of a subclass (class PriorityFiles(FilesWithInfo) inside it's parent class (FilesWithInfo).

 

I'd suggest to add a highest() method (same as you have with oldest() method) inside FilesWithInfo class with the lambda expression I already send you and to remove the PriorityFiles class, which is causing the problem.  At least just to try.

 

Regards,

Jorge

 

0 Likes
Message 5 of 5

vkr.mobile
Participant
Participant

Yeah, not very elegant. I'll change it. Thanks for the tip

0 Likes