1

I have the following two classes MasterProgramList and ProgramList. MasterProgramList takes in a json array object which is defined below in the usage code. I am trying to iterate over each Program object and change the start_date property. When I do so, the value does not change but stays as what is defined in the json array object. Is there something wrong with my ProgramList/Program class? How can I iterate over the class objects and change the property value?

MasterProgramList.py

import json
import datetime
class MasterProgramList(object):
    def __init__(self, program_list, today=None):
        self.program_list = [ProgramList(program) for program in program_list]
        self.today = today

    def current_programs(self):
        if self.today is not None:
            def filter_if_between_start_and_end(program):
                return (datetime.datetime.strptime(program.start_date, '%Y-%m-%d').date()) <= self.today.date() <= (
                        datetime.datetime.strptime(program.end_date, '%Y-%m-%d').date())

                program_list = self.program_list
                for x in program_list:
                    x.programs = filter(filter_if_between_start_and_end, x.programs)

                filtered_program_list = program_list
            else:
                filtered_program_list = self.program_list
            return filtered_program_list

ProgramList.py

class ProgramList(object):
    """
    CRM-specific version of the ProgramList Configuration object
    """
    def __init__(self, config):
        self._config = config
        self.brand = config['brand']
        self.programs = self._parse_programs(config['brand'], config['programs'])

    def _parse_programs(cls, brand, program_list):
        return [Program.from_json(brand, p) for p in program_list]

class Program(object):
    def __init__(self, **kwargs):
        self._config = kwargs.get('config') #required json data
        self.name = kwargs.get('name') #required json data
        self.start_date = kwargs.get('start_date') #required json data
        self.end_date = kwargs.get('end_date') #required json data

    def __repr__(self):
        return str(self._config)

    @classmethod
    def from_json(cls, brand, program_json):
        program_json['name'] = '{0}_{1}'.format(brand.capitalize(), program_json['name'])
        program_json['department'] = 'CRM'
        return Program(
            config = program_json,
            name = program_json['name'],
            start_date = program_json['start_date'],
            end_date = program_json['end_date']
        )

Usage:

from datetime import datetime, timedelta

crm_program_master_list = [
    {
        "brand": "testbrand",
        "programs": [
            {
                "name": "Program1",
                "start_date": "2020-01-02",
                "end_date": "2999-12-31"
            },
            {
                "name": "Program2",
                "start_date": "2020-01-04",
                "end_date": "2999-12-31"
            }
        ]
    }
]

today_date = (datetime.strptime('2020-01-06', '%Y-%m-%d'))
crm_programs_to_analyze = MasterProgramList(crm_program_master_list, today=today_date)
crm_programs_to_analyze.program_list = crm_programs_to_analyze.current_programs()

programs = []
for x in crm_programs_to_analyze.program_list:
    for p in x.programs:
        #change the start_date for each program
        p.start_date = '2020-01-22'
        print('program: {}'.format(p))
        programs.append(p)
output:
program: {'name': 'Program1', 'end_date': '2999-12-31', 'department': 'CRM', 'start_date': '2020-01-02'}
program: {'name': 'Program2', 'end_date': '2999-12-31', 'department': 'CRM', 'start_date': '2020-01-04'}

expected output:
program: {'name': 'Program1', 'end_date': '2999-12-31', 'department': 'CRM', 'start_date': '2020-01-22'}
program: {'name': 'Program2', 'end_date': '2999-12-31', 'department': 'CRM', 'start_date': '2020-01-22'}
1
  • @Z4-tier yes it was an indentation error. i fixed it Commented Jan 7, 2020 at 6:34

2 Answers 2

1

First, a few things to clean up to make this work:

In the Usage section, there are no imports for ProgramList or MasterProgramList. I added them as:

from MasterProgramList import MasterProgramList
from ProgramList import ProgramList

then, in MasterProgramList.py I added an import of ProgramList.

Moving on, I see that crm_programs_to_analyze.program_list is a list that contains one ProgramList.ProgramList object. So your outer for loop is iterating once on that single object. Then the inner for loop iterates over the members of the ProgramList's programs, and there it is setting the start_date to 2020-01-22.

The problem you are having is in the __repr__ method-- specifically where it's getting the values it returns. Here is a very short example that illustrates the problem:

>>> class f:
...   def __init__(self, config):
...     self.config = config
...     self.start_date = config['start_date']
...     self.end_date = config['end_date']
...   def __repr__(self):
...     return str(self.config)
...
>>> conf = {'start_date': '2020-10-10', 'end_date': '2021-12-03'}
>>> foo = f(conf)
>>> foo
{'start_date': '2020-10-10', 'end_date': '2021-12-03'}
>>> foo.start_date = '2019-10-10' # <-- Changes start_date, but not config
>>> foo
{'start_date': '2020-10-10', 'end_date': '2021-12-03'} # <-- From config
>>> foo.start_date # <-- but this as updated as expected
'2019-10-10'
>>> foo.config
{'start_date': '2020-10-10', 'end_date': '2021-12-03'} # <-- unchanged
>>> foo.config['start_date'] = foo.start_date
>>> foo
{'start_date': '2019-10-10', 'end_date': '2021-12-03'}
>>> foo.start_date
'2019-10-10'
>>> foo.config # <-- now it's changed and they match
{'start_date': '2019-10-10', 'end_date': '2021-12-03'}

The value of start_date is being updated. But printing p by way of the __repr__ is getting the original value from _config, which isn't updated when p.start_date is modified. To fix it, either add in an update to change the start_date in p._config, or have __repr__ return the value of start_date instead.

Like this:

    def __repr__(self):
        rv = f'Start Date: {self.start_date}, End Date: {self.end_date}, Config: '
        for k, v in self._config.items():
            rv += f'{k} : {v}, '
        return rv
Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your help i ended up doing def __repr__(self): data = {} data['name'] = self.name data['start_date'] = self.start_date data['end_date'] = self.end_date data['source'] = self.source data['department'] = self.department json_data = json.dumps(data) return str(json_data)
1

There are several issues with this code. Let's deal with the first problem.

class MasterProgramList(object):
    def __init__(self, program_list, today=None):
        #ProgramList is a class, not a function.  It has no return value.  
        self.program_list = [ProgramList(program) for program in program_list]
        self.today = today

    #do not define function after conditional logic.  
    def filter_if_between_start_and_end(self, program):
        return (datetime.datetime.strptime(program.start_date, '%Y-%m-%d').date()) <= self.today.date() <= (
                    datetime.datetime.strptime(program.end_date, '%Y-%m-%d').date())

    def current_programs(self):
        if self.today is not None:
            program_list = self.program_list
            for x in program_list:
                x.programs = filter(self.filter_if_between_start_and_end(x.programs))

            filtered_program_list = program_list
        else:
            filtered_program_list = self.program_list
        return filtered_program_list

Comments

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.