0

I'm working on a Python(3.6) project in which I need to create some strings on the base of some input parameters.

Here's my code:

def generate_multi_svc_config(data):
    no_of_svc = int(data['configuration']['no_of_svc'])
    deployments = ''''''
    services = ''''''
    for var in list(range(1, no_of_svc + 1)):
        services = services + '''\n
apiVersion: v1
kind: Service
metadata:
  name: {}
  labels:
    app: {}
spec:
  ports:
  - port: {}
    name: {}
  selector:
    app: {}
---
'''.format(data['configuration']['svc' + str(var)]['name'],
           data['configuration']['svc' + str(var)]['name'],
           data['configuration']['svc' + str(var)]['versions']['v1']['port']['port'],
           data['configuration']['svc' + str(var)]['versions']['v1']['port']['name'],
           data['configuration']['svc' + str(var)]['name'])
        print(services)
        deployments = deployments + '''\n
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: {}
  labels:
    #Project ID
    app: {}
spec:
  #Run two instances of our application
  replicas: {}
  template:
    metadata:
      labels:
        app: {}
    spec:
      #Container details
      containers:
        - name: {}
          image: {}
          imagePullPolicy: Always
          #Ports to expose
          ports:
          - containerPort: {}
            name: {}
---
'''.format(data['configuration']['svc' + str(var)]['name'] + '-' + 'v1',
           data['configuration']['svc' + str(var)]['name'],
           data['configuration']['svc' + str(var)]['replicas'],
           data['configuration']['svc' + str(var)]['name'],
           data['configuration']['svc' + str(var)]['name'],
           data['configuration']['svc' + str(var)]['versions']['v1']['image'],
           data['configuration']['svc' + str(var)]['versions']['v1']['port']['port'],
           data['configuration']['svc' + str(var)]['versions']['v1']['port']['name'])
    print(deployments)

So, when I pass no_of_svc = 2 it should create 2 service strings and 2 deployments string.

But it created the first entry in services for twice and all others for once. I don't know why it's creating the first service string twice?

Here's the example output:

apiVersion: v1
kind: Service
metadata:
  name: ratings
  labels:
    app: ratings
spec:
  ports:
  - port: 8080
    name: ratings-port
  selector:
    app: ratings
---



apiVersion: v1
kind: Service
metadata:
  name: ratings
  labels:
    app: ratings
spec:
  ports:
  - port: 8080
    name: ratings-port
  selector:
    app: ratings
---


apiVersion: v1
kind: Service
metadata:
  name: reviews
  labels:
    app: reviews
spec:
  ports:
  - port: 8081
    name: reviews-port
  selector:
    app: reviews
---



apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: ratings-v1
  labels:
    #Project ID
    app: ratings
spec:
  #Run two instances of our application
  replicas: 3
  template:
    metadata:
      labels:
        app: ratings
    spec:
      #Container details
      containers:
        - name: ratings
          image: gcr.io/ml001-208807/node-app:0.0.1
          imagePullPolicy: Always
          #Ports to expose
          ports:
          - containerPort: 8080
            name: ratings-port
---


apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: reviews-v1
  labels:
    #Project ID
    app: reviews
spec:
  #Run two instances of our application
  replicas: 2
  template:
    metadata:
      labels:
        app: reviews
    spec:
      #Container details
      containers:
        - name: reviews
          image: gcr.io/ml001-208807/node-app1:0.0.1
          imagePullPolicy: Always
          #Ports to expose
          ports:
          - containerPort: 8081
            name: reviews-port
---
5
  • Those large multiline strings really make your code hard to read. Move them to some module-level constants. Might also help readability to define tmp = data['configuration']['svc' + str(var)]. Commented Jul 4, 2018 at 13:58
  • .... then you might notice that the print(deployments) line is outside of the loop, while print(services) is inside. Could this be the problem? Commented Jul 4, 2018 at 14:01
  • both are inside the loop! Commented Jul 4, 2018 at 15:33
  • Nope, they are not. Check the indentation. Also, this explains why the services are printed repeatedly, but the deployments are not Commented Jul 4, 2018 at 15:35
  • Also, note that I rolled back your question; as I said, chaning the code in your question invalidates all the answers. If you want to provide updated, do so below your original code. Commented Jul 4, 2018 at 16:02

2 Answers 2

2

The problem seems to be that you append to services and deployments in each iteration of the loop, but while you print deployments only at the end, you print services in each iteration of the loop, hence printing the entry that was added in the first iteration twice.

Due to the large multiline-strings this is hard to see in your original code. I suggest extracting those strings to some constants on module-level to make the loop body much easier to read. Also, you can define some temporary variable to shorten the repeated dict lookup:

template1 = '''\n
apiVersion: v1
... more lines ...
    app: {}
---
'''
template2 = '''\n
apiVersion: extensions/v1beta1
... more lines ...
            name: {}
---
'''
def generate_multi_svc_config(data):
    no_of_svc = int(data['configuration']['no_of_svc'])
    deployments = ''
    services = ''
    for var in list(range(1, no_of_svc + 1)):
        d = data['configuration']['svc' + str(var)]
        services += template1.format(d['name'],
           d['name'],
           d['versions']['v1']['port']['port'],
           d['versions']['v1']['port']['name'],
           d['name'])
        deployments += template2.format(d['name'] + '-' + 'v1',
           d['name'],
           d['replicas'],
           d['name'],
           d['name'],
           d['versions']['v1']['image'],
           d['versions']['v1']['port']['port'],
           d['versions']['v1']['port']['name'])
    print(services) # <- move this line here, outside the loop
    print(deployments)

Also, if you want to insert certain values at multiple places in your template string, you can use placeholders like {0} or {1}, so you don't have to pass d["name"] three times.

>>> template = "first {0} second {1} first again {0}"
>>> template.format("foo", "bar")
'first foo second bar first again foo'
Sign up to request clarification or add additional context in comments.

Comments

2

Because on each iteration you're printing an actual content of services variable, that, in turn, contents currently formed service alongside all previously added.

Simply put, your loop works like this:

no_of_svc = 2
services = ''
for var in range(1, no_of_svc + 1):
    services += "{} service\n".format(var)
    print(services)

So, on the second iteration, services contains first and second service. As a result, the first service has been printed on both iterations.

If you need to save all values to the services variable as a string, simply print only current value before appending:

no_of_svc = 2
services = ''
for var in range(1, no_of_svc + 1):
    service = "service {}\n".format(var)
    print(service)
    services += service

5 Comments

Hi @OlegRybalchenko, I have changed my code according to your solution but still the first service created twice.
@AbdulRehman Nope, you did not. You just changed services = services + ... to services += ..., which is exactly the same thing. Also, please do NOT change the code in your question. If you want to provide an update, do so BELOW your original code, otherwise you invalidate all the existing answers and comments.
So, what I need to change? please!
Hi @tobias_k, now I have updated my code, does it indented correctly?
@AbdulRehman No, you moved both print statements inside the loop instead of outside.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.