标签: monkeypatching

Python 中的猴子补丁会影响直接导入吗?

如果我猴子修补一个模块:

# mokeypatch.py
import other_module

def replacement(*args, **kwargs):
    pass

other_module.some_func = replacement
Run Code Online (Sandbox Code Playgroud)

这会影响直接导入的模块some_func,还是取决于导入的顺序?如果第三个模块是这样的:

# third_module.py
from other_module import some_func
Run Code Online (Sandbox Code Playgroud)

首先,运行此代码,然后运行我们的猴子补丁。会third_module.some_func是旧的吗?

python import namespaces monkeypatching

5
推荐指数
1
解决办法
1585
查看次数

猴子修补基础红宝石类是一种不好的做法吗?

我正在开发一个 ruby​​ 项目,我们计划使用 ruby​​ 字符串进行一些操作。有些操作很简单(例如计算单词数),而其他操作则更复杂(例如检查给定字符串是否采用正确的语言)。

实现此目的的一种可能方法是使用String额外的方法修补类,而不修改任何现有方法"some string".word_count,并添加和 等行为"some string".cjk?

另一种方法FileUtils是创建一个充满方法的类或模块,并始终使用字符串作为参数,例如OddClassName.word_count("some string")OddClassName.cjk?("some string")。由于可读性,我们更喜欢第一个。

我知道猴子修补第一个替代方案中描述的基本类可能会发生名称冲突。但是,如果这是主应用程序,而不是库,我应该担心它吗?

所以,问题是:

  • 向 ruby​​ 基类添加方法是一种不好的做法吗?如果是,是在所有情况下还是仅在某些情况下?
  • 实现这一目标的最佳方法是什么?
  • “OddClassName”的名称可能是什么?

请提出任何替代方案。

ruby monkeypatching

5
推荐指数
1
解决办法
1161
查看次数

当 rails 重新加载类时,初始化程序中的控制器猴子补丁丢失

我正在尝试在第三方 gem 中修改控制器类。准确地说,我正在尝试添加参数包装来设计控制器。在initializers/wrap_parameters.rb我添加了以下位:

Rails.application.config.after_initialize do
  DeviseController.class_eval do
    wrap_parameters :user, format: [:json]
  end
end
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时它工作得很好,但是当我修改我的一个控制器类时,参数包装立即停止工作。好像控制器类是在没有上述补丁的情况下重新加载的。

如何让我的猴子补丁持久化?

谢谢

ruby monkeypatching ruby-on-rails devise

5
推荐指数
1
解决办法
1216
查看次数

重写Promise构造函数及其方法

我想覆盖Promise构造函数和Promise中的then方法。因此,每当有人创建一个新的Promise对象时,首先将执行我的代码,然后将调用原始的promise构造函数。

同样,当有人调用Promise的.then函数时,首先将执行我的代码,然后将执行该then函数的回调。

我试过了

var bind = Function.bind;
var unbind = bind.bind(bind);

function instantiate(constructor, args) {
    return new (unbind(constructor, null).apply(null, args));
}

var oldProto = Promise.prototype;
Promise = function() {
    console.log("Promise instantiated");
    var promise = instantiate(Promise, arguments);
    return promise;
};
Promise.prototype = oldProto;
Run Code Online (Sandbox Code Playgroud)

当使用

var myFirstPromise = new Promise((resolve, reject) => {
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 250);
});

myFirstPromise.then((successMessage) => {
  console.log("Yay! " + successMessage);
});
Run Code Online (Sandbox Code Playgroud)

它导致无限循环,控制台充满了Promise instantiated日志。我还尝试了以下方法:

