internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: Lightning-AI/pytorch-lightning

Issue:
Metatags are saved over and over in TensorBoardLogger when logging metrics
Is it okay that the metatags are saved every time metrics are logged in `TensorBoardLogger`? I find that it slows down training a bit.

[I found a related discussion.](https://github.com/PyTorchLightning/pytorch-lightning/pull/687/files#r367010524)

This is the part I'm talking about:

https://github.com/PyTorchLightning/pytorch-lightning/blob/83ab3eadb6bd32a761fd2e710a7a28778efa0360/pytorch_lightning/loggers/tensorboard.py#L201-L211

which is called by:

https://github.com/PyTorchLightning/pytorch-lightning/blob/83ab3eadb6bd32a761fd2e710a7a28778efa0360/pytorch_lightning/trainer/logging.py#L88-L91

which is in turn called by:

https://github.com/PyTorchLightning/pytorch-lightning/blob/83ab3eadb6bd32a761fd2e710a7a28778efa0360/pytorch_lightning/trainer/training_loop.py#L749-L757


Discussion:
mind send a fix PR? 🐰 
@Borda, I am trying to look into this as part of Hacktoberfest. If we stop saving "metatags" every time metrics are logged, don't we lose "metatags"? Please advise
@bryant1410 could you quantify what the bit slowdown is?
@ksasi we could just check it such a file already exists, assuming that the parameters do not change over a training...
cc: @PyTorchLightning/core-contributors 
> mind send a fix PR?

Sorry for the delay. Don't have bandwidth right now unfortunately. Will pin it and revisit it later.

> @bryant1410 could you quantify what the bit slowdown is?

Not working right now on the project with which I found it. However, my understanding is that the slowdown depends on the underlying system and hardware, but that it's small generally.
@Borda, thanks for your thoughts. I am interested in sending a PR for this. Let me know if this is fine.
@ksasi sure, go ahead... 

Resolving patch:
diff --git a/pytorch_lightning/loggers/tensorboard.py b/pytorch_lightning/loggers/tensorboard.py
--- a/pytorch_lightning/loggers/tensorboard.py
+++ b/pytorch_lightning/loggers/tensorboard.py
@@ -215,8 +215,9 @@ def save(self) -> None:
         # prepare the file path
         hparams_file = os.path.join(dir_path, self.NAME_HPARAMS_FILE)
 
-        # save the metatags file
-        save_hparams_to_yaml(hparams_file, self.hparams)
+        # save the metatags file if it doesn't exist
+        if not os.path.isfile(hparams_file):
+            save_hparams_to_yaml(hparams_file, self.hparams)
 
     @rank_zero_only
     def finalize(self, status: str) -> None:


Test patch:
Repository: Lightning-AI/pytorch-lightning

Issue:
DataModules should have a reference to the Trainer
## 🚀 Feature
The DataModule should have a reference to the Trainer, so attributes on the Trainer can be accessed during prepare_data, setup, and the dataloader methods. 

cc @nateraw 

### Motivation
Further uncouple datamodules and lightning modules. For instance, it can be useful for DataModules to know what the current epoch is during training. If I want to use the DataModules, I don't have access to this. However this is readily available if I define my `train_dataloader` in the LightningModule instead. 


### Pitch
We can follow the same setup that LightningModules have and how the trainer is initialized for them



Discussion:

Resolving patch:
diff --git a/pytorch_lightning/core/datamodule.py b/pytorch_lightning/core/datamodule.py
--- a/pytorch_lightning/core/datamodule.py
+++ b/pytorch_lightning/core/datamodule.py
@@ -147,6 +147,9 @@ def __init__(
         self._test_transforms = test_transforms
         self._dims = dims if dims is not None else ()
 
+        # Pointer to the trainer object
+        self.trainer = None
+
         # Private attrs to keep track of whether or not data hooks have been called yet
         self._has_prepared_data = False
         self._has_setup_fit = False


Test patch:
Repository: scoutapp/scout_apm_python

Issue:
Django: CursorWrapper expects a sequence or None for params 
As seen in this partial traceback:
```
  File "python3.6/site-packages/scout_apm/django/instruments/sql.py", line 29, in execute
    return self.cursor.execute(sql, params)
  File "python3.6/site-packages/django/db/backends/utils.py", line 80, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "python3.6/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
IndexError: tuple index out of range
```
Currently making a PR to hopefully fix =)


Discussion:

Resolving patch:
diff --git a/src/scout_apm/django/instruments/sql.py b/src/scout_apm/django/instruments/sql.py
--- a/src/scout_apm/django/instruments/sql.py
+++ b/src/scout_apm/django/instruments/sql.py
@@ -20,7 +20,7 @@
 
 
 class _DetailedTracingCursorWrapper(CursorWrapper):
-    def execute(self, sql, params=()):
+    def execute(self, sql, params=None):
         tr = TrackedRequest.instance()
         span = tr.start_span(operation='SQL/Query')
         span.tag('db.statement', sql)


Test patch:
Repository: scoutapp/scout_apm_python

Issue:
PyYAML security alert
Our application is getting a GitHub security alert from PyYAML, and this is the only package that has it as a dependency in our graph. It looks like this package no longer uses that package, but it is still declared as a dependency.

If this assessment is correct, the dependency should be removed from the `setup.py` and a new release upload to PyPI.

https://nvd.nist.gov/vuln/detail/CVE-2017-18342


Discussion:
Thank you for the report, I'll double check and get it removed and released early next week.

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@
             "core-agent-manager = scout_apm.core.cli.core_agent_manager:main"
         ]
     },
