diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a35300027f..8708d1ac8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - uses: actions/setup-python@f677139bbe7f9c59b41e40162b753c062f5d49a3 # v5 with: - python-version: "3.12.5" + python-version: "3.12.6" cache: "poetry" - name: Validate lockfile diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0a30546482..9294da061b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -74,7 +74,7 @@ repos: - ".*/generated/" additional_dependencies: ["gibberish-detector"] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.6.6" + rev: "v0.6.7" hooks: - id: ruff-format - id: ruff diff --git a/Dockerfile b/Dockerfile index 9d3cf6721e..85076f0560 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.12.5 +FROM python:3.12.6 LABEL maintainer "ODL DevOps " # Add package files, install updated node and pip diff --git a/RELEASE.rst b/RELEASE.rst index 75cb020984..c95e44d2b4 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,20 @@ Release Notes ============= +Version 0.20.0 +-------------- + +- updated header (#1622) +- Switch to using full name (#1621) +- Update dependency lxml to v5 (#1554) +- Remove health checks against opensearch (#1620) +- Add additional event capturing for some interactions (#1596) +- Revert "changes for formatting search subscription emails" +- changes for formatting search subscription emails +- Add custom label for percolate query subscriptions (#1610) +- Update Python to v3.12.6 (#1593) +- [pre-commit.ci] pre-commit autoupdate (#1601) + Version 0.19.6 (Released September 27, 2024) -------------- diff --git a/docker-compose.apps.yml b/docker-compose.apps.yml index 06049cfe6b..0b4ac494aa 100644 --- a/docker-compose.apps.yml +++ b/docker-compose.apps.yml @@ -8,9 +8,6 @@ services: build: context: . dockerfile: Dockerfile - extends: - file: docker-compose.opensearch.${OPENSEARCH_CLUSTER_TYPE:-single-node}.apps.yml - service: web mem_limit: 1gb cpus: 2 command: ./scripts/run-django-dev.sh @@ -50,9 +47,6 @@ services: build: context: . dockerfile: Dockerfile - extends: - file: docker-compose.opensearch.${OPENSEARCH_CLUSTER_TYPE:-single-node}.apps.yml - service: web command: > /bin/bash -c ' sleep 3; diff --git a/docker-compose.opensearch.cluster.apps.yml b/docker-compose.opensearch.cluster.apps.yml deleted file mode 100644 index cd473ffef1..0000000000 --- a/docker-compose.opensearch.cluster.apps.yml +++ /dev/null @@ -1,17 +0,0 @@ -services: - web: - depends_on: - opensearch-node-mitopen-1: - condition: service_healthy - opensearch-node-mitopen-2: - condition: service_healthy - opensearch-node-mitopen-3: - condition: service_healthy - celery: - depends_on: - opensearch-node-mitopen-1: - condition: service_healthy - opensearch-node-mitopen-2: - condition: service_healthy - opensearch-node-mitopen-3: - condition: service_healthy diff --git a/docker-compose.opensearch.single-node.apps.yml b/docker-compose.opensearch.single-node.apps.yml deleted file mode 100644 index 9a66e038f3..0000000000 --- a/docker-compose.opensearch.single-node.apps.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - web: - depends_on: - opensearch-node-mitopen-1: - condition: service_healthy - celery: - depends_on: - opensearch-node-mitopen-1: - condition: service_healthy diff --git a/fixtures/common.py b/fixtures/common.py index 724d6f3569..4f18431505 100644 --- a/fixtures/common.py +++ b/fixtures/common.py @@ -44,7 +44,7 @@ def warnings_as_errors(): # noqa: PT004 # Ignore deprecation warnings in third party libraries warnings.filterwarnings( "ignore", - module=".*(api_jwt|api_jws|rest_framework_jwt|astroid|celery|factory|botocore|posthog).*", + module=".*(api_jwt|api_jws|rest_framework_jwt|astroid|bs4|celery|factory|botocore|posthog).*", category=DeprecationWarning, ) yield diff --git a/frontends/api/src/generated/v0/api.ts b/frontends/api/src/generated/v0/api.ts index a8ecc603ce..694b9b5086 100644 --- a/frontends/api/src/generated/v0/api.ts +++ b/frontends/api/src/generated/v0/api.ts @@ -1597,12 +1597,6 @@ export interface PatchedChannelWriteRequest { * @interface PatchedProfileRequest */ export interface PatchedProfileRequest { - /** - * - * @type {string} - * @memberof PatchedProfileRequest - */ - name?: string | null /** * * @type {string} @@ -1928,11 +1922,11 @@ export interface PreferencesSearch { */ export interface Profile { /** - * + * Get the user\'s name * @type {string} * @memberof Profile */ - name?: string | null + name: string /** * * @type {string} @@ -2054,12 +2048,6 @@ export interface Profile { * @interface ProfileRequest */ export interface ProfileRequest { - /** - * - * @type {string} - * @memberof ProfileRequest - */ - name?: string | null /** * * @type {string} diff --git a/frontends/api/src/generated/v1/api.ts b/frontends/api/src/generated/v1/api.ts index cf9b817ed5..62385b9658 100644 --- a/frontends/api/src/generated/v1/api.ts +++ b/frontends/api/src/generated/v1/api.ts @@ -3638,6 +3638,12 @@ export interface PercolateQuery { * @memberof PercolateQuery */ source_type: SourceTypeEnum + /** + * Friendly display label for the query + * @type {string} + * @memberof PercolateQuery + */ + display_label?: string } /** diff --git a/frontends/mit-learn/public/images/mit-learn-logo.svg b/frontends/mit-learn/public/images/mit-learn-logo.svg index 548d70485f..0069f62884 100644 --- a/frontends/mit-learn/public/images/mit-learn-logo.svg +++ b/frontends/mit-learn/public/images/mit-learn-logo.svg @@ -1,8 +1,5 @@ - - - - - - - + + diff --git a/frontends/mit-learn/public/images/mit_logo_std_cmyk_black.svg b/frontends/mit-learn/public/images/mit-logo-black.svg similarity index 100% rename from frontends/mit-learn/public/images/mit_logo_std_cmyk_black.svg rename to frontends/mit-learn/public/images/mit-logo-black.svg diff --git a/frontends/mit-learn/public/images/mit-logo-transparent.svg b/frontends/mit-learn/public/images/mit-logo-color.svg similarity index 100% rename from frontends/mit-learn/public/images/mit-logo-transparent.svg rename to frontends/mit-learn/public/images/mit-logo-color.svg diff --git a/frontends/mit-learn/public/images/mit-logo-learn-white.svg b/frontends/mit-learn/public/images/mit-logo-learn-white.svg new file mode 100644 index 0000000000..c46990cc9a --- /dev/null +++ b/frontends/mit-learn/public/images/mit-logo-learn-white.svg @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/frontends/mit-learn/public/images/mit-logo-transparent2.svg b/frontends/mit-learn/public/images/mit-logo-transparent2.svg deleted file mode 100644 index 67da18b013..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-transparent2.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -logo2 - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-transparent3.svg b/frontends/mit-learn/public/images/mit-logo-transparent3.svg deleted file mode 100644 index 67da18b013..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-transparent3.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -logo2 - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-transparent4.svg b/frontends/mit-learn/public/images/mit-logo-transparent4.svg deleted file mode 100644 index 7fd59c879c..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-transparent4.svg +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-transparent5.jpg b/frontends/mit-learn/public/images/mit-logo-transparent5.jpg deleted file mode 100644 index fca614d62b..0000000000 Binary files a/frontends/mit-learn/public/images/mit-logo-transparent5.jpg and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-logo-transparent5.png b/frontends/mit-learn/public/images/mit-logo-transparent5.png deleted file mode 100644 index 91a9f6ab32..0000000000 Binary files a/frontends/mit-learn/public/images/mit-logo-transparent5.png and /dev/null differ diff --git a/frontends/mit-learn/public/images/mit-logo-transparent5.svg b/frontends/mit-learn/public/images/mit-logo-transparent5.svg deleted file mode 100644 index a85e39a189..0000000000 --- a/frontends/mit-learn/public/images/mit-logo-transparent5.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -logo2 - - - - - - - diff --git a/frontends/mit-learn/public/images/mit-logo-white.svg b/frontends/mit-learn/public/images/mit-logo-white.svg new file mode 100644 index 0000000000..5b0774426b --- /dev/null +++ b/frontends/mit-learn/public/images/mit-logo-white.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/frontends/mit-learn/src/page-components/Dialogs/AddToListDialog.tsx b/frontends/mit-learn/src/page-components/Dialogs/AddToListDialog.tsx index 037a39031e..239b34563e 100644 --- a/frontends/mit-learn/src/page-components/Dialogs/AddToListDialog.tsx +++ b/frontends/mit-learn/src/page-components/Dialogs/AddToListDialog.tsx @@ -10,6 +10,7 @@ import { } from "ol-components" import { RiAddLine } from "@remixicon/react" +import { usePostHog } from "posthog-js/react" import * as NiceModal from "@ebay/nice-modal-react" @@ -67,6 +68,7 @@ const AddToListDialogInner: React.FC = ({ isLoading: isSavingLearningPathRelationships, mutateAsync: setLearningPathRelationships, } = useLearningResourceSetLearningPathRelationships() + const posthog = usePostHog() const isSaving = isSavingLearningPathRelationships || isSavingUserListRelationships let dialogTitle = "Add to list" @@ -93,6 +95,9 @@ const AddToListDialogInner: React.FC = ({ : null, ) .filter((value) => value !== null) + + const { POSTHOG } = APP_SETTINGS + const formik = useFormik({ enableReinitialize: true, validateOnChange: false, @@ -103,6 +108,15 @@ const AddToListDialogInner: React.FC = ({ }, onSubmit: async (values) => { if (resource) { + if (!(!POSTHOG?.api_key || POSTHOG.api_key.length < 1)) { + posthog.capture("lr_add_to_list", { + listType: listType, + resourceId: resource?.id, + readableId: resource?.readable_id, + platformCode: resource?.platform?.code, + resourceType: resource?.resource_type, + }) + } if (listType === ListType.LearningPath) { const newParents = values.learning_paths.map((id) => parseInt(id)) await setLearningPathRelationships({ diff --git a/frontends/mit-learn/src/page-components/Footer/Footer.test.tsx b/frontends/mit-learn/src/page-components/Footer/Footer.test.tsx index 09f2b25324..0f9ee8d05f 100644 --- a/frontends/mit-learn/src/page-components/Footer/Footer.test.tsx +++ b/frontends/mit-learn/src/page-components/Footer/Footer.test.tsx @@ -3,18 +3,23 @@ import Footer from "./Footer" import React from "react" import { ThemeProvider } from "ol-components" import * as urls from "@/common/urls" +import { MemoryRouter } from "react-router" describe("Footer", () => { test("Renders the appropriate text and links", async () => { - render(
, { - wrapper: ThemeProvider, - }) + render( + + +
+
+
, + ) interface Links { [key: string]: string } const expectedLinks: Links = { // key is blank here because the link is an image - "": "https://mit.edu/", + "": "https://www.mit.edu/", Home: urls.HOME, "About Us": urls.ABOUT, Accessibility: urls.ACCESSIBILITY, diff --git a/frontends/mit-learn/src/page-components/Footer/Footer.tsx b/frontends/mit-learn/src/page-components/Footer/Footer.tsx index bcabe9704d..d399ade81a 100644 --- a/frontends/mit-learn/src/page-components/Footer/Footer.tsx +++ b/frontends/mit-learn/src/page-components/Footer/Footer.tsx @@ -1,7 +1,7 @@ import { Container, styled } from "ol-components" -import { MITLogoLink } from "ol-utilities" import * as urls from "@/common/urls" import React, { FunctionComponent } from "react" +import MITLogoLink from "../MITLogoLink/MITLogoLink" const PUBLIC_URL = APP_SETTINGS.PUBLIC_URL const HOME_URL = `${PUBLIC_URL}/` @@ -147,10 +147,7 @@ const Footer: FunctionComponent = () => { - + Massachusetts Institute of Technology

diff --git a/frontends/mit-learn/src/page-components/Header/Header.test.tsx b/frontends/mit-learn/src/page-components/Header/Header.test.tsx index 39c6962901..f6427bbdd5 100644 --- a/frontends/mit-learn/src/page-components/Header/Header.test.tsx +++ b/frontends/mit-learn/src/page-components/Header/Header.test.tsx @@ -31,10 +31,7 @@ describe("UserMenu", () => { return screen.findByRole("menu") } - test.each([ - { first_name: "", last_name: "" }, - { first_name: null, last_name: null }, - ])( + test.each([{}, { profile: null }, { profile: {} }])( "Trigger button shows UserIcon for authenticated users w/o initials", async (userSettings) => { setMockResponse.get(urls.userMe.get(), userSettings) @@ -46,29 +43,13 @@ describe("UserMenu", () => { }, ) - test.each([ - { - userSettings: { first_name: "Alice", last_name: "Bee" }, - expectedName: "Alice Bee", - }, - { - userSettings: { first_name: "Alice", last_name: "" }, - expectedName: "Alice", - }, - { - userSettings: { first_name: "", last_name: "Bee" }, - expectedName: "Bee", - }, - ])( - "Trigger button shows name if available", - async ({ userSettings, expectedName }) => { - setMockResponse.get(urls.userMe.get(), userSettings) + test("Trigger button shows name if available", async () => { + setMockResponse.get(urls.userMe.get(), { profile: { name: "Alice Bee" } }) - renderWithProviders(
) - const trigger = await screen.findByRole("button", { name: "User Menu" }) - expect(trigger.textContent).toBe(expectedName) - }, - ) + renderWithProviders(
) + const trigger = await screen.findByRole("button", { name: "User Menu" }) + expect(trigger.textContent).toBe("Alice Bee") + }) test("Unauthenticated users see the Sign Up / Login link", async () => { const isAuthenticated = false diff --git a/frontends/mit-learn/src/page-components/Header/Header.tsx b/frontends/mit-learn/src/page-components/Header/Header.tsx index a0756c3d86..64a6d81fa5 100644 --- a/frontends/mit-learn/src/page-components/Header/Header.tsx +++ b/frontends/mit-learn/src/page-components/Header/Header.tsx @@ -3,7 +3,6 @@ import type { NavData } from "ol-components" import { styled, AppBar, - Divider, NavDrawer, Toolbar, ClickAwayListener, @@ -23,7 +22,7 @@ import { RiPriceTag3Line, RiAwardLine, } from "@remixicon/react" -import { MITLogoLink, useToggle } from "ol-utilities" +import { useToggle } from "ol-utilities" import UserMenu from "./UserMenu" import { MenuButton } from "./MenuButton" import { @@ -41,18 +40,24 @@ import { SEARCH_LEARNING_MATERIAL, } from "@/common/urls" import { useUserMe } from "api/hooks/user" +import MITLogoLink from "../MITLogoLink/MITLogoLink" const Bar = styled(AppBar)(({ theme }) => ({ - height: "60px", - padding: "0 8px", - borderBottom: `1px solid ${theme.custom.colors.lightGray2}`, - backgroundColor: theme.custom.colors.white, - color: theme.custom.colors.darkGray1, + padding: "16px 8px", + borderBottom: `4px solid ${theme.custom.colors.darkGray2}`, + backgroundColor: theme.custom.colors.navGray, display: "flex", + justifyContent: "space-between", flexDirection: "column", - boxShadow: "0 2px 10px rgba(120 169 197 / 15%)", + boxShadow: "0px 3px 35px 0px rgba(23, 30, 42, 0.50)", + ".MuiToolbar-root": { + minHeight: "auto", + }, [theme.breakpoints.down("sm")]: { + height: "60px", padding: "0", + borderBottom: `1px solid ${theme.custom.colors.darkGray2}`, + boxShadow: "0px -2px 20px 0px rgba(0, 0, 0, 0.05)", }, })) @@ -83,45 +88,54 @@ const StyledToolbar = styled(Toolbar)({ flex: 1, }) -const LogoLink = styled(MITLogoLink)(({ theme }) => ({ - display: "flex", - border: "none", +const StyledMITLogoLink = styled(MITLogoLink)(({ theme }) => ({ img: { - width: 109, - height: 40, + height: "24px", [theme.breakpoints.down("sm")]: { - marginLeft: "16px", + height: "16px", }, }, })) -const LeftDivider = styled(Divider)({ - margin: "0 24px", - height: "24px", - alignSelf: "auto", +const Spacer = styled.div({ + flex: "1", }) -const RightDivider = styled(Divider)(({ theme }) => ({ - margin: "0 32px", - height: "24px", - alignSelf: "auto", +const LeftSpacer = styled.div(({ theme }) => ({ + width: "24px", [theme.breakpoints.down("sm")]: { - margin: "0 16px", + width: "16px", }, })) -const Spacer = styled.div` - flex: 1; -` +const StyledSearchButton = styled(ActionButtonLink)(({ theme }) => ({ + width: "auto", + height: "auto", + padding: "4px 16px", + "&:hover": { + svg: { + opacity: 1, + }, + }, + [theme.breakpoints.down("sm")]: { + padding: "0", + }, +})) const StyledSearchIcon = styled(RiSearch2Line)(({ theme }) => ({ - color: theme.custom.colors.darkGray2, + width: "24px", + height: "24px", + color: theme.custom.colors.white, + opacity: 0.5, margin: "4px 0", + [theme.breakpoints.down("sm")]: { + opacity: 1, + }, })) const SearchButton: FunctionComponent = () => { return ( - { aria-label="Search" > - + ) } @@ -142,7 +156,6 @@ const LoggedOutView: FunctionComponent = () => { - @@ -153,7 +166,6 @@ const LoggedInView: FunctionComponent = () => { return ( - ) @@ -265,8 +277,8 @@ const Header: FunctionComponent = () => { - - + + { - + + diff --git a/frontends/mit-learn/src/page-components/Header/MenuButton.tsx b/frontends/mit-learn/src/page-components/Header/MenuButton.tsx index 99218234c8..add3d730a7 100644 --- a/frontends/mit-learn/src/page-components/Header/MenuButton.tsx +++ b/frontends/mit-learn/src/page-components/Header/MenuButton.tsx @@ -12,7 +12,6 @@ const CloseMenuIcon = styled(RiCloseLargeLine)(({ theme }) => ({ const MenuButtonText = styled.div(({ theme }) => ({ alignSelf: "center", - color: theme.custom.colors.darkGray2, paddingLeft: "16px", textTransform: "none", [theme.breakpoints.down("sm")]: { @@ -23,12 +22,11 @@ const MenuButtonText = styled.div(({ theme }) => ({ const MenuButtonInner = styled.div({ display: "flex", - padding: "8px 0", alignItems: "flex-start", }) const StyledMenuButton = styled.button(({ theme }) => ({ - padding: "0", + padding: "8px 16px", background: "transparent", "&:hover:not(:disabled)": { background: "transparent", @@ -38,10 +36,21 @@ const StyledMenuButton = styled.button(({ theme }) => ({ display: "inline-flex", justifyContent: "center", alignItems: "center", - color: theme.palette.text.primary, + color: theme.custom.colors.white, transition: `background ${theme.transitions.duration.short}ms`, cursor: "pointer", borderStyle: "none", + opacity: 0.5, + svg: { + color: theme.custom.colors.white, + }, + [theme.breakpoints.down("sm")]: { + padding: "4px 0", + opacity: 1, + }, + "&:hover": { + opacity: 1, + }, })) interface MenuButtonProps { diff --git a/frontends/mit-learn/src/page-components/Header/UserMenu.tsx b/frontends/mit-learn/src/page-components/Header/UserMenu.tsx index 22c6304fc3..6a54459cd6 100644 --- a/frontends/mit-learn/src/page-components/Header/UserMenu.tsx +++ b/frontends/mit-learn/src/page-components/Header/UserMenu.tsx @@ -1,5 +1,11 @@ import React, { useState } from "react" -import { ActionButtonLink, ButtonLink, SimpleMenu, styled } from "ol-components" +import { + ActionButtonLink, + ButtonLink, + SimpleMenu, + styled, + theme, +} from "ol-components" import type { MenuOverrideProps, SimpleMenuItem } from "ol-components" import * as urls from "@/common/urls" import { @@ -9,25 +15,40 @@ import { } from "@remixicon/react" import { useUserMe, User } from "api/hooks/user" import { useLocation } from "react-router" +import MITLogoLink from "../MITLogoLink/MITLogoLink" const FlexContainer = styled.div({ display: "flex", alignItems: "center", }) -const UserMenuContainer = styled.button({ +const UserMenuContainer = styled.button(({ theme }) => ({ display: "flex", alignItems: "center", cursor: "pointer", background: "none", - color: "inherit", - border: "none", - padding: "0", + color: theme.custom.colors.white, + height: "40px", + border: `1px solid ${theme.custom.colors.silverGrayDark}`, + borderRadius: "4px", + padding: "2px 8px", + gap: "8px", font: "inherit", -}) + margin: "0 16px", + opacity: 0.75, + "&:hover": { + opacity: 1, + }, + [theme.breakpoints.down("sm")]: { + border: "none", + opacity: 1, + gap: "2px", + padding: "4px 0", + margin: "0px 24px", + }, +})) const LoginButtonContainer = styled(FlexContainer)(({ theme }) => ({ - paddingLeft: "24px", "&:hover": { textDecoration: "none", }, @@ -50,10 +71,20 @@ const LoginButtonContainer = styled(FlexContainer)(({ theme }) => ({ }, })) -const UserIcon = styled(RiAccountCircleFill)(({ theme }) => ({ +const DesktopLoginButton = styled(ButtonLink)({ + height: "40px", + padding: "18px 12px", + margin: "0 16px", +}) + +const MobileLoginButton = styled(ActionButtonLink)({ width: "24px", height: "24px", - color: theme.custom.colors.black, + margin: "0 24px", +}) + +const UserIcon = styled(RiAccountCircleFill)(({ theme }) => ({ + color: theme.custom.colors.white, })) type UserMenuItem = SimpleMenuItem & { @@ -61,8 +92,7 @@ type UserMenuItem = SimpleMenuItem & { } const UserNameContainer = styled.span(({ theme }) => ({ - color: theme.custom.colors.darkGray2, - padding: "0 12px", + color: theme.custom.colors.white, [theme.breakpoints.down("sm")]: { display: "none", }, @@ -70,26 +100,39 @@ const UserNameContainer = styled.span(({ theme }) => ({ })) const UserName: React.FC<{ user: User | undefined }> = ({ user }) => { - const first = user?.first_name ?? "" - const last = user?.last_name ?? "" - return ( - - {first} - {first && last ? " " : ""} - {last} - - ) + return {user?.profile?.name ?? ""} } const UserMenuChevron: React.FC<{ open: boolean }> = ({ open }) => { return open ? : } +const StyledMITLogoLink = styled(MITLogoLink)(({ theme }) => ({ + width: "64px", + height: "32px", + marginLeft: "16px", + [theme.breakpoints.down("sm")]: { + width: "48px", + height: "24px", + marginLeft: "0", + }, +})) + type DeviceType = "mobile" | "desktop" type UserMenuProps = { variant?: DeviceType } +const MITHomeLink: React.FC = () => { + return ( + + ) +} + const UserMenu: React.FC = ({ variant }) => { const [visible, setVisible] = useState(false) const location = useLocation() @@ -103,6 +146,12 @@ const UserMenu: React.FC = ({ variant }) => { }) const items: UserMenuItem[] = [ + { + label: "Home", + key: "home", + allow: true, + href: urls.HOME, + }, { label: "Dashboard", key: "dashboard", @@ -125,47 +174,73 @@ const UserMenu: React.FC = ({ variant }) => { ] const menuOverrideProps: MenuOverrideProps = { - anchorOrigin: { horizontal: "right", vertical: "bottom" }, - transformOrigin: { horizontal: "right", vertical: "top" }, + anchorOrigin: { horizontal: "left", vertical: "bottom" }, + transformOrigin: { horizontal: "left", vertical: "top" }, + slotProps: { + paper: { + sx: { + borderRadius: "0px 0px 5px 5px", + backgroundColor: theme.custom.colors.darkGray1, + padding: "0 16px", + ".MuiMenu-list": { + padding: "8px 0", + ".MuiMenuItem-root": { + backgroundColor: theme.custom.colors.darkGray1, + color: theme.custom.colors.white, + padding: "8px 0", + "&:hover": { + textDecoration: "underline", + }, + }, + }, + ...theme.typography.body2, + }, + }, + }, } if (user?.is_authenticated) { return ( - allow) - .map(({ allow, ...item }) => item)} - trigger={ - - - - {user?.is_authenticated ? : ""} - - } - /> + <> + allow) + .map(({ allow, ...item }) => item)} + trigger={ + + + + {user?.is_authenticated ? : ""} + + } + /> + + ) } else { return ( {variant === "desktop" ? ( - Log In - + + ) : ( "" )} {variant === "mobile" ? ( - = ({ variant }) => { aria-label="Log in" > - + + ) : ( "" diff --git a/frontends/mit-learn/src/page-components/MITLogoLink/MITLogoLink.tsx b/frontends/mit-learn/src/page-components/MITLogoLink/MITLogoLink.tsx new file mode 100644 index 0000000000..45c4e872c0 --- /dev/null +++ b/frontends/mit-learn/src/page-components/MITLogoLink/MITLogoLink.tsx @@ -0,0 +1,36 @@ +import { Link, styled } from "ol-components" +import React from "react" + +const PUBLIC_URL = APP_SETTINGS.PUBLIC_URL +const MIT_LEARN_HOME_URL = `${PUBLIC_URL}/` + +const MIT_LOGO_URL = `${PUBLIC_URL}/static/images/mit-logo-black.svg` + +const StyledLink = styled(Link)({ + display: "flex", + alignItems: "center", + justifyContent: "center", +}) + +interface Props { + href?: string + src?: string + className?: string + target?: string +} + +const MITLogoLink: React.FC = ({ href, src, className, target }) => ( + + MIT Logo + +) + +export default MITLogoLink diff --git a/frontends/mit-learn/src/pages/DashboardPage/Dashboard.test.tsx b/frontends/mit-learn/src/pages/DashboardPage/Dashboard.test.tsx index d1c1efdbe6..2833ec9e0e 100644 --- a/frontends/mit-learn/src/pages/DashboardPage/Dashboard.test.tsx +++ b/frontends/mit-learn/src/pages/DashboardPage/Dashboard.test.tsx @@ -210,17 +210,20 @@ describe("DashboardPage", () => { setupAPIs() setMockResponse.get(urls.userMe.get(), { [Permissions.Authenticated]: true, - first_name: "User", - last_name: "Info", + first_name: "Joe", + last_name: "Smith", + profile: { + name: "Jane Smith", + }, }) renderWithProviders() await waitFor(() => { /** - * There should be two instances of "User Info" text, + * There should be two instances of "Jane Smith" text, * one in the header and one in the main content */ - const userInfoText = screen.getByText("User Info") + const userInfoText = screen.getByText("Jane Smith") expect(userInfoText).toBeInTheDocument() }) }) diff --git a/frontends/mit-learn/src/pages/DashboardPage/DashboardPage.tsx b/frontends/mit-learn/src/pages/DashboardPage/DashboardPage.tsx index 7b0073d72a..96310366cc 100644 --- a/frontends/mit-learn/src/pages/DashboardPage/DashboardPage.tsx +++ b/frontends/mit-learn/src/pages/DashboardPage/DashboardPage.tsx @@ -330,7 +330,7 @@ const DashboardPage: React.FC = () => { {isLoadingUser ? ( ) : ( - {`${user?.first_name} ${user?.last_name}`} + {`${user?.profile?.name}`} )} diff --git a/frontends/mit-learn/src/pages/DashboardPage/ProfileEditForm.tsx b/frontends/mit-learn/src/pages/DashboardPage/ProfileEditForm.tsx index eefdbe2f66..b7e89a58d9 100644 --- a/frontends/mit-learn/src/pages/DashboardPage/ProfileEditForm.tsx +++ b/frontends/mit-learn/src/pages/DashboardPage/ProfileEditForm.tsx @@ -103,17 +103,10 @@ const ProfileEditForm: React.FC = ({ profile }) => { - diff --git a/frontends/mit-learn/src/pages/SearchPage/SearchPage.tsx b/frontends/mit-learn/src/pages/SearchPage/SearchPage.tsx index 3b8c3830cd..476945824c 100644 --- a/frontends/mit-learn/src/pages/SearchPage/SearchPage.tsx +++ b/frontends/mit-learn/src/pages/SearchPage/SearchPage.tsx @@ -20,6 +20,7 @@ import type { LearningResourceOfferor } from "api" import { useOfferorsList } from "api/hooks/learningResources" import { capitalize } from "ol-utilities" import MetaTags from "@/page-components/MetaTags/MetaTags" +import { usePostHog } from "posthog-js/react" const cssGradient = ` linear-gradient( @@ -175,6 +176,8 @@ const useFacetManifest = (resourceCategory: string | null) => { const SearchPage: React.FC = () => { const [searchParams, setSearchParams] = useSearchParams() const facetManifest = useFacetManifest(searchParams.get("resource_category")) + const posthog = usePostHog() + const { POSTHOG } = APP_SETTINGS const setPage = useCallback( (newPage: number) => { @@ -191,8 +194,11 @@ const SearchPage: React.FC = () => { [setSearchParams], ) const onFacetsChange = useCallback(() => { + if (!(!POSTHOG?.api_key || POSTHOG.api_key.length < 1)) { + posthog.capture("search_update") + } setPage(1) - }, [setPage]) + }, [setPage, posthog, POSTHOG]) const { params, diff --git a/frontends/ol-ckeditor/src/types/settings.d.ts b/frontends/ol-ckeditor/src/types/settings.d.ts index 237e6ca039..5b68d7c8b7 100644 --- a/frontends/ol-ckeditor/src/types/settings.d.ts +++ b/frontends/ol-ckeditor/src/types/settings.d.ts @@ -1,5 +1,11 @@ /* eslint-disable no-var */ +export type PostHogSettings = { + api_key: string + timeout?: int + bootstrap_flags?: Record +} + export declare global { const APP_SETTINGS: { EMBEDLY_KEY: string @@ -9,5 +15,6 @@ export declare global { PUBLIC_URL: string SITE_NAME: string CSRF_COOKIE_NAME: string + POSTHOG?: PostHogSettings } } diff --git a/frontends/ol-components/package.json b/frontends/ol-components/package.json index 8942839161..87b9df5a3c 100644 --- a/frontends/ol-components/package.json +++ b/frontends/ol-components/package.json @@ -26,6 +26,7 @@ "material-ui-popup-state": "^5.1.0", "ol-test-utilities": "0.0.0", "ol-utilities": "0.0.0", + "posthog-js": "^1.165.0", "react": "18.3.1", "react-router": "^6.22.2", "react-router-dom": "^6.22.2", diff --git a/frontends/ol-components/src/components/Banner/Banner.stories.tsx b/frontends/ol-components/src/components/Banner/Banner.stories.tsx index 77521fdd20..e56690ae39 100644 --- a/frontends/ol-components/src/components/Banner/Banner.stories.tsx +++ b/frontends/ol-components/src/components/Banner/Banner.stories.tsx @@ -48,7 +48,7 @@ export const logoBanner: Story = { @@ -66,7 +66,7 @@ export const logoBannerWithExtras: Story = { diff --git a/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx b/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx index 95d711dd49..1f5208bea3 100644 --- a/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx +++ b/frontends/ol-components/src/components/NavDrawer/NavDrawer.tsx @@ -3,7 +3,7 @@ import styled from "@emotion/styled" import React, { ReactElement } from "react" const DrawerContent = styled.div(({ theme }) => ({ - paddingTop: "60px", + paddingTop: "72px", width: "366px", height: "100%", background: theme.custom.colors.white, diff --git a/frontends/ol-components/src/components/SearchInput/SearchInput.tsx b/frontends/ol-components/src/components/SearchInput/SearchInput.tsx index 58c6c0935a..09e711f40e 100644 --- a/frontends/ol-components/src/components/SearchInput/SearchInput.tsx +++ b/frontends/ol-components/src/components/SearchInput/SearchInput.tsx @@ -3,6 +3,7 @@ import { RiSearch2Line, RiCloseLine } from "@remixicon/react" import { Input, AdornmentButton } from "../Input/Input" import type { InputProps } from "../Input/Input" import styled from "@emotion/styled" +import { usePostHog } from "posthog-js/react" const StyledInput = styled(Input)(({ theme }) => ({ boxShadow: "0px 8px 20px 0px rgba(120, 147, 172, 0.10)", @@ -53,18 +54,32 @@ const muiInputProps = { "aria-label": "Search for" } const SearchInput: React.FC = (props) => { const { onSubmit, value } = props - const handleSubmit = useCallback(() => { - const event = { - target: { value }, - preventDefault: () => null, - } - onSubmit(event) - }, [onSubmit, value]) + const posthog = usePostHog() + const { POSTHOG } = APP_SETTINGS + + const handleSubmit = useCallback( + ( + ev: + | React.SyntheticEvent + | React.SyntheticEvent, + isEnter: boolean = false, + ) => { + const event = { + target: { value }, + preventDefault: () => null, + } + if (!(!POSTHOG?.api_key || POSTHOG.api_key.length < 1)) { + posthog.capture("search_update", { isEnter: isEnter }) + } + onSubmit(event) + }, + [onSubmit, value, posthog, POSTHOG], + ) const onInputKeyDown: React.KeyboardEventHandler = useCallback( (e) => { if (e.key !== "Enter") return - handleSubmit() + handleSubmit(e, true) }, [handleSubmit], ) diff --git a/frontends/ol-components/src/components/ThemeProvider/colors.ts b/frontends/ol-components/src/components/ThemeProvider/colors.ts index 47b876a8a3..0c0ae91037 100644 --- a/frontends/ol-components/src/components/ThemeProvider/colors.ts +++ b/frontends/ol-components/src/components/ThemeProvider/colors.ts @@ -10,6 +10,7 @@ const colors = { silverGrayLight: "#B8C2CC", lightGray2: "#DDE1E6", lightGray1: "#F3F4F8", + navGray: "#303337", darkPink: "#750062", pink: "#FF14F0", lightPink: "#FFB3FF", diff --git a/frontends/ol-components/src/types/theme.d.ts b/frontends/ol-components/src/types/theme.d.ts index e971ffe9af..21986bf478 100644 --- a/frontends/ol-components/src/types/theme.d.ts +++ b/frontends/ol-components/src/types/theme.d.ts @@ -24,6 +24,7 @@ interface CustomTheme { silverGrayLight: string lightGray2: string lightGray1: string + navGray: string darkPink: string pink: string lightPink: string diff --git a/frontends/ol-utilities/src/components/MITLogoLink.tsx b/frontends/ol-utilities/src/components/MITLogoLink.tsx deleted file mode 100644 index c232e78170..0000000000 --- a/frontends/ol-utilities/src/components/MITLogoLink.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react" - -const PUBLIC_URL = APP_SETTINGS.PUBLIC_URL -const HOME_URL = `${PUBLIC_URL}/` - -const MIT_LOGO_URL = `${PUBLIC_URL}/static/images/mit-logo-learn.svg` - -interface Props { - href?: string - src?: string - className?: string -} - -const MITLogoLink: React.FC = ({ href, src, className }) => ( - - MIT Logo - -) - -export default MITLogoLink diff --git a/frontends/ol-utilities/src/components/index.ts b/frontends/ol-utilities/src/components/index.ts deleted file mode 100644 index 1281be3867..0000000000 --- a/frontends/ol-utilities/src/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as MITLogoLink } from "./MITLogoLink" diff --git a/frontends/ol-utilities/src/index.ts b/frontends/ol-utilities/src/index.ts index a0497c81cc..c46078b796 100644 --- a/frontends/ol-utilities/src/index.ts +++ b/frontends/ol-utilities/src/index.ts @@ -1,7 +1,6 @@ // eslint-disable-next-line @typescript-eslint/triple-slash-reference /// -export * from "./components" export * from "./styles" export * from "./date/format" diff --git a/learning_resources_search/admin.py b/learning_resources_search/admin.py index c0a6b23160..cf839aae59 100644 --- a/learning_resources_search/admin.py +++ b/learning_resources_search/admin.py @@ -9,8 +9,8 @@ class PercolateQueryAdmin(admin.ModelAdmin): """PercolateQuery Admin""" model = models.PercolateQuery - list_display = ("original_query", "query") - search_fields = ("original_query", "query") + list_display = ("original_query", "query", "display_label") + search_fields = ("original_query", "query", "display_label") admin.site.register(models.PercolateQuery, PercolateQueryAdmin) diff --git a/learning_resources_search/migrations/0005_percolatequery_display_label.py b/learning_resources_search/migrations/0005_percolatequery_display_label.py new file mode 100644 index 0000000000..a2c2814fc0 --- /dev/null +++ b/learning_resources_search/migrations/0005_percolatequery_display_label.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.16 on 2024-09-25 18:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("learning_resources_search", "0004_alter_percolatequery_source_type"), + ] + + operations = [ + migrations.AddField( + model_name="percolatequery", + name="display_label", + field=models.CharField( + blank=True, + help_text="Friendly display label for the query", + max_length=255, + ), + ), + ] diff --git a/learning_resources_search/models.py b/learning_resources_search/models.py index 058381b2af..8b10a69981 100644 --- a/learning_resources_search/models.py +++ b/learning_resources_search/models.py @@ -26,6 +26,12 @@ class PercolateQuery(TimestampedModel): source_type = models.CharField( max_length=255, choices=[(choice, choice) for choice in SOURCE_TYPES] ) + + display_label = models.CharField( + max_length=255, + blank=True, + help_text="Friendly display label for the query", + ) users = models.ManyToManyField(User, related_name="percolate_queries") def source_label(self): @@ -37,6 +43,8 @@ def source_label(self): def source_description(self): channel = self.source_channel() + if self.display_label: + return self.display_label if channel: return channel.title return self.original_url_params() diff --git a/learning_resources_search/models_test.py b/learning_resources_search/models_test.py index fa070c6fe7..3a6058e2ea 100644 --- a/learning_resources_search/models_test.py +++ b/learning_resources_search/models_test.py @@ -1,4 +1,5 @@ from types import SimpleNamespace +from urllib.parse import urlencode import pytest @@ -152,3 +153,57 @@ def test_percolate_query_search_labels(mocker, mocked_es): == "q=testing+search+filter&department=physics&topic=math" ) assert query.source_label() == "saved_search" + + +@pytest.mark.django_db +@pytest.mark.parametrize("is_channel_query", [True, False]) +@pytest.mark.parametrize("test_label", ["new courses about cats", ""]) +def test_percolate_query_display_labels( + mocker, mocked_es, test_label, is_channel_query +): + """ + Test that makes sure we display the display label for a percolate query if it is defined + """ + + def encode_params(oparams): + ignore_params = ["endpoint"] + query = oparams + defined_params = { + key: query[key] for key in query if query[key] and key not in ignore_params + } + return urlencode(defined_params, doseq=True) + + mocker.patch( + "learning_resources_search.indexing_api.index_percolators", autospec=True + ) + mocker.patch( + "learning_resources_search.indexing_api._update_document_by_id", autospec=True + ) + + if is_channel_query: + original_query = {"department": ["physics"]} + channel = ChannelFactory.create( + search_filter=encode_params(original_query), channel_type="unit" + ) + else: + original_query = { + "q": "testing search filter", + "certification": None, + "yearly_decay_percent": None, + } + + query = PercolateQueryFactory.create( + original_query=original_query, + query=original_query, + display_label=test_label, + ) + assert query.original_url_params() == encode_params(original_query) + if not is_channel_query: + assert query.source_label() == "saved_search" + assert query.source_description() == ( + test_label + if test_label + else channel.title + if is_channel_query + else query.original_url_params() + ) diff --git a/main/settings.py b/main/settings.py index 1373918998..edb1f76198 100644 --- a/main/settings.py +++ b/main/settings.py @@ -33,7 +33,7 @@ from main.settings_pluggy import * # noqa: F403 from openapi.settings_spectacular import open_spectacular_settings -VERSION = "0.19.6" +VERSION = "0.20.0" log = logging.getLogger() diff --git a/openapi/specs/v0.yaml b/openapi/specs/v0.yaml index 5bde16164e..98ff99fe1f 100644 --- a/openapi/specs/v0.yaml +++ b/openapi/specs/v0.yaml @@ -1893,9 +1893,6 @@ components: type: object description: Serializer for Profile properties: - name: - type: string - nullable: true image: type: string nullable: true @@ -2096,7 +2093,8 @@ components: properties: name: type: string - nullable: true + description: Get the user's name + readOnly: true image: type: string nullable: true @@ -2179,6 +2177,7 @@ components: - image_file - image_medium_file - image_small_file + - name - placename - preference_search_filters - profile_image_medium @@ -2188,9 +2187,6 @@ components: type: object description: Serializer for Profile properties: - name: - type: string - nullable: true image: type: string nullable: true diff --git a/openapi/specs/v1.yaml b/openapi/specs/v1.yaml index af71655a91..1fe6d76a0e 100644 --- a/openapi/specs/v1.yaml +++ b/openapi/specs/v1.yaml @@ -10106,6 +10106,10 @@ components: query: {} source_type: $ref: '#/components/schemas/SourceTypeEnum' + display_label: + type: string + description: Friendly display label for the query + maxLength: 255 required: - id - original_query diff --git a/poetry.lock b/poetry.lock index 109f4cda6f..d1332e0ccf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2195,111 +2195,157 @@ Werkzeug = ">=2.0.0" [[package]] name = "lxml" -version = "4.9.4" +version = "5.3.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" -files = [ - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e214025e23db238805a600f1f37bf9f9a15413c7bf5f9d6ae194f84980c78722"}, - {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec53a09aee61d45e7dbe7e91252ff0491b6b5fee3d85b2d45b173d8ab453efc1"}, - {file = "lxml-4.9.4-cp27-cp27m-win32.whl", hash = "sha256:7d1d6c9e74c70ddf524e3c09d9dc0522aba9370708c2cb58680ea40174800013"}, - {file = "lxml-4.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:cb53669442895763e61df5c995f0e8361b61662f26c1b04ee82899c2789c8f69"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:647bfe88b1997d7ae8d45dabc7c868d8cb0c8412a6e730a7651050b8c7289cf2"}, - {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4d973729ce04784906a19108054e1fd476bc85279a403ea1a72fdb051c76fa48"}, - {file = "lxml-4.9.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:056a17eaaf3da87a05523472ae84246f87ac2f29a53306466c22e60282e54ff8"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aaa5c173a26960fe67daa69aa93d6d6a1cd714a6eb13802d4e4bd1d24a530644"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:647459b23594f370c1c01768edaa0ba0959afc39caeeb793b43158bb9bb6a663"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bdd9abccd0927673cffe601d2c6cdad1c9321bf3437a2f507d6b037ef91ea307"}, - {file = "lxml-4.9.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:00e91573183ad273e242db5585b52670eddf92bacad095ce25c1e682da14ed91"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a602ed9bd2c7d85bd58592c28e101bd9ff9c718fbde06545a70945ffd5d11868"}, - {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de362ac8bc962408ad8fae28f3967ce1a262b5d63ab8cefb42662566737f1dc7"}, - {file = "lxml-4.9.4-cp310-cp310-win32.whl", hash = "sha256:33714fcf5af4ff7e70a49731a7cc8fd9ce910b9ac194f66eaa18c3cc0a4c02be"}, - {file = "lxml-4.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:d3caa09e613ece43ac292fbed513a4bce170681a447d25ffcbc1b647d45a39c5"}, - {file = "lxml-4.9.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:359a8b09d712df27849e0bcb62c6a3404e780b274b0b7e4c39a88826d1926c28"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:43498ea734ccdfb92e1886dfedaebeb81178a241d39a79d5351ba2b671bff2b2"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4855161013dfb2b762e02b3f4d4a21cc7c6aec13c69e3bffbf5022b3e708dd97"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c71b5b860c5215fdbaa56f715bc218e45a98477f816b46cfde4a84d25b13274e"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9a2b5915c333e4364367140443b59f09feae42184459b913f0f41b9fed55794a"}, - {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d82411dbf4d3127b6cde7da0f9373e37ad3a43e89ef374965465928f01c2b979"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:273473d34462ae6e97c0f4e517bd1bf9588aa67a1d47d93f760a1282640e24ac"}, - {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:389d2b2e543b27962990ab529ac6720c3dded588cc6d0f6557eec153305a3622"}, - {file = "lxml-4.9.4-cp311-cp311-win32.whl", hash = "sha256:8aecb5a7f6f7f8fe9cac0bcadd39efaca8bbf8d1bf242e9f175cbe4c925116c3"}, - {file = "lxml-4.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:c7721a3ef41591341388bb2265395ce522aba52f969d33dacd822da8f018aff8"}, - {file = "lxml-4.9.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:dbcb2dc07308453db428a95a4d03259bd8caea97d7f0776842299f2d00c72fc8"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01bf1df1db327e748dcb152d17389cf6d0a8c5d533ef9bab781e9d5037619229"}, - {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e8f9f93a23634cfafbad6e46ad7d09e0f4a25a2400e4a64b1b7b7c0fbaa06d9d"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3f3f00a9061605725df1816f5713d10cd94636347ed651abdbc75828df302b20"}, - {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:953dd5481bd6252bd480d6ec431f61d7d87fdcbbb71b0d2bdcfc6ae00bb6fb10"}, - {file = "lxml-4.9.4-cp312-cp312-win32.whl", hash = "sha256:266f655d1baff9c47b52f529b5f6bec33f66042f65f7c56adde3fcf2ed62ae8b"}, - {file = "lxml-4.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:f1faee2a831fe249e1bae9cbc68d3cd8a30f7e37851deee4d7962b17c410dd56"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23d891e5bdc12e2e506e7d225d6aa929e0a0368c9916c1fddefab88166e98b20"}, - {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e96a1788f24d03e8d61679f9881a883ecdf9c445a38f9ae3f3f193ab6c591c66"}, - {file = "lxml-4.9.4-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:5557461f83bb7cc718bc9ee1f7156d50e31747e5b38d79cf40f79ab1447afd2d"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:fdb325b7fba1e2c40b9b1db407f85642e32404131c08480dd652110fc908561b"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d74d4a3c4b8f7a1f676cedf8e84bcc57705a6d7925e6daef7a1e54ae543a197"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac7674d1638df129d9cb4503d20ffc3922bd463c865ef3cb412f2c926108e9a4"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:ddd92e18b783aeb86ad2132d84a4b795fc5ec612e3545c1b687e7747e66e2b53"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bd9ac6e44f2db368ef8986f3989a4cad3de4cd55dbdda536e253000c801bcc7"}, - {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc354b1393dce46026ab13075f77b30e40b61b1a53e852e99d3cc5dd1af4bc85"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f836f39678cb47c9541f04d8ed4545719dc31ad850bf1832d6b4171e30d65d23"}, - {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9c131447768ed7bc05a02553d939e7f0e807e533441901dd504e217b76307745"}, - {file = "lxml-4.9.4-cp36-cp36m-win32.whl", hash = "sha256:bafa65e3acae612a7799ada439bd202403414ebe23f52e5b17f6ffc2eb98c2be"}, - {file = "lxml-4.9.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6197c3f3c0b960ad033b9b7d611db11285bb461fc6b802c1dd50d04ad715c225"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:7b378847a09d6bd46047f5f3599cdc64fcb4cc5a5a2dd0a2af610361fbe77b16"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:1343df4e2e6e51182aad12162b23b0a4b3fd77f17527a78c53f0f23573663545"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6dbdacf5752fbd78ccdb434698230c4f0f95df7dd956d5f205b5ed6911a1367c"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:506becdf2ecaebaf7f7995f776394fcc8bd8a78022772de66677c84fb02dd33d"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca8e44b5ba3edb682ea4e6185b49661fc22b230cf811b9c13963c9f982d1d964"}, - {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9d9d5726474cbbef279fd709008f91a49c4f758bec9c062dfbba88eab00e3ff9"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bbdd69e20fe2943b51e2841fc1e6a3c1de460d630f65bde12452d8c97209464d"}, - {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8671622256a0859f5089cbe0ce4693c2af407bc053dcc99aadff7f5310b4aa02"}, - {file = "lxml-4.9.4-cp37-cp37m-win32.whl", hash = "sha256:dd4fda67f5faaef4f9ee5383435048ee3e11ad996901225ad7615bc92245bc8e"}, - {file = "lxml-4.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6bee9c2e501d835f91460b2c904bc359f8433e96799f5c2ff20feebd9bb1e590"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:1f10f250430a4caf84115b1e0f23f3615566ca2369d1962f82bef40dd99cd81a"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b505f2bbff50d261176e67be24e8909e54b5d9d08b12d4946344066d66b3e43"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1449f9451cd53e0fd0a7ec2ff5ede4686add13ac7a7bfa6988ff6d75cff3ebe2"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4ece9cca4cd1c8ba889bfa67eae7f21d0d1a2e715b4d5045395113361e8c533d"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59bb5979f9941c61e907ee571732219fa4774d5a18f3fa5ff2df963f5dfaa6bc"}, - {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b1980dbcaad634fe78e710c8587383e6e3f61dbe146bcbfd13a9c8ab2d7b1192"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9ae6c3363261021144121427b1552b29e7b59de9d6a75bf51e03bc072efb3c37"}, - {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bcee502c649fa6351b44bb014b98c09cb00982a475a1912a9881ca28ab4f9cd9"}, - {file = "lxml-4.9.4-cp38-cp38-win32.whl", hash = "sha256:a8edae5253efa75c2fc79a90068fe540b197d1c7ab5803b800fccfe240eed33c"}, - {file = "lxml-4.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:701847a7aaefef121c5c0d855b2affa5f9bd45196ef00266724a80e439220e46"}, - {file = "lxml-4.9.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:f610d980e3fccf4394ab3806de6065682982f3d27c12d4ce3ee46a8183d64a6a"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aa9b5abd07f71b081a33115d9758ef6077924082055005808f68feccb27616bd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:365005e8b0718ea6d64b374423e870648ab47c3a905356ab6e5a5ff03962b9a9"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:16b9ec51cc2feab009e800f2c6327338d6ee4e752c76e95a35c4465e80390ccd"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a905affe76f1802edcac554e3ccf68188bea16546071d7583fb1b693f9cf756b"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd814847901df6e8de13ce69b84c31fc9b3fb591224d6762d0b256d510cbf382"}, - {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91bbf398ac8bb7d65a5a52127407c05f75a18d7015a270fdd94bbcb04e65d573"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f99768232f036b4776ce419d3244a04fe83784bce871b16d2c2e984c7fcea847"}, - {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bb5bd6212eb0edfd1e8f254585290ea1dadc3687dd8fd5e2fd9a87c31915cdab"}, - {file = "lxml-4.9.4-cp39-cp39-win32.whl", hash = "sha256:88f7c383071981c74ec1998ba9b437659e4fd02a3c4a4d3efc16774eb108d0ec"}, - {file = "lxml-4.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:936e8880cc00f839aa4173f94466a8406a96ddce814651075f95837316369899"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:f6c35b2f87c004270fa2e703b872fcc984d714d430b305145c39d53074e1ffe0"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:606d445feeb0856c2b424405236a01c71af7c97e5fe42fbc778634faef2b47e4"}, - {file = "lxml-4.9.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1bdcbebd4e13446a14de4dd1825f1e778e099f17f79718b4aeaf2403624b0f7"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0a08c89b23117049ba171bf51d2f9c5f3abf507d65d016d6e0fa2f37e18c0fc5"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:232fd30903d3123be4c435fb5159938c6225ee8607b635a4d3fca847003134ba"}, - {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:231142459d32779b209aa4b4d460b175cadd604fed856f25c1571a9d78114771"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:520486f27f1d4ce9654154b4494cf9307b495527f3a2908ad4cb48e4f7ed7ef7"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:562778586949be7e0d7435fcb24aca4810913771f845d99145a6cee64d5b67ca"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a9e7c6d89c77bb2770c9491d988f26a4b161d05c8ca58f63fb1f1b6b9a74be45"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:786d6b57026e7e04d184313c1359ac3d68002c33e4b1042ca58c362f1d09ff58"}, - {file = "lxml-4.9.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95ae6c5a196e2f239150aa4a479967351df7f44800c93e5a975ec726fef005e2"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:9b556596c49fa1232b0fff4b0e69b9d4083a502e60e404b44341e2f8fb7187f5"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cc02c06e9e320869d7d1bd323df6dd4281e78ac2e7f8526835d3d48c69060683"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:857d6565f9aa3464764c2cb6a2e3c2e75e1970e877c188f4aeae45954a314e0c"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c42ae7e010d7d6bc51875d768110c10e8a59494855c3d4c348b068f5fb81fdcd"}, - {file = "lxml-4.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f10250bb190fb0742e3e1958dd5c100524c2cc5096c67c8da51233f7448dc137"}, - {file = "lxml-4.9.4.tar.gz", hash = "sha256:b1541e50b78e15fa06a2670157a1962ef06591d4c998b998047fff5e3236880e"}, +python-versions = ">=3.6" +files = [ + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656"}, + {file = "lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8"}, + {file = "lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03"}, + {file = "lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7"}, + {file = "lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80"}, + {file = "lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74bcb423462233bc5d6066e4e98b0264e7c1bed7541fff2f4e34fe6b21563c8b"}, + {file = "lxml-5.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a3d819eb6f9b8677f57f9664265d0a10dd6551d227afb4af2b9cd7bdc2ccbf18"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b8f5db71b28b8c404956ddf79575ea77aa8b1538e8b2ef9ec877945b3f46442"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3406b63232fc7e9b8783ab0b765d7c59e7c59ff96759d8ef9632fca27c7ee4"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ecdd78ab768f844c7a1d4a03595038c166b609f6395e25af9b0f3f26ae1230f"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:168f2dfcfdedf611eb285efac1516c8454c8c99caf271dccda8943576b67552e"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa617107a410245b8660028a7483b68e7914304a6d4882b5ff3d2d3eb5948d8c"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:69959bd3167b993e6e710b99051265654133a98f20cec1d9b493b931942e9c16"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:bd96517ef76c8654446fc3db9242d019a1bb5fe8b751ba414765d59f99210b79"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ab6dd83b970dc97c2d10bc71aa925b84788c7c05de30241b9e96f9b6d9ea3080"}, + {file = "lxml-5.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:eec1bb8cdbba2925bedc887bc0609a80e599c75b12d87ae42ac23fd199445654"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a7095eeec6f89111d03dabfe5883a1fd54da319c94e0fb104ee8f23616b572d"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f651ebd0b21ec65dfca93aa629610a0dbc13dbc13554f19b0113da2e61a4763"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:f422a209d2455c56849442ae42f25dbaaba1c6c3f501d58761c619c7836642ec"}, + {file = "lxml-5.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:62f7fdb0d1ed2065451f086519865b4c90aa19aed51081979ecd05a21eb4d1be"}, + {file = "lxml-5.3.0-cp311-cp311-win32.whl", hash = "sha256:c6379f35350b655fd817cd0d6cbeef7f265f3ae5fedb1caae2eb442bbeae9ab9"}, + {file = "lxml-5.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c52100e2c2dbb0649b90467935c4b0de5528833c76a35ea1a2691ec9f1ee7a1"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e99f5507401436fdcc85036a2e7dc2e28d962550afe1cbfc07c40e454256a859"}, + {file = "lxml-5.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:384aacddf2e5813a36495233b64cb96b1949da72bef933918ba5c84e06af8f0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a216bf6afaf97c263b56371434e47e2c652d215788396f60477540298218f"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65ab5685d56914b9a2a34d67dd5488b83213d680b0c5d10b47f81da5a16b0b0e"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aac0bbd3e8dd2d9c45ceb82249e8bdd3ac99131a32b4d35c8af3cc9db1657179"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b369d3db3c22ed14c75ccd5af429086f166a19627e84a8fdade3f8f31426e52a"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24037349665434f375645fa9d1f5304800cec574d0310f618490c871fd902b3"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:62d172f358f33a26d6b41b28c170c63886742f5b6772a42b59b4f0fa10526cb1"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:c1f794c02903c2824fccce5b20c339a1a14b114e83b306ff11b597c5f71a1c8d"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:5d6a6972b93c426ace71e0be9a6f4b2cfae9b1baed2eed2006076a746692288c"}, + {file = "lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3879cc6ce938ff4eb4900d901ed63555c778731a96365e53fadb36437a131a99"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:74068c601baff6ff021c70f0935b0c7bc528baa8ea210c202e03757c68c5a4ff"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ecd4ad8453ac17bc7ba3868371bffb46f628161ad0eefbd0a855d2c8c32dd81a"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7e2f58095acc211eb9d8b5771bf04df9ff37d6b87618d1cbf85f92399c98dae8"}, + {file = "lxml-5.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e63601ad5cd8f860aa99d109889b5ac34de571c7ee902d6812d5d9ddcc77fa7d"}, + {file = "lxml-5.3.0-cp312-cp312-win32.whl", hash = "sha256:17e8d968d04a37c50ad9c456a286b525d78c4a1c15dd53aa46c1d8e06bf6fa30"}, + {file = "lxml-5.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:c1a69e58a6bb2de65902051d57fde951febad631a20a64572677a1052690482f"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8c72e9563347c7395910de6a3100a4840a75a6f60e05af5e58566868d5eb2d6a"}, + {file = "lxml-5.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e92ce66cd919d18d14b3856906a61d3f6b6a8500e0794142338da644260595cd"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d04f064bebdfef9240478f7a779e8c5dc32b8b7b0b2fc6a62e39b928d428e51"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c2fb570d7823c2bbaf8b419ba6e5662137f8166e364a8b2b91051a1fb40ab8b"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c120f43553ec759f8de1fee2f4794452b0946773299d44c36bfe18e83caf002"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:562e7494778a69086f0312ec9689f6b6ac1c6b65670ed7d0267e49f57ffa08c4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:423b121f7e6fa514ba0c7918e56955a1d4470ed35faa03e3d9f0e3baa4c7e492"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c00f323cc00576df6165cc9d21a4c21285fa6b9989c5c39830c3903dc4303ef3"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:1fdc9fae8dd4c763e8a31e7630afef517eab9f5d5d31a278df087f307bf601f4"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:658f2aa69d31e09699705949b5fc4719cbecbd4a97f9656a232e7d6c7be1a367"}, + {file = "lxml-5.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1473427aff3d66a3fa2199004c3e601e6c4500ab86696edffdbc84954c72d832"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a87de7dd873bf9a792bf1e58b1c3887b9264036629a5bf2d2e6579fe8e73edff"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0d7b36afa46c97875303a94e8f3ad932bf78bace9e18e603f2085b652422edcd"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:cf120cce539453ae086eacc0130a324e7026113510efa83ab42ef3fcfccac7fb"}, + {file = "lxml-5.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:df5c7333167b9674aa8ae1d4008fa4bc17a313cc490b2cca27838bbdcc6bb15b"}, + {file = "lxml-5.3.0-cp313-cp313-win32.whl", hash = "sha256:c802e1c2ed9f0c06a65bc4ed0189d000ada8049312cfeab6ca635e39c9608957"}, + {file = "lxml-5.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:406246b96d552e0503e17a1006fd27edac678b3fcc9f1be71a2f94b4ff61528d"}, + {file = "lxml-5.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8f0de2d390af441fe8b2c12626d103540b5d850d585b18fcada58d972b74a74e"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1afe0a8c353746e610bd9031a630a95bcfb1a720684c3f2b36c4710a0a96528f"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56b9861a71575f5795bde89256e7467ece3d339c9b43141dbdd54544566b3b94"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:9fb81d2824dff4f2e297a276297e9031f46d2682cafc484f49de182aa5e5df99"}, + {file = "lxml-5.3.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2c226a06ecb8cdef28845ae976da407917542c5e6e75dcac7cc33eb04aaeb237"}, + {file = "lxml-5.3.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:7d3d1ca42870cdb6d0d29939630dbe48fa511c203724820fc0fd507b2fb46577"}, + {file = "lxml-5.3.0-cp36-cp36m-win32.whl", hash = "sha256:094cb601ba9f55296774c2d57ad68730daa0b13dc260e1f941b4d13678239e70"}, + {file = "lxml-5.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:eafa2c8658f4e560b098fe9fc54539f86528651f61849b22111a9b107d18910c"}, + {file = "lxml-5.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb83f8a875b3d9b458cada4f880fa498646874ba4011dc974e071a0a84a1b033"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25f1b69d41656b05885aa185f5fdf822cb01a586d1b32739633679699f220391"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23e0553b8055600b3bf4a00b255ec5c92e1e4aebf8c2c09334f8368e8bd174d6"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ada35dd21dc6c039259596b358caab6b13f4db4d4a7f8665764d616daf9cc1d"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:81b4e48da4c69313192d8c8d4311e5d818b8be1afe68ee20f6385d0e96fc9512"}, + {file = "lxml-5.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:2bc9fd5ca4729af796f9f59cd8ff160fe06a474da40aca03fcc79655ddee1a8b"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:07da23d7ee08577760f0a71d67a861019103e4812c87e2fab26b039054594cc5"}, + {file = "lxml-5.3.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:ea2e2f6f801696ad7de8aec061044d6c8c0dd4037608c7cab38a9a4d316bfb11"}, + {file = "lxml-5.3.0-cp37-cp37m-win32.whl", hash = "sha256:5c54afdcbb0182d06836cc3d1be921e540be3ebdf8b8a51ee3ef987537455f84"}, + {file = "lxml-5.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f2901429da1e645ce548bf9171784c0f74f0718c3f6150ce166be39e4dd66c3e"}, + {file = "lxml-5.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c56a1d43b2f9ee4786e4658c7903f05da35b923fb53c11025712562d5cc02753"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ee8c39582d2652dcd516d1b879451500f8db3fe3607ce45d7c5957ab2596040"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdf3a3059611f7585a78ee10399a15566356116a4288380921a4b598d807a22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:146173654d79eb1fc97498b4280c1d3e1e5d58c398fa530905c9ea50ea849b22"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0a7056921edbdd7560746f4221dca89bb7a3fe457d3d74267995253f46343f15"}, + {file = "lxml-5.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:9e4b47ac0f5e749cfc618efdf4726269441014ae1d5583e047b452a32e221920"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f914c03e6a31deb632e2daa881fe198461f4d06e57ac3d0e05bbcab8eae01945"}, + {file = "lxml-5.3.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:213261f168c5e1d9b7535a67e68b1f59f92398dd17a56d934550837143f79c42"}, + {file = "lxml-5.3.0-cp38-cp38-win32.whl", hash = "sha256:218c1b2e17a710e363855594230f44060e2025b05c80d1f0661258142b2add2e"}, + {file = "lxml-5.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:315f9542011b2c4e1d280e4a20ddcca1761993dda3afc7a73b01235f8641e903"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1ffc23010330c2ab67fac02781df60998ca8fe759e8efde6f8b756a20599c5de"}, + {file = "lxml-5.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2b3778cb38212f52fac9fe913017deea2fdf4eb1a4f8e4cfc6b009a13a6d3fcc"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b0c7a688944891086ba192e21c5229dea54382f4836a209ff8d0a660fac06be"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:747a3d3e98e24597981ca0be0fd922aebd471fa99d0043a3842d00cdcad7ad6a"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86a6b24b19eaebc448dc56b87c4865527855145d851f9fc3891673ff97950540"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b11a5d918a6216e521c715b02749240fb07ae5a1fefd4b7bf12f833bc8b4fe70"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b87753c784d6acb8a25b05cb526c3406913c9d988d51f80adecc2b0775d6aa"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:109fa6fede314cc50eed29e6e56c540075e63d922455346f11e4d7a036d2b8cf"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:02ced472497b8362c8e902ade23e3300479f4f43e45f4105c85ef43b8db85229"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:6b038cc86b285e4f9fea2ba5ee76e89f21ed1ea898e287dc277a25884f3a7dfe"}, + {file = "lxml-5.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:7437237c6a66b7ca341e868cda48be24b8701862757426852c9b3186de1da8a2"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7f41026c1d64043a36fda21d64c5026762d53a77043e73e94b71f0521939cc71"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:482c2f67761868f0108b1743098640fbb2a28a8e15bf3f47ada9fa59d9fe08c3"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:1483fd3358963cc5c1c9b122c80606a3a79ee0875bcac0204149fa09d6ff2727"}, + {file = "lxml-5.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dec2d1130a9cda5b904696cec33b2cfb451304ba9081eeda7f90f724097300a"}, + {file = "lxml-5.3.0-cp39-cp39-win32.whl", hash = "sha256:a0eabd0a81625049c5df745209dc7fcef6e2aea7793e5f003ba363610aa0a3ff"}, + {file = "lxml-5.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:89e043f1d9d341c52bf2af6d02e6adde62e0a46e6755d5eb60dc6e4f0b8aeca2"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83"}, + {file = "lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:94d6c3782907b5e40e21cadf94b13b0842ac421192f26b84c45f13f3c9d5dc27"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c300306673aa0f3ed5ed9372b21867690a17dba38c68c44b287437c362ce486b"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d9b952e07aed35fe2e1a7ad26e929595412db48535921c5013edc8aa4a35ce"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:01220dca0d066d1349bd6a1726856a78f7929f3878f7e2ee83c296c69495309e"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2d9b8d9177afaef80c53c0a9e30fa252ff3036fb1c6494d427c066a4ce6a282f"}, + {file = "lxml-5.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:20094fc3f21ea0a8669dc4c61ed7fa8263bd37d97d93b90f28fc613371e7a875"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ace2c2326a319a0bb8a8b0e5b570c764962e95818de9f259ce814ee666603f19"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92e67a0be1639c251d21e35fe74df6bcc40cba445c2cda7c4a967656733249e2"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd5350b55f9fecddc51385463a4f67a5da829bc741e38cf689f38ec9023f54ab"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c1fefd7e3d00921c44dc9ca80a775af49698bbfd92ea84498e56acffd4c5469"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:71a8dd38fbd2f2319136d4ae855a7078c69c9a38ae06e0c17c73fd70fc6caad8"}, + {file = "lxml-5.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:97acf1e1fd66ab53dacd2c35b319d7e548380c2e9e8c54525c6e76d21b1ae3b1"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:68934b242c51eb02907c5b81d138cb977b2129a0a75a8f8b60b01cb8586c7b21"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b710bc2b8292966b23a6a0121f7a6c51d45d2347edcc75f016ac123b8054d3f2"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18feb4b93302091b1541221196a2155aa296c363fd233814fa11e181adebc52f"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3eb44520c4724c2e1a57c0af33a379eee41792595023f367ba3952a2d96c2aab"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:609251a0ca4770e5a8768ff902aa02bf636339c5a93f9349b48eb1f606f7f3e9"}, + {file = "lxml-5.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:516f491c834eb320d6c843156440fe7fc0d50b33e44387fcec5b02f0bc118a4c"}, + {file = "lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] +html-clean = ["lxml-html-clean"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (==0.29.37)"] +source = ["Cython (>=3.0.11)"] [[package]] name = "markdown2" @@ -4817,5 +4863,5 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" -python-versions = "3.12.5" -content-hash = "7098ba8cd400019854f628baefd55c253ae0a9fcd4af5ed43fab0334ddaab381" +python-versions = "3.12.6" +content-hash = "b66c70450438cb21310133ee079f7c35bc86615f7b744fdfbf08337d54191969" diff --git a/profiles/serializers.py b/profiles/serializers.py index 27315bd0a6..2e0e1b7672 100644 --- a/profiles/serializers.py +++ b/profiles/serializers.py @@ -81,6 +81,7 @@ class PreferencesSearchSerializer(serializers.Serializer): class ProfileSerializer(serializers.ModelSerializer): """Serializer for Profile""" + name = serializers.SerializerMethodField(read_only=True) email_optin = serializers.BooleanField(write_only=True, required=False) toc_optin = serializers.BooleanField(write_only=True, required=False) username = serializers.SerializerMethodField(read_only=True) @@ -90,6 +91,12 @@ class ProfileSerializer(serializers.ModelSerializer): topic_interests = TopicInterestsField(default=list) preference_search_filters = serializers.SerializerMethodField(read_only=True) + def get_name(self, obj) -> str: + """Get the user's name""" + return obj.name or " ".join( + filter(lambda name: name, [obj.user.first_name, obj.user.last_name]) + ) + def get_username(self, obj) -> str: """Custom getter for the username""" # noqa: D401 return str(obj.user.username) diff --git a/profiles/serializers_test.py b/profiles/serializers_test.py index bcd433640d..1393b1b2fa 100644 --- a/profiles/serializers_test.py +++ b/profiles/serializers_test.py @@ -50,7 +50,6 @@ def test_serialize_create_user(db, mocker): Test creating a user """ profile = { - "name": "name", "email_optin": True, "toc_optin": True, "bio": "bio", @@ -67,6 +66,7 @@ def test_serialize_create_user(db, mocker): profile.update( { + "name": "", "image": None, "image_small": None, "image_medium": None, @@ -100,7 +100,6 @@ def test_serialize_create_user(db, mocker): @pytest.mark.parametrize( ("key", "value"), [ - ("name", "name_value"), ("email_optin", True), ("email_optin", False), ("bio", "bio_value"), @@ -191,7 +190,6 @@ def test_location_validation(user, data, is_valid): @pytest.mark.parametrize( ("key", "value"), [ - ("name", "name_value"), ("bio", "bio_value"), ("headline", "headline_value"), ("location", {"value": "Hobbiton, The Shire, Middle-Earth"}), diff --git a/pyproject.toml b/pyproject.toml index 6ed13909f2..7971a5971d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ authors = ["MIT ODL"] [tool.poetry.dependencies] -python = "3.12.5" +python = "3.12.6" attrs = "^24.0.0" base36 = "^0.1.1" beautifulsoup4 = "^4.8.2" @@ -42,7 +42,7 @@ google-api-python-client = "^2.89.0" html5lib = "^1.1" ipython = "^8.14.0" jedi = "^0.19.0" -lxml = "^4.9.2" +lxml = "^5.0.0" markdown2 = "^2.4.8" nested-lookup = "^0.2.25" ocw-data-parser = "^0.35.1" diff --git a/yarn.lock b/yarn.lock index 7fa390a739..6452e2d589 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15408,6 +15408,7 @@ __metadata: material-ui-popup-state: "npm:^5.1.0" ol-test-utilities: "npm:0.0.0" ol-utilities: "npm:0.0.0" + posthog-js: "npm:^1.165.0" prop-types: "npm:^15.8.1" react: "npm:18.3.1" react-router: "npm:^6.22.2" @@ -16577,6 +16578,17 @@ __metadata: languageName: node linkType: hard +"posthog-js@npm:^1.165.0": + version: 1.165.0 + resolution: "posthog-js@npm:1.165.0" + dependencies: + fflate: "npm:^0.4.8" + preact: "npm:^10.19.3" + web-vitals: "npm:^4.0.1" + checksum: 10/4a640b90af24ffb173b4d20f27aab572437c8641b1ff48ad23e98d593fa7e94e63e660a4ce967a18eaabaf5102ecaff8a258315b47d1916e79a7f1ec7ad3bc7d + languageName: node + linkType: hard + "preact@npm:^10.19.3": version: 10.23.1 resolution: "preact@npm:10.23.1"