⚠️ Clean-Room / Educativo

Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.

Corrección de AttributeError: _framebuffer_copy_detailed_count

Fecha: 2025-12-29 Step ID: 0367 Estado: VERIFIED

Resumen

Se corrigió un AttributeError que ocurría durante la ejecución cuando el código intentaba acceder al atributo _framebuffer_copy_detailed_count que no estaba inicializado en la clase Viboy. El error se producía en el método run() cuando se intentaba verificar el contador antes de inicializarlo. Se agregó la inicialización del contador usando el patrón hasattr() antes de usarlo, siguiendo la misma convención que otros contadores similares en el código.

Concepto de Hardware

Este fix no está relacionado directamente con el hardware de la Game Boy, sino con la gestión de estado en el emulador. Sin embargo, es importante entender que los contadores de diagnóstico son herramientas útiles para rastrear el comportamiento del emulador sin afectar el rendimiento del bucle principal.

Inicialización Lazy de Atributos en Python

En Python, es común usar el patrón de "inicialización lazy" (perezosa) para atributos que solo se necesitan en ciertas condiciones. Este patrón consiste en:

  1. Verificar si el atributo existe usando hasattr()
  2. Inicializarlo solo si no existe
  3. Usarlo normalmente después de la verificación

Este patrón es útil cuando:

  • El atributo solo se necesita en ciertas condiciones (ej: cuando se activa el modo debug)
  • Se quiere evitar inicializar muchos atributos en el constructor si no se van a usar
  • Se necesita mantener compatibilidad con código que puede o no inicializar el atributo

Implementación

Problema Identificado

Durante la ejecución, se producía el siguiente error:

AttributeError: 'Viboy' object has no attribute '_framebuffer_copy_detailed_count'
  File "/media/fabini/8CD1-4C30/ViboyColor/src/viboy.py", line 1018, in run
    if self._framebuffer_copy_detailed_count <= 5:

El código intentaba acceder al atributo _framebuffer_copy_detailed_count sin verificar primero si existía, causando un AttributeError cuando el atributo no estaba inicializado.

Solución Implementada

Se agregó la inicialización del contador usando el patrón hasattr() antes de usarlo, siguiendo la misma convención que otros contadores similares en el código (como _framebuffer_copy_verify_count).

Código Antes (Incorrecto)

# 4. Verificar primeros 20 píxeles después de copiar
first_20_after = [fb_data[i] & 0x03 for i in range(min(20, len(fb_data)))]

if self._framebuffer_copy_detailed_count <= 5:  # ❌ AttributeError si no existe
    logger.info(f"[Viboy-Framebuffer-Copy-Detailed] First 20 indices after copy: {first_20_after}")

Código Después (Correcto)

# 4. Verificar primeros 20 píxeles después de copiar
first_20_after = [fb_data[i] & 0x03 for i in range(min(20, len(fb_data)))]

# Inicializar contador si no existe
if not hasattr(self, '_framebuffer_copy_detailed_count'):
    self._framebuffer_copy_detailed_count = 0

if self._framebuffer_copy_detailed_count <= 5:
    self._framebuffer_copy_detailed_count += 1
    logger.info(f"[Viboy-Framebuffer-Copy-Detailed] First 20 indices after copy: {first_20_after}")

Ubicaciones Corregidas

Se agregó la inicialización en dos lugares donde se usa el contador:

  1. Línea ~1018: Antes de verificar los primeros 20 píxeles después de copiar
  2. Línea ~1065: Antes de contar los índices en la copia (inicialización redundante por seguridad)

Archivos Afectados

  • src/viboy.py - Agregada inicialización de _framebuffer_copy_detailed_count en dos lugares (líneas ~1018-1020 y ~1065-1067)

Tests y Verificación

Se ejecutó una prueba rápida para verificar que el error se corrigió:

Comando Ejecutado

timeout 5 python3 main.py roms/tetris.gb 2>&1 | grep -E "(Error|AttributeError|_framebuffer_copy_detailed_count)"

Resultado

✅ El error de AttributeError: 'Viboy' object has no attribute '_framebuffer_copy_detailed_count' ya no aparece.

El código ahora inicializa el contador correctamente antes de usarlo, siguiendo el mismo patrón que otros contadores de diagnóstico en el código.

Fuentes Consultadas

  • Python Documentation: hasattr() - Función para verificar si un objeto tiene un atributo
  • Python Best Practices: Inicialización lazy de atributos

Integridad Educativa

Lo que Entiendo Ahora

  • Inicialización lazy: Es un patrón útil para atributos que solo se necesitan en ciertas condiciones, evitando inicializar muchos atributos en el constructor
  • hasattr(): Permite verificar si un objeto tiene un atributo antes de acceder a él, evitando AttributeError
  • Consistencia de código: Es importante seguir el mismo patrón que otros contadores similares en el código para mantener la consistencia

Lo que Falta Confirmar

  • Inicialización en __init__: Considerar si sería mejor inicializar todos los contadores de diagnóstico en el constructor para evitar este tipo de errores

Hipótesis y Suposiciones

Suposición: La inicialización lazy es preferible para contadores de diagnóstico que solo se usan en modo debug, ya que evita inicializar muchos atributos innecesarios cuando el modo debug está desactivado. Esta suposición está respaldada por el hecho de que otros contadores similares en el código usan el mismo patrón.

Próximos Pasos

  • [ ] Considerar inicializar todos los contadores de diagnóstico en el constructor para evitar errores similares
  • [ ] Verificar que no hay otros atributos que puedan tener el mismo problema
  • [ ] Continuar con las pruebas del renderizado después de la corrección del Step 0366