Repository: ansible/awx

Issue:
awx_collection sanity test fail with python3.9
### Please confirm the following

- [X] I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
- [X] I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
- [X] I understand that AWX is open source software provided for free and that I might not receive a timely response.

### Bug Summary

attempting to run `ansible-test sanity` on awx_collection failed

### AWX version

awx: 21.4.1.dev61+gd2217bc61d.d20220817

### Select the relevant components

- [ ] UI
- [ ] API
- [ ] Docs
- [X] Collection
- [ ] CLI
- [ ] Other

### Installation method

N/A

### Modifications

no

### Ansible version

_No response_

### Operating system

_No response_

### Web browser

_No response_

### Steps to reproduce

- build and install `awx` collection with `make install_collection`
- cd into `~/.ansible/collections/ansible_collections/awx/awx`
- run `ansible-test sanity -v --color --docker --coverage --python=3.9`
- sanity test fail 

### Expected results

sanity test pass

### Actual results

sanity test fail with 
```
ERROR: The 1 sanity test(s) listed below (out of 32) failed. See error output above for details.
import --python 3.9

ERROR: Found 2 import issue(s) on python 3.9 which need to be resolved:
ERROR: plugins/lookup/schedule_rrule.py:103:0: traceback: NameError: name 'rrule' is not defined
ERROR: plugins/lookup/schedule_rruleset.py:139:0: traceback: AnsibleError: No module named 'pytz'
```

### Additional information

