neels has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/41845?usp=email )


Change subject: rather move BatchPersonalization to separate module
......................................................................

rather move BatchPersonalization to separate module

Change-Id: I01ae40a06605eb205bfb409189fcd2b3a128855a
---
A pySim/esim/saip/batch.py
M pySim/esim/saip/personalization.py
2 files changed, 117 insertions(+), 95 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/45/41845/1

diff --git a/pySim/esim/saip/batch.py b/pySim/esim/saip/batch.py
new file mode 100644
index 0000000..0355ad2
--- /dev/null
+++ b/pySim/esim/saip/batch.py
@@ -0,0 +1,117 @@
+"""Implementation of Personalization of eSIM profiles in SimAlliance/TCA 
Interoperable Profile:
+   Run a batch of N personalizations"""
+
+# (C) 2025-2026 by sysmocom - s.f.m.c. GmbH <[email protected]>
+#
+# Author: [email protected]
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import copy
+from typing import Generator
+from pysim.esim.saip.personalization import ConfigurableParameter
+from pySim.esim.saip import param_source
+from pySim.esim.saip import ProfileElementSequence
+
+class BatchPersonalization:
+    """Produce a series of eSIM profiles from predefined parameters.
+    Personalization parameters are derived from 
pysim.esim.saip.param_source.ParamSource.
+
+    Usage example:
+
+    der_input = some_file.open('rb').read()
+    pes = ProfileElementSequence.from_der(der_input)
+    p = pers.BatchPersonalization(
+        n=10,
+        src_pes=pes,
+        csv_rows=get_csv_reader())
+
+    p.add_param_and_src(
+        personalization.Iccid(),
+        param_source.IncDigitSource(
+            num_digits=18,
+            first_value=123456789012340001,
+            last_value=123456789012340010))
+
+    # add more parameters here, using ConfigurableParameter and ParamSource 
subclass instances to define the profile
+    # ...
+
+    # generate all 10 profiles (from n=10 above)
+    for result_pes in p.generate_profiles():
+        upp = result_pes.to_der()
+        store_upp(upp)
+    """
+
+    class ParamAndSrc:
+        'tie a ConfigurableParameter to a source of actual values'
+        def __init__(self, param:ConfigurableParameter, 
src:param_source.ParamSource):
+            self.param = param
+            self.src = src
+
+    def __init__(self,
+                 n:int,
+                 src_pes:ProfileElementSequence,
+                 params:list[ParamAndSrc]=None,
+                 csv_rows:Generator=None,
+                ):
+        """
+        n: number of eSIM profiles to generate.
+        src_pes: a decoded eSIM profile as ProfileElementSequence, to serve as 
template. This is not modified, only
+                 copied.
+        params: list of ParamAndSrc instances, defining a 
ConfigurableParameter and corresponding ParamSource to fill in
+                profile values.
+        csv_rows: A list or generator producing all CSV rows one at a time, 
starting with a row containing the column
+                  headers. This is compatible with the python csv.reader. Each 
row gets passed to
+                  ParamSource.get_next(), such that ParamSource 
implementations can access the row items.
+                  See param_source.CsvSource.
+        """
+        self.n = n
+        self.params = params or []
+        self.src_pes = src_pes
+        self.csv_rows = csv_rows
+
+    def add_param_and_src(self, param:ConfigurableParameter, 
src:param_source.ParamSource):
+        self.params.append(BatchPersonalization.ParamAndSrc(param=param, 
src=src))
+
+    def generate_profiles(self):
+        # get first row of CSV: column names
+        csv_columns = None
+        if self.csv_rows:
+            try:
+                csv_columns = next(self.csv_rows)
+            except StopIteration as e:
+                raise ValueError('the input CSV file appears to be empty') 
from e
+
+        for i in range(self.n):
+            csv_row = None
+            if self.csv_rows and csv_columns:
+                try:
+                    csv_row_list = next(self.csv_rows)
+                except StopIteration as e:
+                    raise ValueError(f'not enough rows in the input CSV for 
eSIM nr {i+1} of {self.n}') from e
+
+                csv_row = dict(zip(csv_columns, csv_row_list))
+
+            pes = copy.deepcopy(self.src_pes)
+
+            for p in self.params:
+                try:
+                    input_value = p.src.get_next(csv_row=csv_row)
+                    assert input_value is not None
+                    value = p.param.__class__.validate_val(input_value)
+                    p.param.__class__.apply_val(pes, value)
+                except Exception as e:
+                    raise ValueError(f'{p.param.name} fed by {p.src.name}: 
{e}') from e
+
+            yield pes
diff --git a/pySim/esim/saip/personalization.py 
b/pySim/esim/saip/personalization.py
index 550cb6c..e024163 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -17,14 +17,12 @@

 import abc
 import io
-import copy
 from typing import List, Tuple, Generator

 from osmocom.tlv import camel_to_snake
 from pySim.utils import enc_iccid, enc_imsi, h2b, rpad, sanitize_iccid
 from pySim.esim.saip import ProfileElement, ProfileElementSequence
 from pySim.ts_51_011 import EF_SMSP
-from pySim.esim.saip import param_source

 def remove_unwanted_tuples_from_list(l: List[Tuple], unwanted_keys: List[str]) 
-> List[Tuple]:
     """In a list of tuples, remove all tuples whose first part equals 
'unwanted_key'."""
@@ -666,96 +664,3 @@
     min_val = 1
     max_val = 255
     example_input = '1'
-
-
-class BatchPersonalization:
-    """Produce a series of eSIM profiles from predefined parameters.
-    Personalization parameters are derived from 
pysim.esim.saip.param_source.ParamSource.
-
-    Usage example:
-
-    der_input = some_file.open('rb').read()
-    pes = ProfileElementSequence.from_der(der_input)
-    p = pers.BatchPersonalization(
-        n=10,
-        src_pes=pes,
-        csv_rows=get_csv_reader())
-
-    p.add_param_and_src(
-        personalization.Iccid(),
-        param_source.IncDigitSource(
-            num_digits=18,
-            first_value=123456789012340001,
-            last_value=123456789012340010))
-
-    # add more parameters here, using ConfigurableParameter and ParamSource 
subclass instances to define the profile
-    # ...
-
-    # generate all 10 profiles (from n=10 above)
-    for result_pes in p.generate_profiles():
-        upp = result_pes.to_der()
-        store_upp(upp)
-    """
-
-    class ParamAndSrc:
-        'tie a ConfigurableParameter to a source of actual values'
-        def __init__(self, param:ConfigurableParameter, 
src:param_source.ParamSource):
-            self.param = param
-            self.src = src
-
-    def __init__(self,
-                 n:int,
-                 src_pes:ProfileElementSequence,
-                 params:list[ParamAndSrc]=None,
-                 csv_rows:Generator=None,
-                ):
-        """
-        n: number of eSIM profiles to generate.
-        src_pes: a decoded eSIM profile as ProfileElementSequence, to serve as 
template. This is not modified, only
-                 copied.
-        params: list of ParamAndSrc instances, defining a 
ConfigurableParameter and corresponding ParamSource to fill in
-                profile values.
-        csv_rows: A list or generator producing all CSV rows one at a time, 
starting with a row containing the column
-                  headers. This is compatible with the python csv.reader. Each 
row gets passed to
-                  ParamSource.get_next(), such that ParamSource 
implementations can access the row items.
-                  See param_source.CsvSource.
-        """
-        self.n = n
-        self.params = params or []
-        self.src_pes = src_pes
-        self.csv_rows = csv_rows
-
-    def add_param_and_src(self, param:ConfigurableParameter, 
src:param_source.ParamSource):
-        self.params.append(BatchPersonalization.ParamAndSrc(param=param, 
src=src))
-
-    def generate_profiles(self):
-        # get first row of CSV: column names
-        csv_columns = None
-        if self.csv_rows:
-            try:
-                csv_columns = next(self.csv_rows)
-            except StopIteration as e:
-                raise ValueError('the input CSV file appears to be empty') 
from e
-
-        for i in range(self.n):
-            csv_row = None
-            if self.csv_rows and csv_columns:
-                try:
-                    csv_row_list = next(self.csv_rows)
-                except StopIteration as e:
-                    raise ValueError(f'not enough rows in the input CSV for 
eSIM nr {i+1} of {self.n}') from e
-
-                csv_row = dict(zip(csv_columns, csv_row_list))
-
-            pes = copy.deepcopy(self.src_pes)
-
-            for p in self.params:
-                try:
-                    input_value = p.src.get_next(csv_row=csv_row)
-                    assert input_value is not None
-                    value = p.param.__class__.validate_val(input_value)
-                    p.param.__class__.apply_val(pes, value)
-                except Exception as e:
-                    raise ValueError(f'{p.param.name} fed by {p.src.name}: 
{e}') from e
-
-            yield pes

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/41845?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I01ae40a06605eb205bfb409189fcd2b3a128855a
Gerrit-Change-Number: 41845
Gerrit-PatchSet: 1
Gerrit-Owner: neels <[email protected]>

Reply via email to