Promise = function(Promise) {
    MyPromise.prototype …
Run Code Online (Sandbox Code Playgroud)

javascript overriding prototype monkeypatching promise

5
推荐指数
0
解决办法
373
查看次数

用于 PySpark 的 Pickling 猴子补丁 Keras 模型

我试图实现的总体目标是将 Keras 模型发送给每个 Spark 工作器,以便我可以在应用于 DataFrame 列的 UDF 中使用该模型。为此,Keras 模型需要是可腌制的。

似乎很多人通过猴子修补 Model 类来成功腌制 keras 模型,如下面的链接所示:

http://zachmoshe.com/2017/04/03/pickling-keras-models.html

但是,我还没有看到任何关于如何与 Spark 一起执行此操作的示例。我的第一次尝试只是make_keras_picklable()在驱动程序中运行该函数,这允许我在驱动程序中腌制和取消腌制模型,但我无法在 UDF 中腌制模型。

def make_keras_picklable():
    "Source: https://zachmoshe.com/2017/04/03/pickling-keras-models.html"
    ...

make_keras_picklable()

model = Sequential() # etc etc

def score(case):
    ....
    score = model.predict(case)
    ...

def scoreUDF = udf(score, ArrayType(FloatType()))
Run Code Online (Sandbox Code Playgroud)

我得到的错误表明在 UDF 中解压模型没有使用猴子修补的模型类。

AttributeError: 'Sequential' object has no attribute '_built'
Run Code Online (Sandbox Code Playgroud)

看起来另一个用户在这篇 SO 帖子中遇到了类似的错误,答案是“make_keras_picklable()也在每个工作人员上运行”。没有给出如何做到这一点的例子。

我的问题是:召集make_keras_picklable()所有工人的适当方式是什么?

我尝试使用broadcast()(见下文)但得到了与上面相同的错误。

def make_keras_picklable():
    "Source: https://zachmoshe.com/2017/04/03/pickling-keras-models.html"
    ...

make_keras_picklable()
spark.sparkContext.broadcast(make_keras_picklable())

model = Sequential() …
Run Code Online (Sandbox Code Playgroud)

monkeypatching pickle apache-spark pyspark keras

5
推荐指数
1
解决办法
1175
查看次数

不能在 Python 单元测试中猴子补丁模块变量

我正在尝试测试模块:

包/模块.py

DATA_PATH = os.path.join(os.path.dirname(__file__), "data")
class SomeClass:
    def __init__(self):
        self.filename = os.path.join(DATA_PATH, "ABC.txt")
Run Code Online (Sandbox Code Playgroud)

在tests/module_test.py中我正在尝试做

from package import module
@patch("package.module.DATA_PATH", "data_path_here") # doesn't work
class TestSomeClass(unittest.TestCase):
    def setUp(self):
        module.DATA_PATH = "data_path_here" # doesn't work
        self.obj= SomeClass()

    @patch("package.module.DATA_PATH", "data_path_here") # doesn't work either
    def test_constructor(self):
        self.assertEqual(r"data_path_here\ABC.txt", self.obj.filename)
Run Code Online (Sandbox Code Playgroud)

但是 DATA_PATH 仍然没有被模拟出来。我想我尝试了所有可能的选项来模拟它,但它仍然返回原始路径而不是“data_path_here”

我究竟做错了什么?

编辑:它不是在 Python 单元测试框架修改全局变量的副本, 因为该解决方案不起作用

python unit-testing monkeypatching mocking

5
推荐指数
2
解决办法
2457
查看次数

pytest -monkeypatch 关键字参数默认值

我想测试一个函数的默认行为。我有以下几点:

# app/foo.py
DEFAULT_VALUE = 'hello'

def bar(text=DEFAULT_VALUE):
    print(text)
Run Code Online (Sandbox Code Playgroud)
# test/test_app.py
import app

def test_app(monkeypatch):
    monkeypatch.setattr('app.foo.DEFAULT_VALUE', 'patched')
    app.foo.bar()
    assert 0
Run Code Online (Sandbox Code Playgroud)

输出是hello; 不是我想要的。

一种解决方案是显式传递默认值: app.foo.bar(text=app.foo.DEFAULT_VALUE)

但我觉得有趣的是,当默认为全局范围时,这似乎不是问题:

# app/foo.py
DEFAULT_VALUE = 'hello'

def bar():
    print(DEFAULT_VALUE)
Run Code Online (Sandbox Code Playgroud)

输出是 patched

为什么会发生这种情况?还有比显式传递默认值更好的解决方案吗?

python monkeypatching pytest

5
推荐指数
1
解决办法
1188
查看次数

我如何使用 Python MonkeyPatch + Mock 来断言调用了一个函数

我有一个使用 MonkeyPatch 来测试某些功能的测试库。我想向这个库添加一个测试来测试对我的端点的请求调用 functionB()。

我使用 Mock() 库来创建模拟函数,然后我使用 MonkeyPatch.setattr() 传递它。但是,模拟函数永远不会被调用并且断言总是失败。我究竟做错了什么?

mock_function_B = Mock()
monkeypatch.setattr(file, 'function_B', mock_function_B)
params = json.dumps({'foo': "bar"})
res = client.post('/some_endpoint', headers=content_type_json, data=params)
assert res.status_code == 201
assert mock_function_B.call_count == 1
Run Code Online (Sandbox Code Playgroud)

我希望 call_count 为 1,因为我知道 some_endpoint 调用 function_B(并且从日志中,我看到它已被调用)但是,断言失败,因为 call_count 为 0。

python monkeypatching mocking pytest

5
推荐指数
1
解决办法
1243
查看次数

如何在 TypeScript 中导入 JavaScript 模块并转换为 TypeScript 命名空间

我有一个 JS 文件,猴子将一些功能修补到 3rd 方包上:

import L from 'leaflet';
import 'leaflet.pm';
import 'leaflet-textpath';

...
// do monkeypatching with all 3 packages.
// Only leaflet and leaflet.pm have typedef packages.
...

export default L;
Run Code Online (Sandbox Code Playgroud)

L(传单)有一个@types包含所有类型的包。

export as namespace L;

...
// export all type defs
...
Run Code Online (Sandbox Code Playgroud)

此时我不想将monkeypatch JS文件转换为TS。我可以处理没有对monkeypatched 功能进行类型检查的情况。

鉴于此,我试图将其monkeypatch.js作为L命名空间导入,以便我至少可以将它与L类型一起使用。

我尝试了以下各种方法,但没有任何运气:

import MonkeyPatch from 'monkey-patch';

const TS = MonkeyPatch as L;
Run Code Online (Sandbox Code Playgroud)

由于无法将命名空间L用作类型,因此这不起作用。

如何将monkeypatch JS 文件作为L命名空间导入以便进行类型检查L

javascript monkeypatching leaflet typescript typescript-typings

5
推荐指数
0
解决办法
152
查看次数

如何断言在pytest中调用了猴子补丁?

考虑以下:

class MockResponse:
    status_code = 200

    @staticmethod
    def json():
        return {'key': 'value'}
                                  # where api_session is a fixture
def test_api_session_get(monkeypatch, api_session) -> None:
    def mock_get(*args, **kwargs):
        return MockResponse()

    monkeypatch.setattr(requests.Session, 'get', mock_get)
    response = api_session.get('endpoint/') # My wrapper around requests.Session
    assert response.status_code == 200
    assert response.json() == {'key': 'value'}
    monkeypatch.assert_called_with(
        'endpoint/',
        headers={
            'user-agent': 'blah',
        },
    )
Run Code Online (Sandbox Code Playgroud)

我如何断言get我正在修补的被调用'/endpoint'headers?当我现在运行测试时,我收到以下失败消息:

FAILED test/utility/test_api_session.py::test_api_session_get - AttributeError: 'MonkeyPatch' object has no attribute 'assert_called_with'

我在这里做错了什么?感谢所有提前回复的人。

monkeypatching mocking pytest python-3.x python-requests

5
推荐指数
2
解决办法
995
查看次数