full log
```
➜  awx ansible-test sanity -v --color --docker --coverage --python=3.9
WARNING: Ignoring tests in "test/" in favor of "tests/".
Run command: docker images quay.io/ansible/default-test-container:3.2.2 --format '{{json .}}'
Run command: docker pull quay.io/ansible/default-test-container:3.2.2
3.2.2: Pulling from ansible/default-test-container
f22ccc0b8772: Pull complete
3cf8fb62ba5f: Pull complete
e80c964ece6a: Pull complete
9b09b8205c21: Pull complete
94a33eccd491: Pull complete
879fb3e00b48: Pull complete
a0fc60deec6d: Pull complete
0146914f596b: Pull complete
9861c35d69c7: Pull complete
254f498a83b4: Pull complete
07d99b38b30c: Pull complete
877d947e7190: Pull complete
221a70eb8225: Pull complete
1f03a775bcfe: Pull complete
37c3d6fe9239: Pull complete
d3f2e2cd796c: Pull complete
18023419ec23: Pull complete
bdc09117b685: Pull complete
be718274d1e7: Pull complete
031103dcf998: Pull complete
893b245223d5: Pull complete
4bf1d8500b9d: Pull complete
a1eb9fa897b8: Pull complete
2f7a5dab24fc: Pull complete
083e7c7a2ba4: Pull complete
80df48ea52f6: Pull complete
ec8466ad84d0: Pull complete
b8091cecfc7a: Pull complete
0bf6ed029087: Pull complete
6b97690d348a: Pull complete
6a22c91b2e72: Pull complete
f5b2cdff9e2d: Pull complete
Digest: sha256:02521efb6ca14d6b75f234fd3a66b4b3d273d545912b377baebe7dc1ccefe83a
Status: Downloaded newer image for quay.io/ansible/default-test-container:3.2.2
quay.io/ansible/default-test-container:3.2.2
Scanning collection root: /Users/liuhao/.ansible/collections/ansible_collections
Run command: git ls-files -z --cached --others --exclude-standard
Run command: git ls-files -z --deleted
Run command: git submodule status --recursive
Including collection: aapqa.openstack (32 files)
Including collection: amazon.aws (601 files)
Including collection: awx.awx (169 files)
Including collection: community.aws (1402 files)
Including collection: community.kubernetes (89 files)
Including collection: community.okd (58 files)
Including collection: kubernetes.core (172 files)
Run command: git ls-files -z --cached --others --exclude-standard
Run command: git ls-files -z --deleted
Run command: git submodule status --recursive
Including collection: ocmplus.cm (84 files)
Including collection: playbook.integrity (15 files)
Run command: git ls-files -z --cached --others --exclude-standard
Run command: git ls-files -z --deleted
Run command: git submodule status --recursive
Including collection: stolostron.core (84 files)
Creating a payload archive containing 3446 files...
Created a 4521547 byte payload archive containing 3446 files in 1 seconds.
Assuming Docker is available on localhost.
Run command: docker run --detach --volume /sys/fs/cgroup:/sys/fs/cgroup:ro --privileged=false --security-opt seccomp=unconfined --volume /var/run/docker.sock ...
Run command: docker exec -i 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 /bin/sh
Run command: docker exec -i 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 dd of=/root/test.tgz bs=65536
Run command: docker exec 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 tar oxzf /root/test.tgz -C /root
Run command: docker exec 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 /usr/bin/env ANSIBLE_TEST_CONTENT_ROOT=/root/ansible_collections/aw ...
WARNING: Ignoring tests in "test/" in favor of "tests/".
Running sanity test 'action-plugin-docs' with Python 3.9
Read 0 sanity test ignore line(s) for Ansible 2.11 from: tests/sanity/ignore-2.11.txt
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check coverage -c /root/ansible/test/lib ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/yamlcheck.py
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/action-plugin-docs.py
Running sanity test 'ansible-doc' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Injecting "/tmp/python-xgxdc5bt-ansible/python" as a execv wrapper for the "/usr/bin/python3.9" interpreter.
Run command: ansible-doc -t inventory awx.awx.controller
Run command: ansible-doc -t inventory --json awx.awx.controller
Run command: ansible-doc -t lookup awx.awx.controller_api awx.awx.schedule_rrule awx.awx.schedule_rruleset
Run command: ansible-doc -t lookup --json awx.awx.controller_api awx.awx.schedule_rrule awx.awx.schedule_rruleset
Run command: ansible-doc -t module awx.awx.ad_hoc_command awx.awx.ad_hoc_command_cancel awx.awx.ad_hoc_command_wait awx.awx.application awx.awx.controller_me ...
Run command: ansible-doc -t module --json awx.awx.ad_hoc_command awx.awx.ad_hoc_command_cancel awx.awx.ad_hoc_command_wait awx.awx.application awx.awx.contro ...
Running sanity test 'changelog' with Python 3.9
No tests applicable.
Running sanity test 'compile' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/compile/compile.py
Running sanity test 'empty-init' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/empty-init.py
Running sanity test 'future-import-boilerplate' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/future-import-boilerplate.py
Running sanity test 'ignores'
Running sanity test 'import' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/virtualenvcheck.py
Run command: /usr/bin/python3.9 -m venv /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39
Created Python 3.9 virtual environment using "venv": /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39/bin/python /root/ansible/test/lib/ansible_test/_data/quiet_pip.py ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39/bin/python /root/ansible/test/lib/ansible_test/_data/quiet_pip.py ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39/bin/python /root/ansible/test/lib/ansible_test/_data/quiet_pip.py ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39/bin/python /root/ansible/test/lib/ansible_test/_data/quiet_pip.py ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39/bin/python /root/ansible/test/lib/ansible_test/_data/quiet_pip.py ...
Run command: importer.py
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/virtualenvcheck.py
Run command: /usr/bin/python3.9 -m venv /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfc ...
Created Python 3.9 virtual environment using "venv": /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8db49f04fa29b
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Detected OpenSSL version 1.1.1 under Python 3.9.
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Collecting cryptography<3.4
  Downloading cryptography-3.3.2-cp36-abi3-manylinux2010_x86_64.whl (2.6 MB)
Collecting cffi!=1.14.4
  Downloading cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (441 kB)
Collecting six>=1.4.1
  Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting pycparser
  Downloading pycparser-2.21-py2.py3-none-any.whl (118 kB)
Installing collected packages: pycparser, cffi, six, cryptography
Successfully installed cffi-1.15.1 cryptography-3.3.2 pycparser-2.21 six-1.16.0
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: /root/ansible_collections/awx/awx/tests/output/.tmp/sanity/import/minimal-py39-requirements-8b83ca76b13364be2f9e02cfcf77dd0bd86a1921ca9e121049d8 ...
Run command: importer.py
ERROR: Found 2 import issue(s) on python 3.9 which need to be resolved:
ERROR: plugins/lookup/schedule_rrule.py:103:0: traceback: NameError: name 'rrule' is not defined
ERROR: plugins/lookup/schedule_rruleset.py:139:0: traceback: AnsibleError: No module named 'pytz'
See documentation for help: https://docs.ansible.com/ansible/2.11/dev_guide/testing/sanity/import.html
Running sanity test 'line-endings' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/line-endings.py
Running sanity test 'metaclass-boilerplate' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/metaclass-boilerplate.py
Running sanity test 'no-assert' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-assert.py
Running sanity test 'no-basestring' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-basestring.py
Running sanity test 'no-dict-iteritems' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-dict-iteritems.py
Running sanity test 'no-dict-iterkeys' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-dict-iterkeys.py
Running sanity test 'no-dict-itervalues' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-dict-itervalues.py
Running sanity test 'no-get-exception' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-get-exception.py
Running sanity test 'no-illegal-filenames' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-illegal-filenames.py
Running sanity test 'no-main-display' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-main-display.py
Running sanity test 'no-smart-quotes' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-smart-quotes.py
Running sanity test 'no-unicode-literals' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/no-unicode-literals.py
Running sanity test 'pep8' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 -m pycodestyle --max-line-length 160 --config /dev/null --ignore E402,E741,W503,W504 plugins/doc_fragments/auth.py plugins/do ...
Running sanity test 'pslint'
No tests applicable.
Running sanity test 'pylint' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/collection_detail.py /root/ansible_collections/awx/awx
Checking 33 file(s) in context "collection" with config: /root/ansible/test/lib/ansible_test/_data/sanity/pylint/config/collection.cfg
Run command: /usr/bin/python3.9 -m pylint --jobs 0 --reports n --max-line-length 160 --max-complexity 20 --rcfile /root/ansible/test/lib/ansible_test/_data/s ...
Checking 3 file(s) in context "module_utils" with config: /root/ansible/test/lib/ansible_test/_data/sanity/pylint/config/collection.cfg
Run command: /usr/bin/python3.9 -m pylint --jobs 0 --reports n --max-line-length 160 --max-complexity 20 --rcfile /root/ansible/test/lib/ansible_test/_data/s ...
Checking 41 file(s) in context "modules" with config: /root/ansible/test/lib/ansible_test/_data/sanity/pylint/config/collection.cfg
Run command: /usr/bin/python3.9 -m pylint --jobs 0 --reports n --max-line-length 160 --max-complexity 20 --rcfile /root/ansible/test/lib/ansible_test/_data/s ...
Running sanity test 'replace-urlopen' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/replace-urlopen.py
Running sanity test 'runtime-metadata' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/runtime-metadata.py
Running sanity test 'shebang' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/shebang.py
Running sanity test 'shellcheck'
No tests applicable.
Running sanity test 'symlinks' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/symlinks.py
Running sanity test 'use-argspec-type-path' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/use-argspec-type-path.py
Running sanity test 'use-compat-six' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/code-smell/use-compat-six.py
Running sanity test 'validate-modules' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/collection_detail.py /root/ansible_collections/awx/awx
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/validate-modules/validate-modules --format json --arg-spec plugins/modules/a ...
Running sanity test 'yamllint' with Python 3.9
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py install --disable-pip-version-check -r /root/ansible/test/lib/ansible_ ...
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/quiet_pip.py check --disable-pip-version-check
Run command: /usr/bin/python3.9 /root/ansible/test/lib/ansible_test/_data/sanity/yamllint/yamllinter.py
ERROR: The 1 sanity test(s) listed below (out of 32) failed. See error output above for details.
import --python 3.9
Run command: docker exec 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 tar czf /root/output.tgz --exclude .tmp -C /root/ansible_collection ...
Run command: docker exec -i 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 dd if=/root/output.tgz bs=65536
Run command: tar oxzf /var/folders/tw/5y6lxkh11rv5pfcmjwt1d1fm0000gn/T/ansible-result-firpvt9a.tgz -C /Users/liuhao/.ansible/collections/ansible_collections/ ...
Run command: docker rm -f 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22
ERROR: Command "docker exec 7fee2ef6abe2087d424523b7642ee5270c76c804aa8f99834e1a6ba2193a6c22 /usr/bin/env ANSIBLE_TEST_CONTENT_ROOT=/root/ansible_collections/awx/awx LC_ALL=en_US.UTF-8 /usr/bin/python3.9 /root/ansible/bin/ansible-test sanity -v --coverage --python=3.9 --metadata tests/output/.tmp/metadata-7omv_d5f.json --truncate 162 --redact --color yes --requirements --coverage-label docker-default" returned exit status 1.
```