-    "install_requires": ["psutil", "PyYAML", "requests"],
+    "install_requires": ["psutil", "requests"],
     "keywords": "apm performance monitoring development",
     "classifiers": [
         "Development Status :: 5 - Production/Stable",


Test patch:
Repository: scoutapp/scout_apm_python

Issue:
Capture details of Celery Chains and Chords
Celery has some more advanced features to join multiple jobs into one. The agent needs testing and investigation into how they can be best instrumented.


Discussion:

Resolving patch:
diff --git a/src/scout_apm/celery.py b/src/scout_apm/celery.py
--- a/src/scout_apm/celery.py
+++ b/src/scout_apm/celery.py
@@ -29,6 +29,13 @@ def prerun_callback(task=None, **kwargs):
         else:
             tracked_request.tag("queue_time", queue_time)
 
+    task_id = getattr(task.request, "id", None)
+    if task_id:
+        tracked_request.tag("task_id", task_id)
+    parent_task_id = getattr(task.request, "parent_id", None)
+    if parent_task_id:
+        tracked_request.tag("parent_task_id", parent_task_id)
+
     delivery_info = task.request.delivery_info
     tracked_request.tag("is_eager", delivery_info.get("is_eager", False))
     tracked_request.tag("exchange", delivery_info.get("exchange", "unknown"))


Test patch:
diff --git a/tests/integration/test_celery.py b/tests/integration/test_celery.py
--- a/tests/integration/test_celery.py
+++ b/tests/integration/test_celery.py
@@ -62,6 +62,7 @@ def test_hello_eager(tracked_requests):
     assert result.result == "Hello World!"
     assert len(tracked_requests) == 1
     tracked_request = tracked_requests[0]
+    assert "task_id" in tracked_request.tags
     assert tracked_request.tags["is_eager"] is True
     assert tracked_request.tags["exchange"] == "unknown"
     assert tracked_request.tags["routing_key"] == "unknown"
@@ -80,6 +81,7 @@ def test_hello_worker(celery_app, celery_worker, tracked_requests):
     assert result == "Hello World!"
     assert len(tracked_requests) == 1
     tracked_request = tracked_requests[0]
+    assert "task_id" in tracked_request.tags
     assert tracked_request.tags["is_eager"] is False
     assert tracked_request.tags["exchange"] == ""
     assert tracked_request.tags["routing_key"] == "celery"
@@ -112,6 +114,23 @@ def test_hello_worker_header_preset(celery_app, celery_worker, tracked_requests)
     assert "queue_time" not in span.tags
 
 
+@skip_unless_celery_4_plus
+def test_hello_worker_chain(celery_app, celery_worker, tracked_requests):
+    with app_with_scout(app=celery_app) as app:
+        hello = app.tasks["tests.integration.test_celery.hello"]
+        result = (hello.si() | hello.si()).apply_async().get()
+
+    assert result == "Hello World!"
+    assert len(tracked_requests) == 2
+    assert [t.complete_spans[0].operation for t in tracked_requests] == [
+        "Job/tests.integration.test_celery.hello",
+        "Job/tests.integration.test_celery.hello",
+    ]
+    assert "parent_task_id" not in tracked_requests[0].tags
+    first_task_id = tracked_requests[0].tags["task_id"]
+    assert tracked_requests[1].tags["parent_task_id"] == first_task_id
+
+
 def test_no_monitor(tracked_requests):
     # With an empty config, "monitor" defaults to False.
     with app_with_scout(config={}) as app:
Repository: scoutapp/scout_apm_python

Issue:
Config to capture query string, not just path
When a request comes in, we capture `request.path`, which doesn't appear to capture any query string.

We should match the Ruby agent:
* Default to capturing the entire path and query string
* Config to not capture query string https://docs.scoutapm.com/#uri_reporting


Discussion:
👍 

This will vary by integration so may need a fix for each :)

