Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
matrix:
# TODO: work on windows-latest compatibility?
os: [ubuntu-latest]
python-version: ['3.5', '3.6', '3.7', '3.8', '3.9', '3.10']
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
include:
- os: macos-latest
python-version: '3.9'
Expand All @@ -28,10 +28,8 @@ jobs:
python-version: ${{ matrix.python-version }}
- run: pip install -r requirements.txt
- run: pip freeze
- if: matrix.python-version > '3.5'
run: make fmt
- if: matrix.python-version >= '3.6'
run: make lint
- run: make fmt
- run: make lint
- run: python setup.py --version
- run: make test-${{ matrix.python-version }}
prerelease-test:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ tooling](https://packaging.python.org/guides/tool-recommendations/).

To get started, you'll want to:
- clone the repo into a project directory
- setup a virtual 3.5+ python environment in the project directory
- setup a virtual 3.7+ python environment in the project directory
- activate that virtual environment
- install the dependencies
- validate your build environment with some sample commands
Expand Down
10 changes: 2 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ SOURCE_DATE_EPOCH := $(shell date +%s)
export SOURCE_DATE_EPOCH

.PHONY: all-tests
all-tests: all-images test-3.5 test-3.6 test-3.7 test-3.8 test-3.9 test-3.10
all-tests: all-images test-3.7 test-3.8 test-3.9 test-3.10

.PHONY: all-images
all-images: image-3.5 image-3.6 image-3.7 image-3.8 image-3.9 image-3.10
all-images: image-3.7 image-3.8 image-3.9 image-3.10

image-%:
docker build -t rsconnect-python:$* --build-arg BASE_IMAGE=python:$*-slim .
Expand All @@ -62,9 +62,6 @@ mock-test-%: clean-stores
fmt-%:
$(RUNNER) 'black .'

.PHONY: fmt-3.5
fmt-3.5: .fmt-unsupported

.PHONY: .fmt-unsupported
.fmt-unsupported:
@echo ERROR: This python version cannot run the fmting tools
Expand All @@ -83,9 +80,6 @@ lint-%:
$(RUNNER) 'flake8 tests/'
$(RUNNER) 'mypy -p rsconnect'

.PHONY: lint-3.5
lint-3.5: .lint-unsupported

.PHONY: .lint-unsupported
.lint-unsupported:
@echo ERROR: This python version cannot run the linting tools
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

!!! warning

As of version 1.7.0, rsconnect-python requires Python version 3.5 or higher. Please see the
[official announcement](https://www.rstudio.com/blog/rstudio-connect-2021-08-python-updates/)
for details about this decision.
As of version 1.14.0, rsconnect-python requires Python version 3.7 or higher.

This package provides a CLI (command-line interface) for interacting
with and deploying to Posit Connect. This is also used by the
Expand Down
9 changes: 4 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
black==22.3.0; python_version >= '3.6'
black==22.3.0
click>=7.0.0
coverage
flake8
Expand All @@ -8,13 +8,12 @@ importlib-metadata
ipykernel
ipython
jupyter_client
mypy; python_version >= '3.6'
mypy
nbconvert
pyjwt>=2.4.0; python_version >= '3.6'
pyjwt; python_version < '3.6'
pyjwt>=2.4.0
pytest
pytest-cov
pytest-mypy; python_version >= '3.5'
pytest-mypy
semver>=2.0.0,<3.0.0
setuptools_scm
six>=1.14.0
Expand Down
9 changes: 0 additions & 9 deletions rsconnect/json_web_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import base64
from datetime import datetime, timedelta, timezone
import os
import sys

import binascii
import jwt
Expand Down Expand Up @@ -64,14 +63,6 @@ def validate_hs256_secret_key(key: bytes):
raise RSConnectException("Secret key expected to be at least 32 bytes in length")


def is_jwt_compatible_python_version() -> bool:
"""
JWT library is incompatible with Python 3.5
"""

return not sys.version_info < (3, 6)


def parse_client_response(response):
"""
Helper to handle the response type from RSConnectClient, because
Expand Down
6 changes: 0 additions & 6 deletions rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
from .json_web_token import (
read_secret_key,
validate_hs256_secret_key,
is_jwt_compatible_python_version,
TokenGenerator,
produce_bootstrap_output,
parse_client_response,
Expand Down Expand Up @@ -333,11 +332,6 @@ def bootstrap(
verbose,
):
set_verbosity(verbose)
if not is_jwt_compatible_python_version():
raise RSConnectException(
"Python version > 3.5 required for JWT generation. Please upgrade your Python installation."
)

if not server.startswith("http"):
raise RSConnectException("Server URL expected to begin with transfer protocol (ex. http/https).")

Expand Down
5 changes: 2 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@ install_requires =
click>=7.0.0
pip>=10.0.0
semver>=2.0.0,<3.0.0
pyjwt>=2.4.0; python_version >= '3.6'
pyjwt; python_version < '3.6'
pyjwt>=2.4.0
setup_requires =
setuptools
setuptools_scm>=3.4
toml
wheel
packages = rsconnect
python_requires = >=3.5
python_requires = >=3.7
zip_safe = true

[options.entry_points]
Expand Down
11 changes: 0 additions & 11 deletions tests/test_json_web_token.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
SECRET_KEY_ENV,
read_secret_key,
produce_bootstrap_output,
is_jwt_compatible_python_version,
parse_client_response,
TokenGenerator,
JWTEncoder,
Expand All @@ -43,9 +42,6 @@ def are_unix_timestamps_approx_equal(a, b):

class TestJsonWebToken(TestCase):
def setUp(self):
if not is_jwt_compatible_python_version():
self.skipTest("JWTs not supported in Python < 3.6")

# decoded copy of the base64-encoded key in testdata/jwt/secret.key
self.secret_key = b"12345678901234567890123456789012345"
self.secret_key_b64 = b"MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU="
Expand Down Expand Up @@ -186,13 +182,6 @@ def test_parse_client_response(self):
with pytest.raises(RSConnectException):
parse_client_response(None)

def test_is_jwt_compatible_python_version(self):
"""
With setUp() skipping invalid versions, this test should always return True
regardless of the particular python env we're running the tests in
"""
self.assertTrue(is_jwt_compatible_python_version())

def test_jwt_encoder_constructor(self):
encoder = JWTEncoder("issuer", "audience", self.secret_key)

Expand Down
5 changes: 1 addition & 4 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest
from click.testing import CliRunner

from rsconnect.json_web_token import SECRET_KEY_ENV, is_jwt_compatible_python_version
from rsconnect.json_web_token import SECRET_KEY_ENV

from .utils import (
apply_common_args,
Expand Down Expand Up @@ -561,9 +561,6 @@ def test_add_shinyapps_missing_options(self):

class TestBootstrap(TestCase):
def setUp(self):
if not is_jwt_compatible_python_version():
self.skipTest("JWTs not supported in Python < 3.6")

self.mock_server = "http://localhost:8080"
self.mock_uri = "http://localhost:8080/__api__/v1/experimental/bootstrap"
self.jwt_keypath = "tests/testdata/jwt/secret.key"
Expand Down
6 changes: 0 additions & 6 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from unittest import TestCase
from datetime import timedelta

from rsconnect.json_web_token import is_jwt_compatible_python_version

from rsconnect.json_web_token import JWTEncoder

from tests.utils import (
Expand All @@ -12,10 +10,6 @@


class TestJwtUtils(TestCase):
def setUp(self):
if not is_jwt_compatible_python_version():
self.skipTest("JWTs not supported in Python < 3.6")

def test_jwt_decoder(self):

secret = b"12345678912345678912345678912345"
Expand Down