Discussion:

Resolving patch:
diff --git a/awx_collection/plugins/lookup/schedule_rrule.py b/awx_collection/plugins/lookup/schedule_rrule.py
--- a/awx_collection/plugins/lookup/schedule_rrule.py
+++ b/awx_collection/plugins/lookup/schedule_rrule.py
@@ -101,39 +101,39 @@
 
 
 class LookupModule(LookupBase):
-    frequencies = {
-        'none': rrule.DAILY,
-        'minute': rrule.MINUTELY,
-        'hour': rrule.HOURLY,
-        'day': rrule.DAILY,
-        'week': rrule.WEEKLY,
-        'month': rrule.MONTHLY,
-    }
-
-    weekdays = {
-        'monday': rrule.MO,
-        'tuesday': rrule.TU,
-        'wednesday': rrule.WE,
-        'thursday': rrule.TH,
-        'friday': rrule.FR,
-        'saturday': rrule.SA,
-        'sunday': rrule.SU,
-    }
-
-    set_positions = {
-        'first': 1,
-        'second': 2,
-        'third': 3,
-        'fourth': 4,
-        'last': -1,
-    }
-
     # plugin constructor
     def __init__(self, *args, **kwargs):
         if LIBRARY_IMPORT_ERROR:
             raise_from(AnsibleError('{0}'.format(LIBRARY_IMPORT_ERROR)), LIBRARY_IMPORT_ERROR)
         super().__init__(*args, **kwargs)
 