Resolving patch:
diff --git a/src/scout_apm/core/config.py b/src/scout_apm/core/config.py
--- a/src/scout_apm/core/config.py
+++ b/src/scout_apm/core/config.py
@@ -233,6 +233,7 @@ def __init__(self):
             "name": "",
             "revision_sha": self._git_revision_sha(),
             "scm_subdirectory": "",
+            "uri_reporting": "filtered_params",
         }
 
     def _git_revision_sha(self):
diff --git a/src/scout_apm/core/web_requests.py b/src/scout_apm/core/web_requests.py
--- a/src/scout_apm/core/web_requests.py
+++ b/src/scout_apm/core/web_requests.py
@@ -1,5 +1,6 @@
 # coding=utf-8
 from scout_apm.compat import urlencode
+from scout_apm.core.context import AgentContext
 
 # Originally derived from:
 # 1. Rails:
@@ -35,6 +36,8 @@
 
 
 def create_filtered_path(path, query_params):
+    if AgentContext.instance.config.value("uri_reporting") == "path":
+        return path
     filtered_params = sorted(
         (
             (k, "[FILTERED]" if k.lower() in FILTER_PARAMETERS else v)


Test patch:
diff --git a/tests/unit/core/test_web_requests.py b/tests/unit/core/test_web_requests.py
--- a/tests/unit/core/test_web_requests.py
+++ b/tests/unit/core/test_web_requests.py
@@ -3,9 +3,17 @@
 
 import pytest
 
+from scout_apm.core.context import AgentContext
 from scout_apm.core.web_requests import create_filtered_path
 
 
+@pytest.fixture(autouse=True)
+def force_context():
+    # Since this function accesses the context, it needs to always be built
+    # TODO: remove when moving to a sensible singleton pattern
+    AgentContext.build()
+
+
 @pytest.mark.parametrize(
     "path, params, expected",
     [
@@ -25,3 +33,14 @@
 )
 def test_create_filtered_path(path, params, expected):
     assert create_filtered_path(path, params) == expected
+
+
+@pytest.mark.parametrize("path, params", [("/", []), ("/", [("foo", "ignored")])])
+def test_create_filtered_path_path(path, params):
+    # If config filtered_params is set to "path", expect we always get the path
+    # back
+    AgentContext.instance.config.set(uri_reporting="path")
+    try:
+        assert create_filtered_path(path, params) == path
+    finally:
+        AgentContext.instance.config.reset_all()
Repository: scoutapp/scout_apm_python

Issue:
Report error requests on Pyramid
Currently if an error occurs in a Pyramid request, we don't report it. Error cases can be just as useful to see so we should try and do this. It looks like it's possible by rearranging the existing code.


Discussion:

Resolving patch:
diff --git a/src/scout_apm/pyramid.py b/src/scout_apm/pyramid.py
--- a/src/scout_apm/pyramid.py
+++ b/src/scout_apm/pyramid.py
@@ -77,17 +77,18 @@ def scout_tween(request):
                     track_amazon_request_queue_time(amazon_queue_time, tracked_request)
 
             try:
-                response = handler(request)
+                try:
+                    response = handler(request)
+                finally:
+                    # Routing further down the call chain. So time it starting
+                    # above, but only name it if it gets a name
+                    if request.matched_route is not None:
+                        tracked_request.mark_real_request()
+                        span.operation = "Controller/" + request.matched_route.name
             except Exception:
                 tracked_request.tag("error", "true")
                 raise
 
-            # This happens further down the call chain. So time it starting
-            # above, but only name it if it gets to here.
-            if request.matched_route is not None:
-                tracked_request.mark_real_request()
-                span.operation = "Controller/" + request.matched_route.name
-
         finally:
             tracked_request.stop_span()
 


Test patch:
diff --git a/tests/integration/test_pyramid.py b/tests/integration/test_pyramid.py
--- a/tests/integration/test_pyramid.py
+++ b/tests/integration/test_pyramid.py
@@ -217,7 +217,13 @@ def test_server_error(tracked_requests):
     with app_with_scout() as app, pytest.raises(ValueError):
         TestApp(app).get("/crash/", expect_errors=True)
 
-    assert tracked_requests == []
+    assert len(tracked_requests) == 1
+    tracked_request = tracked_requests[0]
+    assert tracked_request.tags["path"] == "/crash/"
+    assert tracked_request.tags["error"] == "true"
+    assert len(tracked_request.complete_spans) == 1
+    span = tracked_request.complete_spans[0]
+    assert span.operation == "Controller/crash"
 
 
 def test_no_monitor(tracked_requests):
Repository: scoutapp/scout_apm_python

Issue:
Don't attempt to start on Windows (until supported)
As of right now, we error out when attempting to start on a Microsoft Windows system.

We should detect that the OS is not supported, and not start at all (and log that fact).



Discussion:

Resolving patch:
diff --git a/src/scout_apm/core/__init__.py b/src/scout_apm/core/__init__.py
--- a/src/scout_apm/core/__init__.py
+++ b/src/scout_apm/core/__init__.py
@@ -2,6 +2,7 @@
 from __future__ import absolute_import, division, print_function, unicode_literals
 
 import logging
+import sys
 from os import getpid
 
 from scout_apm.core.config import ScoutConfig
@@ -23,6 +24,10 @@ def install(*args, **kwargs):
         ScoutConfig().set(**kwargs["config"])
     context = AgentContext.build(config=ScoutConfig())
 
+    if sys.platform == "win32":
+        logger.info("APM Not Launching on PID: %s - Windows is not supported", getpid())
+        return False
+
     if not context.config.value("monitor"):
         logger.info(
             "APM Not Launching on PID: %s - Configuration 'monitor' is not true",


Test patch:
diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_core.py
@@ -0,0 +1,55 @@
+# coding=utf-8
+from __future__ import absolute_import, division, print_function, unicode_literals
+
+import logging
+import os
+import sys
+
+from scout_apm.api import Config
+from scout_apm.core import install
+from scout_apm.core.core_agent_manager import CoreAgentManager
+from tests.compat import mock
+
+
+def test_install_fail_windows(caplog):
+    with mock.patch.object(sys, "platform", new="win32"):
+        installed = install()
+
+    assert installed is False
+    assert (
+        "scout_apm.core",
+        logging.INFO,
+        "APM Not Launching on PID: %s - Windows is not supported" % os.getpid(),
+    ) in caplog.record_tuples
+
+
+def test_install_fail_monitor_false(caplog):
+    try:
+        installed = install(config={"monitor": False})
+    finally:
+        Config.reset_all()
+
+    assert installed is False
+    assert (
+        "scout_apm.core",
+        logging.INFO,
+        (
+            "APM Not Launching on PID: %s - Configuration 'monitor' is not true"
+            % os.getpid()
+        ),
+    ) in caplog.record_tuples
+
+
+def test_install_success(caplog):
+    with mock.patch.object(CoreAgentManager, "launch"):
+        try:
+            installed = install(config={"monitor": True})
+        finally:
+            Config.reset_all()
+
+    assert installed is True
+    assert (
+        "scout_apm.core",
+        logging.DEBUG,
+        "APM Launching on PID: %s" % os.getpid(),
+    ) in caplog.record_tuples
Repository: scoutapp/scout_apm_python

Issue:
Metadata should have language / language_version fields
Standardizing metadata between the various agents - put a fixed `python` string in `language`, and  the version (`3.4.1` or whatever) in `language_version`

Keep the existing fields for now. Need to ensure that the CoreAgent handles them nicely when missing.


Discussion:

Resolving patch:
diff --git a/src/scout_apm/core/metadata.py b/src/scout_apm/core/metadata.py
--- a/src/scout_apm/core/metadata.py
+++ b/src/scout_apm/core/metadata.py
@@ -29,6 +29,8 @@ def data(cls):
         try:
             data = {
                 "language": "python",
+                "language_version": "{}.{}.{}".format(*sys.version_info[:3]),
+                # Deprecated: (see #327)
                 "version": "{}.{}.{}".format(*sys.version_info[:3]),
                 "server_time": dt.datetime.utcnow().isoformat() + "Z",
                 "framework": scout_config.value("framework"),


Test patch:
Repository: scoutapp/scout_apm_python

Issue:
SQLAlchemy executemany not detected in hooks
In the Django ORM integration, we record `executemany` calls as the `SQL/Many` operation, but this is missing in the SQLAlchemy integration.


Discussion:

Resolving patch:
diff --git a/src/scout_apm/sqlalchemy.py b/src/scout_apm/sqlalchemy.py
--- a/src/scout_apm/sqlalchemy.py
+++ b/src/scout_apm/sqlalchemy.py
@@ -7,8 +7,12 @@
 
 
 def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
+    if executemany:
+        operation = "SQL/Many"
+    else:
+        operation = "SQL/Query"
     tracked_request = TrackedRequest.instance()
-    span = tracked_request.start_span(operation="SQL/Query")
+    span = tracked_request.start_span(operation=operation)
     span.tag("db.statement", statement)
 
 


Test patch:
diff --git a/tests/integration/test_sqlalchemy.py b/tests/integration/test_sqlalchemy.py
--- a/tests/integration/test_sqlalchemy.py
+++ b/tests/integration/test_sqlalchemy.py
@@ -24,10 +24,29 @@ def conn_with_scout():
         conn.close()
 
 
-def test_hello():
+def test_single_query(tracked_request):
     with conn_with_scout() as conn:
         result = conn.execute("SELECT 'Hello World!'")
-        assert list(result) == [("Hello World!",)]
+
+    assert list(result) == [("Hello World!",)]
+    assert len(tracked_request.complete_spans) == 1
+    span = tracked_request.complete_spans[0]
+    assert span.operation == "SQL/Query"
+    assert span.tags["db.statement"] == "SELECT 'Hello World!'"
+
+
+def test_many_query(tracked_request):
+    tracked_request.start_span(operation="parent")
+    with conn_with_scout() as conn:
+        conn.execute("CREATE TABLE t(i integer)")
+        conn.execute("INSERT INTO t(i) VALUES (?)", [1], [2])
+
+    spans = tracked_request.complete_spans
+    assert len(spans) == 2
+    assert spans[0].operation == "SQL/Query"
+    assert spans[0].tags["db.statement"] == "CREATE TABLE t(i integer)"
+    assert spans[1].operation == "SQL/Many"
+    assert spans[1].tags["db.statement"] == "INSERT INTO t(i) VALUES (?)"
 
 
 # Monkey patch should_capture_backtrace in order to keep the test fast.
Repository: scoutapp/scout_apm_python

Issue:
Switch to importlib.metadata for package versions
Python 3.8 comes with the new standard library [module `importlib.metadata`](https://docs.python.org/3.8/library/importlib.metadata.html). This is the new de-facto way of discovering installed package versions.

For older versions there's the [`importlib-metadata` backport](https://importlib-metadata.readthedocs.io/en/latest/).

We currently use `pkg_resources` to do this, we'd be better off long term switching to the backport and standard library module. The backport supports down to Python 2.7 so it'll work for everything we do.


Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -57,6 +57,7 @@
     },
     install_requires=[
         'asgiref ; python_version >= "3.5"',
+        'importlib-metadata ; python_version < "3.8"',
         "psutil>=5,<6",
         "requests>=2,<3",
         "wrapt>=1.10,<2.0",
diff --git a/src/scout_apm/core/metadata.py b/src/scout_apm/core/metadata.py
--- a/src/scout_apm/core/metadata.py
+++ b/src/scout_apm/core/metadata.py
@@ -47,11 +47,15 @@ def get_metadata():
 
 def get_python_packages_versions():
     try:
-        import pkg_resources
+        if sys.version_info >= (3, 8):
+            from importlib.metadata import distributions
+        else:
+            from importlib_metadata import distributions
     except ImportError:
+        # For some reason it is unavailable
         return []
 
     return sorted(
-        (distribution.project_name, distribution.version)
-        for distribution in pkg_resources.working_set
+        (distribution.metadata["Name"], distribution.metadata["Version"])
+        for distribution in distributions()
     )


Test patch:
Repository: scoutapp/scout_apm_python

Issue:
Don't crash the socket for unrecognized responses
Before #400 when testing against the core agent I discovered the python agent crashes when the core agent doesn't return the expected response, like:

```
2019-11-25T18:08:49+0000 DEBUG  scout_apm.core.socket CoreAgentSocket thread exception: error('unpack requires a buffer of 4 bytes')
Traceback (most recent call last):
  File "/Users/chainz/Documents/Projects/scout_apm_python/src/scout_apm/core/socket.py", line 102, in run
    result = self._send(body)
  File "/Users/chainz/Documents/Projects/scout_apm_python/src/scout_apm/core/socket.py", line 171, in _send
    self._read_response()
  File "/Users/chainz/Documents/Projects/scout_apm_python/src/scout_apm/core/socket.py", line 183, in _read_response
    size = struct.unpack(">I", raw_size)[0]
struct.error: unpack requires a buffer of 4 bytes
```

I think we should make this more robust - we can avoid trying to unpack a response that isn't the right length. The Core agent was sending back nothing on parse error.


Discussion:

Resolving patch:
diff --git a/src/scout_apm/core/socket.py b/src/scout_apm/core/socket.py
--- a/src/scout_apm/core/socket.py
+++ b/src/scout_apm/core/socket.py
@@ -179,6 +179,9 @@ def _message_length(self, body):
     def _read_response(self):
         try:
             raw_size = self.socket.recv(4)
+            if len(raw_size) != 4:
+                # Ignore invalid responses
+                return None
             size = struct.unpack(">I", raw_size)[0]
             message = bytearray(0)
 


Test patch: