diff --git a/aws_embedded_metrics/logger/metrics_context.py b/aws_embedded_metrics/logger/metrics_context.py
index 5d762e3..283f369 100644
--- a/aws_embedded_metrics/logger/metrics_context.py
+++ b/aws_embedded_metrics/logger/metrics_context.py
@@ -125,8 +125,17 @@ class MetricsContext(object):
         new_properties: Dict = {}
         new_properties.update(self.properties)
 
+        # dimensions added with put_dimension will not be copied.
+        # the reason for this is so that you can flush the same scope multiple
+        # times without stacking new dimensions. Example:
+        #
+        # @metric_scope
+        # def my_func(metrics):
+        #  metrics.put_dimensions(...)
+        #
+        # my_func()
+        # my_func()
         new_dimensions: List[Dict] = []
-        new_dimensions = new_dimensions + self.dimensions
 
         new_default_dimensions: Dict = {}
         new_default_dimensions.update(self.default_dimensions)
diff --git a/aws_embedded_metrics/logger/metrics_logger.py b/aws_embedded_metrics/logger/metrics_logger.py
index 60843bc..69e1b62 100644
--- a/aws_embedded_metrics/logger/metrics_logger.py
+++ b/aws_embedded_metrics/logger/metrics_logger.py
@@ -41,7 +41,7 @@ class MetricsLogger:
 
         # accept and reset the context
         sink.accept(self.context)