+        self.frequencies = {
+            'none': rrule.DAILY,
+            'minute': rrule.MINUTELY,
+            'hour': rrule.HOURLY,
+            'day': rrule.DAILY,
+            'week': rrule.WEEKLY,
+            'month': rrule.MONTHLY,
+        }
+
+        self.weekdays = {
+            'monday': rrule.MO,
+            'tuesday': rrule.TU,
+            'wednesday': rrule.WE,
+            'thursday': rrule.TH,
+            'friday': rrule.FR,
+            'saturday': rrule.SA,
+            'sunday': rrule.SU,
+        }
+
+        self.set_positions = {
+            'first': 1,
+            'second': 2,
+            'third': 3,
+            'fourth': 4,
+            'last': -1,
+        }
+
     @staticmethod
     def parse_date_time(date_string):
         try:
@@ -149,14 +149,13 @@ def run(self, terms, variables=None, **kwargs):
 
         return self.get_rrule(frequency, kwargs)
 
-    @staticmethod
-    def get_rrule(frequency, kwargs):
+    def get_rrule(self, frequency, kwargs):
 
-        if frequency not in LookupModule.frequencies:
+        if frequency not in self.frequencies:
             raise AnsibleError('Frequency of {0} is invalid'.format(frequency))
 
         rrule_kwargs = {
-            'freq': LookupModule.frequencies[frequency],
+            'freq': self.frequencies[frequency],
             'interval': kwargs.get('every', 1),
         }
 
@@ -187,9 +186,9 @@ def get_rrule(frequency, kwargs):
                 days = []
                 for day in kwargs['on_days'].split(','):
                     day = day.strip()
-                    if day not in LookupModule.weekdays:
-                        raise AnsibleError('Parameter on_days must only contain values {0}'.format(', '.join(LookupModule.weekdays.keys())))
-                    days.append(LookupModule.weekdays[day])
+                    if day not in self.weekdays:
+                        raise AnsibleError('Parameter on_days must only contain values {0}'.format(', '.join(self.weekdays.keys())))
+                    days.append(self.weekdays[day])
 
                 rrule_kwargs['byweekday'] = days
 
