Skip to content

Commit

Permalink
Merge pull request #79 from openedx/jenkins/add-python312-support-1d0…
Browse files Browse the repository at this point in the history
…d10d

feat: add python 3.11 and 3.12 support
  • Loading branch information
Agrendalath authored Apr 17, 2024
2 parents a344afd + ce9cd7f commit acedf06
Show file tree
Hide file tree
Showing 17 changed files with 242 additions and 230 deletions.
42 changes: 21 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ name: Python CI

on:
push:
branches: [ master ]
branches: [master]
pull_request:
branches:
- '**'
- '**'
workflow_dispatch:

concurrency:
Expand All @@ -18,27 +18,27 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-20.04 ]
python-version: [3.8]
toxenv: [django32, django42, quality, package]
os: [ubuntu-20.04]
python-version: ['3.8', '3.11', '3.12']
toxenv: [django42, quality, package]
steps:
- name: Install translations dependencies
run: sudo apt-get install -y gettext
- name: Install translations dependencies
run: sudo apt-get install -y gettext

- name: checkout repo
uses: actions/checkout@v3
with:
submodules: recursive
- name: checkout repo
uses: actions/checkout@v3
with:
submodules: recursive

- name: setup python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: setup python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install Dependencies
run: pip install -r requirements/ci.txt
- name: Install Dependencies
run: pip install -r requirements/ci.txt

- name: Run Tests
env:
TOXENV: ${{ matrix.toxenv }}
run: tox
- name: Run Tests
env:
TOXENV: ${{ matrix.toxenv }}
run: tox
2 changes: 1 addition & 1 deletion google_drive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
from .google_docs import GoogleDocumentBlock
from .google_calendar import GoogleCalendarBlock

__version__ = '0.6.1'
__version__ = '0.7.0'
4 changes: 2 additions & 2 deletions google_drive/google_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def studio_submit(self, submissions, suffix=''): # pylint: disable=unused-argum

# suffix argument is specified for xblocks, but we are not using herein
@XBlock.json_handler
def check_url(self, data, suffix=''): # pylint: disable=unused-argument,no-self-use
def check_url(self, data, suffix=''): # pylint: disable=unused-argument
"""
Checks that the given document url is accessible, and therefore assumed to be valid
"""
Expand All @@ -155,7 +155,7 @@ def check_url(self, data, suffix=''): # pylint: disable=unused-argument,no-self
}

try:
url_response = requests.head(test_url)
url_response = requests.head(test_url) # pylint: disable=missing-timeout
# Catch wide range of request exceptions
except requests.exceptions.RequestException as ex:
LOG.debug("Unable to connect to %s - %s", test_url, six.text_type(ex))
Expand Down
35 changes: 17 additions & 18 deletions google_drive/tests/unit/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.utils.html import escape
from django.utils.translation import override as override_language
from mock import Mock
from nose.tools import assert_equal, assert_in
from workbench.runtime import WorkbenchRuntime
from xblock.runtime import DictKeyValueStore, KvsFieldData

Expand Down Expand Up @@ -85,7 +84,7 @@ def make_calendar_block(cls):
ids = generate_scope_ids(runtime, 'google_calendar')
return GoogleCalendarBlock(runtime, db_model, scope_ids=ids)

def _render_calendar_block(self): # pylint: disable=no-self-use
def _render_calendar_block(self):
block = TestGoogleCalendarBlock.make_calendar_block()
block.usage_id = Mock()
student_fragment = block.render('student_view', Mock())
Expand All @@ -106,43 +105,43 @@ def test_calendar_template_content(self, override, activate_lang, expected_lang)
src_url = (f'https://www.google.com/calendar/embed?mode=Month&src'
f'={DEFAULT_CALENDAR_ID}&showCalendars=0&hl={expected_lang}')

assert_in('<div class="google-calendar-xblock-wrapper">', student_fragment.content)
assert_in(escape(src_url), student_fragment.content)
assert_in('Google Calendar', student_fragment.content)
assert '<div class="google-calendar-xblock-wrapper">' in student_fragment.content
assert escape(src_url) in student_fragment.content
assert 'Google Calendar' in student_fragment.content

assert_in(STUDIO_EDIT_WRAPPER, studio_fragment.content)
assert_in(VALIDATION_WRAPPER, studio_fragment.content)
assert_in(USER_INPUTS_WRAPPER, studio_fragment.content)
assert_in(BUTTONS_WRAPPER, studio_fragment.content)
assert STUDIO_EDIT_WRAPPER in studio_fragment.content
assert VALIDATION_WRAPPER in studio_fragment.content
assert USER_INPUTS_WRAPPER in studio_fragment.content
assert BUTTONS_WRAPPER in studio_fragment.content

def test_calendar_document_submit(self): # pylint: disable=no-self-use
def test_calendar_document_submit(self):
""" Test studio submission of GoogleCalendarBlock """
block = TestGoogleCalendarBlock.make_calendar_block()

body = json.dumps(TEST_SUBMIT_DATA)
res = block.handle('studio_submit', make_request(body))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), RESULT_SUCCESS)
assert json.loads(res.body.decode('utf8')) == RESULT_SUCCESS

