Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
work:2024-49 [2024/12/14 01:45] – [Pesquisa] magsilvawork:2024-49 [2024/12/14 01:49] (current) magsilva
Line 8: Line 8:
 ===== Pesquisa ===== ===== Pesquisa =====
   * Correção automática de programas   * Correção automática de programas
-    * Um problema que tive recentemente foi quanto a redefinição de módulos e funções da biblioteca básica do Python.+    * Um problema que tive recentemente foi quanto a redefinição de módulos (suas funçõesda biblioteca básica do Python. As funções que estão no módulo ''builtins'' é simples redefinir (basta definir a função manualmente, no escopo global), mas um módulo é importado durante a execução do programa (e qualquer definição no escopo global anterior seria sobreescrita).
     * Normalmente, poderíamos usar dublês (mocks) para sobrepor o comportamento de alguma função ou método de uma classe. No entanto, isso não é tecnicamente possível (ao menos com as ferramentas atuais) para os módulos e funções da biblioteca básica/padrão do Python (builtin).     * Normalmente, poderíamos usar dublês (mocks) para sobrepor o comportamento de alguma função ou método de uma classe. No entanto, isso não é tecnicamente possível (ao menos com as ferramentas atuais) para os módulos e funções da biblioteca básica/padrão do Python (builtin).
     * Mais especificamente, eu precisava sobreescrever o comportamento da função ''time'' do módulo ''time''     * Mais especificamente, eu precisava sobreescrever o comportamento da função ''time'' do módulo ''time''
Line 21: Line 21:
       * As classes a serem utilizadas estão definidas na variável ''sys.meta_path''. Basicamente, ao procurar por um nome (módulo, função ou variável), o Python percorre os objetos disponíveis nessa variável, utilizando-os para encontrar o que deseja.       * As classes a serem utilizadas estão definidas na variável ''sys.meta_path''. Basicamente, ao procurar por um nome (módulo, função ou variável), o Python percorre os objetos disponíveis nessa variável, utilizando-os para encontrar o que deseja.
     * Entendido isso, bastaria criar uma nova classe Finder e colocá-la no início do caminho.     * Entendido isso, bastaria criar uma nova classe Finder e colocá-la no início do caminho.
-    * Bom, nem tudo são flores. Por algum motivo muito estranho, **alguns** módulos builtins do Python não podem ser sobreescritos por esse mecanismo. Mais especificamente o módulo ''time'' não pode. No código de importação do módulo ''importlib'' é feito um grande esforço para não permitir a sobreescrita de módulos builtins. Na função ''_find_and_load()'' do ''_bootstrap.py'', antes de começar a busca pelo módulo é verificado se ele está presente em ''sys.modules' (um dicionário de nome de módulo para o módulo em si). Por exemplo, hoje, em minha máquina, tenho os seguintes módulos nessa variável (e olha o ''time'' lá no fim!): _abc, abc, abrt_exception_handler3, _ast, ast, atexit, builtins, _codecs, codecs, _collections, collections, _collections_abc, collections.abc, contextlib, copyreg, _datetime, datetime, dis, _distutils_hack, encodings, encodings.aliases, encodings.utf_8, encodings.utf_8_sig, enum, errno, _frozen_importlib, _frozen_importlib_external, _functools, functools, __future__, genericpath, google, _imp, importlib, importlib._abc, importlib._bootstrap, importlib._bootstrap_external, importlib.machinery, importlib.util, inspect, _io, io, itertools, keyword, linecache, logging, __main__, marshal, _opcode, opcode, _operator, operator, os, os.path, paste, platform, posix, posixpath, re, readline, re._casefix, re._compiler, re._constants, re._parser, reprlib, rlcompleter, _signal, site, _sitebuiltins, _sre, _stat, stat, _string, string, sys, syslog, systemd, systemd.id128, systemd._journal, systemd.journal, systemd._reader, textwrap, _thread, threading, **time**, token, _tokenize, tokenize, traceback, types, _uuid, uuid, _warnings, warnings, _weakref, weakref, _weakrefset, zipimport.+    * Bom, nem tudo são flores. Por algum motivo muito estranho, **alguns** módulos builtins do Python não podem ser sobreescritos por esse mecanismo. Mais especificamente o módulo ''time'' não pode. No código de importação do módulo ''importlib'' é feito um grande esforço para não permitir a sobreescrita de módulos builtins. Na função ''_find_and_load()'' do ''_bootstrap.py'', antes de começar a busca pelo módulo é verificado se ele está presente em ''sys.modules'' (um dicionário de nome de módulo para o módulo em si). Por exemplo, hoje, em minha máquina, tenho os seguintes módulos nessa variável (e olha o ''time'' lá no fim!): _abc, abc, abrt_exception_handler3, _ast, ast, atexit, builtins, _codecs, codecs, _collections, collections, _collections_abc, collections.abc, contextlib, copyreg, _datetime, datetime, dis, _distutils_hack, encodings, encodings.aliases, encodings.utf_8, encodings.utf_8_sig, enum, errno, _frozen_importlib, _frozen_importlib_external, _functools, functools, __future__, genericpath, google, _imp, importlib, importlib._abc, importlib._bootstrap, importlib._bootstrap_external, importlib.machinery, importlib.util, inspect, _io, io, itertools, keyword, linecache, logging, __main__, marshal, _opcode, opcode, _operator, operator, os, os.path, paste, platform, posix, posixpath, re, readline, re._casefix, re._compiler, re._constants, re._parser, reprlib, rlcompleter, _signal, site, _sitebuiltins, _sre, _stat, stat, _string, string, sys, syslog, systemd, systemd.id128, systemd._journal, systemd.journal, systemd._reader, textwrap, _thread, threading, **time**, token, _tokenize, tokenize, traceback, types, _uuid, uuid, _warnings, warnings, _weakref, weakref, _weakrefset, zipimport.
     * Minha primeira abordagem foi alterar o código da importação para que não ocorresse mais esse impedimento de sobreescrever elementos builtins. Isso funcionou! Colocarei o código a seguir, que sobreescreve o ''time.time()''. O código compreende a criação de duas classes, ''MissingNameFinder'' e ''MissingLoader'', responsáveis por procurar o nome e, ao não encontrá-lo, usar o ''MissingLoader'' para criar, em tempo de execução, o módulo (classe ''LazyModule''), constante ou função (classe ''LazyFunction''). O que sobrou é código aproveitado do ''importlib'':     * Minha primeira abordagem foi alterar o código da importação para que não ocorresse mais esse impedimento de sobreescrever elementos builtins. Isso funcionou! Colocarei o código a seguir, que sobreescreve o ''time.time()''. O código compreende a criação de duas classes, ''MissingNameFinder'' e ''MissingLoader'', responsáveis por procurar o nome e, ao não encontrá-lo, usar o ''MissingLoader'' para criar, em tempo de execução, o módulo (classe ''LazyModule''), constante ou função (classe ''LazyFunction''). O que sobrou é código aproveitado do ''importlib'':
 <code language="python"> <code language="python">
Line 747: Line 747:
 sys.meta_path.insert(0, name_finder) sys.meta_path.insert(0, name_finder)
 del(sys.modules["time"]) del(sys.modules["time"])
-time = __import__("time")+time = __import__("time"!
 print(1731593707.2131279) print(1731593707.2131279)
 print(time.time()) print(time.time())
 </code> </code>
 +    * Bom, em condições normais isso deveria funcionar. Agora já tenho um bom mecanismo para sobreescrever os módulos e suas funções em tempo de execução!