@@ -214,13 +213,13 @@ def get_rrule(frequency, kwargs):
                     except Exception as e:
                         raise_from(AnsibleError('on_the parameter must be two words separated by a space'), e)
 
-                    if weekday not in LookupModule.weekdays:
+                    if weekday not in self.weekdays:
                         raise AnsibleError('Weekday portion of on_the parameter is not valid')
-                    if occurance not in LookupModule.set_positions:
+                    if occurance not in self.set_positions:
                         raise AnsibleError('The first string of the on_the parameter is not valid')
 
-                    rrule_kwargs['byweekday'] = LookupModule.weekdays[weekday]
-                    rrule_kwargs['bysetpos'] = LookupModule.set_positions[occurance]
+                    rrule_kwargs['byweekday'] = self.weekdays[weekday]
+                    rrule_kwargs['bysetpos'] = self.set_positions[occurance]
 
         my_rule = rrule.rrule(**rrule_kwargs)
 
diff --git a/awx_collection/plugins/lookup/schedule_rruleset.py b/awx_collection/plugins/lookup/schedule_rruleset.py
--- a/awx_collection/plugins/lookup/schedule_rruleset.py
+++ b/awx_collection/plugins/lookup/schedule_rruleset.py
@@ -136,40 +136,44 @@
     import pytz
     from dateutil import rrule
 except ImportError as imp_exc:
-    raise_from(AnsibleError('{0}'.format(imp_exc)), imp_exc)
+    LIBRARY_IMPORT_ERROR = imp_exc
+else:
+    LIBRARY_IMPORT_ERROR = None
 
 
 class LookupModule(LookupBase):
-    frequencies = {
-        'none': rrule.DAILY,
-        'minute': rrule.MINUTELY,
-        'hour': rrule.HOURLY,
-        'day': rrule.DAILY,
-        'week': rrule.WEEKLY,
-        'month': rrule.MONTHLY,
-    }
-
-    weekdays = {
-        'monday': rrule.MO,
-        'tuesday': rrule.TU,
-        'wednesday': rrule.WE,
-        'thursday': rrule.TH,
-        'friday': rrule.FR,
-        'saturday': rrule.SA,
-        'sunday': rrule.SU,
-    }
-
-    set_positions = {
-        'first': 1,
-        'second': 2,
-        'third': 3,
-        'fourth': 4,
-        'last': -1,
-    }
-
     # plugin constructor
     def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
+        if LIBRARY_IMPORT_ERROR:
+            raise_from(AnsibleError('{0}'.format(LIBRARY_IMPORT_ERROR)), LIBRARY_IMPORT_ERROR)
+            super().__init__(*args, **kwargs)
+
+            self.frequencies = {
+                'none': rrule.DAILY,
+                'minute': rrule.MINUTELY,
+                'hour': rrule.HOURLY,
+                'day': rrule.DAILY,
+                'week': rrule.WEEKLY,
+                'month': rrule.MONTHLY,
+            }
+
+            self.weekdays = {
+                'monday': rrule.MO,
+                'tuesday': rrule.TU,
+                'wednesday': rrule.WE,
+                'thursday': rrule.TH,
+                'friday': rrule.FR,
+                'saturday': rrule.SA,
+                'sunday': rrule.SU,
+            }
+
+            self.set_positions = {
+                'first': 1,
+                'second': 2,
+                'third': 3,
+                'fourth': 4,
+                'last': -1,
+            }
 
     @staticmethod
     def parse_date_time(date_string):
@@ -260,11 +264,11 @@ def run(self, terms, variables=None, **kwargs):
             frequency = rule.get('frequency', None)
             if not frequency:
                 raise AnsibleError("Rule {0} is missing a frequency".format(rule_number))
-            if frequency not in LookupModule.frequencies:
+            if frequency not in self.frequencies:
                 raise AnsibleError('Frequency of rule {0} is invalid {1}'.format(rule_number, frequency))
 
             rrule_kwargs = {
-                'freq': LookupModule.frequencies[frequency],
+                'freq': self.frequencies[frequency],
                 'interval': rule.get('interval', 1),
                 'dtstart': start_date,
             }
