Skip to content

Commit

Permalink
fix: tox_modernizer added for django42 (#388)
Browse files Browse the repository at this point in the history
* fix: tox_modernizer added for django42
* fix: modified moderniser to add dependencies only for django 4 and above
* fix: console command updated
---------

Co-authored-by: Usama Sadiq <[email protected]>
  • Loading branch information
zubairshakoorarbisoft and UsamaSadiq authored Jun 12, 2023
1 parent 1759375 commit 9e836e9
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
123 changes: 123 additions & 0 deletions edx_repo_tools/codemods/django42/tox_moderniser_django42.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import io
import re
from configparser import ConfigParser, NoSectionError

import click

TOX_SECTION = "tox"
ENVLIST = "envlist"
TEST_ENV_SECTION = "testenv"
TEST_ENV_DEPS = "deps"
PYTHON_SUBSTITUTE = "py38"
DJANGO_SUBSTITUTE = "django{32,40,42}"

DJANGO_40_DEPENDENCY = "django40: Django>=4.0,<4.1\n"
DJANGO_42_DEPENDENCY = "django42: Django>=4.2,<4.3\n"
NEW_DJANGO_DEPENDENCIES = DJANGO_40_DEPENDENCY + DJANGO_42_DEPENDENCY

SECTIONS = [TOX_SECTION, TEST_ENV_SECTION]

PYTHON_PATTERN = "(py{.*?}-?|py[0-9]+,|py[0-9]+-)"

DJANGO_PATTERN = "(django[0-9]+,|django[0-9]+\n|django{.*}\n|django{.*?}|django[0-9]+-|django{.*}-)"

DJANGO4_DEPENDENCY_PATTERN = "(django32:.*\n)"


class ConfigReader:
def __init__(self, file_path=None, config_dict=None):
self.config_dict = config_dict
self.file_path = file_path

def get_modernizer(self):
config_parser = ConfigParser()
if self.config_dict is not None:
config_parser.read_dict(self.config_dict)
else:
config_parser.read(self.file_path)
return ToxModernizer(config_parser, self.file_path)


class ToxModernizer:
def __init__(self, config_parser, file_path):
self.file_path = file_path
self.config_parser = config_parser
self._validate_tox_config_sections()

def _validate_tox_config_sections(self):
if not self.config_parser.sections():
raise NoSectionError("Bad Config. No sections found.")

if all(section not in SECTIONS for section in self.config_parser.sections()):
raise NoSectionError("File doesn't contain required sections")

def _update_env_list(self):
tox_section = self.config_parser[TOX_SECTION]
env_list = tox_section[ENVLIST]

env_list = ToxModernizer._replace_runners(PYTHON_PATTERN, PYTHON_SUBSTITUTE, env_list)
env_list = ToxModernizer._replace_runners(DJANGO_PATTERN, DJANGO_SUBSTITUTE, env_list)
self.config_parser[TOX_SECTION][ENVLIST] = env_list

@staticmethod
def _replace_runners(pattern, substitute, env_list):
matches = re.findall(pattern, env_list)
if not matches:
return env_list
substitute = ToxModernizer._get_runner_substitute(matches, substitute)
return ToxModernizer._replace_matches(pattern, substitute, env_list, matches)

@staticmethod
def _replace_matches(pattern, substitute, target, matches):
if not matches:
return target
occurrences_to_replace = len(matches) - 1
if occurrences_to_replace > 0:
target = re.sub(pattern, '', target, occurrences_to_replace)

# checking if there is any dependency for django32 dont override it
if matches[0].startswith('django32:'):
substitute = matches[0] + substitute
target = re.sub(pattern, substitute, target)
return target

@staticmethod
def _get_runner_substitute(matches, substitute):
last_match = matches[-1]
has_other_runners = last_match.endswith('-')
return substitute + "-" if has_other_runners else substitute

def _replace_django_versions(self):
test_environment = self.config_parser[TEST_ENV_SECTION]
dependencies = test_environment[TEST_ENV_DEPS]
matches = re.findall(DJANGO4_DEPENDENCY_PATTERN, dependencies)
dependencies = self._replace_matches(DJANGO4_DEPENDENCY_PATTERN, NEW_DJANGO_DEPENDENCIES, dependencies, matches)

self.config_parser[TEST_ENV_SECTION][TEST_ENV_DEPS] = dependencies

def _update_config_file(self):
# ConfigParser insists on using tabs for output. We want spaces.
with io.StringIO() as configw:
self.config_parser.write(configw)
new_ini = configw.getvalue()
new_ini = new_ini.replace("\t", " ")
with open(self.file_path, 'w') as configfile:
configfile.write(new_ini)

def modernize(self):
self._update_env_list()
self._replace_django_versions()
self._update_config_file()


@click.command()
@click.option(
'--path', default='tox.ini',
help="Path to target tox config file")
def main(path):
modernizer = ConfigReader(path).get_modernizer()
modernizer.modernize()


if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def is_requirement(line):
'repo_checks = edx_repo_tools.repo_checks.repo_checks:main',
'show_hooks = edx_repo_tools.dev.show_hooks:main',
'tag_release = edx_repo_tools.release.tag_release:main',
'modernize_tox_django42 = edx_repo_tools.codemods.django42.tox_moderniser_django42:main',
],
},
package_data={
Expand Down

0 comments on commit 9e836e9

Please sign in to comment.