Skip to content

Commit 6d13deb

Browse files
committed
Upgrade to Django 6 and switch to uv
1 parent 838241c commit 6d13deb

13 files changed

Lines changed: 623 additions & 478 deletions

File tree

.github/workflows/cicd.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,12 @@ jobs:
1515
uses: actions/setup-python@v2
1616
with:
1717
python-version: 3.13
18-
- name: Set up Chromedriver for e2e
19-
uses: nanasess/setup-chromedriver@v2
2018
- name: Install Dependencies
2119
run: |
22-
pip install pipenv
23-
pipenv install --dev
20+
pip install uv
21+
uv pip install --system -r pyproject.toml
2422
- name: Run Tests
2523
run: |
26-
pipenv run python manage.py test
27-
pipenv run python manage.py collectstatic --noinput
28-
pipenv run python manage.py behave
24+
python manage.py test
25+
python manage.py collectstatic --noinput
26+
python manage.py behave

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ ENV PYTHONUNBUFFERED 1
33
RUN mkdir /code
44
WORKDIR /code
55

6-
COPY Pipfile Pipfile.lock ./
7-
RUN pip install pipenv
8-
RUN pipenv install --system --deploy
6+
COPY pyproject.toml ./
7+
RUN pip install uv
8+
RUN uv pip install --system -r pyproject.toml
99

1010
COPY myrecommendations ./myrecommendations
1111
COPY myrestaurants ./myrestaurants

Pipfile

Lines changed: 0 additions & 20 deletions
This file was deleted.

Pipfile.lock

Lines changed: 0 additions & 383 deletions
This file was deleted.

Procfile

Lines changed: 0 additions & 1 deletion
This file was deleted.

README.md

Lines changed: 20 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Starting the MyRecommendations Project from Scratch
2828
===================================================
2929

