Skip to content

Config loader

Configuration and command-line argument handling for MAY.

build_filters(args, config)

Build filter dictionary from arguments and config. Command-line arguments take precedence over config file.

Parameters:

Name Type Description Default
args

Parsed command-line arguments

required
config

Configuration dictionary

required

Returns:

Type Description

Filter dictionary with 'level' and 'codes' keys, or None if no filter

Source code in may/config_loader.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def build_filters(args, config):
    """
    Build filter dictionary from arguments and config.
    Command-line arguments take precedence over config file.

    Args:
        args: Parsed command-line arguments
        config: Configuration dictionary

    Returns:
        Filter dictionary with 'level' and 'codes' keys, or None if no filter
    """
    # Check if --load-all is specified
    if args.load_all:
        return None

    # Check command-line arguments first (highest priority)
    if args.lgu or args.lgu_file:
        codes = []
        if args.lgu_file:
            codes = list(Geography.load_codes_from_file(args.lgu_file))
        elif args.lgu:
            codes = [c.strip() for c in args.lgu.split(',')]
        return {'level': 'LGU', 'codes': codes}

    if args.mgu or args.mgu_file:
        codes = []
        if args.mgu_file:
            codes = list(Geography.load_codes_from_file(args.mgu_file))
        elif args.mgu:
            codes = [c.strip() for c in args.mgu.split(',')]
        return {'level': 'MGU', 'codes': codes}

    if args.sgu or args.sgu_file:
        codes = []
        if args.sgu_file:
            codes = list(Geography.load_codes_from_file(args.sgu_file))
        elif args.sgu:
            codes = [c.strip() for c in args.sgu.split(',')]
        return {'level': 'SGU', 'codes': codes}

    # Check config file (lower priority)
    geo_config = config.get('geography', {})

    if geo_config.get('load_all', False):
        return None

    # Check filter in config
    filter_config = geo_config.get('filter', {})
    if not filter_config or not filter_config.get('level'):
        return None

    level = filter_config['level']
    codes = []

    # Load codes from file if specified
    if filter_config.get('file'):
        codes = list(Geography.load_codes_from_file(filter_config['file']))
    # Otherwise use inline codes
    elif filter_config.get('codes'):
        codes = filter_config['codes']

    # Only return filter if we have codes
    if codes:
        return {'level': level, 'codes': codes}

    return None

load_config(config_path='config.yaml')

Load configuration from YAML file.

Parameters:

Name Type Description Default
config_path

Path to the config file

'config.yaml'

Returns:

Type Description

Dictionary with configuration

Source code in may/config_loader.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
def load_config(config_path="config.yaml"):
    """
    Load configuration from YAML file.

    Args:
        config_path: Path to the config file

    Returns:
        Dictionary with configuration
    """
    if not os.path.exists(config_path):
        logger.warning(f"Config file not found: {config_path}, using defaults")
        return {}

    with open(config_path, 'r') as f:
        config = yaml.safe_load(f)

    logger.info(f"Loaded configuration from {config_path}")
    return config

parse_arguments()

Parse command-line arguments.

Returns:

Type Description

Parsed arguments

Source code in may/config_loader.py
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def parse_arguments():
    """
    Parse command-line arguments.

    Returns:
        Parsed arguments
    """
    parser = argparse.ArgumentParser(
        description="MAY - Geographical Simulation",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Load all units using config.yaml
  python create_world.py

  # Load all units (override config)
  python create_world.py --load-all

  # Filter by LGU
  python create_world.py --lgu London

  # Filter by MGU codes (comma-separated)
  python create_world.py --mgu E02000173,E02000187

  # Filter by MGU from file
  python create_world.py --mgu-file filters/my_mgus.txt

  # Filter by SGU codes
  python create_world.py --sgu E00004320,E00004321

  # Use custom config file
  python create_world.py --config my_config.yaml
        """
    )

    parser.add_argument(
        '--config',
        type=str,
        default='config.yaml',
        help='Path to configuration file (default: config.yaml)'
    )

    parser.add_argument(
        '--load-all',
        action='store_true',
        help='Load all geographical units (ignores all filters)'
    )

    # LGU filters
    parser.add_argument(
        '--lgu',
        type=str,
        help='Filter by LGU codes (comma-separated)'
    )
    parser.add_argument(
        '--lgu-file',
        type=str,
        help='Filter by LGU codes from file'
    )

    # MGU filters
    parser.add_argument(
        '--mgu',
        type=str,
        help='Filter by MGU codes (comma-separated)'
    )
    parser.add_argument(
        '--mgu-file',
        type=str,
        help='Filter by MGU codes from file'
    )

    # SGU filters
    parser.add_argument(
        '--sgu',
        type=str,
        help='Filter by SGU codes (comma-separated)'
    )
    parser.add_argument(
        '--sgu-file',
        type=str,
        help='Filter by SGU codes from file'
    )

    return parser.parse_known_args()

setup_geography(args=None, config=None)

Setup geography based on arguments and config. Convenience function that handles all the configuration loading.

Parameters:

Name Type Description Default
args

Parsed arguments (if None, will parse from command line)

None
config

Configuration dict (if None, will load from file)

None

Returns:

Type Description

Tuple of (Geography object, filters dict)

Source code in may/config_loader.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
def setup_geography(args=None, config=None):
    """
    Setup geography based on arguments and config.
    Convenience function that handles all the configuration loading.

    Args:
        args: Parsed arguments (if None, will parse from command line)
        config: Configuration dict (if None, will load from file)

    Returns:
        Tuple of (Geography object, filters dict)
    """
    # Parse arguments if not provided
    if args is None:
        args, unknown_args = parse_arguments()

    # Load configuration if not provided
    if config is None:
        config = load_config(args.config)

    # Build filters from args and config
    filters = build_filters(args, config)

    if filters:
        logger.info(f"Using filter: {filters['level']} with {len(filters['codes'])} codes")
    else:
        logger.info("Loading all geographical units (no filters)")

    # Get data directory and levels from config
    geo_config = config.get('geography', {})
    data_dir = pr.resolve(geo_config.get('data_dir', 'data/geography'))
    levels = geo_config.get('levels', None)  # None = use Geography default

    # Create Geography object
    geo = Geography(data_dir=data_dir, filters=filters, levels=levels)

    return geo, filters