assert_equal(block.display_name, TEST_SUBMIT_DATA['display_name'])
assert_equal(block.calendar_id, TEST_SUBMIT_DATA['calendar_id'])
assert_equal(block.default_view, TEST_SUBMIT_DATA['default_view'])
assert block.display_name == TEST_SUBMIT_DATA['display_name']
assert block.calendar_id == TEST_SUBMIT_DATA['calendar_id']
assert block.default_view == TEST_SUBMIT_DATA['default_view']

body = json.dumps('')
res = block.handle('studio_submit', make_request(body))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), RESULT_ERROR)
assert json.loads(res.body.decode('utf8')) == RESULT_ERROR

def test_calendar_publish_event(self): # pylint: disable=no-self-use
def test_calendar_publish_event(self):
""" Test event publishing in GoogleCalendarBlock"""
block = TestGoogleCalendarBlock.make_calendar_block()

body = json.dumps(TEST_COMPLETE_PUBLISH_DATA)
res = block.handle('publish_event', make_request(body))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), RESULT_SUCCESS)
assert json.loads(res.body.decode('utf8')) == RESULT_SUCCESS

body = json.dumps(TEST_INCOMPLETE_PUBLISH_DATA)
res = block.handle('publish_event', make_request(body))

assert_equal(json.loads(res.body.decode('utf8')), RESULT_MISSING_EVENT_TYPE)
assert json.loads(res.body.decode('utf8')) == RESULT_MISSING_EVENT_TYPE
47 changes: 23 additions & 24 deletions google_drive/tests/unit/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import unittest

from mock import Mock
from nose.tools import assert_equal, assert_in
from workbench.runtime import WorkbenchRuntime
from xblock.runtime import DictKeyValueStore, KvsFieldData

Expand Down Expand Up @@ -76,79 +75,79 @@ def make_document_block(cls):
ids = generate_scope_ids(runtime, 'google_document')
return GoogleDocumentBlock(runtime, db_model, scope_ids=ids)

def test_document_template_content(self): # pylint: disable=no-self-use
def test_document_template_content(self):
""" Test content of GoogleDocumentBlock's rendered views """
block = TestGoogleDocumentBlock.make_document_block()
block.usage_id = Mock()

student_fragment = block.render('student_view', Mock())
# pylint: disable=no-value-for-parameter
assert_in('<div class="google-docs-xblock-wrapper"', student_fragment.content)
assert_in('Google Document', student_fragment.content)
assert_in(DEFAULT_EMBED_CODE, student_fragment.content)
assert '<div class="google-docs-xblock-wrapper"' in student_fragment.content
assert 'Google Document' in student_fragment.content
assert DEFAULT_EMBED_CODE in student_fragment.content

studio_fragment = block.render('studio_view', Mock())
assert_in(STUDIO_EDIT_WRAPPER, studio_fragment.content)
assert_in(VALIDATION_WRAPPER, studio_fragment.content)
assert_in(USER_INPUTS_WRAPPER, studio_fragment.content)
assert_in(BUTTONS_WRAPPER, studio_fragment.content)
assert STUDIO_EDIT_WRAPPER in studio_fragment.content
assert VALIDATION_WRAPPER in studio_fragment.content
assert USER_INPUTS_WRAPPER in studio_fragment.content
assert BUTTONS_WRAPPER in studio_fragment.content

def test_studio_document_submit(self): # pylint: disable=no-self-use
def test_studio_document_submit(self):
""" Test studio submission of GoogleDocumentBlock """
block = TestGoogleDocumentBlock.make_document_block()

body = json.dumps(TEST_SUBMIT_DATA)
res = block.handle('studio_submit', make_request(body))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), RESULT_SUCCESS)
assert json.loads(res.body.decode('utf8')) == RESULT_SUCCESS

assert_equal(block.display_name, TEST_SUBMIT_DATA['display_name'])
assert_equal(block.embed_code, TEST_SUBMIT_DATA['embed_code'])
assert_equal(block.alt_text, TEST_SUBMIT_DATA['alt_text'])
assert block.display_name == TEST_SUBMIT_DATA['display_name']
assert block.embed_code == TEST_SUBMIT_DATA['embed_code']
assert block.alt_text == TEST_SUBMIT_DATA['alt_text']

body = json.dumps('')
res = block.handle('studio_submit', make_request(body))
assert_equal(json.loads(res.body.decode('utf8')), RESULT_ERROR)
assert json.loads(res.body.decode('utf8')) == RESULT_ERROR

def test_check_document_url(self): # pylint: disable=no-self-use
def test_check_document_url(self):
""" Test verification of the provided Google Document URL"""
block = TestGoogleDocumentBlock.make_document_block()

data = json.dumps(TEST_VALIDATE_URL_DATA)
res = block.handle('check_url', make_request(data))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), STATUS_CODE_200)
assert json.loads(res.body.decode('utf8')) == STATUS_CODE_200

data = json.dumps(TEST_VALIDATE_UNDEFINED_DATA)
res = block.handle('check_url', make_request(data))