3030
First of all, install the latest version of Python from [downloads](https://www.python.org/downloads/) and
31-
[pipenv](https://pipenv.readthedocs.io/en/latest/install/) to help you manage dependencies and virtual environments.
31+
[uv](https://docs.astral.sh/uv/getting-started/installation/) to help you manage dependencies and virtual environments.
3232

3333
Then, create the folder for the new project, in our case the project is called 'myrecommendations':
3434

@@ -38,13 +38,15 @@ $ mkdir myrecommendations
3838
$ cd myrecommendations
3939
```
4040

41-
Once in the `myrecommendations` folder, activate the pipenv virtual environment to keep the Python packages
41+
Once in the `myrecommendations` folder, create a uv virtual environment to keep the Python packages
4242
for your project organised and start by installing Django. Then, create a new Django project:
4343

4444
```shell script
45-
$ pipenv shell
45+
$ uv venv
4646

47-
$ pipenv install Django
47+
$ source .venv/bin/activate # On Windows use: .venv\Scripts\activate
48+
49+
$ uv pip install Django
4850

4951
$ django-admin startproject myrecommendations .
5052
```
@@ -174,8 +176,8 @@ To facilitate the description of the feature scenarios, while connecting them to
174176
To get Behave and integrate it with Django, install:
175177

176178
```shell script
177-
$ pipenv install behave
178-
$ pipenv install behave-django
179+
$ uv pip install behave
180+
$ uv pip install behave-django
179181
```
180182

181183
And add the 'behave_django' application at the end of the INSTALLED_APPS list in *myrecommendations/settings.py*:
@@ -196,52 +198,10 @@ INSTALLED_APPS = [
196198
Moreover, to make it possible to guide a browser from the test, and thus check if the application follows the expected behaviour from a end-user perspective, we will also use Splinter. It can be installed with the following command:
197199

198200
```shell script
199-
$ pipenv install splinter
200-
```
201-
202-
Finally, for end-to-end test, it is necessary to have a browser to test from client side. With Splinter, different browsers can be configured for testing, for instance Chrome, the most common one.
203-
204-
Assuming Chrome is already installed in your computer, the only requirement to use it for automated testing is the ChromeDriver, available for Windows, Linux and Mac from [https://sites.google.com/a/chromium.org/chromedriver/downloads](https://sites.google.com/a/chromium.org/chromedriver/downloads)
205-
206-
You can also install it using different package managers. For instance with **apt** on Linux:
207-
208-
```shell script
209-
apt-get update
210-
apt-get install chromedriver
201+
$ uv pip install splinter selenium
211202
```
212203

213-
Or **[Brew](https://brew.sh)** on OSX:
214-
215-
```shell script
216-
brew update
217-
brew install chromedriver
218-
xattr -d com.apple.quarantine $(which chromedriver)
219-
```
220-
221-
Or **[Chocolatey](https://chocolatey.org/docs/installation)** on Windows:
222-
223-
```shell script
224-
choco install chromedriver
225-
```
226-
227-
### Testing with Firefox instead of Chrome ###
228-
229-
Alternatively, for Firefox, install the browser:
230-
231-
```
232-
sudo apt-get update
233-
sudo apt-get install firefox
234-
```
235-
236-
Then, download Geckodriver and unpack it from [https://github.com/mozilla/geckodriver/releases/](https://github.com/mozilla/geckodriver/releases/)
237-
238-
Finally, add the geckodriver to your path:
239-
240-
```
241-
export PATH=$PATH:/your/path/to/geckodriver
242-
```
243-
244-
And configure the test environment in `environment.py`, as detailed next, to use `firefox` instead of `chrome`.
204+
Finally, for end-to-end test, it is necessary to have a browser to test from client side. With Splinter and Selenium, different browsers can be configured for testing, for instance Chrome or Firefox, which should be installed in the machine where the tests are run.
245205

246206
## Environment ##
247207

@@ -254,6 +214,7 @@ from splinter.browser import Browser
254214

255215
def before_all(context):
256216
context.browser = Browser('chrome', headless=True)
217+
# Alternatively, use `firefox` and headless=False to see the browser while testing
257218

258219
def after_all(context):
259220
context.browser.quit()
@@ -362,6 +323,15 @@ def step_impl(context, username, password):
362323
context.browser.fill('password', password)
363324
form.find_by_value('login').first.click()
364325
assert context.browser.is_text_present('User: ' + username)
326+
327+
@then("I'm redirected to the login form")
328+
def step_impl(context):
329+
wait = WebDriverWait(context.browser.driver, 3)
330+
login_form = wait.until(
331+
visibility_of_element_located((By.ID, "login-form"))
332+
)
333+
# context.browser.driver.save_screenshot("debug_redirect.png")
334+
assert context.browser.url.startswith(context.get_url('login'))
365335
```
366336

367337
Both steps are parameterized, so we can use the steps to login users with any username and password, as long as we have previously created them and the password matches.

db.sqlite3

0 Bytes
Binary file not shown.

features/environment.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,47 @@
1+
import re
2+
import os
13
from splinter.browser import Browser
24

5+
def chrome_browser(headless=True):
6+
from selenium.webdriver.chrome.options import Options
7+
chrome_options = Options()
8+
if headless:
9+
chrome_options.add_argument("--headless=new") # recommended headless mode
10+
chrome_options.add_argument("--disable-notifications")
11+
chrome_options.add_argument("--disable-infobars")
12+
chrome_options.add_argument("--no-sandbox")
13+
chrome_options.add_argument("--disable-dev-shm-usage")
14+
chrome_options.add_argument("--window-size=1920,1080")
15+
prefs = {
16+
"credentials_enable_service": False, # disable password manager
17+
"profile.password_manager_enabled": False,
18+
"profile.password_manager_leak_detection": False
19+
}
20+
chrome_options.add_experimental_option("prefs", prefs)
21+
return Browser("chrome", options=chrome_options)
22+
23+
def firefox_browser(headless=True):
24+
return Browser("firefox", headless=headless)
25+
326
def before_all(context):
4-
context.browser = Browser('chrome', headless=True)
27+
context.browser = chrome_browser(headless=True)
28+
# Alternatively, use `firefox_browser` and headless=False to see the browser while testing
529

630
def after_all(context):
731
context.browser.quit()
832
context.browser = None
33+
34+
def slugify(text):
35+
text = text.lower()
36+
text = re.sub(r"[^\w\s-]", "", text)
37+
text = re.sub(r"[\s]+", "-", text)
38+
return text
39+
40+
def after_step(context, step):
41+
if step.status == "failed":
42+
feature = slugify(context.feature.name)
43+
scenario = slugify(context.scenario.name)
44+
step_name = slugify(step.name)
45+
os.makedirs("screenshots", exist_ok=True)
46+
filename = f"screenshots/{feature}__{scenario}__{step_name}.png"
47+
context.browser.driver.save_screenshot(filename)

media/myrestaurants/random.png

67.3 KB
Loading

myrecommendations/settings_heroku.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)