@@ -287,7 +291,7 @@ def run(self, terms, variables=None, **kwargs):
                             )
 
             if 'bysetpos' in rule:
-                rrule_kwargs['bysetpos'] = self.process_list('bysetpos', rule, LookupModule.set_positions, rule_number)
+                rrule_kwargs['bysetpos'] = self.process_list('bysetpos', rule, self.set_positions, rule_number)
 
             if 'bymonth' in rule:
                 rrule_kwargs['bymonth'] = self.process_integer('bymonth', rule, 1, 12, rule_number)
@@ -302,7 +306,7 @@ def run(self, terms, variables=None, **kwargs):
                 rrule_kwargs['byweekno'] = self.process_integer('byweekno', rule, 1, 52, rule_number)
 
             if 'byweekday' in rule:
-                rrule_kwargs['byweekday'] = self.process_list('byweekday', rule, LookupModule.weekdays, rule_number)
+                rrule_kwargs['byweekday'] = self.process_list('byweekday', rule, self.weekdays, rule_number)
 
             if 'byhour' in rule:
                 rrule_kwargs['byhour'] = self.process_integer('byhour', rule, 0, 23, rule_number)


Test patch:
diff --git a/awx_collection/test/awx/test_schedule.py b/awx_collection/test/awx/test_schedule.py
--- a/awx_collection/test/awx/test_schedule.py
+++ b/awx_collection/test/awx/test_schedule.py
@@ -81,7 +81,7 @@ def test_delete_same_named_schedule(run_module, project, inventory, admin_user):
     ],
 )
 def test_rrule_lookup_plugin(collection_import, freq, kwargs, expect):
-    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule
+    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule()
     generated_rule = LookupModule.get_rrule(freq, kwargs)
     assert generated_rule == expect
     rrule_checker = SchedulePreviewSerializer()
@@ -92,7 +92,7 @@ def test_rrule_lookup_plugin(collection_import, freq, kwargs, expect):
 
 @pytest.mark.parametrize("freq", ('none', 'minute', 'hour', 'day', 'week', 'month'))
 def test_empty_schedule_rrule(collection_import, freq):
-    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule
+    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule()
     if freq == 'day':
         pfreq = 'DAILY'
     elif freq == 'none':
@@ -136,7 +136,7 @@ def test_empty_schedule_rrule(collection_import, freq):
     ],
 )
 def test_rrule_lookup_plugin_failure(collection_import, freq, kwargs, msg):
-    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule
+    LookupModule = collection_import('plugins.lookup.schedule_rrule').LookupModule()
     with pytest.raises(AnsibleError) as e:
         assert LookupModule.get_rrule(freq, kwargs)
     assert msg in str(e.value)