-        self.context = MetricsContext.empty()
+        self.context = self.context.create_copy_with_context()
 
     def __configureContextForEnvironment(self, env: Environment) -> None:
         default_dimensions = {

Preserve logger context across flushes
See https://github.com/awslabs/aws-embedded-metrics-node/issues/15

https://github.com/awslabs/aws-embedded-metrics-python/blob/6cf02e6a5b1849be7aaa5300f2ec9425c5fbc398/aws_embedded_metrics/logger/metrics_logger.py#L44
diff --git a/tests/logger/test_metrics_context.py b/tests/logger/test_metrics_context.py
index e188314..550440d 100644
--- a/tests/logger/test_metrics_context.py
+++ b/tests/logger/test_metrics_context.py
@@ -197,7 +197,7 @@ def test_create_copy_with_context_copies_properties():
     assert context.properties is not new_context.properties
 
 
-def test_create_copy_with_context_copies_dimensions():
+def test_create_copy_with_context_does_not_copy_dimensions():
     # arrange
     context = MetricsContext()
     dimension_key = fake.word()
@@ -208,8 +208,7 @@ def test_create_copy_with_context_copies_dimensions():
     new_context = context.create_copy_with_context()
 
     # assert
-    assert context.dimensions == new_context.dimensions
-    assert context.dimensions is not new_context.dimensions
+    assert len(new_context.dimensions) == 0
 
 
 def test_create_copy_with_context_copies_default_dimensions():
@@ -225,6 +224,20 @@ def test_create_copy_with_context_copies_default_dimensions():
     assert context.default_dimensions is not new_context.default_dimensions
 
 
+def test_create_copy_with_context_does_not_copy_metrics():
+    # arrange
+    context = MetricsContext()
+    prop_key = fake.word()
+    prop_value = fake.word()
+    context.set_property(prop_key, prop_value)
+
+    # act
+    new_context = context.create_copy_with_context()
+
+    # assert
+    assert len(new_context.metrics) == 0
+
+
 def test_set_dimensions_overwrites_all_dimensions():
     # arrange
     context = MetricsContext()
@@ -238,3 +251,20 @@ def test_set_dimensions_overwrites_all_dimensions():
 
     # assert
     assert context.dimensions == expected_dimensions
+
+
+def test_create_copy_with_context_does_not_repeat_dimensions():
+    # arrange
+    context = MetricsContext()
+    expected_dimensions = {fake.word(): fake.word()}
+
+    custom = {fake.word(): fake.word()}
+    context.set_default_dimensions(expected_dimensions)
+    context.put_dimensions(custom)
+
+    new_context = context.create_copy_with_context()
+    new_context.set_default_dimensions(expected_dimensions)
+    new_context.put_dimensions(custom)
+
+    # assert
+    assert len(new_context.get_dimensions()) == 1
diff --git a/tests/logger/test_metrics_logger.py b/tests/logger/test_metrics_logger.py
index 23a33a5..895b02b 100644
--- a/tests/logger/test_metrics_logger.py
+++ b/tests/logger/test_metrics_logger.py
@@ -180,6 +180,39 @@ async def test_can_set_namespace(mocker):
     assert context.namespace == expected_value
 
 
+@pytest.mark.asyncio
+async def test_context_is_preserved_across_flushes(mocker):
+    # arrange
+    expected_namespace = "Namespace"
+    metric_key = "Metric"
+    expected_dimension_key = "Dim"
+    expected_property_key = "Prop"
+    expected_value = "Value"
+
+    logger, sink, env = get_logger_and_sink(mocker)
+
+    logger.set_namespace(expected_namespace)
+    logger.set_property(expected_property_key, expected_value)
+    logger.set_dimensions({expected_dimension_key: expected_value})
+
+    # act
+    logger.put_metric(metric_key, 0)
+    await logger.flush()
+
+    context = sink.accept.call_args[0][0]
+    assert context.namespace == expected_namespace
+    assert context.properties[expected_property_key] == expected_value
+    assert context.metrics[metric_key].values == [0]
+
+    logger.put_metric(metric_key, 1)
+    await logger.flush()
+
+    context = sink.accept.call_args[0][0]
+    assert context.namespace == expected_namespace
+    assert context.properties[expected_property_key] == expected_value
+    assert context.metrics[metric_key].values == [1]
+
+
 # Test helper methods
 
 

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-asyncio pytest-mock Faker aresponses boto3 pytest-timeout
apt-get update apt-get install -y gcc
3.7
requirements/base.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aiohttp==3.8.6
aiosignal==1.3.1
aresponses==3.0.0
async-timeout==4.0.3
asynctest==0.13.0
attrs==24.2.0
-e git+https://github.com/awslabs/aws-embedded-metrics-python.git@6cf02e6a5b1849be7aaa5300f2ec9425c5fbc398#egg=aws_embedded_metrics
boto3==1.33.13
botocore==1.33.13
certifi @ file:///croot/certifi_1671487769961/work/certifi
charset-normalizer==3.4.1
exceptiongroup==1.2.2
Faker==18.13.0
frozenlist==1.3.3
idna==3.10
importlib-metadata==6.7.0
iniconfig==2.0.0
jmespath==1.0.1
multidict==6.0.5
packaging==24.0
pluggy==1.2.0
pytest==7.4.4
pytest-asyncio==0.21.2
pytest-mock==3.11.1
pytest-timeout==2.3.1
python-dateutil==2.9.0.post0
s3transfer==0.8.2
six==1.17.0
tomli==2.0.1
typing_extensions==4.7.1
urllib3==1.26.20
yarl==1.9.4
zipp==3.15.0

name: aws-embedded-metrics-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aiohttp==3.8.6
      - aiosignal==1.3.1
      - aresponses==3.0.0
      - async-timeout==4.0.3
      - asynctest==0.13.0
      - attrs==24.2.0
      - boto3==1.33.13
      - botocore==1.33.13
      - charset-normalizer==3.4.1
      - exceptiongroup==1.2.2
      - faker==18.13.0
      - frozenlist==1.3.3
      - idna==3.10
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - jmespath==1.0.1
      - multidict==6.0.5
      - packaging==24.0
      - pluggy==1.2.0
      - pytest==7.4.4
      - pytest-asyncio==0.21.2
      - pytest-mock==3.11.1
      - pytest-timeout==2.3.1
      - python-dateutil==2.9.0.post0
      - s3transfer==0.8.2
      - six==1.17.0
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - urllib3==1.26.20
      - yarl==1.9.4
      - zipp==3.15.0
prefix: /opt/conda/envs/aws-embedded-metrics-python

tests/logger/test_metrics_context.py::test_create_copy_with_context_does_not_copy_dimensions tests/logger/test_metrics_context.py::test_create_copy_with_context_does_not_repeat_dimensions tests/logger/test_metrics_logger.py::test_context_is_preserved_across_flushes
tests/logger/test_metrics_context.py::test_can_create_context_with_no_arguments tests/logger/test_metrics_context.py::test_can_set_property tests/logger/test_metrics_context.py::test_put_dimension_adds_to_dimensions tests/logger/test_metrics_context.py::test_get_dimensions_returns_only_custom_dimensions_if_no_default_dimensions_not_set tests/logger/test_metrics_context.py::test_get_dimensions_returns_only_custom_dimensions_if_default_dimensions_are_empty tests/logger/test_metrics_context.py::test_get_dimensions_returns_default_dimensions_if_custom_dimensions_not_set tests/logger/test_metrics_context.py::test_get_dimensions_returns_merged_custom_and_default_dimensions tests/logger/test_metrics_context.py::test_put_metric_adds_metrics tests/logger/test_metrics_context.py::test_put_metric_uses_None_unit_if_not_provided tests/logger/test_metrics_context.py::test_create_copy_with_context_creates_new_instance tests/logger/test_metrics_context.py::test_create_copy_with_context_copies_namespace tests/logger/test_metrics_context.py::test_create_copy_with_context_copies_properties tests/logger/test_metrics_context.py::test_create_copy_with_context_copies_default_dimensions tests/logger/test_metrics_context.py::test_create_copy_with_context_does_not_copy_metrics tests/logger/test_metrics_context.py::test_set_dimensions_overwrites_all_dimensions tests/logger/test_metrics_logger.py::test_can_set_property tests/logger/test_metrics_logger.py::test_can_put_metric tests/logger/test_metrics_logger.py::test_put_metric_appends_values_to_array tests/logger/test_metrics_logger.py::test_put_dimension tests/logger/test_metrics_logger.py::test_logger_configures_default_dimensions_on_flush tests/logger/test_metrics_logger.py::test_logger_configures_uses_config_overrides_for_default_dimensions tests/logger/test_metrics_logger.py::test_set_dimensions_overrides_all_dimensions tests/logger/test_metrics_logger.py::test_can_set_namespace
aws_embedded_metrics/logger/metrics_logger.py aws_embedded_metrics/logger/metrics_context.py
aws_embedded_metrics/logger/metrics_logger.py aws_embedded_metrics/logger/metrics_context.py