assert_equal(json.loads(res.body.decode('utf8')), STATUS_CODE_400)
assert json.loads(res.body.decode('utf8')) == STATUS_CODE_400

data = json.dumps(TEST_VALIDATE_NONEXISTENT_URL_DATA)
res = block.handle('check_url', make_request(data))

assert_equal(json.loads(res.body.decode('utf8')), STATUS_CODE_404)
assert json.loads(res.body.decode('utf8')) == STATUS_CODE_404

data = json.dumps({})
res = block.handle('check_url', make_request(data))

assert_equal(json.loads(res.body.decode('utf8')), STATUS_CODE_400)
assert json.loads(res.body.decode('utf8')) == STATUS_CODE_400

def test_document_publish_event(self): # pylint: disable=no-self-use
def test_document_publish_event(self):
""" Test event publishing in GoogleDocumentBlock"""
block = TestGoogleDocumentBlock.make_document_block()

body = json.dumps(TEST_COMPLETE_PUBLISH_DOCUMENT_DATA)
res = block.handle('publish_event', make_request(body))
# pylint: disable=no-value-for-parameter
assert_equal(json.loads(res.body.decode('utf8')), RESULT_SUCCESS)
assert json.loads(res.body.decode('utf8')) == RESULT_SUCCESS

body = json.dumps(TEST_COMPLETE_PUBLISH_IMAGE_DATA)
res = block.handle('publish_event', make_request(body))

assert_equal(json.loads(res.body.decode('utf8')), RESULT_SUCCESS)
assert json.loads(res.body.decode('utf8')) == RESULT_SUCCESS

body = json.dumps(TEST_INCOMPLETE_PUBLISH_DATA)
res = block.handle('publish_event', make_request(body))

assert_equal(json.loads(res.body.decode('utf8')), RESULT_MISSING_EVENT_TYPE)
assert json.loads(res.body.decode('utf8')) == RESULT_MISSING_EVENT_TYPE
32 changes: 17 additions & 15 deletions requirements/ci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
#
# make upgrade
#
asgiref==3.7.2
asgiref==3.8.1
# via django
cachetools==5.3.2
backports-zoneinfo==0.2.1 ; python_version < "3.9"
# via
# -c requirements/constraints.txt
# django
cachetools==5.3.3
# via tox
certifi==2024.2.2
# via requests
Expand All @@ -22,27 +26,27 @@ coveralls==3.3.1
# via -r requirements/ci.in
distlib==0.3.8
# via virtualenv
django==3.2.24
django==4.2.11
# via
# -c requirements/common_constraints.txt
# edx-i18n-tools
docopt==0.6.2
# via coveralls
edx-i18n-tools==1.3.0
edx-i18n-tools==1.5.0
# via -r requirements/ci.in
filelock==3.13.1
filelock==3.13.4
# via
# tox
# virtualenv
idna==3.6
idna==3.7
# via requests
lxml==5.1.0
lxml==5.2.1
# via edx-i18n-tools
packaging==23.2
packaging==24.0
# via
# pyproject-api
# tox
path==16.10.0
path==16.14.0
# via edx-i18n-tools
platformdirs==4.2.0
# via
Expand All @@ -54,23 +58,21 @@ polib==1.2.0
# via edx-i18n-tools
pyproject-api==1.6.1
# via tox
pytz==2024.1
# via django
pyyaml==6.0.1
# via edx-i18n-tools
requests==2.31.0
# via coveralls
sqlparse==0.4.4
sqlparse==0.5.0
# via django
tomli==2.0.1
# via
# pyproject-api
# tox
tox==4.13.0
tox==4.14.2
# via -r requirements/ci.in
typing-extensions==4.10.0
typing-extensions==4.11.0
# via asgiref
urllib3==2.2.1
# via requests
virtualenv==20.25.1
virtualenv==20.25.2
# via tox
11 changes: 10 additions & 1 deletion requirements/common_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@


# using LTS django version
Django<4.0
Django<5.0

# elasticsearch>=7.14.0 includes breaking changes in it which caused issues in discovery upgrade process.
# elastic search changelog: https://www.elastic.co/guide/en/enterprise-search/master/release-notes-7.14.0.html
elasticsearch<7.14.0

# django-simple-history>3.0.0 adds indexing and causes a lot of migrations to be affected
django-simple-history==3.0.0

# opentelemetry requires version 6.x at the moment:
# https://github.com/open-telemetry/opentelemetry-python/issues/3570
# Normally this could be added as a constraint in edx-django-utils, where we're
# adding the opentelemetry dependency. However, when we compile pip-tools.txt,
# that uses version 7.x, and then there's no undoing that when compiling base.txt.
# So we need to pin it globally, for now.
# Ticket for unpinning: https://github.com/openedx/edx-lint/issues/407
importlib-metadata<7
4 changes: 2 additions & 2 deletions requirements/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@

-c common_constraints.txt

# TODO: Many pinned dependencies should be unpinned and/or moved to this constraints file.
pylint==2.12.2
# Temporary to Support the python 3.11 Upgrade
backports.zoneinfo;python_version<"3.9" # Newer versions have zoneinfo available in the standard library
Loading

0 comments on commit acedf06

Please sign in to comment.