diff --git a/awx_collection/tests/sanity/ignore-2.13.txt b/awx_collection/tests/sanity/ignore-2.13.txt
new file mode 100644
--- /dev/null
+++ b/awx_collection/tests/sanity/ignore-2.13.txt
@@ -0,0 +1,88 @@
+plugins/module_utils/awxkit.py import-3.9
+plugins/module_utils/controller_api.py import-3.9
+plugins/modules/ad_hoc_command.py import-3.9
+plugins/modules/ad_hoc_command_cancel.py import-3.9
+plugins/modules/ad_hoc_command_wait.py import-3.9
+plugins/modules/application.py import-3.9
+plugins/modules/controller_meta.py import-3.9
+plugins/modules/credential.py import-3.92
+plugins/modules/credential_input_source.py import-3.9
+plugins/modules/credential_type.py import-3.9
+plugins/modules/execution_environment.py import-3.9
+plugins/modules/export.py import-3.9
+plugins/modules/group.py import-3.9
+plugins/modules/host.py import-3.9
+plugins/modules/import.py import-3.9
+plugins/modules/instance.py import-3.9
+plugins/modules/instance_group.py import-3.9
+plugins/modules/inventory.py import-3.9
+plugins/modules/inventory_source.py import-3.9
+plugins/modules/inventory_source_update.py import-3.9
+plugins/modules/job_cancel.py import-3.9
+plugins/modules/job_launch.py import-3.9
+plugins/modules/job_list.py import-3.9
+plugins/modules/job_template.py import-3.93
+plugins/modules/job_wait.py import-3.9
+plugins/modules/label.py import-3.9
+plugins/modules/license.py import-3.9
+plugins/modules/notification_template.py import-3.9
+plugins/modules/organization.py import-3.9
+plugins/modules/project.py import-3.92
+plugins/modules/project_update.py import-3.9
+plugins/modules/role.py import-3.9
+plugins/modules/schedule.py import-3.9
+plugins/modules/settings.py import-3.9
+plugins/modules/subscriptions.py import-3.9
+plugins/modules/team.py import-3.9
+plugins/modules/token.py import-3.9
+plugins/modules/user.py import-3.9
+plugins/modules/workflow_approval.py import-3.9
+plugins/modules/workflow_job_template.py import-3.9
+plugins/modules/workflow_job_template_node.py import-3.9
+plugins/modules/workflow_launch.py import-3.9
+plugins/modules/workflow_node_wait.py import-3.9
+plugins/inventory/controller.py import-3.10
+plugins/lookup/controller_api.py import-3.10
+plugins/module_utils/awxkit.py import-3.10
+plugins/module_utils/controller_api.py import-3.10
+plugins/modules/ad_hoc_command.py import-3.10
+plugins/modules/ad_hoc_command_cancel.py import-3.10
+plugins/modules/ad_hoc_command_wait.py import-3.10
+plugins/modules/application.py import-3.10
+plugins/modules/controller_meta.py import-3.10
+plugins/modules/credential.py import-3.10
+plugins/modules/credential_input_source.py import-3.10
+plugins/modules/credential_type.py import-3.10
+plugins/modules/execution_environment.py import-3.10
+plugins/modules/export.py import-3.10
+plugins/modules/group.py import-3.10
+plugins/modules/host.py import-3.10
+plugins/modules/import.py import-3.10
+plugins/modules/instance.py import-3.10
+plugins/modules/instance_group.py import-3.10
+plugins/modules/inventory.py import-3.10
+plugins/modules/inventory_source.py import-3.10
+plugins/modules/inventory_source_update.py import-3.10
+plugins/modules/job_cancel.py import-3.10
+plugins/modules/job_launch.py import-3.10
+plugins/modules/job_list.py import-3.10  
+plugins/modules/job_template.py import-3.10
+plugins/modules/job_wait.py import-3.10
+plugins/modules/label.py import-3.10
+plugins/modules/license.py import-3.10
+plugins/modules/notification_template.py import-3.10
+plugins/modules/organization.py import-3.10
+plugins/modules/project.py import-3.10
+plugins/modules/project_update.py import-3.10
+plugins/modules/role.py import-3.10
+plugins/modules/schedule.py import-3.10
+plugins/modules/settings.py import-3.10 
+plugins/modules/subscriptions.py import-3.10
+plugins/modules/team.py import-3.10
+plugins/modules/token.py import-3.10
+plugins/modules/user.py import-3.10
+plugins/modules/workflow_approval.py import-3.10
+plugins/modules/workflow_job_template.py import-3.10
+plugins/modules/workflow_job_template_node.py import-3.10
+plugins/modules/workflow_launch.py import-3.10
+plugins/modules/workflow_node_wait.py import-3.10
diff --git a/awx_collection/tests/sanity/ignore-2.14.txt b/awx_collection/tests/sanity/ignore-2.14.txt
new file mode 100644
--- /dev/null
+++ b/awx_collection/tests/sanity/ignore-2.14.txt
@@ -0,0 +1,88 @@
+plugins/module_utils/awxkit.py import-3.9
+plugins/module_utils/controller_api.py import-3.9
+plugins/modules/ad_hoc_command.py import-3.9
+plugins/modules/ad_hoc_command_cancel.py import-3.9
+plugins/modules/ad_hoc_command_wait.py import-3.9
+plugins/modules/application.py import-3.9
+plugins/modules/controller_meta.py import-3.9
+plugins/modules/credential.py import-3.92
+plugins/modules/credential_input_source.py import-3.9
+plugins/modules/credential_type.py import-3.9
+plugins/modules/execution_environment.py import-3.9
+plugins/modules/export.py import-3.9
+plugins/modules/group.py import-3.9
+plugins/modules/host.py import-3.9
+plugins/modules/import.py import-3.9
+plugins/modules/instance.py import-3.9
+plugins/modules/instance_group.py import-3.9
+plugins/modules/inventory.py import-3.9
+plugins/modules/inventory_source.py import-3.9
+plugins/modules/inventory_source_update.py import-3.9
+plugins/modules/job_cancel.py import-3.9
+plugins/modules/job_launch.py import-3.9
+plugins/modules/job_list.py import-3.9
+plugins/modules/job_template.py import-3.93
+plugins/modules/job_wait.py import-3.9
+plugins/modules/label.py import-3.9
+plugins/modules/license.py import-3.9
+plugins/modules/notification_template.py import-3.9
+plugins/modules/organization.py import-3.9
+plugins/modules/project.py import-3.92
+plugins/modules/project_update.py import-3.9
+plugins/modules/role.py import-3.9
+plugins/modules/schedule.py import-3.9
+plugins/modules/settings.py import-3.9
+plugins/modules/subscriptions.py import-3.9
+plugins/modules/team.py import-3.9
+plugins/modules/token.py import-3.9
+plugins/modules/user.py import-3.9
+plugins/modules/workflow_approval.py import-3.9
+plugins/modules/workflow_job_template.py import-3.9
+plugins/modules/workflow_job_template_node.py import-3.9
+plugins/modules/workflow_launch.py import-3.9
+plugins/modules/workflow_node_wait.py import-3.9
+plugins/inventory/controller.py import-3.10
+plugins/lookup/controller_api.py import-3.10
+plugins/module_utils/awxkit.py import-3.10
+plugins/module_utils/controller_api.py import-3.10
+plugins/modules/ad_hoc_command.py import-3.10
+plugins/modules/ad_hoc_command_cancel.py import-3.10
+plugins/modules/ad_hoc_command_wait.py import-3.10
+plugins/modules/application.py import-3.10
+plugins/modules/controller_meta.py import-3.10
+plugins/modules/credential.py import-3.10
+plugins/modules/credential_input_source.py import-3.10
+plugins/modules/credential_type.py import-3.10
+plugins/modules/execution_environment.py import-3.10
+plugins/modules/export.py import-3.10
+plugins/modules/group.py import-3.10
+plugins/modules/host.py import-3.10
+plugins/modules/import.py import-3.10
+plugins/modules/instance.py import-3.10
+plugins/modules/instance_group.py import-3.10
+plugins/modules/inventory.py import-3.10
+plugins/modules/inventory_source.py import-3.10
+plugins/modules/inventory_source_update.py import-3.10
+plugins/modules/job_cancel.py import-3.10
+plugins/modules/job_launch.py import-3.10
+plugins/modules/job_list.py import-3.10  
+plugins/modules/job_template.py import-3.10
+plugins/modules/job_wait.py import-3.10
+plugins/modules/label.py import-3.10
+plugins/modules/license.py import-3.10
+plugins/modules/notification_template.py import-3.10
+plugins/modules/organization.py import-3.10
+plugins/modules/project.py import-3.10
+plugins/modules/project_update.py import-3.10
+plugins/modules/role.py import-3.10
+plugins/modules/schedule.py import-3.10
+plugins/modules/settings.py import-3.10 
+plugins/modules/subscriptions.py import-3.10
+plugins/modules/team.py import-3.10
+plugins/modules/token.py import-3.10
+plugins/modules/user.py import-3.10
+plugins/modules/workflow_approval.py import-3.10
+plugins/modules/workflow_job_template.py import-3.10
+plugins/modules/workflow_job_template_node.py import-3.10
+plugins/modules/workflow_launch.py import-3.10
+plugins/modules/workflow_node_wait.py import-3.10