diff --git a/.DS_Store b/.DS_Store index 173f67c..c6ef5ce 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/molenda.net/.coveralls.yml b/.coveralls.yml similarity index 100% rename from molenda.net/.coveralls.yml rename to .coveralls.yml diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 0000000..7fcdb06 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,74 @@ +name: Deploy on merge to main + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + # ── 1. Checkout ────────────────────────────────────────────────────────── + - name: Checkout repository + uses: actions/checkout@v4 + + # ── 2. PHP + Composer ──────────────────────────────────────────────────── + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: pdo, pdo_sqlite, sqlite3 + + - name: Install Composer dependencies (production only) + run: composer install --no-dev --optimize-autoloader + + # ── 3. Pobierz aktualną bazę SQLite z serwera ──────────────────────────── + # data.sqlite3 z repo NIE trafia na serwer – ściągamy produkcyjną wersję, + # uruchamiamy na niej migracje i wgrywamy z powrotem. + - name: Install lftp + run: sudo apt-get install -y lftp + + - name: Download production data.sqlite3 via FTP + run: | + lftp -u "${{ secrets.FTP_USER }}","${{ secrets.FTP_PASS }}" \ + -e "set ftp:ssl-allow no; \ + set ssl:verify-certificate no; \ + get ${{ secrets.FTP_REMOTE_DIR }}/data.sqlite3 -o ./data.sqlite3; \ + quit" \ + ${{ secrets.FTP_HOST }} + + # ── 4. Uruchom migracje Phinx na pobranej bazie ────────────────────────── + # phinx.php: 'name' => __DIR__ . '/data' → plik data.sqlite3 + - name: Run Phinx migrations + run: ./vendor/bin/phinx migrate -e main + + # ── 5. Wgraj pliki na serwer (z zaktualizowaną bazą) ──────────────────── + - name: Deploy files to server via FTP + uses: SamKirkland/FTP-Deploy-Action@v4.3.5 + with: + server: ${{ secrets.FTP_HOST }} + username: ${{ secrets.FTP_USER }} + password: ${{ secrets.FTP_PASS }} + local-dir: ./ + server-dir: ${{ secrets.FTP_REMOTE_DIR }}/ + exclude: | + **/.git/** + **/.gitea/** + **/tests/** + **/docker/** + **/html_template/** + **/lib/** + **/var/cache/** + **/logs/** + docker-compose*.yml + Dockerfile + phpunit.xml + phpcs.xml + phpstan.neon.dist + README.md + CONTRIBUTING.md + .env* + local.data.sqlite3 + server.data.sqlite3 diff --git a/molenda.net/.github/dependabot.yml b/.github/dependabot.yml similarity index 100% rename from molenda.net/.github/dependabot.yml rename to .github/dependabot.yml diff --git a/molenda.net/.github/workflows/tests.yml b/.github/workflows/tests.yml similarity index 100% rename from molenda.net/.github/workflows/tests.yml rename to .github/workflows/tests.yml diff --git a/molenda.net/.gitignore b/.gitignore similarity index 86% rename from molenda.net/.gitignore rename to .gitignore index 63066a6..991a4bb 100644 --- a/molenda.net/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /logs/* !/logs/README.md .phpunit.result.cache +data.sqlite3 diff --git a/molenda.net/.htaccess b/.htaccess similarity index 100% rename from molenda.net/.htaccess rename to .htaccess diff --git a/.oda/config.yaml b/.oda/config.yaml deleted file mode 100644 index f0f08d8..0000000 --- a/.oda/config.yaml +++ /dev/null @@ -1,12 +0,0 @@ -github: - repo: seba-aln/tar-pit -dashboard: - port: 5000 -workers: - count: 3 -opencode: - url: http://localhost:5002 -pipeline: - max_retries: 5 -sprint: - tasks_per_sprint: 10 diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 03f983c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "sqltools.connections": [ - { - "previewLimit": 50, - "driver": "SQLite", - "name": "26.molenda.net", - "database": "data.sqlite" - } - ], - "sqltools.useNodeRuntime": true -} diff --git a/molenda.net/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from molenda.net/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bf6a5da --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM php:8.3-fpm + +WORKDIR /var/www + +# Install system dependencies and PHP extensions +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + git \ + unzip \ + zip \ + libzip-dev \ + sqlite3 \ + libsqlite3-dev \ + libonig-dev \ + && docker-php-ext-configure zip \ + && docker-php-ext-install -j$(nproc) pdo pdo_sqlite zip \ + && rm -rf /var/lib/apt/lists/* + +# Install Composer from the official image +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +# Ensure www-data owns the working dir +RUN chown -R www-data:www-data /var/www || true + +EXPOSE 9000 + +CMD ["php-fpm"] diff --git a/molenda.net/README.md b/README.md similarity index 100% rename from molenda.net/README.md rename to README.md diff --git a/molenda.net/app/dependencies.php b/app/dependencies.php similarity index 100% rename from molenda.net/app/dependencies.php rename to app/dependencies.php diff --git a/molenda.net/app/middleware.php b/app/middleware.php similarity index 100% rename from molenda.net/app/middleware.php rename to app/middleware.php diff --git a/molenda.net/app/repositories.php b/app/repositories.php similarity index 100% rename from molenda.net/app/repositories.php rename to app/repositories.php diff --git a/molenda.net/app/routes.php b/app/routes.php similarity index 95% rename from molenda.net/app/routes.php rename to app/routes.php index 53ff97d..0a94962 100644 --- a/molenda.net/app/routes.php +++ b/app/routes.php @@ -35,6 +35,7 @@ return function (App $app) { // Protected admin area $app->group('/admin', function (Group $group) { $group->get('', \App\Application\Actions\Admin\DashboardAction::class); + $group->get('/blog-visits', \App\Application\Actions\Admin\BlogVisitsAction::class); $group->get('/contents', \App\Application\Actions\Content\ContentCrudAction::class . ':list'); $group->get('/access-logs', \App\Application\Actions\Admin\AccessLogsAction::class); $group->map(['GET', 'POST'], '/contents/create', \App\Application\Actions\Content\ContentCrudAction::class . ':create'); diff --git a/molenda.net/app/settings.php b/app/settings.php similarity index 100% rename from molenda.net/app/settings.php rename to app/settings.php diff --git a/molenda.net/composer.json b/composer.json similarity index 100% rename from molenda.net/composer.json rename to composer.json diff --git a/molenda.net/composer.lock b/composer.lock similarity index 100% rename from molenda.net/composer.lock rename to composer.lock diff --git a/data.sqlite3 b/data.sqlite3 index e69de29..f93f83d 100644 Binary files a/data.sqlite3 and b/data.sqlite3 differ diff --git a/molenda.net/db/migrations/20260209213746_create_users_table.php b/db/migrations/20260209213746_create_users_table.php similarity index 100% rename from molenda.net/db/migrations/20260209213746_create_users_table.php rename to db/migrations/20260209213746_create_users_table.php diff --git a/molenda.net/db/migrations/20260209213754_create_contents_table.php b/db/migrations/20260209213754_create_contents_table.php similarity index 100% rename from molenda.net/db/migrations/20260209213754_create_contents_table.php rename to db/migrations/20260209213754_create_contents_table.php diff --git a/molenda.net/db/migrations/20260210204236_create_access_logs.php b/db/migrations/20260210204236_create_access_logs.php similarity index 100% rename from molenda.net/db/migrations/20260210204236_create_access_logs.php rename to db/migrations/20260210204236_create_access_logs.php diff --git a/db/migrations/20260513000000_create_blog_visits.php b/db/migrations/20260513000000_create_blog_visits.php new file mode 100644 index 0000000..f01d8a3 --- /dev/null +++ b/db/migrations/20260513000000_create_blog_visits.php @@ -0,0 +1,23 @@ +table('blog_visits'); + if (!$table->exists()) { + $table->addColumn('ip', 'string', ['null' => true, 'limit' => 255]) + ->addColumn('useragent', 'text', ['null' => true]) + ->addColumn('cnt', 'integer', ['default' => 0]) + ->addColumn('first_seen', 'integer', ['null' => true]) + ->addColumn('last_seen', 'integer', ['null' => true]) + ->addIndex(['ip', 'useragent'], ['unique' => true, 'name' => 'idx_ip_useragent']) + ->create(); + } + } +} diff --git a/molenda.net/db/seeds/BasicAdminUser.php b/db/seeds/BasicAdminUser.php similarity index 100% rename from molenda.net/db/seeds/BasicAdminUser.php rename to db/seeds/BasicAdminUser.php diff --git a/molenda.net/db/seeds/ContentsSample.php b/db/seeds/ContentsSample.php similarity index 100% rename from molenda.net/db/seeds/ContentsSample.php rename to db/seeds/ContentsSample.php diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..0bf33d8 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,36 @@ +version: '3.8' + +services: + php: + build: + context: . + dockerfile: Dockerfile + working_dir: /var/www + volumes: + - ./:/var/www:cached + - ./docker/php/memory.ini:/usr/local/etc/php/conf.d/memory.ini:ro + environment: + COMPOSER_ALLOW_SUPERUSER: "1" + mem_limit: 1G + deploy: + resources: + limits: + memory: 1G + networks: + - appnet + + nginx: + image: nginx:1.25-alpine + ports: + - "8080:80" + volumes: + - ./:/var/www:ro + - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro + depends_on: + - php + networks: + - appnet + +networks: + appnet: + driver: bridge diff --git a/molenda.net/docker-compose.yml b/docker-compose.yml similarity index 100% rename from molenda.net/docker-compose.yml rename to docker-compose.yml diff --git a/docker/nginx/default.conf b/docker/nginx/default.conf new file mode 100644 index 0000000..415833b --- /dev/null +++ b/docker/nginx/default.conf @@ -0,0 +1,25 @@ +server { + listen 80; + server_name _; + root /var/www/public; + index index.php index.html; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location ~ \.php$ { + include fastcgi_params; + fastcgi_pass php:9000; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + } + + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires max; + log_not_found off; + } +} diff --git a/docker/php/memory.ini b/docker/php/memory.ini new file mode 100644 index 0000000..a6a203a --- /dev/null +++ b/docker/php/memory.ini @@ -0,0 +1 @@ +memory_limit = 1G diff --git a/eeeeee/.venv/bin/Activate.ps1 b/eeeeee/.venv/bin/Activate.ps1 deleted file mode 100644 index 2fb3852..0000000 --- a/eeeeee/.venv/bin/Activate.ps1 +++ /dev/null @@ -1,241 +0,0 @@ -<# -.Synopsis -Activate a Python virtual environment for the current PowerShell session. - -.Description -Pushes the python executable for a virtual environment to the front of the -$Env:PATH environment variable and sets the prompt to signify that you are -in a Python virtual environment. Makes use of the command line switches as -well as the `pyvenv.cfg` file values present in the virtual environment. - -.Parameter VenvDir -Path to the directory that contains the virtual environment to activate. The -default value for this is the parent of the directory that the Activate.ps1 -script is located within. - -.Parameter Prompt -The prompt prefix to display when this virtual environment is activated. By -default, this prompt is the name of the virtual environment folder (VenvDir) -surrounded by parentheses and followed by a single space (ie. '(.venv) '). - -.Example -Activate.ps1 -Activates the Python virtual environment that contains the Activate.ps1 script. - -.Example -Activate.ps1 -Verbose -Activates the Python virtual environment that contains the Activate.ps1 script, -and shows extra information about the activation as it executes. - -.Example -Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv -Activates the Python virtual environment located in the specified location. - -.Example -Activate.ps1 -Prompt "MyPython" -Activates the Python virtual environment that contains the Activate.ps1 script, -and prefixes the current prompt with the specified string (surrounded in -parentheses) while the virtual environment is active. - -.Notes -On Windows, it may be required to enable this Activate.ps1 script by setting the -execution policy for the user. You can do this by issuing the following PowerShell -command: - -PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - -For more information on Execution Policies: -https://go.microsoft.com/fwlink/?LinkID=135170 - -#> -Param( - [Parameter(Mandatory = $false)] - [String] - $VenvDir, - [Parameter(Mandatory = $false)] - [String] - $Prompt -) - -<# Function declarations --------------------------------------------------- #> - -<# -.Synopsis -Remove all shell session elements added by the Activate script, including the -addition of the virtual environment's Python executable from the beginning of -the PATH variable. - -.Parameter NonDestructive -If present, do not remove this function from the global namespace for the -session. - -#> -function global:deactivate ([switch]$NonDestructive) { - # Revert to original values - - # The prior prompt: - if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { - Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt - Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT - } - - # The prior PYTHONHOME: - if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { - Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME - Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME - } - - # The prior PATH: - if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { - Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH - Remove-Item -Path Env:_OLD_VIRTUAL_PATH - } - - # Just remove the VIRTUAL_ENV altogether: - if (Test-Path -Path Env:VIRTUAL_ENV) { - Remove-Item -Path env:VIRTUAL_ENV - } - - # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: - if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { - Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force - } - - # Leave deactivate function in the global namespace if requested: - if (-not $NonDestructive) { - Remove-Item -Path function:deactivate - } -} - -<# -.Description -Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the -given folder, and returns them in a map. - -For each line in the pyvenv.cfg file, if that line can be parsed into exactly -two strings separated by `=` (with any amount of whitespace surrounding the =) -then it is considered a `key = value` line. The left hand string is the key, -the right hand is the value. - -If the value starts with a `'` or a `"` then the first and last character is -stripped from the value before being captured. - -.Parameter ConfigDir -Path to the directory that contains the `pyvenv.cfg` file. -#> -function Get-PyVenvConfig( - [String] - $ConfigDir -) { - Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" - - # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). - $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue - - # An empty map will be returned if no config file is found. - $pyvenvConfig = @{ } - - if ($pyvenvConfigPath) { - - Write-Verbose "File exists, parse `key = value` lines" - $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath - - $pyvenvConfigContent | ForEach-Object { - $keyval = $PSItem -split "\s*=\s*", 2 - if ($keyval[0] -and $keyval[1]) { - $val = $keyval[1] - - # Remove extraneous quotations around a string value. - if ("'""".Contains($val.Substring(0, 1))) { - $val = $val.Substring(1, $val.Length - 2) - } - - $pyvenvConfig[$keyval[0]] = $val - Write-Verbose "Adding Key: '$($keyval[0])'='$val'" - } - } - } - return $pyvenvConfig -} - - -<# Begin Activate script --------------------------------------------------- #> - -# Determine the containing directory of this script -$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition -$VenvExecDir = Get-Item -Path $VenvExecPath - -Write-Verbose "Activation script is located in path: '$VenvExecPath'" -Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" -Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" - -# Set values required in priority: CmdLine, ConfigFile, Default -# First, get the location of the virtual environment, it might not be -# VenvExecDir if specified on the command line. -if ($VenvDir) { - Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" -} -else { - Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." - $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") - Write-Verbose "VenvDir=$VenvDir" -} - -# Next, read the `pyvenv.cfg` file to determine any required value such -# as `prompt`. -$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir - -# Next, set the prompt from the command line, or the config file, or -# just use the name of the virtual environment folder. -if ($Prompt) { - Write-Verbose "Prompt specified as argument, using '$Prompt'" -} -else { - Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" - if ($pyvenvCfg -and $pyvenvCfg['prompt']) { - Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" - $Prompt = $pyvenvCfg['prompt']; - } - else { - Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" - Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" - $Prompt = Split-Path -Path $venvDir -Leaf - } -} - -Write-Verbose "Prompt = '$Prompt'" -Write-Verbose "VenvDir='$VenvDir'" - -# Deactivate any currently active virtual environment, but leave the -# deactivate function in place. -deactivate -nondestructive - -# Now set the environment variable VIRTUAL_ENV, used by many tools to determine -# that there is an activated venv. -$env:VIRTUAL_ENV = $VenvDir - -if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { - - Write-Verbose "Setting prompt to '$Prompt'" - - # Set the prompt to include the env name - # Make sure _OLD_VIRTUAL_PROMPT is global - function global:_OLD_VIRTUAL_PROMPT { "" } - Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT - New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt - - function global:prompt { - Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " - _OLD_VIRTUAL_PROMPT - } -} - -# Clear PYTHONHOME -if (Test-Path -Path Env:PYTHONHOME) { - Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME - Remove-Item -Path Env:PYTHONHOME -} - -# Add the venv to the PATH -Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH -$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/eeeeee/.venv/bin/activate b/eeeeee/.venv/bin/activate deleted file mode 100644 index 48132b4..0000000 --- a/eeeeee/.venv/bin/activate +++ /dev/null @@ -1,66 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - # reset old environment variables - if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then - PATH="${_OLD_VIRTUAL_PATH:-}" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then - PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null - fi - - if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then - PS1="${_OLD_VIRTUAL_PS1:-}" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "${1:-}" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="/Users/aln/Work/26.molenda.net/eeeeee/.venv" -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/bin:$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "${PYTHONHOME:-}" ] ; then - _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" - unset PYTHONHOME -fi - -if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then - _OLD_VIRTUAL_PS1="${PS1:-}" - PS1="(.venv) ${PS1:-}" - export PS1 -fi - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r 2> /dev/null -fi diff --git a/eeeeee/.venv/bin/activate.csh b/eeeeee/.venv/bin/activate.csh deleted file mode 100644 index 9769e0b..0000000 --- a/eeeeee/.venv/bin/activate.csh +++ /dev/null @@ -1,25 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi . -# Ported to Python 3.3 venv by Andrew Svetlov - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "/Users/aln/Work/26.molenda.net/eeeeee/.venv" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/bin:$PATH" - - -set _OLD_VIRTUAL_PROMPT="$prompt" - -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - set prompt = "(.venv) $prompt" -endif - -alias pydoc python -m pydoc - -rehash diff --git a/eeeeee/.venv/bin/activate.fish b/eeeeee/.venv/bin/activate.fish deleted file mode 100644 index 6a72d94..0000000 --- a/eeeeee/.venv/bin/activate.fish +++ /dev/null @@ -1,64 +0,0 @@ -# This file must be used with "source /bin/activate.fish" *from fish* -# (https://fishshell.com/); you cannot run it directly. - -function deactivate -d "Exit virtual environment and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self-destruct! - functions -e deactivate - end -end - -# Unset irrelevant variables. -deactivate nondestructive - -set -gx VIRTUAL_ENV "/Users/aln/Work/26.molenda.net/eeeeee/.venv" - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/bin" $PATH - -# Unset PYTHONHOME if set. -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # Save the current fish_prompt function as the function _old_fish_prompt. - functions -c fish_prompt _old_fish_prompt - - # With the original prompt function renamed, we can override with our own. - function fish_prompt - # Save the return status of the last command. - set -l old_status $status - - # Output the venv prompt; color taken from the blue of the Python logo. - printf "%s%s%s" (set_color 4B8BBE) "(.venv) " (set_color normal) - - # Restore the return status of the previous command. - echo "exit $old_status" | . - # Output the original/"old" prompt. - _old_fish_prompt - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" -end diff --git a/eeeeee/.venv/bin/pip b/eeeeee/.venv/bin/pip deleted file mode 100755 index 20ab9ca..0000000 --- a/eeeeee/.venv/bin/pip +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/aln/Work/26.molenda.net/eeeeee/.venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/eeeeee/.venv/bin/pip3 b/eeeeee/.venv/bin/pip3 deleted file mode 100755 index 20ab9ca..0000000 --- a/eeeeee/.venv/bin/pip3 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/aln/Work/26.molenda.net/eeeeee/.venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/eeeeee/.venv/bin/pip3.9 b/eeeeee/.venv/bin/pip3.9 deleted file mode 100755 index 20ab9ca..0000000 --- a/eeeeee/.venv/bin/pip3.9 +++ /dev/null @@ -1,8 +0,0 @@ -#!/Users/aln/Work/26.molenda.net/eeeeee/.venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/eeeeee/.venv/bin/python b/eeeeee/.venv/bin/python deleted file mode 120000 index b8a0adb..0000000 --- a/eeeeee/.venv/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/eeeeee/.venv/bin/python3 b/eeeeee/.venv/bin/python3 deleted file mode 120000 index f25545f..0000000 --- a/eeeeee/.venv/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -/Library/Developer/CommandLineTools/usr/bin/python3 \ No newline at end of file diff --git a/eeeeee/.venv/bin/python3.9 b/eeeeee/.venv/bin/python3.9 deleted file mode 120000 index b8a0adb..0000000 --- a/eeeeee/.venv/bin/python3.9 +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/__init__.py b/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/__init__.py deleted file mode 100644 index 5f40996..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/__init__.py +++ /dev/null @@ -1,128 +0,0 @@ -import sys -import os -import re -import importlib -import warnings - - -is_pypy = '__pypy__' in sys.builtin_module_names - - -warnings.filterwarnings('ignore', - r'.+ distutils\b.+ deprecated', - DeprecationWarning) - - -def warn_distutils_present(): - if 'distutils' not in sys.modules: - return - if is_pypy and sys.version_info < (3, 7): - # PyPy for 3.6 unconditionally imports distutils, so bypass the warning - # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 - return - warnings.warn( - "Distutils was imported before Setuptools, but importing Setuptools " - "also replaces the `distutils` module in `sys.modules`. This may lead " - "to undesirable behaviors or errors. To avoid these issues, avoid " - "using distutils directly, ensure that setuptools is installed in the " - "traditional way (e.g. not an editable install), and/or make sure " - "that setuptools is always imported before distutils.") - - -def clear_distutils(): - if 'distutils' not in sys.modules: - return - warnings.warn("Setuptools is replacing distutils.") - mods = [name for name in sys.modules if re.match(r'distutils\b', name)] - for name in mods: - del sys.modules[name] - - -def enabled(): - """ - Allow selection of distutils by environment variable. - """ - which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') - return which == 'local' - - -def ensure_local_distutils(): - clear_distutils() - distutils = importlib.import_module('setuptools._distutils') - distutils.__name__ = 'distutils' - sys.modules['distutils'] = distutils - - # sanity check that submodules load as expected - core = importlib.import_module('distutils.core') - assert '_distutils' in core.__file__, core.__file__ - - -def do_override(): - """ - Ensure that the local copy of distutils is preferred over stdlib. - - See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 - for more motivation. - """ - if enabled(): - warn_distutils_present() - ensure_local_distutils() - - -class DistutilsMetaFinder: - def find_spec(self, fullname, path, target=None): - if path is not None: - return - - method_name = 'spec_for_{fullname}'.format(**locals()) - method = getattr(self, method_name, lambda: None) - return method() - - def spec_for_distutils(self): - import importlib.abc - import importlib.util - - class DistutilsLoader(importlib.abc.Loader): - - def create_module(self, spec): - return importlib.import_module('setuptools._distutils') - - def exec_module(self, module): - pass - - return importlib.util.spec_from_loader('distutils', DistutilsLoader()) - - def spec_for_pip(self): - """ - Ensure stdlib distutils when running under pip. - See pypa/pip#8761 for rationale. - """ - if self.pip_imported_during_build(): - return - clear_distutils() - self.spec_for_distutils = lambda: None - - @staticmethod - def pip_imported_during_build(): - """ - Detect if pip is being imported in a build script. Ref #2355. - """ - import traceback - return any( - frame.f_globals['__file__'].endswith('setup.py') - for frame, line in traceback.walk_stack(None) - ) - - -DISTUTILS_FINDER = DistutilsMetaFinder() - - -def add_shim(): - sys.meta_path.insert(0, DISTUTILS_FINDER) - - -def remove_shim(): - try: - sys.meta_path.remove(DISTUTILS_FINDER) - except ValueError: - pass diff --git a/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/override.py b/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/override.py deleted file mode 100644 index 2cc433a..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/_distutils_hack/override.py +++ /dev/null @@ -1 +0,0 @@ -__import__('_distutils_hack').do_override() diff --git a/eeeeee/.venv/lib/python3.9/site-packages/distutils-precedence.pth b/eeeeee/.venv/lib/python3.9/site-packages/distutils-precedence.pth deleted file mode 100644 index 6de4198..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/distutils-precedence.pth +++ /dev/null @@ -1 +0,0 @@ -import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'stdlib') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/INSTALLER b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/METADATA b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/METADATA deleted file mode 100644 index f1d57c5..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/METADATA +++ /dev/null @@ -1,103 +0,0 @@ -Metadata-Version: 2.4 -Name: lxml -Version: 6.0.2 -Summary: Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API. -Home-page: https://lxml.de/ -Author: lxml dev team -Author-email: lxml@lxml.de -Maintainer: lxml dev team -Maintainer-email: lxml@lxml.de -License: BSD-3-Clause -Project-URL: Source, https://github.com/lxml/lxml -Project-URL: Bug Tracker, https://bugs.launchpad.net/lxml -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Information Technology -Classifier: Programming Language :: Cython -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.8 -Classifier: Programming Language :: Python :: 3.9 -Classifier: Programming Language :: Python :: 3.10 -Classifier: Programming Language :: Python :: 3.11 -Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 -Classifier: Programming Language :: C -Classifier: Operating System :: OS Independent -Classifier: Topic :: Text Processing :: Markup :: HTML -Classifier: Topic :: Text Processing :: Markup :: XML -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Requires-Python: >=3.8 -License-File: LICENSE.txt -License-File: LICENSES.txt -Provides-Extra: source -Provides-Extra: cssselect -Requires-Dist: cssselect>=0.7; extra == "cssselect" -Provides-Extra: html5 -Requires-Dist: html5lib; extra == "html5" -Provides-Extra: htmlsoup -Requires-Dist: BeautifulSoup4; extra == "htmlsoup" -Provides-Extra: html-clean -Requires-Dist: lxml_html_clean; extra == "html-clean" -Dynamic: author -Dynamic: author-email -Dynamic: classifier -Dynamic: description -Dynamic: home-page -Dynamic: license -Dynamic: license-file -Dynamic: maintainer -Dynamic: maintainer-email -Dynamic: project-url -Dynamic: provides-extra -Dynamic: requires-python -Dynamic: summary - -lxml is a Pythonic, mature binding for the libxml2 and libxslt libraries. -It provides safe and convenient access to these libraries using the -ElementTree API. - -It extends the ElementTree API significantly to offer support for XPath, -RelaxNG, XML Schema, XSLT, C14N and much more. - -To contact the project, go to the `project home page `_ -or see our bug tracker at https://launchpad.net/lxml - -In case you want to use the current in-development version of lxml, -you can get it from the github repository at -https://github.com/lxml/lxml . Note that this requires Cython to -build the sources, see the build instructions on the project home page. - - -After an official release of a new stable series, bug fixes may become available at -https://github.com/lxml/lxml/tree/lxml-6.0 . -Running ``pip install https://github.com/lxml/lxml/archive/refs/heads/lxml-6.0.tar.gz`` -will install the unreleased branch state as soon as a maintenance branch has been established. -Note that this requires Cython to be installed at an appropriate version for the build. - -6.0.2 (2025-09-21) -================== - -Bugs fixed ----------- - -* LP#2125278: Compilation with libxml2 2.15.0 failed. - Original patch by Xi Ruoyao. - -* Setting ``decompress=True`` in the parser had no effect in libxml2 2.15. - -* Binary wheels on Linux and macOS use the library version libxml2 2.14.6. - See https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.14.6 - -* Test failures in libxml2 2.15.0 were fixed. - -Other changes -------------- - -* Binary wheels for Py3.9-3.11 on the ``riscv64`` architecture were added. - -* Error constants were updated to match libxml2 2.15.0. - -* Built using Cython 3.1.4. - - diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/RECORD b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/RECORD deleted file mode 100644 index f3129d4..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/RECORD +++ /dev/null @@ -1,205 +0,0 @@ -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/ElementInclude.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/cssselect.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/doctestcompare.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/ElementSoup.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/_diffcommand.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/_difflib.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/_html5builder.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/_setmixin.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/builder.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/clean.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/defs.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/diff.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/formfill.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/html5parser.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/soupparser.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/usedoctest.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/includes/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/includes/extlibs/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/includes/libexslt/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/includes/libxml/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/includes/libxslt/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/isoschematron/__init__.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/pyclasslookup.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/sax.cpython-39.pyc,, -../../../../../../../Library/Caches/com.apple.python/Users/aln/Work/26.molenda.net/eeeeee/.venv/lib/python3.9/site-packages/lxml/usedoctest.cpython-39.pyc,, -lxml-6.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -lxml-6.0.2.dist-info/METADATA,sha256=0qIHkwlNTTMz4-c5e8ZnbbGgt_vpYZHCEoqXyckR95Q,3622 -lxml-6.0.2.dist-info/RECORD,, -lxml-6.0.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml-6.0.2.dist-info/WHEEL,sha256=Sli93J_eWejDC8SYRdplFsirRhz71iXfsqaGlL-WXt4,139 -lxml-6.0.2.dist-info/licenses/LICENSE.txt,sha256=j8K1aBM1FuRoRdIUeRet7uFkjnCumrXtbFQXr-9M6FU,1507 -lxml-6.0.2.dist-info/licenses/LICENSES.txt,sha256=QdSd1AaqDhVIptXyGjDWv2OLPNlutyid00jYPtLkA5I,1514 -lxml-6.0.2.dist-info/top_level.txt,sha256=NjD988wqaKq512nshNdLt-uDxsjkp4Bh51m6N-dhUrk,5 -lxml/ElementInclude.py,sha256=PSLeZFvCa76WHJulPLxcZXJtCI2-4dK2CtqPRiYOAQg,8560 -lxml/__init__.py,sha256=rgOcPyZUNBFL30ylxIxd8fHHWi6TwyIUCi8Av84XWwo,574 -lxml/_elementpath.cpython-39-darwin.so,sha256=bLMQjJKxDD_TYBnSjkj8Ulaz_x-OGZyBBANoroBP9Rs,497776 -lxml/_elementpath.py,sha256=b80hM3ndAkTtRX6v54za3LkkAqCcd0700BbMPZHnTBU,10959 -lxml/apihelpers.pxi,sha256=9S6bzp-VKCUPZv0f6-el5PsbPFN4FJqSnMCIYilS0eU,63881 -lxml/builder.cpython-39-darwin.so,sha256=FMGelyMN0skDjhPYG_2wHGrFn60_atPRt0pF9XNjYhg,291248 -lxml/builder.py,sha256=KI1HxHTd4wJqqVfmTRtSbXBQdl2T-P36ih4hT-J3MNw,8485 -lxml/classlookup.pxi,sha256=Tax8Vhbm5C6UCjgmRFsYjW0pFHxIuTthH1MOgASDLgc,22435 -lxml/cleanup.pxi,sha256=ZNEpbv7qx_ICPzsxhCaMUHCOfiznOoZ_u3jlYXHAuh4,8454 -lxml/cssselect.py,sha256=_wZdX-B9p5MeIYABmENIYRWEkwXwX-7jO8Dkf-1rUZU,3306 -lxml/debug.pxi,sha256=KTcpR8-slUYvmIPbE35GoHDNTb-gjTEvD7bw6LltM4c,1125 -lxml/docloader.pxi,sha256=bYSZAxxbBEfVzfLXTUWFRfOyUTfV23L7i9hR2dgtSNY,5772 -lxml/doctestcompare.py,sha256=40EDnkwpcvW86qNa86990OXF42xdHaosSZoiBsEjkzU,17731 -lxml/dtd.pxi,sha256=IAKkmA4ZoC68sqAWcTqoS8jEGYcPQrVMCZgn4iLBYko,15281 -lxml/etree.cpython-39-darwin.so,sha256=1dxECBWNkHaqx3kW2B_rdGJJOGqhAwifHiwpIM9fJPc,9667432 -lxml/etree.h,sha256=_NkGkD3C_jpE4UegvQ6Y32_ycTbUCLyOBz9xfWRPkug,9792 -lxml/etree.pyx,sha256=2qCb8ZNjsdoB0fUELYwAM4ldLQZWS5_gt-OxKEUM-vs,138014 -lxml/etree_api.h,sha256=dNCm28ubaVS8SbhLuxs9JvYWg41NoR_yD3qTRr7hliA,17372 -lxml/extensions.pxi,sha256=xKLad35EQgpsDhs07tw31aKJBBMWIK9rMc0JTXETAUA,32022 -lxml/html/ElementSoup.py,sha256=s_dLobLMuKn2DhexR-iDXdZrMFg1RjLy1feHsIeZMpw,320 -lxml/html/__init__.py,sha256=CC5WdsvSptZhr9MZya1qsL6JKVbviYdrHOhXrGhmORg,64425 -lxml/html/_diffcommand.py,sha256=kz_7EP9PmYWuczlZcGiw74_rG0eTKvQ2lrO0rkiwlYE,2081 -lxml/html/_difflib.cpython-39-darwin.so,sha256=dMVHZht3-JzseMx38JS4F4PleEoGgocS-DeNmK0wlr4,1121904 -lxml/html/_difflib.py,sha256=GgH_jVrZQC8tI8WV_lFZQsXFJ3mOTAPup1zjBJNvkPo,84954 -lxml/html/_html5builder.py,sha256=NLaT-Ev-aBgJpeQl-6ZbJChLZK5GV-znDkHOJD5VQC4,3230 -lxml/html/_setmixin.py,sha256=8IFIOLmVz0G-XzsD2tCEkSFWO-dgPBHgvHufC8ni67s,1188 -lxml/html/builder.py,sha256=Uz3r5uiuCdoN0UPa7ngoLMwAadVIhslzGvlRPGigY_M,6187 -lxml/html/clean.py,sha256=FghSJy4jt2RaBy6dgusowkU18hxpZ4XLE5ceCK9qxyA,503 -lxml/html/defs.py,sha256=l_6nh4DHvrsVyWVqWCUUx14QiahRyZv4Melqy_thf6Q,4250 -lxml/html/diff.cpython-39-darwin.so,sha256=JRjIXbSLwiLMZgYR6HCADsQvm885MQ6IpNCYT0PlAyI,732312 -lxml/html/diff.py,sha256=Za0By-yeYlQEjUu7m7xKB288kKiy8VBS5gT0RPOaFY0,32989 -lxml/html/formfill.py,sha256=umgk0BbkAI1W6q9musFbL-cDnI_aap2NsLBJqk0UmVI,9681 -lxml/html/html5parser.py,sha256=dnyC4cqHxywjZSzk0mu2L7THTZjxhg4yF4pncjusa_w,8634 -lxml/html/soupparser.py,sha256=xo8VvNeOEb-SChuXLKCRECh8J7HBiJLE9sAbEskoUUQ,10197 -lxml/html/usedoctest.py,sha256=tPlmVz4KK1GRKV5DJLrdVECeqsT9PlDzSqqTodVi5s0,249 -lxml/includes/__init__.pxd,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/c14n.pxd,sha256=DBQcOJ0c_YS245ohMb8fmuEC1kFyv1LrNY_8Mf-syZg,1110 -lxml/includes/config.pxd,sha256=H6Mrl8It21hzRI2hzMId9W48QqkYYkoLT4dniLNmdTw,96 -lxml/includes/dtdvalid.pxd,sha256=Nv0OykjYehv2lO-Zj--q6jS3TAC_dvQVPSgPMuse1NM,689 -lxml/includes/etree_defs.h,sha256=h_UjJTmNUqPyKNNrWB9hxmt6v4CF7_83XVY8dOfxqW0,14524 -lxml/includes/etreepublic.pxd,sha256=Bn4d3JkWPqXputXqI-eJ0xmPrwNFPTfDCa7axgjB7FM,10184 -lxml/includes/extlibs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/extlibs/libcharset.h,sha256=GA0FumrbNI4VDGlzq3lf5CLaCwXgn4unw2l0btGQFwI,1510 -lxml/includes/extlibs/localcharset.h,sha256=Z_AagaQeq0aDE7NPsVOqEf4nO4KcUp46ggo4d0ONIOQ,6338 -lxml/includes/extlibs/zconf.h,sha256=ROVD_0UUx6mgHWSAGcLJqB0RBcv6PHfx-vbNhur6ir0,16464 -lxml/includes/extlibs/zlib.h,sha256=ilV5r3LqT0J_8ApBUPDMs_xcHkN59ybhARM7Grn8YAw,96829 -lxml/includes/htmlparser.pxd,sha256=9uASkP5dU7OE2lCOLT-z2e01qSbFlp4ehgwdostF_qk,2802 -lxml/includes/libexslt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/libexslt/exslt.h,sha256=eSW5tMJAewSUANLqk7AGEiU8b2BbCNRyauHnez7nKSU,3114 -lxml/includes/libexslt/exsltconfig.h,sha256=QHxzEbRlv_h0USBvpr0Zrl0Muzlc71VCrvgR6lqnLEY,1172 -lxml/includes/libexslt/exsltexports.h,sha256=1Jm9KTXm2FUUJIZ6V6-Uw55yG0BMULX3_goyxDd2LL8,1077 -lxml/includes/libxml/HTMLparser.h,sha256=sU4xGqj-vBtEvzlxA3hBPWJboifvkc4F1hynKXmsl3k,9569 -lxml/includes/libxml/HTMLtree.h,sha256=Q7UBKFbQ8fx4d_dMnmR6ay8JmfOhopFkDp2B63YkLDU,3517 -lxml/includes/libxml/SAX.h,sha256=SFnG27EFrYGUB9HDL_xSIGBwEns5pl07rApXWThFZFM,386 -lxml/includes/libxml/SAX2.h,sha256=RfFP5o3le-Rg8bnA2GW7L7L9_pfXCs3TieODcv1DTWY,4240 -lxml/includes/libxml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/libxml/c14n.h,sha256=BSBXw6nIZutC8mWvbRrLLmoWjw3wRt-nM93vjXGMCm8,2742 -lxml/includes/libxml/catalog.h,sha256=H9ssTCaBjtDqc-AZqCk1R7h8F2iD9szqLjJyHpaczXg,4633 -lxml/includes/libxml/chvalid.h,sha256=TZcceNp6Cw0QlYwIqK9GxyYqL5UiAjpQyjt_yrZGTQE,5087 -lxml/includes/libxml/debugXML.h,sha256=XXRNI39gJW7bGRC4SzE4ad-SJ906BsUGz3AwOtkKuS4,1667 -lxml/includes/libxml/dict.h,sha256=SweaPGMtTTf4je6dNTIoEzcfEvpsAT9_PhR7FC0K-rQ,1770 -lxml/includes/libxml/encoding.h,sha256=haL7ratww2wkIERGmtwUqU2BbTVe52FZFU7MmrOpsPk,9623 -lxml/includes/libxml/entities.h,sha256=LEOCA826-0f8dhRJzC_2hvUVsSH7lKQjrea9hSTdBbo,4419 -lxml/includes/libxml/globals.h,sha256=NH8zyRI5cXJJGp5k2aLxOm-reJEGOFX6LYP82GBXRlY,583 -lxml/includes/libxml/hash.h,sha256=KIIpAYKBfGUU3ydWhGehUyfuauZz_Ps0gyambzQo_rc,7017 -lxml/includes/libxml/list.h,sha256=oh7iJNQajRA_cHsNk9CcFPYkaW2smf4J_MpedPPjC4k,3128 -lxml/includes/libxml/nanoftp.h,sha256=22PBtWhJueYLFvwukt4oFooRct_xJA83hbluHRBNXUM,302 -lxml/includes/libxml/nanohttp.h,sha256=bLbzYjAyAKmP3ComMOPH6XaUImu6bNAESF1HrVtRve0,2124 -lxml/includes/libxml/parser.h,sha256=Uq7-ce55UUAsvo4n6CiBlNQpmowewvWhOsQtgGM1UQ8,48498 -lxml/includes/libxml/parserInternals.h,sha256=8_Wr6UgRzm8BRn1RPLxyBkw6BagAdDvVqMA_e181_EI,14539 -lxml/includes/libxml/relaxng.h,sha256=VXZ74r5Yja06KqypdBHc8neDwPxQ2aMrsWHSdRt5oi4,5991 -lxml/includes/libxml/schemasInternals.h,sha256=V8M4In3zf24EX55Yt4dcfxwp7NpHGYViKnLKwtyrPJ4,26233 -lxml/includes/libxml/schematron.h,sha256=8EhPDhvtlMxl9e0C5rSbEruOvzJS5BC_OOFbq9RXZnY,4255 -lxml/includes/libxml/threads.h,sha256=mT3CgK4lXK7-NDnUOFXqYuCK6fyY70S3BsHF-TnT45k,1619 -lxml/includes/libxml/tree.h,sha256=zTRLt6h5x6ApyeXgs90CKQZSAl2hKm7b5NxtPKUQFAE,36106 -lxml/includes/libxml/uri.h,sha256=J9teJHme5z883c4twF5oImEYY-E3xSvhdSGpyRVtvIg,2855 -lxml/includes/libxml/valid.h,sha256=By61IbPvk_eLux7a8x0mOaly7oclFaSGaFE8b2xZcUE,13226 -lxml/includes/libxml/xinclude.h,sha256=K3I5jhw2zAMj26LuRNZc15Bwv2JE2hWxwVn4TCqv2b4,3258 -lxml/includes/libxml/xlink.h,sha256=TVLOkISrcKDelo9n_XIUyPiStDYa8NxuF2dz70aBFCI,5062 -lxml/includes/libxml/xmlIO.h,sha256=FvbuMYTy1-S5PScabE03wz0oWKf626pmXvOPZNuLm-w,11948 -lxml/includes/libxml/xmlautomata.h,sha256=7Sc3YgPz1ZIBKCHPSxs5oAwJEZWQ1RT2kyUw85pUtmU,4004 -lxml/includes/libxml/xmlerror.h,sha256=mMfltMxUza6kiSBfP2QfnY3UlMP_rEXKfX0wruBLl4A,37561 -lxml/includes/libxml/xmlexports.h,sha256=IyV3AMeQVbOl0wkjlnNX4B8WUZ-5GNKQmxZc6-maWUU,2025 -lxml/includes/libxml/xmlmemory.h,sha256=m7wGvVMxNzZiuOAo3vkjxaVWstc8aQLzb6obbjPsebE,4658 -lxml/includes/libxml/xmlmodule.h,sha256=ERUHUmDdZRmh6NjLYWUpse51rLWR8qNjPHOtdgmlLF0,1198 -lxml/includes/libxml/xmlreader.h,sha256=BAHinlSOTXX3DEax9BniaIIPAXJyLGfzym9R-27LCcU,12387 -lxml/includes/libxml/xmlregexp.h,sha256=_q6C1XRy8DS3kSmLbEKpvkKQciTgjTJgGc_zUQ6m22M,2632 -lxml/includes/libxml/xmlsave.h,sha256=zcEQr9sO5CsFrnoOLshhdsqMEr8k4AeFhbkYyNfO9Fs,2934 -lxml/includes/libxml/xmlschemas.h,sha256=5AfLnYUcfmxHRzg0dVpdHig--4ui1-XDwDgpKGDKCiU,7067 -lxml/includes/libxml/xmlschemastypes.h,sha256=MYwlGmoKAo3lHRaaKgnCXiLmPT9KRjdxyCJ7TEyZ6jM,4583 -lxml/includes/libxml/xmlstring.h,sha256=d5PpqxP1I1sfmCUHvVJtjoC9h7hLHcAAQ5ok_Rtf50I,5271 -lxml/includes/libxml/xmlunicode.h,sha256=8sq3wEW2AiyTCuc3ZceOEkce7lfrI7VnkRfwEQgc6pU,278 -lxml/includes/libxml/xmlversion.h,sha256=oVpaE_xbttaeZNFKSuSfcLOceWz7LQgKP71Z1msXZNo,5112 -lxml/includes/libxml/xmlwriter.h,sha256=BEUwYNKx3xymDE9vepksEK7yVq9SXYm1d2pQnzlPy90,20688 -lxml/includes/libxml/xpath.h,sha256=CQv6X_pRhuXoCVpqoDXYB7FfusLK7AuPxCNigwhNYAA,16156 -lxml/includes/libxml/xpathInternals.h,sha256=mc9B5tdpfssyz_NPUzww6dKuWCtBybBiBRJkTe4AE4U,18504 -lxml/includes/libxml/xpointer.h,sha256=DAxMsfPp2SSZgXFrPbxBA84RwTMRf35Qg_LBbUzPQhA,1026 -lxml/includes/libxslt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -lxml/includes/libxslt/attributes.h,sha256=qKwzfGf7r89esLC65s96iYJWRA-s-Ezss2_V6Mmo1hk,957 -lxml/includes/libxslt/documents.h,sha256=kBihgH5pqRvFalhm_fOFHtJTFhTpBcm681yT5dxgwfw,2704 -lxml/includes/libxslt/extensions.h,sha256=W5UMyJqUP_1zt6sXZ0mgc0gAIwDJrZ8gjByhyrWqvd8,6899 -lxml/includes/libxslt/extra.h,sha256=6X3Wu3NdPtrlqz-Koo7dB-rccnnszi6j3zg599gTByg,1640 -lxml/includes/libxslt/functions.h,sha256=fc4CZj-9KeBHzO9-WWU_bNqmaEZAz3n7NNwClIBXk14,1972 -lxml/includes/libxslt/imports.h,sha256=18kIjoGqdFXR63Ce3ZtzxsTiYV3XGKpchYakMUPDuUI,1840 -lxml/includes/libxslt/keys.h,sha256=16v25VEluS7jYhgg6gYFwVxgGMn-1ctnlhhWWT4RcBY,1155 -lxml/includes/libxslt/namespaces.h,sha256=VofSn2Kkn-a5JyRKCmY3jPp7amQy3n09vzy0KUQt4q0,1666 -lxml/includes/libxslt/numbersInternals.h,sha256=Eg5gYZ5p3h0_e5wyI61S-0E6_ArVJzv0yr63j6BU2fc,2019 -lxml/includes/libxslt/pattern.h,sha256=tJ-BPfs9UYgiZMMoQZbhij3g7xVppYq7TrrOu25eR7Q,2110 -lxml/includes/libxslt/preproc.h,sha256=D_LjEdHhsdyBnEAvflnwFgoR4hGUb72kgEhXkkmPRsw,896 -lxml/includes/libxslt/security.h,sha256=fUD1cy_WxFCTvTNAF0WOQIU4p5CNWn1LHFyZJd-Fx5U,2652 -lxml/includes/libxslt/templates.h,sha256=bnt6Jqui6KU5pNUdMNPbQZkZ5d-VTWqC0TMGkOlVoIo,2268 -lxml/includes/libxslt/transform.h,sha256=ICT7meUV0OTAx27WaKVrKj-aUmR9LSpTNaOAJd2UStg,6311 -lxml/includes/libxslt/variables.h,sha256=cQAgPe4QCcK2uKbWg7Iz-9peM9xWGm7m3M6jQm0sjIA,3143 -lxml/includes/libxslt/xslt.h,sha256=wmFx2Q31Pd8Iq2phAQpY9J3QQatb8lWg3gABtqKFgEw,1964 -lxml/includes/libxslt/xsltInternals.h,sha256=2EbEKYmnYZq0HjGnUMAlpqnqZJurRXzjlgk5Js1WYaY,57949 -lxml/includes/libxslt/xsltconfig.h,sha256=cV5scdRK6xmOHeOg3OCw6hBfcQ_nrtNs_tKefX67304,2910 -lxml/includes/libxslt/xsltexports.h,sha256=1-luH-0bCIgBAlKAXhV-dqHBfwOAQNDamiYbxIlTf0k,1124 -lxml/includes/libxslt/xsltlocale.h,sha256=ppxGEmJfZIJgwRQzCM0_77p9WNekEWq1NrdYZrQl4IE,942 -lxml/includes/libxslt/xsltutils.h,sha256=1eguYgR9-jeNOVlBUktHboaq-VLX6JXraO80TfbARKM,9085 -lxml/includes/lxml-version.h,sha256=KZfk_lJnXSnxkyRdUV5taHsWJe4xbC6UEYfYldlfouI,71 -lxml/includes/relaxng.pxd,sha256=HzHlQ6mCcf_tj_JZ9NAVJTVAv8ScCkE8Ifq15y3bS0c,2615 -lxml/includes/schematron.pxd,sha256=Hob7xh-K-MKqp7WiG8thMagf5EkQzmgfi4ds0EF91JA,1604 -lxml/includes/tree.pxd,sha256=XApzMRy_LSqCtQ-OTS-vNSW7CT_OWstybfIT2H84LsA,20179 -lxml/includes/uri.pxd,sha256=3vOXw6AbSPxAM9uo71T1qnfx-wd9ezXLDQtWsb2zX0I,145 -lxml/includes/xinclude.pxd,sha256=CuO_XZNB6E2JK1qXXWn11APrjFQV5kA6SMyb77WZn0A,804 -lxml/includes/xmlerror.pxd,sha256=OQqayytkV0NigAPbsQCCcvmy7luRe0XhVzpTdzJjP3g,58837 -lxml/includes/xmlparser.pxd,sha256=eDGyU5kZyNVksK0dUhMIi7rnE-LSevXsqyl72v99Ess,13730 -lxml/includes/xmlschema.pxd,sha256=OLZPd2WDJyopiXJJyo-dAyyYHaeSYFiMAI4tqIiv-Ik,1702 -lxml/includes/xpath.pxd,sha256=e8-ZYUbRG7N1mHETAlknJ_QqAteOosrYLRgpH-OsTkg,5603 -lxml/includes/xslt.pxd,sha256=4yl3pOu7pAvsx5Tc-W4IWCoB8wgtSSR62HI1jqu6jko,8241 -lxml/isoschematron/__init__.py,sha256=uauerYeKTlWFCJSqieIHhF5l6rYV2myeEJ0Imd1LzRc,13274 -lxml/isoschematron/resources/rng/iso-schematron.rng,sha256=VsWxPyi3iViJDDbjJJw0wWkEHkLrz9zoCA8zJLor9N4,18337 -lxml/isoschematron/resources/xsl/RNG2Schtrn.xsl,sha256=ObebsB8Wt-d3uIA_U5NU85TpnQ3PxPX38TdOAqosMac,3172 -lxml/isoschematron/resources/xsl/XSD2Schtrn.xsl,sha256=QweRrIIM-zFcgg98GXA2CaWfIbgVE0XKEeYSfvv67A0,4563 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_abstract_expand.xsl,sha256=xSZ_Ekq_I-62ZpiE5AqYYHwFW_qh855zt9V4_s7rbkY,11703 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_dsdl_include.xsl,sha256=x42QJ-dxQ1waPzydsCoQnp2Xj15y53nW43O7BuoDRHk,39957 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_message.xsl,sha256=Tr9BnO6pzjVWwhqJfm10UlvAy95EgfSCz2iMlrVGT6Q,2015 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_schematron_skeleton_for_xslt1.xsl,sha256=ue8q_88X4e_jsJizo31GRNBxNhdxkEE9fY20oq0Iqwk,71764 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/iso_svrl_for_xslt1.xsl,sha256=BBAdsVSi5zAzeGepuN6gS1saQINDqITXKplmmj4dTWg,20382 -lxml/isoschematron/resources/xsl/iso-schematron-xslt1/readme.txt,sha256=OGLiFswuLJEW5EPYKOeoauuCJFEtVa6jyzBE1OcJI98,3310 -lxml/iterparse.pxi,sha256=JXvYhSOCaRjT_hYbRGMlJt2rlqx0TiRpN4FE1jQc63w,16521 -lxml/lxml.etree.h,sha256=_NkGkD3C_jpE4UegvQ6Y32_ycTbUCLyOBz9xfWRPkug,9792 -lxml/lxml.etree_api.h,sha256=dAbJPd53D_9CIGzePAUB3otgyhG4o2cSdA4-6apdzRA,17377 -lxml/nsclasses.pxi,sha256=5pzNBhBtlqObPdThL9QIGRs1Dxj1qnr0PyXuTCURqTg,9129 -lxml/objectify.cpython-39-darwin.so,sha256=ViaJLjaF61LbuAfG1W_JQjiw94eI0t4W6Fo39Vr7qiA,5235008 -lxml/objectify.pyx,sha256=I4bQQXmQssBtk5bTrid-eVURBLKRTM5iQZiviugIrts,75823 -lxml/objectpath.pxi,sha256=s5TNG2-EbaWWKLFAiX303B95zK_Ui8ausB__3QvFFGw,11450 -lxml/parser.pxi,sha256=VZfychEJ3-XPE3x6oGOEzn6HVAr74R7lXfDSVF-hq-U,85411 -lxml/parsertarget.pxi,sha256=v1PidxRaG5giwXcTDkpBI7PDFmsZuOcK0y9LdkQaY8M,6326 -lxml/proxy.pxi,sha256=8IVvYF2KTuzl7Hb3XGHEmcxfSLbUZkA2Q1Y50hLsyzE,23929 -lxml/public-api.pxi,sha256=XoP6_cJOEoQIItvE1RiYCKYD1ry4AobaOr4XLo0KSE4,6666 -lxml/pyclasslookup.py,sha256=gLD1HM2HtITYYiGzjEOewSwbB7XkVx_NZv_quCt79Oc,92 -lxml/readonlytree.pxi,sha256=ddRYczhHieJ4XUvWvTPW9N9oQ8vuKtv7lC1mtE1qvH8,18976 -lxml/relaxng.pxi,sha256=3OQ-fZMzP-KF5vM6HTozT_9ee3J0DJnpj9RcHC8LoMw,6339 -lxml/sax.cpython-39-darwin.so,sha256=S7bAW0Qog3b2gbfTY143QChGQgF_F64jRRQbBZafJIM,416008 -lxml/sax.py,sha256=yrNvKD6rlon48jrR-1qpFXER8j4psYC2R5yt0u6TWLs,9706 -lxml/saxparser.pxi,sha256=TmkdM5h9xII9iKRaBk_1NGk2KTfeesl5Ha8bpFQGqLc,33529 -lxml/schematron.pxi,sha256=F2OHKZUl57-byBk_wWtPTnHZ1fwlj0FtwG3VuGtG-UY,6064 -lxml/serializer.pxi,sha256=iIXfechFHfvFs2sTk7wMIy3sDJxmaMPbNO33mkLLBUE,68063 -lxml/usedoctest.py,sha256=qRgZKQVcAZcl-zN0AIXVJnOsETUXz2nPXkxuzs1lGgk,230 -lxml/xinclude.pxi,sha256=7eBrI_OK47mmrHQ0ixbixRI8pKqQ1nwkMV-OmKUVlD4,2456 -lxml/xmlerror.pxi,sha256=i1kR42WB2BAxtrmh7m2ADlH-jffVQ-blW3pW0Ps4s-g,50061 -lxml/xmlid.pxi,sha256=5zf9oR6bsCtavGiOmilNyHqYwgG_bnrIabSd2SURtm0,6073 -lxml/xmlschema.pxi,sha256=mumNoHni5S3BQPtcmOHRd61KRaVWu4eOie2wQeB0e6E,8490 -lxml/xpath.pxi,sha256=aqW24V817dUxps4Gnc8h7Tm3QVlITKvxU5_9WgJUIFg,19132 -lxml/xslt.pxi,sha256=wxdbuvNFVA8eP57tHmBYWER__ceFhf6HGdsbBHbx_0A,36315 -lxml/xsltext.pxi,sha256=TImDiAPlAezC07P7RY1N9YChA7AuKFH-G53hXdel9yc,11088 diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/REQUESTED b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/WHEEL b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/WHEEL deleted file mode 100644 index e752d95..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: setuptools (80.9.0) -Root-Is-Purelib: false -Tag: cp39-cp39-macosx_10_9_universal2 -Generator: delocate 0.13.0 - diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSE.txt b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSE.txt deleted file mode 100644 index 0bdf039..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSE.txt +++ /dev/null @@ -1,31 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2004 Infrae. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - 3. Neither the name of Infrae nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INFRAE OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSES.txt b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSES.txt deleted file mode 100644 index 9f97c18..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/licenses/LICENSES.txt +++ /dev/null @@ -1,29 +0,0 @@ -lxml is copyright Infrae and distributed under the BSD license (see -doc/licenses/BSD.txt), with the following exceptions: - -Some code, such a selftest.py, selftest2.py and -src/lxml/_elementpath.py are derived from ElementTree and -cElementTree. See doc/licenses/elementtree.txt for the license text. - -lxml.cssselect and lxml.html are copyright Ian Bicking and distributed -under the BSD license (see doc/licenses/BSD.txt). - -test.py, the test-runner script, is GPL and copyright Shuttleworth -Foundation. See doc/licenses/GPL.txt. It is believed the unchanged -inclusion of test.py to run the unit test suite falls under the -"aggregation" clause of the GPL and thus does not affect the license -of the rest of the package. - -The isoschematron implementation uses several XSL and RelaxNG resources: - * The (XML syntax) RelaxNG schema for schematron, copyright International - Organization for Standardization (see - src/lxml/isoschematron/resources/rng/iso-schematron.rng for the license - text) - * The skeleton iso-schematron-xlt1 pure-xslt schematron implementation - xsl stylesheets, copyright Rick Jelliffe and Academia Sinica Computing - Center, Taiwan (see the xsl files here for the license text: - src/lxml/isoschematron/resources/xsl/iso-schematron-xslt1/) - * The xsd/rng schema schematron extraction xsl transformations are unlicensed - and copyright the respective authors as noted (see - src/lxml/isoschematron/resources/xsl/RNG2Schtrn.xsl and - src/lxml/isoschematron/resources/xsl/XSD2Schtrn.xsl) diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/top_level.txt b/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/top_level.txt deleted file mode 100644 index ab90481..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml-6.0.2.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -lxml diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/ElementInclude.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/ElementInclude.py deleted file mode 100644 index 2188433..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/ElementInclude.py +++ /dev/null @@ -1,244 +0,0 @@ -# -# ElementTree -# $Id: ElementInclude.py 1862 2004-06-18 07:31:02Z Fredrik $ -# -# limited xinclude support for element trees -# -# history: -# 2003-08-15 fl created -# 2003-11-14 fl fixed default loader -# -# Copyright (c) 2003-2004 by Fredrik Lundh. All rights reserved. -# -# fredrik@pythonware.com -# http://www.pythonware.com -# -# -------------------------------------------------------------------- -# The ElementTree toolkit is -# -# Copyright (c) 1999-2004 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -""" -Limited XInclude support for the ElementTree package. - -While lxml.etree has full support for XInclude (see -`etree.ElementTree.xinclude()`), this module provides a simpler, pure -Python, ElementTree compatible implementation that supports a simple -form of custom URL resolvers. -""" - -from lxml import etree -try: - from urlparse import urljoin - from urllib2 import urlopen -except ImportError: - # Python 3 - from urllib.parse import urljoin - from urllib.request import urlopen - -XINCLUDE = "{http://www.w3.org/2001/XInclude}" - -XINCLUDE_INCLUDE = XINCLUDE + "include" -XINCLUDE_FALLBACK = XINCLUDE + "fallback" -XINCLUDE_ITER_TAG = XINCLUDE + "*" - -# For security reasons, the inclusion depth is limited to this read-only value by default. -DEFAULT_MAX_INCLUSION_DEPTH = 6 - - -## -# Fatal include error. - -class FatalIncludeError(etree.LxmlSyntaxError): - pass - - -class LimitedRecursiveIncludeError(FatalIncludeError): - pass - - -## -# ET compatible default loader. -# This loader reads an included resource from disk. -# -# @param href Resource reference. -# @param parse Parse mode. Either "xml" or "text". -# @param encoding Optional text encoding. -# @return The expanded resource. If the parse mode is "xml", this -# is an ElementTree instance. If the parse mode is "text", this -# is a Unicode string. If the loader fails, it can return None -# or raise an IOError exception. -# @throws IOError If the loader fails to load the resource. - -def default_loader(href, parse, encoding=None): - file = open(href, 'rb') - if parse == "xml": - data = etree.parse(file).getroot() - else: - data = file.read() - if not encoding: - encoding = 'utf-8' - data = data.decode(encoding) - file.close() - return data - - -## -# Default loader used by lxml.etree - handles custom resolvers properly -# - -def _lxml_default_loader(href, parse, encoding=None, parser=None): - if parse == "xml": - data = etree.parse(href, parser).getroot() - else: - if "://" in href: - f = urlopen(href) - else: - f = open(href, 'rb') - data = f.read() - f.close() - if not encoding: - encoding = 'utf-8' - data = data.decode(encoding) - return data - - -## -# Wrapper for ET compatibility - drops the parser - -def _wrap_et_loader(loader): - def load(href, parse, encoding=None, parser=None): - return loader(href, parse, encoding) - return load - - -## -# Expand XInclude directives. -# -# @param elem Root element. -# @param loader Optional resource loader. If omitted, it defaults -# to {@link default_loader}. If given, it should be a callable -# that implements the same interface as default_loader. -# @param base_url The base URL of the original file, to resolve -# relative include file references. -# @param max_depth The maximum number of recursive inclusions. -# Limited to reduce the risk of malicious content explosion. -# Pass None to disable the limitation. -# @throws LimitedRecursiveIncludeError If the {@link max_depth} was exceeded. -# @throws FatalIncludeError If the function fails to include a given -# resource, or if the tree contains malformed XInclude elements. -# @throws IOError If the function fails to load a given resource. -# @returns the node or its replacement if it was an XInclude node - -def include(elem, loader=None, base_url=None, - max_depth=DEFAULT_MAX_INCLUSION_DEPTH): - if max_depth is None: - max_depth = -1 - elif max_depth < 0: - raise ValueError("expected non-negative depth or None for 'max_depth', got %r" % max_depth) - - if base_url is None: - if hasattr(elem, 'getroot'): - tree = elem - elem = elem.getroot() - else: - tree = elem.getroottree() - if hasattr(tree, 'docinfo'): - base_url = tree.docinfo.URL - elif hasattr(elem, 'getroot'): - elem = elem.getroot() - _include(elem, loader, base_url, max_depth) - - -def _include(elem, loader=None, base_url=None, - max_depth=DEFAULT_MAX_INCLUSION_DEPTH, _parent_hrefs=None): - if loader is not None: - load_include = _wrap_et_loader(loader) - else: - load_include = _lxml_default_loader - - if _parent_hrefs is None: - _parent_hrefs = set() - - parser = elem.getroottree().parser - - include_elements = list( - elem.iter(XINCLUDE_ITER_TAG)) - - for e in include_elements: - if e.tag == XINCLUDE_INCLUDE: - # process xinclude directive - href = urljoin(base_url, e.get("href")) - parse = e.get("parse", "xml") - parent = e.getparent() - if parse == "xml": - if href in _parent_hrefs: - raise FatalIncludeError( - "recursive include of %r detected" % href - ) - if max_depth == 0: - raise LimitedRecursiveIncludeError( - "maximum xinclude depth reached when including file %s" % href) - node = load_include(href, parse, parser=parser) - if node is None: - raise FatalIncludeError( - "cannot load %r as %r" % (href, parse) - ) - node = _include(node, loader, href, max_depth - 1, {href} | _parent_hrefs) - if e.tail: - node.tail = (node.tail or "") + e.tail - if parent is None: - return node # replaced the root node! - parent.replace(e, node) - elif parse == "text": - text = load_include(href, parse, encoding=e.get("encoding")) - if text is None: - raise FatalIncludeError( - "cannot load %r as %r" % (href, parse) - ) - predecessor = e.getprevious() - if predecessor is not None: - predecessor.tail = (predecessor.tail or "") + text - elif parent is None: - return text # replaced the root node! - else: - parent.text = (parent.text or "") + text + (e.tail or "") - parent.remove(e) - else: - raise FatalIncludeError( - "unknown parse type in xi:include tag (%r)" % parse - ) - elif e.tag == XINCLUDE_FALLBACK: - parent = e.getparent() - if parent is not None and parent.tag != XINCLUDE_INCLUDE: - raise FatalIncludeError( - "xi:fallback tag must be child of xi:include (%r)" % e.tag - ) - else: - raise FatalIncludeError( - "Invalid element found in XInclude namespace (%r)" % e.tag - ) - return elem diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/__init__.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/__init__.py deleted file mode 100644 index 58c2133..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# this is a package - -__version__ = "6.0.2" - - -def get_include(): - """ - Returns a list of header include paths (for lxml itself, libxml2 - and libxslt) needed to compile C code against lxml if it was built - with statically linked libraries. - """ - import os - lxml_path = __path__[0] - include_path = os.path.join(lxml_path, 'includes') - includes = [include_path, lxml_path] - - for name in os.listdir(include_path): - path = os.path.join(include_path, name) - if os.path.isdir(path): - includes.append(path) - - return includes diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.cpython-39-darwin.so b/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.cpython-39-darwin.so deleted file mode 100755 index 5343c03..0000000 Binary files a/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.cpython-39-darwin.so and /dev/null differ diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.py deleted file mode 100644 index 760a1e0..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/_elementpath.py +++ /dev/null @@ -1,343 +0,0 @@ -# cython: language_level=3 - -# -# ElementTree -# $Id: ElementPath.py 3375 2008-02-13 08:05:08Z fredrik $ -# -# limited xpath support for element trees -# -# history: -# 2003-05-23 fl created -# 2003-05-28 fl added support for // etc -# 2003-08-27 fl fixed parsing of periods in element names -# 2007-09-10 fl new selection engine -# 2007-09-12 fl fixed parent selector -# 2007-09-13 fl added iterfind; changed findall to return a list -# 2007-11-30 fl added namespaces support -# 2009-10-30 fl added child element value filter -# -# Copyright (c) 2003-2009 by Fredrik Lundh. All rights reserved. -# -# fredrik@pythonware.com -# http://www.pythonware.com -# -# -------------------------------------------------------------------- -# The ElementTree toolkit is -# -# Copyright (c) 1999-2009 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -## -# Implementation module for XPath support. There's usually no reason -# to import this module directly; the ElementTree does this for -# you, if needed. -## - - -import re - -xpath_tokenizer_re = re.compile( - "(" - "'[^']*'|\"[^\"]*\"|" - "::|" - "//?|" - r"\.\.|" - r"\(\)|" - r"[/.*:\[\]\(\)@=])|" - r"((?:\{[^}]+\})?[^/\[\]\(\)@=\s]+)|" - r"\s+" - ) - -def xpath_tokenizer(pattern, namespaces=None, with_prefixes=True): - # ElementTree uses '', lxml used None originally. - default_namespace = (namespaces.get(None) or namespaces.get('')) if namespaces else None - parsing_attribute = False - for token in xpath_tokenizer_re.findall(pattern): - ttype, tag = token - if tag and tag[0] != "{": - if ":" in tag and with_prefixes: - prefix, uri = tag.split(":", 1) - try: - if not namespaces: - raise KeyError - yield ttype, "{%s}%s" % (namespaces[prefix], uri) - except KeyError: - raise SyntaxError("prefix %r not found in prefix map" % prefix) - elif tag.isdecimal(): - yield token # index - elif default_namespace and not parsing_attribute: - yield ttype, "{%s}%s" % (default_namespace, tag) - else: - yield token - parsing_attribute = False - else: - yield token - parsing_attribute = ttype == '@' - - -def prepare_child(next, token): - tag = token[1] - def select(result): - for elem in result: - yield from elem.iterchildren(tag) - return select - -def prepare_star(next, token): - def select(result): - for elem in result: - yield from elem.iterchildren('*') - return select - -def prepare_self(next, token): - def select(result): - return result - return select - -def prepare_descendant(next, token): - token = next() - if token[0] == "*": - tag = "*" - elif not token[0]: - tag = token[1] - else: - raise SyntaxError("invalid descendant") - def select(result): - for elem in result: - yield from elem.iterdescendants(tag) - return select - -def prepare_parent(next, token): - def select(result): - for elem in result: - parent = elem.getparent() - if parent is not None: - yield parent - return select - -def prepare_predicate(next, token): - # FIXME: replace with real parser!!! refs: - # http://effbot.org/zone/simple-iterator-parser.htm - # http://javascript.crockford.com/tdop/tdop.html - signature = '' - predicate = [] - while 1: - token = next() - if token[0] == "]": - break - if token == ('', ''): - # ignore whitespace - continue - if token[0] and token[0][:1] in "'\"": - token = "'", token[0][1:-1] - signature += token[0] or "-" - predicate.append(token[1]) - - # use signature to determine predicate type - if signature == "@-": - # [@attribute] predicate - key = predicate[1] - def select(result): - for elem in result: - if elem.get(key) is not None: - yield elem - return select - if signature == "@-='": - # [@attribute='value'] - key = predicate[1] - value = predicate[-1] - def select(result): - for elem in result: - if elem.get(key) == value: - yield elem - return select - if signature == "-" and not re.match(r"-?\d+$", predicate[0]): - # [tag] - tag = predicate[0] - def select(result): - for elem in result: - for _ in elem.iterchildren(tag): - yield elem - break - return select - if signature == ".='" or (signature == "-='" and not re.match(r"-?\d+$", predicate[0])): - # [.='value'] or [tag='value'] - tag = predicate[0] - value = predicate[-1] - if tag: - def select(result): - for elem in result: - for e in elem.iterchildren(tag): - if "".join(e.itertext()) == value: - yield elem - break - else: - def select(result): - for elem in result: - if "".join(elem.itertext()) == value: - yield elem - return select - if signature == "-" or signature == "-()" or signature == "-()-": - # [index] or [last()] or [last()-index] - if signature == "-": - # [index] - index = int(predicate[0]) - 1 - if index < 0: - if index == -1: - raise SyntaxError( - "indices in path predicates are 1-based, not 0-based") - else: - raise SyntaxError("path index >= 1 expected") - else: - if predicate[0] != "last": - raise SyntaxError("unsupported function") - if signature == "-()-": - try: - index = int(predicate[2]) - 1 - except ValueError: - raise SyntaxError("unsupported expression") - else: - index = -1 - def select(result): - for elem in result: - parent = elem.getparent() - if parent is None: - continue - try: - # FIXME: what if the selector is "*" ? - elems = list(parent.iterchildren(elem.tag)) - if elems[index] is elem: - yield elem - except IndexError: - pass - return select - raise SyntaxError("invalid predicate") - -ops = { - "": prepare_child, - "*": prepare_star, - ".": prepare_self, - "..": prepare_parent, - "//": prepare_descendant, - "[": prepare_predicate, -} - - -# -------------------------------------------------------------------- - -_cache = {} - - -def _build_path_iterator(path, namespaces, with_prefixes=True): - """compile selector pattern""" - if path[-1:] == "/": - path += "*" # implicit all (FIXME: keep this?) - - cache_key = (path,) - if namespaces: - # lxml originally used None for the default namespace but ElementTree uses the - # more convenient (all-strings-dict) empty string, so we support both here, - # preferring the more convenient '', as long as they aren't ambiguous. - if None in namespaces: - if '' in namespaces and namespaces[None] != namespaces['']: - raise ValueError("Ambiguous default namespace provided: %r versus %r" % ( - namespaces[None], namespaces[''])) - cache_key += (namespaces[None],) + tuple(sorted( - item for item in namespaces.items() if item[0] is not None)) - else: - cache_key += tuple(sorted(namespaces.items())) - - try: - return _cache[cache_key] - except KeyError: - pass - if len(_cache) > 100: - _cache.clear() - - if path[:1] == "/": - raise SyntaxError("cannot use absolute path on element") - stream = iter(xpath_tokenizer(path, namespaces, with_prefixes=with_prefixes)) - try: - _next = stream.next - except AttributeError: - # Python 3 - _next = stream.__next__ - try: - token = _next() - except StopIteration: - raise SyntaxError("empty path expression") - selector = [] - while 1: - try: - selector.append(ops[token[0]](_next, token)) - except StopIteration: - raise SyntaxError("invalid path") - try: - token = _next() - if token[0] == "/": - token = _next() - except StopIteration: - break - _cache[cache_key] = selector - return selector - - -## -# Iterate over the matching nodes - -def iterfind(elem, path, namespaces=None, with_prefixes=True): - selector = _build_path_iterator(path, namespaces, with_prefixes=with_prefixes) - result = iter((elem,)) - for select in selector: - result = select(result) - return result - - -## -# Find first matching object. - -def find(elem, path, namespaces=None, with_prefixes=True): - it = iterfind(elem, path, namespaces, with_prefixes=with_prefixes) - try: - return next(it) - except StopIteration: - return None - - -## -# Find all matching objects. - -def findall(elem, path, namespaces=None, with_prefixes=True): - return list(iterfind(elem, path, namespaces)) - - -## -# Find text for first matching object. - -def findtext(elem, path, default=None, namespaces=None, with_prefixes=True): - el = find(elem, path, namespaces, with_prefixes=with_prefixes) - if el is None: - return default - else: - return el.text or '' diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/apihelpers.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/apihelpers.pxi deleted file mode 100644 index f683e70..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/apihelpers.pxi +++ /dev/null @@ -1,1801 +0,0 @@ -# Private/public helper functions for API functions - -from lxml.includes cimport uri - - -cdef void displayNode(xmlNode* c_node, indent) noexcept: - # to help with debugging - cdef xmlNode* c_child - try: - print(indent * ' ', c_node) - c_child = c_node.children - while c_child is not NULL: - displayNode(c_child, indent + 1) - c_child = c_child.next - finally: - return # swallow any exceptions - -cdef inline bint _isHtmlDocument(_Element element) except -1: - cdef xmlNode* c_node = element._c_node - return ( - c_node is not NULL and c_node.doc is not NULL and - c_node.doc.properties & tree.XML_DOC_HTML != 0 - ) - -cdef inline int _assertValidNode(_Element element) except -1: - assert element._c_node is not NULL, "invalid Element proxy at %s" % id(element) - -cdef inline int _assertValidDoc(_Document doc) except -1: - assert doc._c_doc is not NULL, "invalid Document proxy at %s" % id(doc) - -cdef _Document _documentOrRaise(object input): - """Call this to get the document of a _Document, _ElementTree or _Element - object, or to raise an exception if it can't be determined. - - Should be used in all API functions for consistency. - """ - cdef _Document doc - if isinstance(input, _ElementTree): - if (<_ElementTree>input)._context_node is not None: - doc = (<_ElementTree>input)._context_node._doc - else: - doc = None - elif isinstance(input, _Element): - doc = (<_Element>input)._doc - elif isinstance(input, _Document): - doc = <_Document>input - else: - raise TypeError, f"Invalid input object: {python._fqtypename(input).decode('utf8')}" - if doc is None: - raise ValueError, f"Input object has no document: {python._fqtypename(input).decode('utf8')}" - _assertValidDoc(doc) - return doc - -cdef _Element _rootNodeOrRaise(object input): - """Call this to get the root node of a _Document, _ElementTree or - _Element object, or to raise an exception if it can't be determined. - - Should be used in all API functions for consistency. - """ - cdef _Element node - if isinstance(input, _ElementTree): - node = (<_ElementTree>input)._context_node - elif isinstance(input, _Element): - node = <_Element>input - elif isinstance(input, _Document): - node = (<_Document>input).getroot() - else: - raise TypeError, f"Invalid input object: {python._fqtypename(input).decode('utf8')}" - if (node is None or not node._c_node or - node._c_node.type != tree.XML_ELEMENT_NODE): - raise ValueError, f"Input object is not an XML element: {python._fqtypename(input).decode('utf8')}" - _assertValidNode(node) - return node - -cdef bint _isAncestorOrSame(xmlNode* c_ancestor, xmlNode* c_node) noexcept: - while c_node: - if c_node is c_ancestor: - return True - c_node = c_node.parent - return False - -cdef _Element _makeElement(tag, xmlDoc* c_doc, _Document doc, - _BaseParser parser, text, tail, attrib, nsmap, - dict extra_attrs): - """Create a new element and initialize text content, namespaces and - attributes. - - This helper function will reuse as much of the existing document as - possible: - - If 'parser' is None, the parser will be inherited from 'doc' or the - default parser will be used. - - If 'doc' is None, 'c_doc' is used to create a new _Document and the new - element is made its root node. - - If 'c_doc' is also NULL, a new xmlDoc will be created. - """ - cdef xmlNode* c_node - if doc is not None: - c_doc = doc._c_doc - ns_utf, name_utf = _getNsTag(tag) - if parser is not None and parser._for_html: - _htmlTagValidOrRaise(name_utf) - if c_doc is NULL: - c_doc = _newHTMLDoc() - else: - _tagValidOrRaise(name_utf) - if c_doc is NULL: - c_doc = _newXMLDoc() - c_node = _createElement(c_doc, name_utf) - if c_node is NULL: - if doc is None and c_doc is not NULL: - tree.xmlFreeDoc(c_doc) - raise MemoryError() - try: - if doc is None: - tree.xmlDocSetRootElement(c_doc, c_node) - doc = _documentFactory(c_doc, parser) - if text is not None: - _setNodeText(c_node, text) - if tail is not None: - _setTailText(c_node, tail) - # add namespaces to node if necessary - _setNodeNamespaces(c_node, doc, ns_utf, nsmap) - _initNodeAttributes(c_node, doc, attrib, extra_attrs) - return _elementFactory(doc, c_node) - except: - # free allocated c_node/c_doc unless Python does it for us - if c_node.doc is not c_doc: - # node not yet in document => will not be freed by document - if tail is not None: - _removeText(c_node.next) # tail - tree.xmlFreeNode(c_node) - if doc is None: - # c_doc will not be freed by doc - tree.xmlFreeDoc(c_doc) - raise - -cdef int _initNewElement(_Element element, bint is_html, name_utf, ns_utf, - _BaseParser parser, attrib, nsmap, dict extra_attrs) except -1: - """Initialise a new Element object. - - This is used when users instantiate a Python Element subclass - directly, without it being mapped to an existing XML node. - """ - cdef xmlDoc* c_doc - cdef xmlNode* c_node - cdef _Document doc - if is_html: - _htmlTagValidOrRaise(name_utf) - c_doc = _newHTMLDoc() - else: - _tagValidOrRaise(name_utf) - c_doc = _newXMLDoc() - c_node = _createElement(c_doc, name_utf) - if c_node is NULL: - if c_doc is not NULL: - tree.xmlFreeDoc(c_doc) - raise MemoryError() - tree.xmlDocSetRootElement(c_doc, c_node) - doc = _documentFactory(c_doc, parser) - # add namespaces to node if necessary - _setNodeNamespaces(c_node, doc, ns_utf, nsmap) - _initNodeAttributes(c_node, doc, attrib, extra_attrs) - _registerProxy(element, doc, c_node) - element._init() - return 0 - -cdef _Element _makeSubElement(_Element parent, tag, text, tail, - attrib, nsmap, dict extra_attrs): - """Create a new child element and initialize text content, namespaces and - attributes. - """ - cdef xmlNode* c_node - cdef xmlDoc* c_doc - if parent is None or parent._doc is None: - return None - _assertValidNode(parent) - ns_utf, name_utf = _getNsTag(tag) - c_doc = parent._doc._c_doc - - if parent._doc._parser is not None and parent._doc._parser._for_html: - _htmlTagValidOrRaise(name_utf) - else: - _tagValidOrRaise(name_utf) - - c_node = _createElement(c_doc, name_utf) - if c_node is NULL: - raise MemoryError() - tree.xmlAddChild(parent._c_node, c_node) - - try: - if text is not None: - _setNodeText(c_node, text) - if tail is not None: - _setTailText(c_node, tail) - - # add namespaces to node if necessary - _setNodeNamespaces(c_node, parent._doc, ns_utf, nsmap) - _initNodeAttributes(c_node, parent._doc, attrib, extra_attrs) - return _elementFactory(parent._doc, c_node) - except: - # make sure we clean up in case of an error - _removeNode(parent._doc, c_node) - raise - - -cdef int _setNodeNamespaces(xmlNode* c_node, _Document doc, - object node_ns_utf, object nsmap) except -1: - """Lookup current namespace prefixes, then set namespace structure for - node (if 'node_ns_utf' was provided) and register new ns-prefix mappings. - - 'node_ns_utf' should only be passed for a newly created node. - """ - cdef xmlNs* c_ns - cdef list nsdefs - - if nsmap: - for prefix, href in _iter_nsmap(nsmap): - href_utf = _utf8(href) - _uriValidOrRaise(href_utf) - c_href = _xcstr(href_utf) - if prefix is not None: - prefix_utf = _utf8(prefix) - _prefixValidOrRaise(prefix_utf) - c_prefix = _xcstr(prefix_utf) - else: - c_prefix = NULL - # add namespace with prefix if it is not already known - c_ns = tree.xmlSearchNs(doc._c_doc, c_node, c_prefix) - if c_ns is NULL or \ - c_ns.href is NULL or \ - tree.xmlStrcmp(c_ns.href, c_href) != 0: - c_ns = tree.xmlNewNs(c_node, c_href, c_prefix) - if href_utf == node_ns_utf: - tree.xmlSetNs(c_node, c_ns) - node_ns_utf = None - - if node_ns_utf is not None: - _uriValidOrRaise(node_ns_utf) - doc._setNodeNs(c_node, _xcstr(node_ns_utf)) - return 0 - - -cdef dict _build_nsmap(xmlNode* c_node): - """ - Namespace prefix->URI mapping known in the context of this Element. - This includes all namespace declarations of the parents. - """ - cdef xmlNs* c_ns - nsmap = {} - while c_node is not NULL and c_node.type == tree.XML_ELEMENT_NODE: - c_ns = c_node.nsDef - while c_ns is not NULL: - if c_ns.prefix or c_ns.href: - prefix = funicodeOrNone(c_ns.prefix) - if prefix not in nsmap: - nsmap[prefix] = funicodeOrNone(c_ns.href) - c_ns = c_ns.next - c_node = c_node.parent - return nsmap - - -cdef _iter_nsmap(nsmap): - """ - Create a reproducibly ordered iterable from an nsmap mapping. - Tries to preserve an existing order and sorts if it assumes no order. - - The difference to _iter_attrib() is that None doesn't sort with strings - in Py3.x. - """ - if isinstance(nsmap, dict): - # dicts are insertion-ordered in Py3.6+ => keep the user provided order. - return nsmap.items() - if len(nsmap) <= 1: - return nsmap.items() - # nsmap will usually be a plain unordered dict => avoid type checking overhead - if type(nsmap) is not dict and isinstance(nsmap, OrderedDict): - return nsmap.items() # keep existing order - if None not in nsmap: - return sorted(nsmap.items()) - - # Move the default namespace to the end. This makes sure libxml2 - # prefers a prefix if the ns is defined redundantly on the same - # element. That way, users can work around a problem themselves - # where default namespace attributes on non-default namespaced - # elements serialise without prefix (i.e. into the non-default - # namespace). - default_ns = nsmap[None] - nsdefs = [(k, v) for k, v in nsmap.items() if k is not None] - nsdefs.sort() - nsdefs.append((None, default_ns)) - return nsdefs - - -cdef _iter_attrib(attrib): - """ - Create a reproducibly ordered iterable from an attrib mapping. - Tries to preserve an existing order and sorts if it assumes no order. - """ - # dicts are insertion-ordered in Py3.6+ => keep the user provided order. - if isinstance(attrib, (dict, _Attrib, OrderedDict)): - return attrib.items() - # assume it's an unordered mapping of some kind - return sorted(attrib.items()) - - -cdef _initNodeAttributes(xmlNode* c_node, _Document doc, attrib, dict extra): - """Initialise the attributes of an element node. - """ - cdef bint is_html - cdef xmlNs* c_ns - if attrib is not None and not hasattr(attrib, 'items'): - raise TypeError, f"Invalid attribute dictionary: {python._fqtypename(attrib).decode('utf8')}" - if not attrib and not extra: - return # nothing to do - is_html = doc._parser._for_html - seen = set() - if extra: - for name, value in extra.items(): - _addAttributeToNode(c_node, doc, is_html, name, value, seen) - if attrib: - for name, value in _iter_attrib(attrib): - _addAttributeToNode(c_node, doc, is_html, name, value, seen) - - -cdef int _addAttributeToNode(xmlNode* c_node, _Document doc, bint is_html, - name, value, set seen_tags) except -1: - ns_utf, name_utf = tag = _getNsTag(name) - if tag in seen_tags: - return 0 - seen_tags.add(tag) - if not is_html: - _attributeValidOrRaise(name_utf) - value_utf = _utf8(value) - if ns_utf is None: - tree.xmlNewProp(c_node, _xcstr(name_utf), _xcstr(value_utf)) - else: - _uriValidOrRaise(ns_utf) - c_ns = doc._findOrBuildNodeNs(c_node, _xcstr(ns_utf), NULL, 1) - tree.xmlNewNsProp(c_node, c_ns, - _xcstr(name_utf), _xcstr(value_utf)) - return 0 - - -ctypedef struct _ns_node_ref: - xmlNs* ns - xmlNode* node - - -cdef int _collectNsDefs(xmlNode* c_element, _ns_node_ref **_c_ns_list, - size_t *_c_ns_list_len, size_t *_c_ns_list_size) except -1: - c_ns_list = _c_ns_list[0] - cdef size_t c_ns_list_len = _c_ns_list_len[0] - cdef size_t c_ns_list_size = _c_ns_list_size[0] - - c_nsdef = c_element.nsDef - while c_nsdef is not NULL: - if c_ns_list_len >= c_ns_list_size: - if c_ns_list is NULL: - c_ns_list_size = 20 - else: - c_ns_list_size *= 2 - c_nsref_ptr = <_ns_node_ref*> python.lxml_realloc( - c_ns_list, c_ns_list_size, sizeof(_ns_node_ref)) - if c_nsref_ptr is NULL: - if c_ns_list is not NULL: - python.lxml_free(c_ns_list) - _c_ns_list[0] = NULL - raise MemoryError() - c_ns_list = c_nsref_ptr - - c_ns_list[c_ns_list_len] = _ns_node_ref(c_nsdef, c_element) - c_ns_list_len += 1 - c_nsdef = c_nsdef.next - - _c_ns_list_size[0] = c_ns_list_size - _c_ns_list_len[0] = c_ns_list_len - _c_ns_list[0] = c_ns_list - - -cdef int _removeUnusedNamespaceDeclarations(xmlNode* c_element, set prefixes_to_keep) except -1: - """Remove any namespace declarations from a subtree that are not used by - any of its elements (or attributes). - - If a 'prefixes_to_keep' is provided, it must be a set of prefixes. - Any corresponding namespace mappings will not be removed as part of the cleanup. - """ - cdef xmlNode* c_node - cdef _ns_node_ref* c_ns_list = NULL - cdef size_t c_ns_list_size = 0 - cdef size_t c_ns_list_len = 0 - cdef size_t i - - if c_element.parent and c_element.parent.type == tree.XML_DOCUMENT_NODE: - # include declarations on the document node - _collectNsDefs(c_element.parent, &c_ns_list, &c_ns_list_len, &c_ns_list_size) - - tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_element, c_element, 1) - # collect all new namespace declarations into the ns list - if c_element.nsDef: - _collectNsDefs(c_element, &c_ns_list, &c_ns_list_len, &c_ns_list_size) - - # remove all namespace declarations from the list that are referenced - if c_ns_list_len and c_element.type == tree.XML_ELEMENT_NODE: - c_node = c_element - while c_node and c_ns_list_len: - if c_node.ns: - for i in range(c_ns_list_len): - if c_node.ns is c_ns_list[i].ns: - c_ns_list_len -= 1 - c_ns_list[i] = c_ns_list[c_ns_list_len] - #c_ns_list[c_ns_list_len] = _ns_node_ref(NULL, NULL) - break - if c_node is c_element: - # continue with attributes - c_node = c_element.properties - else: - c_node = c_node.next - tree.END_FOR_EACH_ELEMENT_FROM(c_element) - - if c_ns_list is NULL: - return 0 - - # free all namespace declarations that remained in the list, - # except for those we should keep explicitly - cdef xmlNs* c_nsdef - for i in range(c_ns_list_len): - if prefixes_to_keep is not None: - if c_ns_list[i].ns.prefix and c_ns_list[i].ns.prefix in prefixes_to_keep: - continue - c_node = c_ns_list[i].node - c_nsdef = c_node.nsDef - if c_nsdef is c_ns_list[i].ns: - c_node.nsDef = c_node.nsDef.next - else: - while c_nsdef.next is not c_ns_list[i].ns: - c_nsdef = c_nsdef.next - c_nsdef.next = c_nsdef.next.next - tree.xmlFreeNs(c_ns_list[i].ns) - - if c_ns_list is not NULL: - python.lxml_free(c_ns_list) - return 0 - -cdef xmlNs* _searchNsByHref(xmlNode* c_node, const_xmlChar* c_href, bint is_attribute) noexcept: - """Search a namespace declaration that covers a node (element or - attribute). - - For attributes, try to find a prefixed namespace declaration - instead of the default namespaces. This helps in supporting - round-trips for attributes on elements with a different namespace. - """ - cdef xmlNs* c_ns - cdef xmlNs* c_default_ns = NULL - cdef xmlNode* c_element - if c_href is NULL or c_node is NULL or c_node.type == tree.XML_ENTITY_REF_NODE: - return NULL - if tree.xmlStrcmp(c_href, tree.XML_XML_NAMESPACE) == 0: - # no special cases here, let libxml2 handle this - return tree.xmlSearchNsByHref(c_node.doc, c_node, c_href) - if c_node.type == tree.XML_ATTRIBUTE_NODE: - is_attribute = 1 - while c_node is not NULL and c_node.type != tree.XML_ELEMENT_NODE: - c_node = c_node.parent - c_element = c_node - while c_node is not NULL: - if c_node.type == tree.XML_ELEMENT_NODE: - c_ns = c_node.nsDef - while c_ns is not NULL: - if c_ns.href is not NULL and tree.xmlStrcmp(c_href, c_ns.href) == 0: - if c_ns.prefix is NULL and is_attribute: - # for attributes, continue searching a named - # prefix, but keep the first default namespace - # declaration that we found - if c_default_ns is NULL: - c_default_ns = c_ns - elif tree.xmlSearchNs( - c_element.doc, c_element, c_ns.prefix) is c_ns: - # start node is in namespace scope => found! - return c_ns - c_ns = c_ns.next - if c_node is not c_element and c_node.ns is not NULL: - # optimise: the node may have the namespace itself - c_ns = c_node.ns - if c_ns.href is not NULL and tree.xmlStrcmp(c_href, c_ns.href) == 0: - if c_ns.prefix is NULL and is_attribute: - # for attributes, continue searching a named - # prefix, but keep the first default namespace - # declaration that we found - if c_default_ns is NULL: - c_default_ns = c_ns - elif tree.xmlSearchNs( - c_element.doc, c_element, c_ns.prefix) is c_ns: - # start node is in namespace scope => found! - return c_ns - c_node = c_node.parent - # nothing found => use a matching default namespace or fail - if c_default_ns is not NULL: - if tree.xmlSearchNs(c_element.doc, c_element, NULL) is c_default_ns: - return c_default_ns - return NULL - -cdef int _replaceNodeByChildren(_Document doc, xmlNode* c_node) except -1: - # NOTE: this does not deallocate the node, just unlink it! - cdef xmlNode* c_parent - cdef xmlNode* c_child - if c_node.children is NULL: - tree.xmlUnlinkNode(c_node) - return 0 - - c_parent = c_node.parent - # fix parent links of children - c_child = c_node.children - while c_child is not NULL: - c_child.parent = c_parent - c_child = c_child.next - - # fix namespace references of children if their parent's namespace - # declarations get lost - if c_node.nsDef is not NULL: - c_child = c_node.children - while c_child is not NULL: - moveNodeToDocument(doc, doc._c_doc, c_child) - c_child = c_child.next - - # fix sibling links to/from child slice - if c_node.prev is NULL: - c_parent.children = c_node.children - else: - c_node.prev.next = c_node.children - c_node.children.prev = c_node.prev - if c_node.next is NULL: - c_parent.last = c_node.last - else: - c_node.next.prev = c_node.last - c_node.last.next = c_node.next - - # unlink c_node - c_node.children = c_node.last = NULL - c_node.parent = c_node.next = c_node.prev = NULL - return 0 - -cdef unicode _attributeValue(xmlNode* c_element, xmlAttr* c_attrib_node): - c_href = _getNs(c_attrib_node) - value = tree.xmlGetNsProp(c_element, c_attrib_node.name, c_href) - try: - result = funicode(value) - finally: - tree.xmlFree(value) - return result - -cdef unicode _attributeValueFromNsName(xmlNode* c_element, - const_xmlChar* c_href, const_xmlChar* c_name): - c_result = tree.xmlGetNsProp(c_element, c_name, c_href) - if c_result is NULL: - return None - try: - result = funicode(c_result) - finally: - tree.xmlFree(c_result) - return result - -cdef object _getNodeAttributeValue(xmlNode* c_node, key, default): - ns, tag = _getNsTag(key) - c_href = NULL if ns is None else _xcstr(ns) - c_result = tree.xmlGetNsProp(c_node, _xcstr(tag), c_href) - if c_result is NULL: - # XXX free namespace that is not in use..? - return default - try: - result = funicode(c_result) - finally: - tree.xmlFree(c_result) - return result - -cdef inline object _getAttributeValue(_Element element, key, default): - return _getNodeAttributeValue(element._c_node, key, default) - -cdef int _setAttributeValue(_Element element, key, value) except -1: - cdef const_xmlChar* c_value - cdef xmlNs* c_ns - ns, tag = _getNsTag(key) - is_html = element._doc._parser._for_html - if not is_html: - _attributeValidOrRaise(tag) - c_tag = _xcstr(tag) - if value is None and is_html: - c_value = NULL - else: - if isinstance(value, QName): - value = _resolveQNameText(element, value) - else: - value = _utf8(value) - c_value = _xcstr(value) - if ns is None: - c_ns = NULL - else: - c_ns = element._doc._findOrBuildNodeNs(element._c_node, _xcstr(ns), NULL, 1) - tree.xmlSetNsProp(element._c_node, c_ns, c_tag, c_value) - return 0 - -cdef int _delAttribute(_Element element, key) except -1: - ns, tag = _getNsTag(key) - c_href = NULL if ns is None else _xcstr(ns) - if _delAttributeFromNsName(element._c_node, c_href, _xcstr(tag)): - raise KeyError, key - return 0 - -cdef int _delAttributeFromNsName(xmlNode* c_node, const_xmlChar* c_href, const_xmlChar* c_name) noexcept: - c_attr = tree.xmlHasNsProp(c_node, c_name, c_href) - if c_attr is NULL: - # XXX free namespace that is not in use..? - return -1 - tree.xmlRemoveProp(c_attr) - return 0 - -cdef list _collectAttributes(xmlNode* c_node, int collecttype): - """Collect all attributes of a node in a list. Depending on collecttype, - it collects either the name (1), the value (2) or the name-value tuples. - """ - cdef Py_ssize_t count - c_attr = c_node.properties - count = 0 - while c_attr is not NULL: - if c_attr.type == tree.XML_ATTRIBUTE_NODE: - count += 1 - c_attr = c_attr.next - - if not count: - return [] - - attributes = [None] * count - c_attr = c_node.properties - count = 0 - while c_attr is not NULL: - if c_attr.type == tree.XML_ATTRIBUTE_NODE: - if collecttype == 1: - item = _namespacedName(c_attr) - elif collecttype == 2: - item = _attributeValue(c_node, c_attr) - else: - item = (_namespacedName(c_attr), - _attributeValue(c_node, c_attr)) - attributes[count] = item - count += 1 - c_attr = c_attr.next - return attributes - -cdef object __RE_XML_ENCODING = re.compile( - r'^(<\?xml[^>]+)\s+encoding\s*=\s*["\'][^"\']*["\'](\s*\?>|)', re.U) - -cdef object __REPLACE_XML_ENCODING = __RE_XML_ENCODING.sub -cdef object __HAS_XML_ENCODING = __RE_XML_ENCODING.match - -cdef object _stripEncodingDeclaration(object xml_string): - # this is a hack to remove the XML encoding declaration from unicode - return __REPLACE_XML_ENCODING(r'\g<1>\g<2>', xml_string) - -cdef bint _hasEncodingDeclaration(object xml_string) except -1: - # check if a (unicode) string has an XML encoding declaration - return __HAS_XML_ENCODING(xml_string) is not None - -cdef inline bint _hasText(xmlNode* c_node) noexcept: - return c_node is not NULL and _textNodeOrSkip(c_node.children) is not NULL - -cdef inline bint _hasTail(xmlNode* c_node) noexcept: - return c_node is not NULL and _textNodeOrSkip(c_node.next) is not NULL - -cdef inline bint _hasNonWhitespaceTail(xmlNode* c_node) except -1: - return _hasNonWhitespaceText(c_node, tail=True) - -cdef bint _hasNonWhitespaceText(xmlNode* c_node, bint tail=False) except -1: - c_text_node = c_node and _textNodeOrSkip(c_node.next if tail else c_node.children) - if c_text_node is NULL: - return False - while c_text_node is not NULL: - if c_text_node.content[0] != c'\0' and not _collectText(c_text_node).isspace(): - return True - c_text_node = _textNodeOrSkip(c_text_node.next) - return False - -cdef unicode _collectText(xmlNode* c_node): - """Collect all text nodes and return them as a unicode string. - - Start collecting at c_node. - - If there was no text to collect, return None - """ - cdef Py_ssize_t scount - cdef xmlChar* c_text - cdef xmlNode* c_node_cur - # check for multiple text nodes - scount = 0 - c_text = NULL - c_node_cur = c_node = _textNodeOrSkip(c_node) - while c_node_cur is not NULL: - if c_node_cur.content[0] != c'\0': - c_text = c_node_cur.content - scount += 1 - c_node_cur = _textNodeOrSkip(c_node_cur.next) - - # handle two most common cases first - if c_text is NULL: - return '' if scount > 0 else None - if scount == 1: - return funicode(c_text) - - # the rest is not performance critical anymore - result = b'' - while c_node is not NULL: - result += c_node.content - c_node = _textNodeOrSkip(c_node.next) - return funicode(result) - -cdef void _removeText(xmlNode* c_node) noexcept: - """Remove all text nodes. - - Start removing at c_node. - """ - cdef xmlNode* c_next - c_node = _textNodeOrSkip(c_node) - while c_node is not NULL: - c_next = _textNodeOrSkip(c_node.next) - tree.xmlUnlinkNode(c_node) - tree.xmlFreeNode(c_node) - c_node = c_next - -cdef xmlNode* _createTextNode(xmlDoc* doc, value) except NULL: - cdef xmlNode* c_text_node - if isinstance(value, CDATA): - c_text_node = tree.xmlNewCDataBlock( - doc, _xcstr((value)._utf8_data), - python.PyBytes_GET_SIZE((value)._utf8_data)) - else: - text = _utf8(value) - c_text_node = tree.xmlNewDocText(doc, _xcstr(text)) - if not c_text_node: - raise MemoryError() - return c_text_node - -cdef int _setNodeText(xmlNode* c_node, value) except -1: - # remove all text nodes at the start first - _removeText(c_node.children) - if value is None: - return 0 - # now add new text node with value at start - c_text_node = _createTextNode(c_node.doc, value) - if c_node.children is NULL: - tree.xmlAddChild(c_node, c_text_node) - else: - tree.xmlAddPrevSibling(c_node.children, c_text_node) - return 0 - -cdef int _setTailText(xmlNode* c_node, value) except -1: - # remove all text nodes at the start first - _removeText(c_node.next) - if value is None: - return 0 - # now append new text node with value - c_text_node = _createTextNode(c_node.doc, value) - tree.xmlAddNextSibling(c_node, c_text_node) - return 0 - -cdef bytes _resolveQNameText(_Element element, value): - cdef xmlNs* c_ns - ns, tag = _getNsTag(value) - if ns is None: - return tag - else: - c_ns = element._doc._findOrBuildNodeNs( - element._c_node, _xcstr(ns), NULL, 0) - return python.PyBytes_FromFormat('%s:%s', c_ns.prefix, _cstr(tag)) - -cdef inline bint _hasChild(xmlNode* c_node) noexcept: - return c_node is not NULL and _findChildForwards(c_node, 0) is not NULL - -cdef inline Py_ssize_t _countElements(xmlNode* c_node) noexcept: - "Counts the elements within the following siblings and the node itself." - cdef Py_ssize_t count - count = 0 - while c_node is not NULL: - if _isElement(c_node): - count += 1 - c_node = c_node.next - return count - -cdef int _findChildSlice( - slice sliceobject, xmlNode* c_parent, - xmlNode** c_start_node, Py_ssize_t* c_step, Py_ssize_t* c_length) except -1: - """Resolve a children slice. - - Returns the start node, step size and the slice length in the - pointer arguments. - """ - cdef Py_ssize_t start = 0, stop = 0, childcount - childcount = _countElements(c_parent.children) - if childcount == 0: - c_start_node[0] = NULL - c_length[0] = 0 - if sliceobject.step is None: - c_step[0] = 1 - else: - python._PyEval_SliceIndex(sliceobject.step, c_step) - return 0 - python.PySlice_GetIndicesEx( - sliceobject, childcount, &start, &stop, c_step, c_length) - if start > childcount // 2: - c_start_node[0] = _findChildBackwards(c_parent, childcount - start - 1) - else: - c_start_node[0] = _findChild(c_parent, start) - return 0 - -cdef bint _isFullSlice(slice sliceobject) except -1: - """Conservative guess if this slice is a full slice as in ``s[:]``. - """ - cdef Py_ssize_t step = 0 - if sliceobject is None: - return 0 - if sliceobject.start is None and \ - sliceobject.stop is None: - if sliceobject.step is None: - return 1 - python._PyEval_SliceIndex(sliceobject.step, &step) - if step == 1: - return 1 - return 0 - return 0 - -cdef _collectChildren(_Element element): - cdef xmlNode* c_node - cdef list result = [] - c_node = element._c_node.children - if c_node is not NULL: - if not _isElement(c_node): - c_node = _nextElement(c_node) - while c_node is not NULL: - result.append(_elementFactory(element._doc, c_node)) - c_node = _nextElement(c_node) - return result - -cdef inline xmlNode* _findChild(xmlNode* c_node, Py_ssize_t index) noexcept: - if index < 0: - return _findChildBackwards(c_node, -index - 1) - else: - return _findChildForwards(c_node, index) - -cdef inline xmlNode* _findChildForwards(xmlNode* c_node, Py_ssize_t index) noexcept: - """Return child element of c_node with index, or return NULL if not found. - """ - cdef xmlNode* c_child - cdef Py_ssize_t c - c_child = c_node.children - c = 0 - while c_child is not NULL: - if _isElement(c_child): - if c == index: - return c_child - c += 1 - c_child = c_child.next - return NULL - -cdef inline xmlNode* _findChildBackwards(xmlNode* c_node, Py_ssize_t index) noexcept: - """Return child element of c_node with index, or return NULL if not found. - Search from the end. - """ - cdef xmlNode* c_child - cdef Py_ssize_t c - c_child = c_node.last - c = 0 - while c_child is not NULL: - if _isElement(c_child): - if c == index: - return c_child - c += 1 - c_child = c_child.prev - return NULL - -cdef inline xmlNode* _textNodeOrSkip(xmlNode* c_node) noexcept nogil: - """Return the node if it's a text node. Skip over ignorable nodes in a - series of text nodes. Return NULL if a non-ignorable node is found. - - This is used to skip over XInclude nodes when collecting adjacent text - nodes. - """ - while c_node is not NULL: - if c_node.type == tree.XML_TEXT_NODE or \ - c_node.type == tree.XML_CDATA_SECTION_NODE: - return c_node - elif c_node.type == tree.XML_XINCLUDE_START or \ - c_node.type == tree.XML_XINCLUDE_END: - c_node = c_node.next - else: - return NULL - return NULL - -cdef inline xmlNode* _nextElement(xmlNode* c_node) noexcept: - """Given a node, find the next sibling that is an element. - """ - if c_node is NULL: - return NULL - c_node = c_node.next - while c_node is not NULL: - if _isElement(c_node): - return c_node - c_node = c_node.next - return NULL - -cdef inline xmlNode* _previousElement(xmlNode* c_node) noexcept: - """Given a node, find the next sibling that is an element. - """ - if c_node is NULL: - return NULL - c_node = c_node.prev - while c_node is not NULL: - if _isElement(c_node): - return c_node - c_node = c_node.prev - return NULL - -cdef inline xmlNode* _parentElement(xmlNode* c_node) noexcept: - "Given a node, find the parent element." - if c_node is NULL or not _isElement(c_node): - return NULL - c_node = c_node.parent - if c_node is NULL or not _isElement(c_node): - return NULL - return c_node - -cdef inline bint _tagMatches(xmlNode* c_node, const_xmlChar* c_href, const_xmlChar* c_name) noexcept: - """Tests if the node matches namespace URI and tag name. - - A node matches if it matches both c_href and c_name. - - A node matches c_href if any of the following is true: - * c_href is NULL - * its namespace is NULL and c_href is the empty string - * its namespace string equals the c_href string - - A node matches c_name if any of the following is true: - * c_name is NULL - * its name string equals the c_name string - """ - if c_node is NULL: - return 0 - if c_node.type != tree.XML_ELEMENT_NODE: - # not an element, only succeed if we match everything - return c_name is NULL and c_href is NULL - if c_name is NULL: - if c_href is NULL: - # always match - return 1 - else: - c_node_href = _getNs(c_node) - if c_node_href is NULL: - return c_href[0] == c'\0' - else: - return tree.xmlStrcmp(c_node_href, c_href) == 0 - elif c_href is NULL: - if _getNs(c_node) is not NULL: - return 0 - return c_node.name == c_name or tree.xmlStrcmp(c_node.name, c_name) == 0 - elif c_node.name == c_name or tree.xmlStrcmp(c_node.name, c_name) == 0: - c_node_href = _getNs(c_node) - if c_node_href is NULL: - return c_href[0] == c'\0' - else: - return tree.xmlStrcmp(c_node_href, c_href) == 0 - else: - return 0 - -cdef inline bint _tagMatchesExactly(xmlNode* c_node, qname* c_qname) noexcept: - """Tests if the node matches namespace URI and tag name. - - This differs from _tagMatches() in that it does not consider a - NULL value in qname.href a wildcard, and that it expects the c_name - to be taken from the doc dict, i.e. it only compares the names by - address. - - A node matches if it matches both href and c_name of the qname. - - A node matches c_href if any of the following is true: - * its namespace is NULL and c_href is the empty string - * its namespace string equals the c_href string - - A node matches c_name if any of the following is true: - * c_name is NULL - * its name string points to the same address (!) as c_name - """ - return _nsTagMatchesExactly(_getNs(c_node), c_node.name, c_qname) - -cdef inline bint _nsTagMatchesExactly(const_xmlChar* c_node_href, - const_xmlChar* c_node_name, - qname* c_qname) noexcept: - """Tests if name and namespace URI match those of c_qname. - - This differs from _tagMatches() in that it does not consider a - NULL value in qname.href a wildcard, and that it expects the c_name - to be taken from the doc dict, i.e. it only compares the names by - address. - - A node matches if it matches both href and c_name of the qname. - - A node matches c_href if any of the following is true: - * its namespace is NULL and c_href is the empty string - * its namespace string equals the c_href string - - A node matches c_name if any of the following is true: - * c_name is NULL - * its name string points to the same address (!) as c_name - """ - cdef char* c_href - if c_qname.c_name is not NULL and c_qname.c_name is not c_node_name: - return 0 - if c_qname.href is NULL: - return 1 - c_href = python.__cstr(c_qname.href) - if c_href[0] == b'\0': - return c_node_href is NULL or c_node_href[0] == b'\0' - elif c_node_href is NULL: - return 0 - else: - return tree.xmlStrcmp(c_href, c_node_href) == 0 - -cdef Py_ssize_t _mapTagsToQnameMatchArray(xmlDoc* c_doc, list ns_tags, - qname* c_ns_tags, bint force_into_dict) except -1: - """Map a sequence of (name, namespace) pairs to a qname array for efficient - matching with _tagMatchesExactly() above. - - Note that each qname struct in the array owns its href byte string object - if it is not NULL. - """ - cdef Py_ssize_t count = 0, i, c_tag_len - cdef bytes ns, tag - cdef const_xmlChar* c_tag - - for ns, tag in ns_tags: - if tag is None: - c_tag = NULL - else: - c_tag_len = len(tag) - if c_tag_len > limits.INT_MAX: - # too long, not in the dict => not in the document - continue - elif force_into_dict: - c_tag = tree.xmlDictLookup(c_doc.dict, _xcstr(tag), c_tag_len) - if c_tag is NULL: - # clean up before raising the error - for i in xrange(count): - cpython.ref.Py_XDECREF(c_ns_tags[i].href) - raise MemoryError() - else: - c_tag = tree.xmlDictExists(c_doc.dict, _xcstr(tag), c_tag_len) - if c_tag is NULL: - # not in the dict => not in the document - continue - - c_ns_tags[count].c_name = c_tag - if ns is None: - c_ns_tags[count].href = NULL - else: - cpython.ref.Py_INCREF(ns) # keep an owned reference! - c_ns_tags[count].href = ns - count += 1 - return count - -cdef int _removeNode(_Document doc, xmlNode* c_node) except -1: - """Unlink and free a node and subnodes if possible. Otherwise, make sure - it's self-contained. - """ - cdef xmlNode* c_next - c_next = c_node.next - tree.xmlUnlinkNode(c_node) - _moveTail(c_next, c_node) - if not attemptDeallocation(c_node): - # make namespaces absolute - moveNodeToDocument(doc, c_node.doc, c_node) - return 0 - -cdef int _removeSiblings(xmlNode* c_element, tree.xmlElementType node_type, bint with_tail) except -1: - cdef xmlNode* c_node - cdef xmlNode* c_next - c_node = c_element.next - while c_node is not NULL: - c_next = _nextElement(c_node) - if c_node.type == node_type: - if with_tail: - _removeText(c_node.next) - tree.xmlUnlinkNode(c_node) - attemptDeallocation(c_node) - c_node = c_next - c_node = c_element.prev - while c_node is not NULL: - c_next = _previousElement(c_node) - if c_node.type == node_type: - if with_tail: - _removeText(c_node.next) - tree.xmlUnlinkNode(c_node) - attemptDeallocation(c_node) - c_node = c_next - return 0 - -cdef void _moveTail(xmlNode* c_tail, xmlNode* c_target) noexcept: - cdef xmlNode* c_next - # tail support: look for any text nodes trailing this node and - # move them too - c_tail = _textNodeOrSkip(c_tail) - while c_tail is not NULL: - c_next = _textNodeOrSkip(c_tail.next) - c_target = tree.xmlAddNextSibling(c_target, c_tail) - c_tail = c_next - -cdef int _copyTail(xmlNode* c_tail, xmlNode* c_target) except -1: - cdef xmlNode* c_new_tail - # tail copying support: look for any text nodes trailing this node and - # copy it to the target node - c_tail = _textNodeOrSkip(c_tail) - while c_tail is not NULL: - if c_target.doc is not c_tail.doc: - c_new_tail = tree.xmlDocCopyNode(c_tail, c_target.doc, 0) - else: - c_new_tail = tree.xmlCopyNode(c_tail, 0) - if c_new_tail is NULL: - raise MemoryError() - c_target = tree.xmlAddNextSibling(c_target, c_new_tail) - c_tail = _textNodeOrSkip(c_tail.next) - return 0 - -cdef int _copyNonElementSiblings(xmlNode* c_node, xmlNode* c_target) except -1: - cdef xmlNode* c_copy - cdef xmlNode* c_sibling = c_node - while c_sibling.prev != NULL and \ - (c_sibling.prev.type == tree.XML_PI_NODE or - c_sibling.prev.type == tree.XML_COMMENT_NODE or - c_sibling.prev.type == tree.XML_DTD_NODE): - c_sibling = c_sibling.prev - while c_sibling != c_node: - if c_sibling.type == tree.XML_DTD_NODE: - c_copy = _copyDtd(c_sibling) - if c_sibling == c_node.doc.intSubset: - c_target.doc.intSubset = c_copy - else: # c_sibling == c_node.doc.extSubset - c_target.doc.extSubset = c_copy - else: - c_copy = tree.xmlDocCopyNode(c_sibling, c_target.doc, 1) - if c_copy is NULL: - raise MemoryError() - tree.xmlAddPrevSibling(c_target, c_copy) - c_sibling = c_sibling.next - while c_sibling.next != NULL and \ - (c_sibling.next.type == tree.XML_PI_NODE or - c_sibling.next.type == tree.XML_COMMENT_NODE): - c_sibling = c_sibling.next - c_copy = tree.xmlDocCopyNode(c_sibling, c_target.doc, 1) - if c_copy is NULL: - raise MemoryError() - tree.xmlAddNextSibling(c_target, c_copy) - -cdef int _deleteSlice(_Document doc, xmlNode* c_node, - Py_ssize_t count, Py_ssize_t step) except -1: - """Delete slice, ``count`` items starting with ``c_node`` with a step - width of ``step``. - """ - cdef xmlNode* c_next - cdef Py_ssize_t c, i - cdef _node_to_node_function next_element - if c_node is NULL: - return 0 - if step > 0: - next_element = _nextElement - else: - step = -step - next_element = _previousElement - # now start deleting nodes - c = 0 - c_next = c_node - while c_node is not NULL and c < count: - for i in range(step): - c_next = next_element(c_next) - if c_next is NULL: - break - _removeNode(doc, c_node) - c += 1 - c_node = c_next - return 0 - -cdef int _replaceSlice(_Element parent, xmlNode* c_node, - Py_ssize_t slicelength, Py_ssize_t step, - bint left_to_right, elements) except -1: - """Replace the slice of ``count`` elements starting at ``c_node`` with - positive step width ``step`` by the Elements in ``elements``. The - direction is given by the boolean argument ``left_to_right``. - - ``c_node`` may be NULL to indicate the end of the children list. - """ - cdef xmlNode* c_orig_neighbour - cdef xmlNode* c_next - cdef xmlDoc* c_source_doc - cdef _Element element - cdef Py_ssize_t seqlength, i, c - cdef _node_to_node_function next_element - assert step > 0 - if left_to_right: - next_element = _nextElement - else: - next_element = _previousElement - - if not isinstance(elements, (list, tuple)): - elements = list(elements) - - if step != 1 or not left_to_right: - # *replacing* children stepwise with list => check size! - seqlength = len(elements) - if seqlength != slicelength: - raise ValueError, f"attempt to assign sequence of size {seqlength} " \ - f"to extended slice of size {slicelength}" - - if c_node is NULL: - # no children yet => add all elements straight away - if left_to_right: - for element in elements: - assert element is not None, "Node must not be None" - _appendChild(parent, element) - else: - for element in elements: - assert element is not None, "Node must not be None" - _prependChild(parent, element) - return 0 - - # remove the elements first as some might be re-added - if left_to_right: - # L->R, remember left neighbour - c_orig_neighbour = _previousElement(c_node) - else: - # R->L, remember right neighbour - c_orig_neighbour = _nextElement(c_node) - - # We remove the original slice elements one by one. Since we hold - # a Python reference to all elements that we will insert, it is - # safe to let _removeNode() try (and fail) to free them even if - # the element itself or one of its descendents will be reinserted. - c = 0 - c_next = c_node - while c_node is not NULL and c < slicelength: - for i in range(step): - c_next = next_element(c_next) - if c_next is NULL: - break - _removeNode(parent._doc, c_node) - c += 1 - c_node = c_next - - # make sure each element is inserted only once - elements = iter(elements) - - # find the first node right of the new insertion point - if left_to_right: - if c_orig_neighbour is not NULL: - c_node = next_element(c_orig_neighbour) - else: - # before the first element - c_node = _findChildForwards(parent._c_node, 0) - elif c_orig_neighbour is NULL: - # at the end, but reversed stepping - # append one element and go to the next insertion point - for element in elements: - assert element is not None, "Node must not be None" - _appendChild(parent, element) - c_node = element._c_node - if slicelength > 0: - slicelength -= 1 - for i in range(1, step): - c_node = next_element(c_node) - if c_node is NULL: - break - break - else: - c_node = c_orig_neighbour - - if left_to_right: - # adjust step size after removing slice as we are not stepping - # over the newly inserted elements - step -= 1 - - # now insert elements where we removed them - if c_node is not NULL: - for element in elements: - assert element is not None, "Node must not be None" - _assertValidNode(element) - # move element and tail over - c_source_doc = element._c_node.doc - c_next = element._c_node.next - tree.xmlAddPrevSibling(c_node, element._c_node) - _moveTail(c_next, element._c_node) - - # integrate element into new document - moveNodeToDocument(parent._doc, c_source_doc, element._c_node) - - # stop at the end of the slice - if slicelength > 0: - slicelength -= 1 - for i in range(step): - c_node = next_element(c_node) - if c_node is NULL: - break - if c_node is NULL: - break - else: - # everything inserted - return 0 - - # append the remaining elements at the respective end - if left_to_right: - for element in elements: - assert element is not None, "Node must not be None" - _assertValidNode(element) - _appendChild(parent, element) - else: - for element in elements: - assert element is not None, "Node must not be None" - _assertValidNode(element) - _prependChild(parent, element) - - return 0 - - -cdef int _linkChild(xmlNode* c_parent, xmlNode* c_node) except -1: - """Adaptation of 'xmlAddChild()' that deep-fix the document links iteratively. - """ - assert _isElement(c_node) - c_node.parent = c_parent - if c_parent.children is NULL: - c_parent.children = c_parent.last = c_node - else: - c_node.prev = c_parent.last - c_parent.last.next = c_node - c_parent.last = c_node - - _setTreeDoc(c_node, c_parent.doc) - return 0 - - -cdef int _appendChild(_Element parent, _Element child) except -1: - """Append a new child to a parent element. - """ - c_node = child._c_node - c_source_doc = c_node.doc - # prevent cycles - if _isAncestorOrSame(c_node, parent._c_node): - raise ValueError("cannot append parent to itself") - # store possible text node - c_next = c_node.next - # move node itself - tree.xmlUnlinkNode(c_node) - # do not call xmlAddChild() here since it would deep-traverse the tree - _linkChild(parent._c_node, c_node) - _moveTail(c_next, c_node) - # uh oh, elements may be pointing to different doc when - # parent element has moved; change them too.. - moveNodeToDocument(parent._doc, c_source_doc, c_node) - return 0 - -cdef int _prependChild(_Element parent, _Element child) except -1: - """Prepend a new child to a parent element. - """ - c_node = child._c_node - c_source_doc = c_node.doc - # prevent cycles - if _isAncestorOrSame(c_node, parent._c_node): - raise ValueError("cannot append parent to itself") - # store possible text node - c_next = c_node.next - # move node itself - c_child = _findChildForwards(parent._c_node, 0) - if c_child is NULL: - tree.xmlUnlinkNode(c_node) - # do not call xmlAddChild() here since it would deep-traverse the tree - _linkChild(parent._c_node, c_node) - else: - tree.xmlAddPrevSibling(c_child, c_node) - _moveTail(c_next, c_node) - # uh oh, elements may be pointing to different doc when - # parent element has moved; change them too.. - moveNodeToDocument(parent._doc, c_source_doc, c_node) - return 0 - -cdef int _appendSibling(_Element element, _Element sibling) except -1: - """Add a new sibling behind an element. - """ - return _addSibling(element, sibling, as_next=True) - -cdef int _prependSibling(_Element element, _Element sibling) except -1: - """Add a new sibling before an element. - """ - return _addSibling(element, sibling, as_next=False) - -cdef int _addSibling(_Element element, _Element sibling, bint as_next) except -1: - c_node = sibling._c_node - c_source_doc = c_node.doc - # prevent cycles - if _isAncestorOrSame(c_node, element._c_node): - if element._c_node is c_node: - return 0 # nothing to do - raise ValueError("cannot add ancestor as sibling, please break cycle first") - # store possible text node - c_next = c_node.next - # move node itself - if as_next: - # must insert after any tail text - c_next_node = _nextElement(element._c_node) - if c_next_node is NULL: - c_next_node = element._c_node - while c_next_node.next: - c_next_node = c_next_node.next - tree.xmlAddNextSibling(c_next_node, c_node) - else: - tree.xmlAddPrevSibling(c_next_node, c_node) - else: - tree.xmlAddPrevSibling(element._c_node, c_node) - _moveTail(c_next, c_node) - # uh oh, elements may be pointing to different doc when - # parent element has moved; change them too.. - moveNodeToDocument(element._doc, c_source_doc, c_node) - return 0 - -cdef inline bint isutf8(const_xmlChar* s) noexcept: - cdef xmlChar c = s[0] - while c != c'\0': - if c & 0x80: - return True - s += 1 - c = s[0] - return False - -cdef bint isutf8l(const_xmlChar* s, size_t length) noexcept: - """ - Search for non-ASCII characters in the string, knowing its length in advance. - """ - cdef unsigned int i - cdef unsigned long non_ascii_mask - cdef const unsigned long *lptr = s - - cdef const unsigned long *end = lptr + length // sizeof(unsigned long) - if length >= sizeof(non_ascii_mask): - # Build constant 0x80808080... mask (and let the C compiler fold it). - non_ascii_mask = 0 - for i in range(sizeof(non_ascii_mask) // 2): - non_ascii_mask = (non_ascii_mask << 16) | 0x8080 - - # Advance to long-aligned character before we start reading longs. - while (s) % sizeof(unsigned long) and s < end: - if s[0] & 0x80: - return True - s += 1 - - # Read one long at a time - lptr = s - while lptr < end: - if lptr[0] & non_ascii_mask: - return True - lptr += 1 - s = lptr - - while s < (end + length % sizeof(unsigned long)): - if s[0] & 0x80: - return True - s += 1 - - return False - -cdef int _is_valid_xml_ascii(bytes pystring) except -1: - """Check if a string is XML ascii content.""" - cdef signed char ch - # When ch is a *signed* char, non-ascii characters are negative integers - # and xmlIsChar_ch does not accept them. - for ch in pystring: - if not tree.xmlIsChar_ch(ch): - return 0 - return 1 - -cdef bint _is_valid_xml_utf8(bytes pystring) except -1: - """Check if a string is like valid UTF-8 XML content.""" - cdef const_xmlChar* s = _xcstr(pystring) - cdef const_xmlChar* c_end = s + len(pystring) - cdef unsigned long next3 = 0 - if s < c_end - 2: - next3 = (s[0] << 8) | (s[1]) - - while s < c_end - 2: - next3 = 0x00ffffff & ((next3 << 8) | s[2]) - if s[0] & 0x80: - # 0xefbfbe and 0xefbfbf are utf-8 encodings of - # forbidden characters \ufffe and \uffff - if next3 == 0x00efbfbe or next3 == 0x00efbfbf: - return 0 - # 0xeda080 and 0xedbfbf are utf-8 encodings of - # \ud800 and \udfff. Anything between them (inclusive) - # is forbidden, because they are surrogate blocks in utf-16. - if 0x00eda080 <= next3 <= 0x00edbfbf: - return 0 - elif not tree.xmlIsChar_ch(s[0]): - return 0 # invalid ascii char - s += 1 - - while s < c_end: - if not s[0] & 0x80 and not tree.xmlIsChar_ch(s[0]): - return 0 # invalid ascii char - s += 1 - - return 1 - -cdef inline unicode funicodeOrNone(const_xmlChar* s): - return funicode(s) if s is not NULL else None - -cdef inline unicode funicodeOrEmpty(const_xmlChar* s): - return funicode(s) if s is not NULL else '' - -cdef unicode funicode(const_xmlChar* s): - return s.decode('UTF-8') - -cdef bytes _utf8(object s): - """Test if a string is valid user input and encode it to UTF-8. - Reject all bytes/unicode input that contains non-XML characters. - Reject all bytes input that contains non-ASCII characters. - """ - cdef int valid - cdef bytes utf8_string - if isinstance(s, unicode): - utf8_string = (s).encode('utf8') - valid = _is_valid_xml_utf8(utf8_string) - elif isinstance(s, (bytes, bytearray)): - utf8_string = s if type(s) is bytes else bytes(s) - valid = _is_valid_xml_ascii(utf8_string) - else: - raise TypeError("Argument must be bytes or unicode, got '%.200s'" % type(s).__name__) - if not valid: - raise ValueError( - "All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters") - return utf8_string - - -cdef bytes _utf8orNone(object s): - return _utf8(s) if s is not None else None - - -cdef enum: - NO_FILE_PATH = 0 - ABS_UNIX_FILE_PATH = 1 - ABS_WIN_FILE_PATH = 2 - REL_FILE_PATH = 3 - - -cdef bint _isFilePath(const_xmlChar* c_path) noexcept: - "simple heuristic to see if a path is a filename" - cdef xmlChar c - # test if it looks like an absolute Unix path or a Windows network path - if c_path[0] == c'/': - return ABS_UNIX_FILE_PATH - - # test if it looks like an absolute Windows path or URL - if c'a' <= c_path[0] <= c'z' or c'A' <= c_path[0] <= c'Z': - c_path += 1 - if c_path[0] == c':' and c_path[1] in b'\0\\': - return ABS_WIN_FILE_PATH # C: or C:\... - - # test if it looks like a URL with scheme:// - while c'a' <= c_path[0] <= c'z' or c'A' <= c_path[0] <= c'Z': - c_path += 1 - if c_path[0] == c':' and c_path[1] == c'/' and c_path[2] == c'/': - return NO_FILE_PATH - - # assume it's a relative path - return REL_FILE_PATH - - -cdef object _getFSPathOrObject(object obj): - """ - Get the __fspath__ attribute of an object if it exists. - Otherwise, the original object is returned. - """ - if _isString(obj): - return obj - try: - return python.PyOS_FSPath(obj) - except TypeError: - return obj - - -cdef object _encodeFilename(object filename): - """Make sure a filename is 8-bit encoded (or None). - """ - if filename is None: - return None - elif isinstance(filename, bytes): - return filename - elif isinstance(filename, unicode): - filename8 = (filename).encode('utf8') - if _isFilePath(filename8): - try: - return python.PyUnicode_AsEncodedString( - filename, _C_FILENAME_ENCODING, NULL) - except UnicodeEncodeError: - pass - return filename8 - else: - raise TypeError("Argument must be string or unicode.") - -cdef object _decodeFilename(const_xmlChar* c_path): - """Make the filename a unicode string if we are in Py3. - """ - return _decodeFilenameWithLength(c_path, tree.xmlStrlen(c_path)) - -cdef object _decodeFilenameWithLength(const_xmlChar* c_path, size_t c_len): - """Make the filename a unicode string if we are in Py3. - """ - if _isFilePath(c_path): - try: - return python.PyUnicode_Decode( - c_path, c_len, _C_FILENAME_ENCODING, NULL) - except UnicodeDecodeError: - pass - try: - return (c_path)[:c_len].decode('UTF-8') - except UnicodeDecodeError: - # this is a stupid fallback, but it might still work... - return (c_path)[:c_len].decode('latin-1', 'replace') - -cdef object _encodeFilenameUTF8(object filename): - """Recode filename as UTF-8. Tries ASCII, local filesystem encoding and - UTF-8 as source encoding. - """ - cdef char* c_filename - if filename is None: - return None - elif isinstance(filename, bytes): - if not isutf8l(filename, len(filename)): - # plain ASCII! - return filename - c_filename = _cstr(filename) - try: - # try to decode with default encoding - filename = python.PyUnicode_Decode( - c_filename, len(filename), - _C_FILENAME_ENCODING, NULL) - except UnicodeDecodeError as decode_exc: - try: - # try if it's proper UTF-8 - (filename).decode('utf8') - return filename - except UnicodeDecodeError: - raise decode_exc # otherwise re-raise original exception - if isinstance(filename, unicode): - return (filename).encode('utf8') - else: - raise TypeError("Argument must be string or unicode.") - -cdef tuple _getNsTag(tag): - """Given a tag, find namespace URI and tag name. - Return None for NS uri if no namespace URI provided. - """ - return __getNsTag(tag, 0) - -cdef tuple _getNsTagWithEmptyNs(tag): - """Given a tag, find namespace URI and tag name. Return None for NS uri - if no namespace URI provided, or the empty string if namespace - part is '{}'. - """ - return __getNsTag(tag, 1) - -cdef tuple __getNsTag(tag, bint empty_ns): - cdef char* c_tag - cdef char* c_ns_end - cdef Py_ssize_t taglen - cdef Py_ssize_t nslen - cdef bytes ns = None - # _isString() is much faster than isinstance() - if not _isString(tag) and isinstance(tag, QName): - tag = (tag).text - tag = _utf8(tag) - c_tag = _cstr(tag) - if c_tag[0] == c'{': - c_tag += 1 - c_ns_end = cstring_h.strchr(c_tag, c'}') - if c_ns_end is NULL: - raise ValueError, "Invalid tag name" - nslen = c_ns_end - c_tag - taglen = python.PyBytes_GET_SIZE(tag) - nslen - 2 - if taglen == 0: - raise ValueError, "Empty tag name" - if nslen > 0: - ns = c_tag[:nslen] - elif empty_ns: - ns = b'' - tag = c_ns_end[1:taglen+1] - elif python.PyBytes_GET_SIZE(tag) == 0: - raise ValueError, "Empty tag name" - return ns, tag - -cdef inline int _pyXmlNameIsValid(name_utf8): - return _xmlNameIsValid(_xcstr(name_utf8)) and b':' not in name_utf8 - -cdef inline int _pyHtmlNameIsValid(name_utf8): - return _htmlNameIsValid(_xcstr(name_utf8)) - -cdef inline int _xmlNameIsValid(const_xmlChar* c_name) noexcept: - return tree.xmlValidateNameValue(c_name) - -cdef int _htmlNameIsValid(const_xmlChar* c_name) noexcept: - if c_name is NULL or c_name[0] == c'\0': - return 0 - while c_name[0] != c'\0': - if c_name[0] in b'&<>/"\'\t\n\x0B\x0C\r ': - return 0 - c_name += 1 - return 1 - -cdef bint _characterReferenceIsValid(const_xmlChar* c_name) noexcept: - cdef bint is_hex - if c_name[0] == c'x': - c_name += 1 - is_hex = 1 - else: - is_hex = 0 - if c_name[0] == c'\0': - return 0 - while c_name[0] != c'\0': - if c_name[0] < c'0' or c_name[0] > c'9': - if not is_hex: - return 0 - if not (c'a' <= c_name[0] <= c'f'): - if not (c'A' <= c_name[0] <= c'F'): - return 0 - c_name += 1 - return 1 - -cdef int _tagValidOrRaise(tag_utf) except -1: - if not _pyXmlNameIsValid(tag_utf): - raise ValueError(f"Invalid tag name {(tag_utf).decode('utf8')!r}") - return 0 - -cdef int _htmlTagValidOrRaise(tag_utf) except -1: - if not _pyHtmlNameIsValid(tag_utf): - raise ValueError(f"Invalid HTML tag name {(tag_utf).decode('utf8')!r}") - return 0 - -cdef int _attributeValidOrRaise(name_utf) except -1: - if not _pyXmlNameIsValid(name_utf): - raise ValueError(f"Invalid attribute name {(name_utf).decode('utf8')!r}") - return 0 - -cdef int _prefixValidOrRaise(tag_utf) except -1: - if not _pyXmlNameIsValid(tag_utf): - raise ValueError(f"Invalid namespace prefix {(tag_utf).decode('utf8')!r}") - return 0 - -cdef int _uriValidOrRaise(uri_utf) except -1: - cdef uri.xmlURI* c_uri = uri.xmlParseURI(_cstr(uri_utf)) - if c_uri is NULL: - raise ValueError(f"Invalid namespace URI {(uri_utf).decode('utf8')!r}") - uri.xmlFreeURI(c_uri) - return 0 - -cdef inline unicode _namespacedName(xmlNode* c_node): - return _namespacedNameFromNsName(_getNs(c_node), c_node.name) - - -cdef unicode _namespacedNameFromNsName(const_xmlChar* c_href, const_xmlChar* c_name): - name = funicode(c_name) - if c_href is NULL: - return name - href = funicode(c_href) - return f"{{{href}}}{name}" - - -cdef _getFilenameForFile(source): - """Given a Python File or Gzip object, give filename back. - - Returns None if not a file object. - """ - # urllib2 provides a geturl() method - try: - return source.geturl() - except: - pass - # file instances have a name attribute - try: - filename = source.name - if _isString(filename): - return os_path_abspath(filename) - except: - pass - # gzip file instances have a filename attribute (before Py3k) - try: - filename = source.filename - if _isString(filename): - return os_path_abspath(filename) - except: - pass - # can't determine filename - return None diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.cpython-39-darwin.so b/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.cpython-39-darwin.so deleted file mode 100755 index 6f07458..0000000 Binary files a/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.cpython-39-darwin.so and /dev/null differ diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.py deleted file mode 100644 index f5831fb..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/builder.py +++ /dev/null @@ -1,243 +0,0 @@ -# cython: language_level=2 - -# -# Element generator factory by Fredrik Lundh. -# -# Source: -# http://online.effbot.org/2006_11_01_archive.htm#et-builder -# http://effbot.python-hosting.com/file/stuff/sandbox/elementlib/builder.py -# -# -------------------------------------------------------------------- -# The ElementTree toolkit is -# -# Copyright (c) 1999-2004 by Fredrik Lundh -# -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: -# -# Permission to use, copy, modify, and distribute this software and -# its associated documentation for any purpose and without fee is -# hereby granted, provided that the above copyright notice appears in -# all copies, and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of -# Secret Labs AB or the author not be used in advertising or publicity -# pertaining to distribution of the software without specific, written -# prior permission. -# -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD -# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- -# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR -# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# -------------------------------------------------------------------- - -""" -The ``E`` Element factory for generating XML documents. -""" - - -import lxml.etree as ET -_QName = ET.QName - -from functools import partial - -try: - from types import GenericAlias as _GenericAlias -except ImportError: - # Python 3.8 - we only need this as return value from "__class_getitem__" - def _GenericAlias(cls, item): - return f"{cls.__name__}[{item.__name__}]" - -try: - basestring -except NameError: - basestring = str - -try: - unicode -except NameError: - unicode = str - - -class ElementMaker: - """Element generator factory. - - Unlike the ordinary Element factory, the E factory allows you to pass in - more than just a tag and some optional attributes; you can also pass in - text and other elements. The text is added as either text or tail - attributes, and elements are inserted at the right spot. Some small - examples:: - - >>> from lxml import etree as ET - >>> from lxml.builder import E - - >>> ET.tostring(E("tag")) - '' - >>> ET.tostring(E("tag", "text")) - 'text' - >>> ET.tostring(E("tag", "text", key="value")) - 'text' - >>> ET.tostring(E("tag", E("subtag", "text"), "tail")) - 'texttail' - - For simple tags, the factory also allows you to write ``E.tag(...)`` instead - of ``E('tag', ...)``:: - - >>> ET.tostring(E.tag()) - '' - >>> ET.tostring(E.tag("text")) - 'text' - >>> ET.tostring(E.tag(E.subtag("text"), "tail")) - 'texttail' - - Here's a somewhat larger example; this shows how to generate HTML - documents, using a mix of prepared factory functions for inline elements, - nested ``E.tag`` calls, and embedded XHTML fragments:: - - # some common inline elements - A = E.a - I = E.i - B = E.b - - def CLASS(v): - # helper function, 'class' is a reserved word - return {'class': v} - - page = ( - E.html( - E.head( - E.title("This is a sample document") - ), - E.body( - E.h1("Hello!", CLASS("title")), - E.p("This is a paragraph with ", B("bold"), " text in it!"), - E.p("This is another paragraph, with a ", - A("link", href="http://www.python.org"), "."), - E.p("Here are some reserved characters: ."), - ET.XML("

And finally, here is an embedded XHTML fragment.

"), - ) - ) - ) - - print ET.tostring(page) - - Here's a prettyprinted version of the output from the above script:: - - - - This is a sample document - - -

Hello!

-

This is a paragraph with bold text in it!

-

This is another paragraph, with link.

-

Here are some reserved characters: <spam&egg>.

-

And finally, here is an embedded XHTML fragment.

- - - - For namespace support, you can pass a namespace map (``nsmap``) - and/or a specific target ``namespace`` to the ElementMaker class:: - - >>> E = ElementMaker(namespace="http://my.ns/") - >>> print(ET.tostring( E.test )) - - - >>> E = ElementMaker(namespace="http://my.ns/", nsmap={'p':'http://my.ns/'}) - >>> print(ET.tostring( E.test )) - - """ - - def __init__(self, typemap=None, - namespace=None, nsmap=None, makeelement=None): - self._namespace = '{' + namespace + '}' if namespace is not None else None - self._nsmap = dict(nsmap) if nsmap else None - - assert makeelement is None or callable(makeelement) - self._makeelement = makeelement if makeelement is not None else ET.Element - - # initialize the default type map functions for this element factory - typemap = dict(typemap) if typemap else {} - - def add_text(elem, item): - try: - last_child = elem[-1] - except IndexError: - elem.text = (elem.text or "") + item - else: - last_child.tail = (last_child.tail or "") + item - - def add_cdata(elem, cdata): - if elem.text: - raise ValueError("Can't add a CDATA section. Element already has some text: %r" % elem.text) - elem.text = cdata - - if str not in typemap: - typemap[str] = add_text - if unicode not in typemap: - typemap[unicode] = add_text - if ET.CDATA not in typemap: - typemap[ET.CDATA] = add_cdata - - def add_dict(elem, item): - attrib = elem.attrib - for k, v in item.items(): - if isinstance(v, basestring): - attrib[k] = v - else: - attrib[k] = typemap[type(v)](None, v) - - if dict not in typemap: - typemap[dict] = add_dict - - self._typemap = typemap - - def __call__(self, tag, *children, **attrib): - typemap = self._typemap - - # We'll usually get a 'str', and the compiled type check is very fast. - if not isinstance(tag, str) and isinstance(tag, _QName): - # A QName is explicitly qualified, do not look at self._namespace. - tag = tag.text - elif self._namespace is not None and tag[0] != '{': - tag = self._namespace + tag - elem = self._makeelement(tag, nsmap=self._nsmap) - if attrib: - typemap[dict](elem, attrib) - - for item in children: - if callable(item): - item = item() - t = typemap.get(type(item)) - if t is None: - if ET.iselement(item): - elem.append(item) - continue - for basetype in type(item).__mro__: - # See if the typemap knows of any of this type's bases. - t = typemap.get(basetype) - if t is not None: - break - else: - raise TypeError("bad argument type: %s(%r)" % - (type(item).__name__, item)) - v = t(elem, item) - if v: - typemap.get(type(v))(elem, v) - - return elem - - def __getattr__(self, tag): - return partial(self, tag) - - # Allow subscripting ElementMaker in type annotions (PEP 560) - def __class_getitem__(cls, item): - return _GenericAlias(cls, item) - - -# create factory object -E = ElementMaker() diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/classlookup.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/classlookup.pxi deleted file mode 100644 index 92d1d47..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/classlookup.pxi +++ /dev/null @@ -1,580 +0,0 @@ -# Configurable Element class lookup - -################################################################################ -# Custom Element classes - -cdef public class ElementBase(_Element) [ type LxmlElementBaseType, - object LxmlElementBase ]: - """ElementBase(*children, attrib=None, nsmap=None, **_extra) - - The public Element class. All custom Element classes must inherit - from this one. To create an Element, use the `Element()` factory. - - BIG FAT WARNING: Subclasses *must not* override __init__ or - __new__ as it is absolutely undefined when these objects will be - created or destroyed. All persistent state of Elements must be - stored in the underlying XML. If you really need to initialize - the object after creation, you can implement an ``_init(self)`` - method that will be called directly after object creation. - - Subclasses of this class can be instantiated to create a new - Element. By default, the tag name will be the class name and the - namespace will be empty. You can modify this with the following - class attributes: - - * TAG - the tag name, possibly containing a namespace in Clark - notation - - * NAMESPACE - the default namespace URI, unless provided as part - of the TAG attribute. - - * HTML - flag if the class is an HTML tag, as opposed to an XML - tag. This only applies to un-namespaced tags and defaults to - false (i.e. XML). - - * PARSER - the parser that provides the configuration for the - newly created document. Providing an HTML parser here will - default to creating an HTML element. - - In user code, the latter three are commonly inherited in class - hierarchies that implement a common namespace. - """ - def __init__(self, *children, attrib=None, nsmap=None, **_extra): - """ElementBase(*children, attrib=None, nsmap=None, **_extra) - """ - cdef bint is_html = 0 - cdef _BaseParser parser - cdef _Element last_child - # don't use normal attribute access as it might be overridden - _getattr = object.__getattribute__ - try: - namespace = _utf8(_getattr(self, 'NAMESPACE')) - except AttributeError: - namespace = None - try: - ns, tag = _getNsTag(_getattr(self, 'TAG')) - if ns is not None: - namespace = ns - except AttributeError: - tag = _utf8(_getattr(_getattr(self, '__class__'), '__name__')) - if b'.' in tag: - tag = tag.split(b'.')[-1] - try: - parser = _getattr(self, 'PARSER') - except AttributeError: - parser = None - for child in children: - if isinstance(child, _Element): - parser = (<_Element>child)._doc._parser - break - if isinstance(parser, HTMLParser): - is_html = 1 - if namespace is None: - try: - is_html = _getattr(self, 'HTML') - except AttributeError: - pass - _initNewElement(self, is_html, tag, namespace, parser, - attrib, nsmap, _extra) - last_child = None - for child in children: - if _isString(child): - if last_child is None: - _setNodeText(self._c_node, - (_collectText(self._c_node.children) or '') + child) - else: - _setTailText(last_child._c_node, - (_collectText(last_child._c_node.next) or '') + child) - elif isinstance(child, _Element): - last_child = child - _appendChild(self, last_child) - elif isinstance(child, type) and issubclass(child, ElementBase): - last_child = child() - _appendChild(self, last_child) - else: - raise TypeError, f"Invalid child type: {type(child)!r}" - -cdef class CommentBase(_Comment): - """All custom Comment classes must inherit from this one. - - To create an XML Comment instance, use the ``Comment()`` factory. - - Subclasses *must not* override __init__ or __new__ as it is - absolutely undefined when these objects will be created or - destroyed. All persistent state of Comments must be stored in the - underlying XML. If you really need to initialize the object after - creation, you can implement an ``_init(self)`` method that will be - called after object creation. - """ - def __init__(self, text): - # copied from Comment() factory - cdef _Document doc - cdef xmlDoc* c_doc - if text is None: - text = b'' - else: - text = _utf8(text) - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - self._c_node = _createComment(c_doc, _xcstr(text)) - if self._c_node is NULL: - raise MemoryError() - tree.xmlAddChild(c_doc, self._c_node) - _registerProxy(self, doc, self._c_node) - self._init() - -cdef class PIBase(_ProcessingInstruction): - """All custom Processing Instruction classes must inherit from this one. - - To create an XML ProcessingInstruction instance, use the ``PI()`` - factory. - - Subclasses *must not* override __init__ or __new__ as it is - absolutely undefined when these objects will be created or - destroyed. All persistent state of PIs must be stored in the - underlying XML. If you really need to initialize the object after - creation, you can implement an ``_init(self)`` method that will be - called after object creation. - """ - def __init__(self, target, text=None): - # copied from PI() factory - cdef _Document doc - cdef xmlDoc* c_doc - target = _utf8(target) - if text is None: - text = b'' - else: - text = _utf8(text) - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - self._c_node = _createPI(c_doc, _xcstr(target), _xcstr(text)) - if self._c_node is NULL: - raise MemoryError() - tree.xmlAddChild(c_doc, self._c_node) - _registerProxy(self, doc, self._c_node) - self._init() - -cdef class EntityBase(_Entity): - """All custom Entity classes must inherit from this one. - - To create an XML Entity instance, use the ``Entity()`` factory. - - Subclasses *must not* override __init__ or __new__ as it is - absolutely undefined when these objects will be created or - destroyed. All persistent state of Entities must be stored in the - underlying XML. If you really need to initialize the object after - creation, you can implement an ``_init(self)`` method that will be - called after object creation. - """ - def __init__(self, name): - cdef _Document doc - cdef xmlDoc* c_doc - name_utf = _utf8(name) - c_name = _xcstr(name_utf) - if c_name[0] == c'#': - if not _characterReferenceIsValid(c_name + 1): - raise ValueError, f"Invalid character reference: '{name}'" - elif not _xmlNameIsValid(c_name): - raise ValueError, f"Invalid entity reference: '{name}'" - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - self._c_node = _createEntity(c_doc, c_name) - if self._c_node is NULL: - raise MemoryError() - tree.xmlAddChild(c_doc, self._c_node) - _registerProxy(self, doc, self._c_node) - self._init() - - -cdef int _validateNodeClass(xmlNode* c_node, cls) except -1: - if c_node.type == tree.XML_ELEMENT_NODE: - expected = ElementBase - elif c_node.type == tree.XML_COMMENT_NODE: - expected = CommentBase - elif c_node.type == tree.XML_ENTITY_REF_NODE: - expected = EntityBase - elif c_node.type == tree.XML_PI_NODE: - expected = PIBase - else: - assert False, f"Unknown node type: {c_node.type}" - - if not (isinstance(cls, type) and issubclass(cls, expected)): - raise TypeError( - f"result of class lookup must be subclass of {type(expected)}, got {type(cls)}") - return 0 - - -################################################################################ -# Element class lookup - -ctypedef public object (*_element_class_lookup_function)(object, _Document, xmlNode*) - -# class to store element class lookup functions -cdef public class ElementClassLookup [ type LxmlElementClassLookupType, - object LxmlElementClassLookup ]: - """ElementClassLookup(self) - Superclass of Element class lookups. - """ - cdef _element_class_lookup_function _lookup_function - - -cdef public class FallbackElementClassLookup(ElementClassLookup) \ - [ type LxmlFallbackElementClassLookupType, - object LxmlFallbackElementClassLookup ]: - """FallbackElementClassLookup(self, fallback=None) - - Superclass of Element class lookups with additional fallback. - """ - cdef readonly ElementClassLookup fallback - cdef _element_class_lookup_function _fallback_function - def __cinit__(self): - # fall back to default lookup - self._fallback_function = _lookupDefaultElementClass - - def __init__(self, ElementClassLookup fallback=None): - if fallback is not None: - self._setFallback(fallback) - else: - self._fallback_function = _lookupDefaultElementClass - - cdef void _setFallback(self, ElementClassLookup lookup): - """Sets the fallback scheme for this lookup method. - """ - self.fallback = lookup - self._fallback_function = lookup._lookup_function - if self._fallback_function is NULL: - self._fallback_function = _lookupDefaultElementClass - - def set_fallback(self, ElementClassLookup lookup not None): - """set_fallback(self, lookup) - - Sets the fallback scheme for this lookup method. - """ - self._setFallback(lookup) - -cdef inline object _callLookupFallback(FallbackElementClassLookup lookup, - _Document doc, xmlNode* c_node): - return lookup._fallback_function(lookup.fallback, doc, c_node) - - -################################################################################ -# default lookup scheme - -cdef class ElementDefaultClassLookup(ElementClassLookup): - """ElementDefaultClassLookup(self, element=None, comment=None, pi=None, entity=None) - Element class lookup scheme that always returns the default Element - class. - - The keyword arguments ``element``, ``comment``, ``pi`` and ``entity`` - accept the respective Element classes. - """ - cdef readonly object element_class - cdef readonly object comment_class - cdef readonly object pi_class - cdef readonly object entity_class - def __cinit__(self): - self._lookup_function = _lookupDefaultElementClass - - def __init__(self, element=None, comment=None, pi=None, entity=None): - if element is None: - self.element_class = _Element - elif issubclass(element, ElementBase): - self.element_class = element - else: - raise TypeError, "element class must be subclass of ElementBase" - - if comment is None: - self.comment_class = _Comment - elif issubclass(comment, CommentBase): - self.comment_class = comment - else: - raise TypeError, "comment class must be subclass of CommentBase" - - if entity is None: - self.entity_class = _Entity - elif issubclass(entity, EntityBase): - self.entity_class = entity - else: - raise TypeError, "Entity class must be subclass of EntityBase" - - if pi is None: - self.pi_class = None # special case, see below - elif issubclass(pi, PIBase): - self.pi_class = pi - else: - raise TypeError, "PI class must be subclass of PIBase" - -cdef object _lookupDefaultElementClass(state, _Document _doc, xmlNode* c_node): - "Trivial class lookup function that always returns the default class." - if c_node.type == tree.XML_ELEMENT_NODE: - if state is not None: - return (state).element_class - else: - return _Element - elif c_node.type == tree.XML_COMMENT_NODE: - if state is not None: - return (state).comment_class - else: - return _Comment - elif c_node.type == tree.XML_ENTITY_REF_NODE: - if state is not None: - return (state).entity_class - else: - return _Entity - elif c_node.type == tree.XML_PI_NODE: - if state is None or (state).pi_class is None: - # special case XSLT-PI - if c_node.name is not NULL and c_node.content is not NULL: - if tree.xmlStrcmp(c_node.name, "xml-stylesheet") == 0: - if tree.xmlStrstr(c_node.content, "text/xsl") is not NULL or \ - tree.xmlStrstr(c_node.content, "text/xml") is not NULL: - return _XSLTProcessingInstruction - return _ProcessingInstruction - else: - return (state).pi_class - else: - assert False, f"Unknown node type: {c_node.type}" - - -################################################################################ -# attribute based lookup scheme - -cdef class AttributeBasedElementClassLookup(FallbackElementClassLookup): - """AttributeBasedElementClassLookup(self, attribute_name, class_mapping, fallback=None) - Checks an attribute of an Element and looks up the value in a - class dictionary. - - Arguments: - - attribute name - '{ns}name' style string - - class mapping - Python dict mapping attribute values to Element classes - - fallback - optional fallback lookup mechanism - - A None key in the class mapping will be checked if the attribute is - missing. - """ - cdef object _class_mapping - cdef tuple _pytag - cdef const_xmlChar* _c_ns - cdef const_xmlChar* _c_name - def __cinit__(self): - self._lookup_function = _attribute_class_lookup - - def __init__(self, attribute_name, class_mapping, - ElementClassLookup fallback=None): - self._pytag = _getNsTag(attribute_name) - ns, name = self._pytag - if ns is None: - self._c_ns = NULL - else: - self._c_ns = _xcstr(ns) - self._c_name = _xcstr(name) - self._class_mapping = dict(class_mapping) - - FallbackElementClassLookup.__init__(self, fallback) - -cdef object _attribute_class_lookup(state, _Document doc, xmlNode* c_node): - cdef AttributeBasedElementClassLookup lookup - cdef python.PyObject* dict_result - - lookup = state - if c_node.type == tree.XML_ELEMENT_NODE: - value = _attributeValueFromNsName( - c_node, lookup._c_ns, lookup._c_name) - dict_result = python.PyDict_GetItem(lookup._class_mapping, value) - if dict_result is not NULL: - cls = dict_result - _validateNodeClass(c_node, cls) - return cls - return _callLookupFallback(lookup, doc, c_node) - - -################################################################################ -# per-parser lookup scheme - -cdef class ParserBasedElementClassLookup(FallbackElementClassLookup): - """ParserBasedElementClassLookup(self, fallback=None) - Element class lookup based on the XML parser. - """ - def __cinit__(self): - self._lookup_function = _parser_class_lookup - -cdef object _parser_class_lookup(state, _Document doc, xmlNode* c_node): - if doc._parser._class_lookup is not None: - return doc._parser._class_lookup._lookup_function( - doc._parser._class_lookup, doc, c_node) - return _callLookupFallback(state, doc, c_node) - - -################################################################################ -# custom class lookup based on node type, namespace, name - -cdef class CustomElementClassLookup(FallbackElementClassLookup): - """CustomElementClassLookup(self, fallback=None) - Element class lookup based on a subclass method. - - You can inherit from this class and override the method:: - - lookup(self, type, doc, namespace, name) - - to lookup the element class for a node. Arguments of the method: - * type: one of 'element', 'comment', 'PI', 'entity' - * doc: document that the node is in - * namespace: namespace URI of the node (or None for comments/PIs/entities) - * name: name of the element/entity, None for comments, target for PIs - - If you return None from this method, the fallback will be called. - """ - def __cinit__(self): - self._lookup_function = _custom_class_lookup - - def lookup(self, type, doc, namespace, name): - "lookup(self, type, doc, namespace, name)" - return None - -cdef object _custom_class_lookup(state, _Document doc, xmlNode* c_node): - cdef CustomElementClassLookup lookup - - lookup = state - - if c_node.type == tree.XML_ELEMENT_NODE: - element_type = "element" - elif c_node.type == tree.XML_COMMENT_NODE: - element_type = "comment" - elif c_node.type == tree.XML_PI_NODE: - element_type = "PI" - elif c_node.type == tree.XML_ENTITY_REF_NODE: - element_type = "entity" - else: - element_type = "element" - if c_node.name is NULL: - name = None - else: - name = funicode(c_node.name) - c_str = tree._getNs(c_node) - ns = funicode(c_str) if c_str is not NULL else None - - cls = lookup.lookup(element_type, doc, ns, name) - if cls is not None: - _validateNodeClass(c_node, cls) - return cls - return _callLookupFallback(lookup, doc, c_node) - - -################################################################################ -# read-only tree based class lookup - -cdef class PythonElementClassLookup(FallbackElementClassLookup): - """PythonElementClassLookup(self, fallback=None) - Element class lookup based on a subclass method. - - This class lookup scheme allows access to the entire XML tree in - read-only mode. To use it, re-implement the ``lookup(self, doc, - root)`` method in a subclass:: - - from lxml import etree, pyclasslookup - - class MyElementClass(etree.ElementBase): - honkey = True - - class MyLookup(pyclasslookup.PythonElementClassLookup): - def lookup(self, doc, root): - if root.tag == "sometag": - return MyElementClass - else: - for child in root: - if child.tag == "someothertag": - return MyElementClass - # delegate to default - return None - - If you return None from this method, the fallback will be called. - - The first argument is the opaque document instance that contains - the Element. The second argument is a lightweight Element proxy - implementation that is only valid during the lookup. Do not try - to keep a reference to it. Once the lookup is done, the proxy - will be invalid. - - Also, you cannot wrap such a read-only Element in an ElementTree, - and you must take care not to keep a reference to them outside of - the `lookup()` method. - - Note that the API of the Element objects is not complete. It is - purely read-only and does not support all features of the normal - `lxml.etree` API (such as XPath, extended slicing or some - iteration methods). - - See https://lxml.de/element_classes.html - """ - def __cinit__(self): - self._lookup_function = _python_class_lookup - - def lookup(self, doc, element): - """lookup(self, doc, element) - - Override this method to implement your own lookup scheme. - """ - return None - -cdef object _python_class_lookup(state, _Document doc, tree.xmlNode* c_node): - cdef PythonElementClassLookup lookup - cdef _ReadOnlyProxy proxy - lookup = state - - proxy = _newReadOnlyProxy(None, c_node) - cls = lookup.lookup(doc, proxy) - _freeReadOnlyProxies(proxy) - - if cls is not None: - _validateNodeClass(c_node, cls) - return cls - return _callLookupFallback(lookup, doc, c_node) - -################################################################################ -# Global setup - -cdef _element_class_lookup_function LOOKUP_ELEMENT_CLASS -cdef object ELEMENT_CLASS_LOOKUP_STATE - -cdef void _setElementClassLookupFunction( - _element_class_lookup_function function, object state): - global LOOKUP_ELEMENT_CLASS, ELEMENT_CLASS_LOOKUP_STATE - if function is NULL: - state = DEFAULT_ELEMENT_CLASS_LOOKUP - function = DEFAULT_ELEMENT_CLASS_LOOKUP._lookup_function - - ELEMENT_CLASS_LOOKUP_STATE = state - LOOKUP_ELEMENT_CLASS = function - -def set_element_class_lookup(ElementClassLookup lookup = None): - """set_element_class_lookup(lookup = None) - - Set the global element class lookup method. - - This defines the main entry point for looking up element implementations. - The standard implementation uses the :class:`ParserBasedElementClassLookup` - to delegate to different lookup schemes for each parser. - - .. warning:: - - This should only be changed by applications, not by library packages. - In most cases, parser specific lookups should be preferred, - which can be configured via - :meth:`~lxml.etree.XMLParser.set_element_class_lookup` - (and the same for HTML parsers). - - Globally replacing the element class lookup by something other than a - :class:`ParserBasedElementClassLookup` will prevent parser specific lookup - schemes from working. Several tools rely on parser specific lookups, - including :mod:`lxml.html` and :mod:`lxml.objectify`. - """ - if lookup is None or lookup._lookup_function is NULL: - _setElementClassLookupFunction(NULL, None) - else: - _setElementClassLookupFunction(lookup._lookup_function, lookup) - -# default setup: parser delegation -cdef ParserBasedElementClassLookup DEFAULT_ELEMENT_CLASS_LOOKUP -DEFAULT_ELEMENT_CLASS_LOOKUP = ParserBasedElementClassLookup() - -set_element_class_lookup(DEFAULT_ELEMENT_CLASS_LOOKUP) diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/cleanup.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/cleanup.pxi deleted file mode 100644 index 8e266b3..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/cleanup.pxi +++ /dev/null @@ -1,215 +0,0 @@ -# functions for tree cleanup and removing elements from subtrees - -def cleanup_namespaces(tree_or_element, top_nsmap=None, keep_ns_prefixes=None): - """cleanup_namespaces(tree_or_element, top_nsmap=None, keep_ns_prefixes=None) - - Remove all namespace declarations from a subtree that are not used - by any of the elements or attributes in that tree. - - If a 'top_nsmap' is provided, it must be a mapping from prefixes - to namespace URIs. These namespaces will be declared on the top - element of the subtree before running the cleanup, which allows - moving namespace declarations to the top of the tree. - - If a 'keep_ns_prefixes' is provided, it must be a list of prefixes. - These prefixes will not be removed as part of the cleanup. - """ - element = _rootNodeOrRaise(tree_or_element) - c_element = element._c_node - - if top_nsmap: - doc = element._doc - # declare namespaces from nsmap, then apply them to the subtree - _setNodeNamespaces(c_element, doc, None, top_nsmap) - moveNodeToDocument(doc, c_element.doc, c_element) - - keep_ns_prefixes = ( - set([_utf8(prefix) for prefix in keep_ns_prefixes]) - if keep_ns_prefixes else None) - - _removeUnusedNamespaceDeclarations(c_element, keep_ns_prefixes) - - -def strip_attributes(tree_or_element, *attribute_names): - """strip_attributes(tree_or_element, *attribute_names) - - Delete all attributes with the provided attribute names from an - Element (or ElementTree) and its descendants. - - Attribute names can contain wildcards as in `_Element.iter`. - - Example usage:: - - strip_attributes(root_element, - 'simpleattr', - '{http://some/ns}attrname', - '{http://other/ns}*') - """ - cdef _MultiTagMatcher matcher - element = _rootNodeOrRaise(tree_or_element) - if not attribute_names: - return - - matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, attribute_names) - matcher.cacheTags(element._doc) - if matcher.rejectsAllAttributes(): - return - _strip_attributes(element._c_node, matcher) - - -cdef _strip_attributes(xmlNode* c_node, _MultiTagMatcher matcher): - cdef xmlAttr* c_attr - cdef xmlAttr* c_next_attr - tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_node, c_node, 1) - if c_node.type == tree.XML_ELEMENT_NODE: - c_attr = c_node.properties - while c_attr is not NULL: - c_next_attr = c_attr.next - if matcher.matchesAttribute(c_attr): - tree.xmlRemoveProp(c_attr) - c_attr = c_next_attr - tree.END_FOR_EACH_ELEMENT_FROM(c_node) - - -def strip_elements(tree_or_element, *tag_names, bint with_tail=True): - """strip_elements(tree_or_element, *tag_names, with_tail=True) - - Delete all elements with the provided tag names from a tree or - subtree. This will remove the elements and their entire subtree, - including all their attributes, text content and descendants. It - will also remove the tail text of the element unless you - explicitly set the ``with_tail`` keyword argument option to False. - - Tag names can contain wildcards as in `_Element.iter`. - - Note that this will not delete the element (or ElementTree root - element) that you passed even if it matches. It will only treat - its descendants. If you want to include the root element, check - its tag name directly before even calling this function. - - Example usage:: - - strip_elements(some_element, - 'simpletagname', # non-namespaced tag - '{http://some/ns}tagname', # namespaced tag - '{http://some/other/ns}*' # any tag from a namespace - lxml.etree.Comment # comments - ) - """ - cdef _MultiTagMatcher matcher - doc = _documentOrRaise(tree_or_element) - element = _rootNodeOrRaise(tree_or_element) - if not tag_names: - return - - matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, tag_names) - matcher.cacheTags(doc) - if matcher.rejectsAll(): - return - - if isinstance(tree_or_element, _ElementTree): - # include PIs and comments next to the root node - if matcher.matchesType(tree.XML_COMMENT_NODE): - _removeSiblings(element._c_node, tree.XML_COMMENT_NODE, with_tail) - if matcher.matchesType(tree.XML_PI_NODE): - _removeSiblings(element._c_node, tree.XML_PI_NODE, with_tail) - _strip_elements(doc, element._c_node, matcher, with_tail) - -cdef _strip_elements(_Document doc, xmlNode* c_node, _MultiTagMatcher matcher, - bint with_tail): - cdef xmlNode* c_child - cdef xmlNode* c_next - - tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_node, c_node, 1) - if c_node.type == tree.XML_ELEMENT_NODE: - # we run through the children here to prevent any problems - # with the tree iteration which would occur if we unlinked the - # c_node itself - c_child = _findChildForwards(c_node, 0) - while c_child is not NULL: - c_next = _nextElement(c_child) - if matcher.matches(c_child): - if c_child.type == tree.XML_ELEMENT_NODE: - if not with_tail: - tree.xmlUnlinkNode(c_child) - _removeNode(doc, c_child) - else: - if with_tail: - _removeText(c_child.next) - tree.xmlUnlinkNode(c_child) - attemptDeallocation(c_child) - c_child = c_next - tree.END_FOR_EACH_ELEMENT_FROM(c_node) - - -def strip_tags(tree_or_element, *tag_names): - """strip_tags(tree_or_element, *tag_names) - - Delete all elements with the provided tag names from a tree or - subtree. This will remove the elements and their attributes, but - *not* their text/tail content or descendants. Instead, it will - merge the text content and children of the element into its - parent. - - Tag names can contain wildcards as in `_Element.iter`. - - Note that this will not delete the element (or ElementTree root - element) that you passed even if it matches. It will only treat - its descendants. - - Example usage:: - - strip_tags(some_element, - 'simpletagname', # non-namespaced tag - '{http://some/ns}tagname', # namespaced tag - '{http://some/other/ns}*' # any tag from a namespace - Comment # comments (including their text!) - ) - """ - cdef _MultiTagMatcher matcher - doc = _documentOrRaise(tree_or_element) - element = _rootNodeOrRaise(tree_or_element) - if not tag_names: - return - - matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, tag_names) - matcher.cacheTags(doc) - if matcher.rejectsAll(): - return - - if isinstance(tree_or_element, _ElementTree): - # include PIs and comments next to the root node - if matcher.matchesType(tree.XML_COMMENT_NODE): - _removeSiblings(element._c_node, tree.XML_COMMENT_NODE, 0) - if matcher.matchesType(tree.XML_PI_NODE): - _removeSiblings(element._c_node, tree.XML_PI_NODE, 0) - _strip_tags(doc, element._c_node, matcher) - -cdef _strip_tags(_Document doc, xmlNode* c_node, _MultiTagMatcher matcher): - cdef xmlNode* c_child - cdef xmlNode* c_next - - tree.BEGIN_FOR_EACH_ELEMENT_FROM(c_node, c_node, 1) - if c_node.type == tree.XML_ELEMENT_NODE: - # we run through the children here to prevent any problems - # with the tree iteration which would occur if we unlinked the - # c_node itself - c_child = _findChildForwards(c_node, 0) - while c_child is not NULL: - if not matcher.matches(c_child): - c_child = _nextElement(c_child) - continue - if c_child.type == tree.XML_ELEMENT_NODE: - c_next = _findChildForwards(c_child, 0) or _nextElement(c_child) - _replaceNodeByChildren(doc, c_child) - if not attemptDeallocation(c_child): - if c_child.nsDef is not NULL: - # make namespaces absolute - moveNodeToDocument(doc, doc._c_doc, c_child) - c_child = c_next - else: - c_next = _nextElement(c_child) - tree.xmlUnlinkNode(c_child) - attemptDeallocation(c_child) - c_child = c_next - tree.END_FOR_EACH_ELEMENT_FROM(c_node) diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/cssselect.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/cssselect.py deleted file mode 100644 index 54cd75a..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/cssselect.py +++ /dev/null @@ -1,101 +0,0 @@ -"""CSS Selectors based on XPath. - -This module supports selecting XML/HTML tags based on CSS selectors. -See the `CSSSelector` class for details. - -This is a thin wrapper around cssselect 0.7 or later. -""" - - -from . import etree -try: - import cssselect as external_cssselect -except ImportError: - raise ImportError( - 'cssselect does not seem to be installed. ' - 'See https://pypi.org/project/cssselect/') - - -SelectorSyntaxError = external_cssselect.SelectorSyntaxError -ExpressionError = external_cssselect.ExpressionError -SelectorError = external_cssselect.SelectorError - - -__all__ = ['SelectorSyntaxError', 'ExpressionError', 'SelectorError', - 'CSSSelector'] - - -class LxmlTranslator(external_cssselect.GenericTranslator): - """ - A custom CSS selector to XPath translator with lxml-specific extensions. - """ - def xpath_contains_function(self, xpath, function): - # Defined there, removed in later drafts: - # http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#content-selectors - if function.argument_types() not in (['STRING'], ['IDENT']): - raise ExpressionError( - "Expected a single string or ident for :contains(), got %r" - % function.arguments) - value = function.arguments[0].value - return xpath.add_condition( - 'contains(__lxml_internal_css:lower-case(string(.)), %s)' - % self.xpath_literal(value.lower())) - - -class LxmlHTMLTranslator(LxmlTranslator, external_cssselect.HTMLTranslator): - """ - lxml extensions + HTML support. - """ - - -def _make_lower_case(context, s): - return s.lower() - -ns = etree.FunctionNamespace('http://codespeak.net/lxml/css/') -ns.prefix = '__lxml_internal_css' -ns['lower-case'] = _make_lower_case - - -class CSSSelector(etree.XPath): - """A CSS selector. - - Usage:: - - >>> from lxml import etree, cssselect - >>> select = cssselect.CSSSelector("a tag > child") - - >>> root = etree.XML("TEXT") - >>> [ el.tag for el in select(root) ] - ['child'] - - To use CSS namespaces, you need to pass a prefix-to-namespace - mapping as ``namespaces`` keyword argument:: - - >>> rdfns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' - >>> select_ns = cssselect.CSSSelector('root > rdf|Description', - ... namespaces={'rdf': rdfns}) - - >>> rdf = etree.XML(( - ... '' - ... 'blah' - ... '') % rdfns) - >>> [(el.tag, el.text) for el in select_ns(rdf)] - [('{http://www.w3.org/1999/02/22-rdf-syntax-ns#}Description', 'blah')] - - """ - def __init__(self, css, namespaces=None, translator='xml'): - if translator == 'xml': - translator = LxmlTranslator() - elif translator == 'html': - translator = LxmlHTMLTranslator() - elif translator == 'xhtml': - translator = LxmlHTMLTranslator(xhtml=True) - path = translator.css_to_xpath(css) - super().__init__(path, namespaces=namespaces) - self.css = css - - def __repr__(self): - return '<%s %x for %r>' % ( - self.__class__.__name__, - abs(id(self)), - self.css) diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/debug.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/debug.pxi deleted file mode 100644 index d728e84..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/debug.pxi +++ /dev/null @@ -1,36 +0,0 @@ -@cython.final -@cython.internal -cdef class _MemDebug: - """Debugging support for the memory allocation in libxml2. - """ - def bytes_used(self): - """bytes_used(self) - - Returns the total amount of memory (in bytes) currently used by libxml2. - Note that libxml2 constrains this value to a C int, which limits - the accuracy on 64 bit systems. - """ - return tree.xmlMemUsed() - - def blocks_used(self): - """blocks_used(self) - - Returns the total number of memory blocks currently allocated by libxml2. - Note that libxml2 constrains this value to a C int, which limits - the accuracy on 64 bit systems. - """ - return tree.xmlMemBlocks() - - def dict_size(self): - """dict_size(self) - - Returns the current size of the global name dictionary used by libxml2 - for the current thread. Each thread has its own dictionary. - """ - c_dict = __GLOBAL_PARSER_CONTEXT._getThreadDict(NULL) - if c_dict is NULL: - raise MemoryError() - return tree.xmlDictSize(c_dict) - - -memory_debugger = _MemDebug() diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/docloader.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/docloader.pxi deleted file mode 100644 index 7b38f43..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/docloader.pxi +++ /dev/null @@ -1,178 +0,0 @@ -# Custom resolver API - -ctypedef enum _InputDocumentDataType: - PARSER_DATA_INVALID - PARSER_DATA_EMPTY - PARSER_DATA_STRING - PARSER_DATA_FILENAME - PARSER_DATA_FILE - -@cython.final -@cython.internal -cdef class _InputDocument: - cdef _InputDocumentDataType _type - cdef bytes _data_bytes - cdef object _filename - cdef object _file - cdef bint _close_file - - def __cinit__(self): - self._type = PARSER_DATA_INVALID - - -cdef class Resolver: - "This is the base class of all resolvers." - def resolve(self, system_url, public_id, context): - """resolve(self, system_url, public_id, context) - - Override this method to resolve an external source by - ``system_url`` and ``public_id``. The third argument is an - opaque context object. - - Return the result of one of the ``resolve_*()`` methods. - """ - return None - - def resolve_empty(self, context): - """resolve_empty(self, context) - - Return an empty input document. - - Pass context as parameter. - """ - cdef _InputDocument doc_ref - doc_ref = _InputDocument() - doc_ref._type = PARSER_DATA_EMPTY - return doc_ref - - def resolve_string(self, string, context, *, base_url=None): - """resolve_string(self, string, context, base_url=None) - - Return a parsable string as input document. - - Pass data string and context as parameters. You can pass the - source URL or filename through the ``base_url`` keyword - argument. - """ - cdef _InputDocument doc_ref - if isinstance(string, unicode): - string = (string).encode('utf8') - elif not isinstance(string, bytes): - raise TypeError, "argument must be a byte string or unicode string" - doc_ref = _InputDocument() - doc_ref._type = PARSER_DATA_STRING - doc_ref._data_bytes = string - if base_url is not None: - doc_ref._filename = _encodeFilename(base_url) - return doc_ref - - def resolve_filename(self, filename, context): - """resolve_filename(self, filename, context) - - Return the name of a parsable file as input document. - - Pass filename and context as parameters. You can also pass a - URL with an HTTP, FTP or file target. - """ - cdef _InputDocument doc_ref - doc_ref = _InputDocument() - doc_ref._type = PARSER_DATA_FILENAME - doc_ref._filename = _encodeFilename(filename) - return doc_ref - - def resolve_file(self, f, context, *, base_url=None, bint close=True): - """resolve_file(self, f, context, base_url=None, close=True) - - Return an open file-like object as input document. - - Pass open file and context as parameters. You can pass the - base URL or filename of the file through the ``base_url`` - keyword argument. If the ``close`` flag is True (the - default), the file will be closed after reading. - - Note that using ``.resolve_filename()`` is more efficient, - especially in threaded environments. - """ - cdef _InputDocument doc_ref - try: - f.read - except AttributeError: - raise TypeError, "Argument is not a file-like object" - doc_ref = _InputDocument() - doc_ref._type = PARSER_DATA_FILE - if base_url is not None: - doc_ref._filename = _encodeFilename(base_url) - else: - doc_ref._filename = _getFilenameForFile(f) - doc_ref._close_file = close - doc_ref._file = f - return doc_ref - -@cython.final -@cython.internal -cdef class _ResolverRegistry: - cdef object _resolvers - cdef Resolver _default_resolver - def __cinit__(self, Resolver default_resolver=None): - self._resolvers = set() - self._default_resolver = default_resolver - - def add(self, Resolver resolver not None): - """add(self, resolver) - - Register a resolver. - - For each requested entity, the 'resolve' method of the resolver will - be called and the result will be passed to the parser. If this method - returns None, the request will be delegated to other resolvers or the - default resolver. The resolvers will be tested in an arbitrary order - until the first match is found. - """ - self._resolvers.add(resolver) - - def remove(self, resolver): - "remove(self, resolver)" - self._resolvers.discard(resolver) - - cdef _ResolverRegistry _copy(self): - cdef _ResolverRegistry registry - registry = _ResolverRegistry(self._default_resolver) - registry._resolvers = self._resolvers.copy() - return registry - - def copy(self): - "copy(self)" - return self._copy() - - def resolve(self, system_url, public_id, context): - "resolve(self, system_url, public_id, context)" - for resolver in self._resolvers: - result = resolver.resolve(system_url, public_id, context) - if result is not None: - return result - if self._default_resolver is None: - return None - return self._default_resolver.resolve(system_url, public_id, context) - - def __repr__(self): - return repr(self._resolvers) - - -@cython.internal -cdef class _ResolverContext(_ExceptionContext): - cdef _ResolverRegistry _resolvers - cdef _TempStore _storage - - cdef int clear(self) except -1: - _ExceptionContext.clear(self) - self._storage.clear() - return 0 - - -cdef _initResolverContext(_ResolverContext context, - _ResolverRegistry resolvers): - if resolvers is None: - context._resolvers = _ResolverRegistry() - else: - context._resolvers = resolvers - context._storage = _TempStore() diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/doctestcompare.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/doctestcompare.py deleted file mode 100644 index 8099771..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/doctestcompare.py +++ /dev/null @@ -1,488 +0,0 @@ -""" -lxml-based doctest output comparison. - -Note: normally, you should just import the `lxml.usedoctest` and -`lxml.html.usedoctest` modules from within a doctest, instead of this -one:: - - >>> import lxml.usedoctest # for XML output - - >>> import lxml.html.usedoctest # for HTML output - -To use this module directly, you must call ``lxmldoctest.install()``, -which will cause doctest to use this in all subsequent calls. - -This changes the way output is checked and comparisons are made for -XML or HTML-like content. - -XML or HTML content is noticed because the example starts with ``<`` -(it's HTML if it starts with ```` or include an ``any`` -attribute in the tag. An ``any`` tag matches any tag, while the -attribute matches any and all attributes. - -When a match fails, the reformatted example and gotten text is -displayed (indented), and a rough diff-like output is given. Anything -marked with ``+`` is in the output but wasn't supposed to be, and -similarly ``-`` means its in the example but wasn't in the output. - -You can disable parsing on one line with ``# doctest:+NOPARSE_MARKUP`` -""" - -from lxml import etree -import sys -import re -import doctest -try: - from html import escape as html_escape -except ImportError: - from cgi import escape as html_escape - -__all__ = ['PARSE_HTML', 'PARSE_XML', 'NOPARSE_MARKUP', 'LXMLOutputChecker', - 'LHTMLOutputChecker', 'install', 'temp_install'] - -PARSE_HTML = doctest.register_optionflag('PARSE_HTML') -PARSE_XML = doctest.register_optionflag('PARSE_XML') -NOPARSE_MARKUP = doctest.register_optionflag('NOPARSE_MARKUP') - -OutputChecker = doctest.OutputChecker - -def strip(v): - if v is None: - return None - else: - return v.strip() - -def norm_whitespace(v): - return _norm_whitespace_re.sub(' ', v) - -_html_parser = etree.HTMLParser(recover=False, remove_blank_text=True) - -def html_fromstring(html): - return etree.fromstring(html, _html_parser) - -# We use this to distinguish repr()s from elements: -_repr_re = re.compile(r'^<[^>]+ (at|object) ') -_norm_whitespace_re = re.compile(r'[ \t\n][ \t\n]+') - -class LXMLOutputChecker(OutputChecker): - - empty_tags = ( - 'param', 'img', 'area', 'br', 'basefont', 'input', - 'base', 'meta', 'link', 'col') - - def get_default_parser(self): - return etree.XML - - def check_output(self, want, got, optionflags): - alt_self = getattr(self, '_temp_override_self', None) - if alt_self is not None: - super_method = self._temp_call_super_check_output - self = alt_self - else: - super_method = OutputChecker.check_output - parser = self.get_parser(want, got, optionflags) - if not parser: - return super_method( - self, want, got, optionflags) - try: - want_doc = parser(want) - except etree.XMLSyntaxError: - return False - try: - got_doc = parser(got) - except etree.XMLSyntaxError: - return False - return self.compare_docs(want_doc, got_doc) - - def get_parser(self, want, got, optionflags): - parser = None - if NOPARSE_MARKUP & optionflags: - return None - if PARSE_HTML & optionflags: - parser = html_fromstring - elif PARSE_XML & optionflags: - parser = etree.XML - elif (want.strip().lower().startswith('' % el.tag - return '<%s %s>' % (el.tag, ' '.join(attrs)) - - def format_end_tag(self, el): - if isinstance(el, etree.CommentBase): - # FIXME: probably PIs should be handled specially too? - return '-->' - return '' % el.tag - - def collect_diff(self, want, got, html, indent): - parts = [] - if not len(want) and not len(got): - parts.append(' '*indent) - parts.append(self.collect_diff_tag(want, got)) - if not self.html_empty_tag(got, html): - parts.append(self.collect_diff_text(want.text, got.text)) - parts.append(self.collect_diff_end_tag(want, got)) - parts.append(self.collect_diff_text(want.tail, got.tail)) - parts.append('\n') - return ''.join(parts) - parts.append(' '*indent) - parts.append(self.collect_diff_tag(want, got)) - parts.append('\n') - if strip(want.text) or strip(got.text): - parts.append(' '*indent) - parts.append(self.collect_diff_text(want.text, got.text)) - parts.append('\n') - want_children = list(want) - got_children = list(got) - while want_children or got_children: - if not want_children: - parts.append(self.format_doc(got_children.pop(0), html, indent+2, '+')) - continue - if not got_children: - parts.append(self.format_doc(want_children.pop(0), html, indent+2, '-')) - continue - parts.append(self.collect_diff( - want_children.pop(0), got_children.pop(0), html, indent+2)) - parts.append(' '*indent) - parts.append(self.collect_diff_end_tag(want, got)) - parts.append('\n') - if strip(want.tail) or strip(got.tail): - parts.append(' '*indent) - parts.append(self.collect_diff_text(want.tail, got.tail)) - parts.append('\n') - return ''.join(parts) - - def collect_diff_tag(self, want, got): - if not self.tag_compare(want.tag, got.tag): - tag = '%s (got: %s)' % (want.tag, got.tag) - else: - tag = got.tag - attrs = [] - any = want.tag == 'any' or 'any' in want.attrib - for name, value in sorted(got.attrib.items()): - if name not in want.attrib and not any: - attrs.append('+%s="%s"' % (name, self.format_text(value, False))) - else: - if name in want.attrib: - text = self.collect_diff_text(want.attrib[name], value, False) - else: - text = self.format_text(value, False) - attrs.append('%s="%s"' % (name, text)) - if not any: - for name, value in sorted(want.attrib.items()): - if name in got.attrib: - continue - attrs.append('-%s="%s"' % (name, self.format_text(value, False))) - if attrs: - tag = '<%s %s>' % (tag, ' '.join(attrs)) - else: - tag = '<%s>' % tag - return tag - - def collect_diff_end_tag(self, want, got): - if want.tag != got.tag: - tag = '%s (got: %s)' % (want.tag, got.tag) - else: - tag = got.tag - return '' % tag - - def collect_diff_text(self, want, got, strip=True): - if self.text_compare(want, got, strip): - if not got: - return '' - return self.format_text(got, strip) - text = '%s (got: %s)' % (want, got) - return self.format_text(text, strip) - -class LHTMLOutputChecker(LXMLOutputChecker): - def get_default_parser(self): - return html_fromstring - -def install(html=False): - """ - Install doctestcompare for all future doctests. - - If html is true, then by default the HTML parser will be used; - otherwise the XML parser is used. - """ - if html: - doctest.OutputChecker = LHTMLOutputChecker - else: - doctest.OutputChecker = LXMLOutputChecker - -def temp_install(html=False, del_module=None): - """ - Use this *inside* a doctest to enable this checker for this - doctest only. - - If html is true, then by default the HTML parser will be used; - otherwise the XML parser is used. - """ - if html: - Checker = LHTMLOutputChecker - else: - Checker = LXMLOutputChecker - frame = _find_doctest_frame() - dt_self = frame.f_locals['self'] - checker = Checker() - old_checker = dt_self._checker - dt_self._checker = checker - # The unfortunate thing is that there is a local variable 'check' - # in the function that runs the doctests, that is a bound method - # into the output checker. We have to update that. We can't - # modify the frame, so we have to modify the object in place. The - # only way to do this is to actually change the func_code - # attribute of the method. We change it, and then wait for - # __record_outcome to be run, which signals the end of the __run - # method, at which point we restore the previous check_output - # implementation. - check_func = frame.f_locals['check'].__func__ - checker_check_func = checker.check_output.__func__ - # Because we can't patch up func_globals, this is the only global - # in check_output that we care about: - doctest.etree = etree - _RestoreChecker(dt_self, old_checker, checker, - check_func, checker_check_func, - del_module) - -class _RestoreChecker: - def __init__(self, dt_self, old_checker, new_checker, check_func, clone_func, - del_module): - self.dt_self = dt_self - self.checker = old_checker - self.checker._temp_call_super_check_output = self.call_super - self.checker._temp_override_self = new_checker - self.check_func = check_func - self.clone_func = clone_func - self.del_module = del_module - self.install_clone() - self.install_dt_self() - def install_clone(self): - self.func_code = self.check_func.__code__ - self.func_globals = self.check_func.__globals__ - self.check_func.__code__ = self.clone_func.__code__ - def uninstall_clone(self): - self.check_func.__code__ = self.func_code - def install_dt_self(self): - self.prev_func = self.dt_self._DocTestRunner__record_outcome - self.dt_self._DocTestRunner__record_outcome = self - def uninstall_dt_self(self): - self.dt_self._DocTestRunner__record_outcome = self.prev_func - def uninstall_module(self): - if self.del_module: - import sys - del sys.modules[self.del_module] - if '.' in self.del_module: - package, module = self.del_module.rsplit('.', 1) - package_mod = sys.modules[package] - delattr(package_mod, module) - def __call__(self, *args, **kw): - self.uninstall_clone() - self.uninstall_dt_self() - del self.checker._temp_override_self - del self.checker._temp_call_super_check_output - result = self.prev_func(*args, **kw) - self.uninstall_module() - return result - def call_super(self, *args, **kw): - self.uninstall_clone() - try: - return self.check_func(*args, **kw) - finally: - self.install_clone() - -def _find_doctest_frame(): - import sys - frame = sys._getframe(1) - while frame: - l = frame.f_locals - if 'BOOM' in l: - # Sign of doctest - return frame - frame = frame.f_back - raise LookupError( - "Could not find doctest (only use this function *inside* a doctest)") - -__test__ = { - 'basic': ''' - >>> temp_install() - >>> print """stuff""" - ... - >>> print """""" - - - - >>> print """blahblahblah""" # doctest: +NOPARSE_MARKUP, +ELLIPSIS - ...foo /> - '''} - -if __name__ == '__main__': - import doctest - doctest.testmod() - - diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/dtd.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/dtd.pxi deleted file mode 100644 index ee1b3d4..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/dtd.pxi +++ /dev/null @@ -1,479 +0,0 @@ -# support for DTD validation -from lxml.includes cimport dtdvalid - -cdef class DTDError(LxmlError): - """Base class for DTD errors. - """ - -cdef class DTDParseError(DTDError): - """Error while parsing a DTD. - """ - -cdef class DTDValidateError(DTDError): - """Error while validating an XML document with a DTD. - """ - - -cdef inline int _assertValidDTDNode(node, void *c_node) except -1: - assert c_node is not NULL, "invalid DTD proxy at %s" % id(node) - - -@cython.final -@cython.internal -@cython.freelist(8) -cdef class _DTDElementContentDecl: - cdef DTD _dtd - cdef tree.xmlElementContent* _c_node - - def __repr__(self): - return "<%s.%s object name=%r type=%r occur=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.type, self.occur, id(self)) - - @property - def name(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.name) - - @property - def type(self): - _assertValidDTDNode(self, self._c_node) - cdef int type = self._c_node.type - if type == tree.XML_ELEMENT_CONTENT_PCDATA: - return "pcdata" - elif type == tree.XML_ELEMENT_CONTENT_ELEMENT: - return "element" - elif type == tree.XML_ELEMENT_CONTENT_SEQ: - return "seq" - elif type == tree.XML_ELEMENT_CONTENT_OR: - return "or" - else: - return None - - @property - def occur(self): - _assertValidDTDNode(self, self._c_node) - cdef int occur = self._c_node.ocur - if occur == tree.XML_ELEMENT_CONTENT_ONCE: - return "once" - elif occur == tree.XML_ELEMENT_CONTENT_OPT: - return "opt" - elif occur == tree.XML_ELEMENT_CONTENT_MULT: - return "mult" - elif occur == tree.XML_ELEMENT_CONTENT_PLUS: - return "plus" - else: - return None - - @property - def left(self): - _assertValidDTDNode(self, self._c_node) - c1 = self._c_node.c1 - if c1: - node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl) - node._dtd = self._dtd - node._c_node = c1 - return node - else: - return None - - @property - def right(self): - _assertValidDTDNode(self, self._c_node) - c2 = self._c_node.c2 - if c2: - node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl) - node._dtd = self._dtd - node._c_node = c2 - return node - else: - return None - - -@cython.final -@cython.internal -@cython.freelist(8) -cdef class _DTDAttributeDecl: - cdef DTD _dtd - cdef tree.xmlAttribute* _c_node - - def __repr__(self): - return "<%s.%s object name=%r elemname=%r prefix=%r type=%r default=%r default_value=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.elemname, self.prefix, self.type, self.default, self.default_value, id(self)) - - @property - def name(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.name) - - @property - def elemname(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.elem) - - @property - def prefix(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.prefix) - - @property - def type(self): - _assertValidDTDNode(self, self._c_node) - cdef int type = self._c_node.atype - if type == tree.XML_ATTRIBUTE_CDATA: - return "cdata" - elif type == tree.XML_ATTRIBUTE_ID: - return "id" - elif type == tree.XML_ATTRIBUTE_IDREF: - return "idref" - elif type == tree.XML_ATTRIBUTE_IDREFS: - return "idrefs" - elif type == tree.XML_ATTRIBUTE_ENTITY: - return "entity" - elif type == tree.XML_ATTRIBUTE_ENTITIES: - return "entities" - elif type == tree.XML_ATTRIBUTE_NMTOKEN: - return "nmtoken" - elif type == tree.XML_ATTRIBUTE_NMTOKENS: - return "nmtokens" - elif type == tree.XML_ATTRIBUTE_ENUMERATION: - return "enumeration" - elif type == tree.XML_ATTRIBUTE_NOTATION: - return "notation" - else: - return None - - @property - def default(self): - _assertValidDTDNode(self, self._c_node) - cdef int default = self._c_node.def_ - if default == tree.XML_ATTRIBUTE_NONE: - return "none" - elif default == tree.XML_ATTRIBUTE_REQUIRED: - return "required" - elif default == tree.XML_ATTRIBUTE_IMPLIED: - return "implied" - elif default == tree.XML_ATTRIBUTE_FIXED: - return "fixed" - else: - return None - - @property - def default_value(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.defaultValue) - - def itervalues(self): - _assertValidDTDNode(self, self._c_node) - cdef tree.xmlEnumeration *c_node = self._c_node.tree - while c_node is not NULL: - yield funicode(c_node.name) - c_node = c_node.next - - def values(self): - return list(self.itervalues()) - - -@cython.final -@cython.internal -@cython.freelist(8) -cdef class _DTDElementDecl: - cdef DTD _dtd - cdef tree.xmlElement* _c_node - - def __repr__(self): - return "<%s.%s object name=%r prefix=%r type=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, self.prefix, self.type, id(self)) - - @property - def name(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.name) - - @property - def prefix(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.prefix) - - @property - def type(self): - _assertValidDTDNode(self, self._c_node) - cdef int type = self._c_node.etype - if type == tree.XML_ELEMENT_TYPE_UNDEFINED: - return "undefined" - elif type == tree.XML_ELEMENT_TYPE_EMPTY: - return "empty" - elif type == tree.XML_ELEMENT_TYPE_ANY: - return "any" - elif type == tree.XML_ELEMENT_TYPE_MIXED: - return "mixed" - elif type == tree.XML_ELEMENT_TYPE_ELEMENT: - return "element" - else: - return None - - @property - def content(self): - _assertValidDTDNode(self, self._c_node) - cdef tree.xmlElementContent *content = self._c_node.content - if content: - node = <_DTDElementContentDecl>_DTDElementContentDecl.__new__(_DTDElementContentDecl) - node._dtd = self._dtd - node._c_node = content - return node - else: - return None - - def iterattributes(self): - _assertValidDTDNode(self, self._c_node) - cdef tree.xmlAttribute *c_node = self._c_node.attributes - while c_node: - node = <_DTDAttributeDecl>_DTDAttributeDecl.__new__(_DTDAttributeDecl) - node._dtd = self._dtd - node._c_node = c_node - yield node - c_node = c_node.nexth - - def attributes(self): - return list(self.iterattributes()) - - -@cython.final -@cython.internal -@cython.freelist(8) -cdef class _DTDEntityDecl: - cdef DTD _dtd - cdef tree.xmlEntity* _c_node - def __repr__(self): - return "<%s.%s object name=%r at 0x%x>" % (self.__class__.__module__, self.__class__.__name__, self.name, id(self)) - - @property - def name(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.name) - - @property - def orig(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.orig) - - @property - def content(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.content) - - @property - def system_url(self): - _assertValidDTDNode(self, self._c_node) - return funicodeOrNone(self._c_node.SystemID) - - -################################################################################ -# DTD - -cdef class DTD(_Validator): - """DTD(self, file=None, external_id=None) - A DTD validator. - - Can load from filesystem directly given a filename or file-like object. - Alternatively, pass the keyword parameter ``external_id`` to load from a - catalog. - """ - cdef tree.xmlDtd* _c_dtd - def __init__(self, file=None, *, external_id=None): - _Validator.__init__(self) - if file is not None: - file = _getFSPathOrObject(file) - if _isString(file): - file = _encodeFilename(file) - with self._error_log: - orig_loader = _register_document_loader() - self._c_dtd = xmlparser.xmlParseDTD(NULL, _xcstr(file)) - _reset_document_loader(orig_loader) - elif hasattr(file, 'read'): - orig_loader = _register_document_loader() - self._c_dtd = _parseDtdFromFilelike(file) - _reset_document_loader(orig_loader) - else: - raise DTDParseError, "file must be a filename, file-like or path-like object" - elif external_id is not None: - external_id_utf = _utf8(external_id) - with self._error_log: - orig_loader = _register_document_loader() - self._c_dtd = xmlparser.xmlParseDTD(external_id_utf, NULL) - _reset_document_loader(orig_loader) - else: - raise DTDParseError, "either filename or external ID required" - - if self._c_dtd is NULL: - raise DTDParseError( - self._error_log._buildExceptionMessage("error parsing DTD"), - self._error_log) - - @property - def name(self): - if self._c_dtd is NULL: - return None - return funicodeOrNone(self._c_dtd.name) - - @property - def external_id(self): - if self._c_dtd is NULL: - return None - return funicodeOrNone(self._c_dtd.ExternalID) - - @property - def system_url(self): - if self._c_dtd is NULL: - return None - return funicodeOrNone(self._c_dtd.SystemID) - - def iterelements(self): - cdef tree.xmlNode *c_node = self._c_dtd.children if self._c_dtd is not NULL else NULL - while c_node is not NULL: - if c_node.type == tree.XML_ELEMENT_DECL: - node = _DTDElementDecl() - node._dtd = self - node._c_node = c_node - yield node - c_node = c_node.next - - def elements(self): - return list(self.iterelements()) - - def iterentities(self): - cdef tree.xmlNode *c_node = self._c_dtd.children if self._c_dtd is not NULL else NULL - while c_node is not NULL: - if c_node.type == tree.XML_ENTITY_DECL: - node = _DTDEntityDecl() - node._dtd = self - node._c_node = c_node - yield node - c_node = c_node.next - - def entities(self): - return list(self.iterentities()) - - def __dealloc__(self): - tree.xmlFreeDtd(self._c_dtd) - - def __call__(self, etree): - """__call__(self, etree) - - Validate doc using the DTD. - - Returns true if the document is valid, false if not. - """ - cdef _Document doc - cdef _Element root_node - cdef xmlDoc* c_doc - cdef dtdvalid.xmlValidCtxt* valid_ctxt - cdef int ret = -1 - - assert self._c_dtd is not NULL, "DTD not initialised" - doc = _documentOrRaise(etree) - root_node = _rootNodeOrRaise(etree) - - valid_ctxt = dtdvalid.xmlNewValidCtxt() - if valid_ctxt is NULL: - raise DTDError("Failed to create validation context") - - # work around error reporting bug in libxml2 <= 2.9.1 (and later?) - # https://bugzilla.gnome.org/show_bug.cgi?id=724903 - valid_ctxt.error = _nullGenericErrorFunc - valid_ctxt.userData = NULL - - try: - with self._error_log: - c_doc = _fakeRootDoc(doc._c_doc, root_node._c_node) - ret = dtdvalid.xmlValidateDtd(valid_ctxt, c_doc, self._c_dtd) - _destroyFakeDoc(doc._c_doc, c_doc) - finally: - dtdvalid.xmlFreeValidCtxt(valid_ctxt) - - if ret == -1: - raise DTDValidateError("Internal error in DTD validation", - self._error_log) - return ret == 1 - - -cdef tree.xmlDtd* _parseDtdFromFilelike(file) except NULL: - cdef _ExceptionContext exc_context - cdef _FileReaderContext dtd_parser - cdef _ErrorLog error_log - cdef tree.xmlDtd* c_dtd = NULL - exc_context = _ExceptionContext() - dtd_parser = _FileReaderContext(file, exc_context, None) - error_log = _ErrorLog() - - with error_log: - c_dtd = dtd_parser._readDtd() - - exc_context._raise_if_stored() - if c_dtd is NULL: - raise DTDParseError("error parsing DTD", error_log) - return c_dtd - -cdef DTD _dtdFactory(tree.xmlDtd* c_dtd): - # do not run through DTD.__init__()! - cdef DTD dtd - if c_dtd is NULL: - return None - dtd = DTD.__new__(DTD) - dtd._c_dtd = _copyDtd(c_dtd) - _Validator.__init__(dtd) - return dtd - - -cdef tree.xmlDtd* _copyDtd(tree.xmlDtd* c_orig_dtd) except NULL: - """ - Copy a DTD. libxml2 (currently) fails to set up the element->attributes - links when copying DTDs, so we have to rebuild them here. - """ - c_dtd = tree.xmlCopyDtd(c_orig_dtd) - if not c_dtd: - raise MemoryError - cdef tree.xmlNode* c_node = c_dtd.children - while c_node: - if c_node.type == tree.XML_ATTRIBUTE_DECL: - _linkDtdAttribute(c_dtd, c_node) - c_node = c_node.next - return c_dtd - - -cdef void _linkDtdAttribute(tree.xmlDtd* c_dtd, tree.xmlAttribute* c_attr) noexcept: - """ - Create the link to the DTD attribute declaration from the corresponding - element declaration. - """ - c_elem = dtdvalid.xmlGetDtdElementDesc(c_dtd, c_attr.elem) - if not c_elem: - # no such element? something is wrong with the DTD ... - return - c_pos = c_elem.attributes - if not c_pos: - c_elem.attributes = c_attr - c_attr.nexth = NULL - return - # libxml2 keeps namespace declarations first, and we need to make - # sure we don't re-insert attributes that are already there - if _isDtdNsDecl(c_attr): - if not _isDtdNsDecl(c_pos): - c_elem.attributes = c_attr - c_attr.nexth = c_pos - return - while c_pos != c_attr and c_pos.nexth and _isDtdNsDecl(c_pos.nexth): - c_pos = c_pos.nexth - else: - # append at end - while c_pos != c_attr and c_pos.nexth: - c_pos = c_pos.nexth - if c_pos == c_attr: - return - c_attr.nexth = c_pos.nexth - c_pos.nexth = c_attr - - -cdef bint _isDtdNsDecl(tree.xmlAttribute* c_attr) noexcept: - if cstring_h.strcmp(c_attr.name, "xmlns") == 0: - return True - if (c_attr.prefix is not NULL and - cstring_h.strcmp(c_attr.prefix, "xmlns") == 0): - return True - return False diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.cpython-39-darwin.so b/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.cpython-39-darwin.so deleted file mode 100755 index 9c3769e..0000000 Binary files a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.cpython-39-darwin.so and /dev/null differ diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.h b/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.h deleted file mode 100644 index 17b99a7..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.h +++ /dev/null @@ -1,244 +0,0 @@ -/* Generated by Cython 3.1.4 */ - -#ifndef __PYX_HAVE__lxml__etree -#define __PYX_HAVE__lxml__etree - -#include "Python.h" -struct LxmlDocument; -struct LxmlElement; -struct LxmlElementTree; -struct LxmlElementTagMatcher; -struct LxmlElementIterator; -struct LxmlElementBase; -struct LxmlElementClassLookup; -struct LxmlFallbackElementClassLookup; - -/* "lxml/etree.pyx":451 - * - * # type of a function that steps from node to node - * ctypedef public xmlNode* (*_node_to_node_function)(xmlNode*) # <<<<<<<<<<<<<< - * - * -*/ -typedef xmlNode *(*_node_to_node_function)(xmlNode *); - -/* "lxml/etree.pyx":465 - * # Public Python API - * - * @cython.final # <<<<<<<<<<<<<< - * @cython.freelist(8) - * cdef public class _Document [ type LxmlDocumentType, object LxmlDocument ]: -*/ -struct LxmlDocument { - PyObject_HEAD - struct __pyx_vtabstruct_4lxml_5etree__Document *__pyx_vtab; - int _ns_counter; - PyObject *_prefix_tail; - xmlDoc *_c_doc; - struct __pyx_obj_4lxml_5etree__BaseParser *_parser; -}; - -/* "lxml/etree.pyx":817 - * - * - * @cython.no_gc_clear # <<<<<<<<<<<<<< - * cdef public class _Element [ type LxmlElementType, object LxmlElement ]: - * """Element class. -*/ -struct LxmlElement { - PyObject_HEAD - struct LxmlDocument *_doc; - xmlNode *_c_node; - PyObject *_tag; -}; - -/* "lxml/etree.pyx":1991 - * - * - * cdef public class _ElementTree [ type LxmlElementTreeType, # <<<<<<<<<<<<<< - * object LxmlElementTree ]: - * cdef _Document _doc -*/ -struct LxmlElementTree { - PyObject_HEAD - struct __pyx_vtabstruct_4lxml_5etree__ElementTree *__pyx_vtab; - struct LxmlDocument *_doc; - struct LxmlElement *_context_node; -}; - -/* "lxml/etree.pyx":2765 - * - * - * cdef public class _ElementTagMatcher [ object LxmlElementTagMatcher, # <<<<<<<<<<<<<< - * type LxmlElementTagMatcherType ]: - * """ -*/ -struct LxmlElementTagMatcher { - PyObject_HEAD - struct __pyx_vtabstruct_4lxml_5etree__ElementTagMatcher *__pyx_vtab; - PyObject *_pystrings; - int _node_type; - char *_href; - char *_name; -}; - -/* "lxml/etree.pyx":2796 - * self._name = NULL - * - * cdef public class _ElementIterator(_ElementTagMatcher) [ # <<<<<<<<<<<<<< - * object LxmlElementIterator, type LxmlElementIteratorType ]: - * """ -*/ -struct LxmlElementIterator { - struct LxmlElementTagMatcher __pyx_base; - struct LxmlElement *_node; - _node_to_node_function _next_element; -}; - -/* "src/lxml/classlookup.pxi":6 - * # Custom Element classes - * - * cdef public class ElementBase(_Element) [ type LxmlElementBaseType, # <<<<<<<<<<<<<< - * object LxmlElementBase ]: - * """ElementBase(*children, attrib=None, nsmap=None, **_extra) -*/ -struct LxmlElementBase { - struct LxmlElement __pyx_base; -}; - -/* "src/lxml/classlookup.pxi":210 - * # Element class lookup - * - * ctypedef public object (*_element_class_lookup_function)(object, _Document, xmlNode*) # <<<<<<<<<<<<<< - * - * # class to store element class lookup functions -*/ -typedef PyObject *(*_element_class_lookup_function)(PyObject *, struct LxmlDocument *, xmlNode *); - -/* "src/lxml/classlookup.pxi":213 - * - * # class to store element class lookup functions - * cdef public class ElementClassLookup [ type LxmlElementClassLookupType, # <<<<<<<<<<<<<< - * object LxmlElementClassLookup ]: - * """ElementClassLookup(self) -*/ -struct LxmlElementClassLookup { - PyObject_HEAD - _element_class_lookup_function _lookup_function; -}; - -/* "src/lxml/classlookup.pxi":221 - * - * - * cdef public class FallbackElementClassLookup(ElementClassLookup) \ # <<<<<<<<<<<<<< - * [ type LxmlFallbackElementClassLookupType, - * object LxmlFallbackElementClassLookup ]: -*/ -struct LxmlFallbackElementClassLookup { - struct LxmlElementClassLookup __pyx_base; - struct __pyx_vtabstruct_4lxml_5etree_FallbackElementClassLookup *__pyx_vtab; - struct LxmlElementClassLookup *fallback; - _element_class_lookup_function _fallback_function; -}; - -#ifndef __PYX_HAVE_API__lxml__etree - -#ifdef CYTHON_EXTERN_C - #undef __PYX_EXTERN_C - #define __PYX_EXTERN_C CYTHON_EXTERN_C -#elif defined(__PYX_EXTERN_C) - #ifdef _MSC_VER - #pragma message ("Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead.") - #else - #warning Please do not define the '__PYX_EXTERN_C' macro externally. Use 'CYTHON_EXTERN_C' instead. - #endif -#else - #ifdef __cplusplus - #define __PYX_EXTERN_C extern "C" - #else - #define __PYX_EXTERN_C extern - #endif -#endif - -#ifndef DL_IMPORT - #define DL_IMPORT(_T) _T -#endif - -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlDocumentType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementTreeType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementTagMatcherType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementIteratorType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementBaseType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlElementClassLookupType; -__PYX_EXTERN_C DL_IMPORT(PyTypeObject) LxmlFallbackElementClassLookupType; - -__PYX_EXTERN_C struct LxmlElement *deepcopyNodeToDocument(struct LxmlDocument *, xmlNode *); -__PYX_EXTERN_C struct LxmlElementTree *elementTreeFactory(struct LxmlElement *); -__PYX_EXTERN_C struct LxmlElementTree *newElementTree(struct LxmlElement *, PyObject *); -__PYX_EXTERN_C struct LxmlElementTree *adoptExternalDocument(xmlDoc *, PyObject *, int); -__PYX_EXTERN_C struct LxmlElement *elementFactory(struct LxmlDocument *, xmlNode *); -__PYX_EXTERN_C struct LxmlElement *makeElement(PyObject *, struct LxmlDocument *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *); -__PYX_EXTERN_C struct LxmlElement *makeSubElement(struct LxmlElement *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *); -__PYX_EXTERN_C void setElementClassLookupFunction(_element_class_lookup_function, PyObject *); -__PYX_EXTERN_C PyObject *lookupDefaultElementClass(PyObject *, PyObject *, xmlNode *); -__PYX_EXTERN_C PyObject *lookupNamespaceElementClass(PyObject *, PyObject *, xmlNode *); -__PYX_EXTERN_C PyObject *callLookupFallback(struct LxmlFallbackElementClassLookup *, struct LxmlDocument *, xmlNode *); -__PYX_EXTERN_C int tagMatches(xmlNode *, const xmlChar *, const xmlChar *); -__PYX_EXTERN_C struct LxmlDocument *documentOrRaise(PyObject *); -__PYX_EXTERN_C struct LxmlElement *rootNodeOrRaise(PyObject *); -__PYX_EXTERN_C int hasText(xmlNode *); -__PYX_EXTERN_C int hasTail(xmlNode *); -__PYX_EXTERN_C PyObject *textOf(xmlNode *); -__PYX_EXTERN_C PyObject *tailOf(xmlNode *); -__PYX_EXTERN_C int setNodeText(xmlNode *, PyObject *); -__PYX_EXTERN_C int setTailText(xmlNode *, PyObject *); -__PYX_EXTERN_C PyObject *attributeValue(xmlNode *, xmlAttr *); -__PYX_EXTERN_C PyObject *attributeValueFromNsName(xmlNode *, const xmlChar *, const xmlChar *); -__PYX_EXTERN_C PyObject *getAttributeValue(struct LxmlElement *, PyObject *, PyObject *); -__PYX_EXTERN_C PyObject *iterattributes(struct LxmlElement *, int); -__PYX_EXTERN_C PyObject *collectAttributes(xmlNode *, int); -__PYX_EXTERN_C int setAttributeValue(struct LxmlElement *, PyObject *, PyObject *); -__PYX_EXTERN_C int delAttribute(struct LxmlElement *, PyObject *); -__PYX_EXTERN_C int delAttributeFromNsName(xmlNode *, const xmlChar *, const xmlChar *); -__PYX_EXTERN_C int hasChild(xmlNode *); -__PYX_EXTERN_C xmlNode *findChild(xmlNode *, Py_ssize_t); -__PYX_EXTERN_C xmlNode *findChildForwards(xmlNode *, Py_ssize_t); -__PYX_EXTERN_C xmlNode *findChildBackwards(xmlNode *, Py_ssize_t); -__PYX_EXTERN_C xmlNode *nextElement(xmlNode *); -__PYX_EXTERN_C xmlNode *previousElement(xmlNode *); -__PYX_EXTERN_C void appendChild(struct LxmlElement *, struct LxmlElement *); -__PYX_EXTERN_C int appendChildToElement(struct LxmlElement *, struct LxmlElement *); -__PYX_EXTERN_C PyObject *pyunicode(const xmlChar *); -__PYX_EXTERN_C PyObject *utf8(PyObject *); -__PYX_EXTERN_C PyObject *getNsTag(PyObject *); -__PYX_EXTERN_C PyObject *getNsTagWithEmptyNs(PyObject *); -__PYX_EXTERN_C PyObject *namespacedName(xmlNode *); -__PYX_EXTERN_C PyObject *namespacedNameFromNsName(const xmlChar *, const xmlChar *); -__PYX_EXTERN_C void iteratorStoreNext(struct LxmlElementIterator *, struct LxmlElement *); -__PYX_EXTERN_C void initTagMatch(struct LxmlElementTagMatcher *, PyObject *); -__PYX_EXTERN_C xmlNs *findOrBuildNodeNsPrefix(struct LxmlDocument *, xmlNode *, const xmlChar *, const xmlChar *); - -#endif /* !__PYX_HAVE_API__lxml__etree */ - -/* WARNING: the interface of the module init function changed in CPython 3.5. */ -/* It now returns a PyModuleDef instance instead of a PyModule instance. */ - -/* WARNING: Use PyImport_AppendInittab("etree", PyInit_etree) instead of calling PyInit_etree directly from Python 3.5 */ -PyMODINIT_FUNC PyInit_etree(void); - -#if PY_VERSION_HEX >= 0x03050000 && (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || (defined(__cplusplus) && __cplusplus >= 201402L)) -#if defined(__cplusplus) && __cplusplus >= 201402L -[[deprecated("Use PyImport_AppendInittab(\"etree\", PyInit_etree) instead of calling PyInit_etree directly.")]] inline -#elif defined(__GNUC__) || defined(__clang__) -__attribute__ ((__deprecated__("Use PyImport_AppendInittab(\"etree\", PyInit_etree) instead of calling PyInit_etree directly."), __unused__)) __inline__ -#elif defined(_MSC_VER) -__declspec(deprecated("Use PyImport_AppendInittab(\"etree\", PyInit_etree) instead of calling PyInit_etree directly.")) __inline -#endif -static PyObject* __PYX_WARN_IF_PyInit_etree_INIT_CALLED(PyObject* res) { - return res; -} -#define PyInit_etree() __PYX_WARN_IF_PyInit_etree_INIT_CALLED(PyInit_etree()) -#endif - -#endif /* !__PYX_HAVE__lxml__etree */ diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.pyx b/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.pyx deleted file mode 100644 index 562d95e..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree.pyx +++ /dev/null @@ -1,3853 +0,0 @@ -# cython: binding=True -# cython: auto_pickle=False -# cython: language_level=3 - -""" -The ``lxml.etree`` module implements the extended ElementTree API for XML. -""" - -__docformat__ = "restructuredtext en" - -__all__ = [ - 'AttributeBasedElementClassLookup', 'C14NError', 'C14NWriterTarget', 'CDATA', - 'Comment', 'CommentBase', 'CustomElementClassLookup', 'DEBUG', - 'DTD', 'DTDError', 'DTDParseError', 'DTDValidateError', - 'DocumentInvalid', 'ETCompatXMLParser', 'ETXPath', 'Element', - 'ElementBase', 'ElementClassLookup', 'ElementDefaultClassLookup', - 'ElementNamespaceClassLookup', 'ElementTree', 'Entity', 'EntityBase', - 'Error', 'ErrorDomains', 'ErrorLevels', 'ErrorTypes', 'Extension', - 'FallbackElementClassLookup', 'FunctionNamespace', 'HTML', 'HTMLParser', - 'ICONV_COMPILED_VERSION', - 'LIBXML_COMPILED_VERSION', 'LIBXML_VERSION', - 'LIBXML_FEATURES', - 'LIBXSLT_COMPILED_VERSION', 'LIBXSLT_VERSION', - 'LXML_VERSION', - 'LxmlError', 'LxmlRegistryError', 'LxmlSyntaxError', - 'NamespaceRegistryError', 'PI', 'PIBase', 'ParseError', - 'ParserBasedElementClassLookup', 'ParserError', 'ProcessingInstruction', - 'PyErrorLog', 'PythonElementClassLookup', 'QName', 'RelaxNG', - 'RelaxNGError', 'RelaxNGErrorTypes', 'RelaxNGParseError', - 'RelaxNGValidateError', 'Resolver', 'Schematron', 'SchematronError', - 'SchematronParseError', 'SchematronValidateError', 'SerialisationError', - 'SubElement', 'TreeBuilder', 'XInclude', 'XIncludeError', 'XML', - 'XMLDTDID', 'XMLID', 'XMLParser', 'XMLSchema', 'XMLSchemaError', - 'XMLSchemaParseError', 'XMLSchemaValidateError', 'XMLSyntaxError', - 'XMLTreeBuilder', 'XPath', 'XPathDocumentEvaluator', 'XPathError', - 'XPathEvalError', 'XPathEvaluator', 'XPathFunctionError', 'XPathResultError', - 'XPathSyntaxError', 'XSLT', 'XSLTAccessControl', 'XSLTApplyError', - 'XSLTError', 'XSLTExtension', 'XSLTExtensionError', 'XSLTParseError', - 'XSLTSaveError', 'canonicalize', - 'cleanup_namespaces', 'clear_error_log', 'dump', - 'fromstring', 'fromstringlist', 'get_default_parser', 'iselement', - 'iterparse', 'iterwalk', 'parse', 'parseid', 'register_namespace', - 'set_default_parser', 'set_element_class_lookup', 'strip_attributes', - 'strip_elements', 'strip_tags', 'tostring', 'tostringlist', 'tounicode', - 'use_global_python_log' - ] - -cimport cython - -from lxml cimport python -from lxml.includes cimport tree, config -from lxml.includes.tree cimport xmlDoc, xmlNode, xmlAttr, xmlNs, _isElement, _getNs -from lxml.includes.tree cimport const_xmlChar, xmlChar, _xcstr -from lxml.python cimport _cstr, _isString -from lxml.includes cimport xpath -from lxml.includes cimport c14n - -# Cython's standard declarations -cimport cpython.mem -cimport cpython.ref -from libc cimport limits, stdio, stdlib -from libc cimport string as cstring_h # not to be confused with stdlib 'string' -from libc.string cimport const_char - -cdef object os_path_abspath -from os.path import abspath as os_path_abspath - -cdef object BytesIO, StringIO -from io import BytesIO, StringIO - -cdef object OrderedDict -from collections import OrderedDict - -cdef object _elementpath -from lxml import _elementpath - -cdef object sys -import sys - -cdef object re -import re - -cdef object partial -from functools import partial - -cdef object islice -from itertools import islice - -cdef object ITER_EMPTY = iter(()) - -cdef object MutableMapping -from collections.abc import MutableMapping - -class _ImmutableMapping(MutableMapping): - def __getitem__(self, key): - raise KeyError, key - - def __setitem__(self, key, value): - raise KeyError, key - - def __delitem__(self, key): - raise KeyError, key - - def __contains__(self, key): - return False - - def __len__(self): - return 0 - - def __iter__(self): - return ITER_EMPTY - iterkeys = itervalues = iteritems = __iter__ - -cdef object IMMUTABLE_EMPTY_MAPPING = _ImmutableMapping() -del _ImmutableMapping - - -# the rules -# --------- -# any libxml C argument/variable is prefixed with c_ -# any non-public function/class is prefixed with an underscore -# instance creation is always through factories - -# what to do with libxml2/libxslt error messages? -# 0 : drop -# 1 : use log -DEF __DEBUG = 1 - -# maximum number of lines in the libxml2/xslt log if __DEBUG == 1 -DEF __MAX_LOG_SIZE = 100 - -# make the compiled-in debug state publicly available -DEBUG = __DEBUG - -# A struct to store a cached qualified tag name+href pair. -# While we can borrow the c_name from the document dict, -# PyPy requires us to store a Python reference for the -# namespace in order to keep the byte buffer alive. -cdef struct qname: - const_xmlChar* c_name - python.PyObject* href - -# initialize parser (and threading) -xmlparser.xmlInitParser() - -# global per-thread setup -tree.xmlThrDefIndentTreeOutput(1) -tree.xmlThrDefLineNumbersDefaultValue(1) - -_initThreadLogging() - -# filename encoding -cdef bytes _FILENAME_ENCODING = (sys.getfilesystemencoding() or sys.getdefaultencoding() or 'ascii').encode("UTF-8") -cdef char* _C_FILENAME_ENCODING = _cstr(_FILENAME_ENCODING) - -# set up some default namespace prefixes -cdef dict _DEFAULT_NAMESPACE_PREFIXES = { - b"http://www.w3.org/XML/1998/namespace": b'xml', - b"http://www.w3.org/1999/xhtml": b"html", - b"http://www.w3.org/1999/XSL/Transform": b"xsl", - b"http://www.w3.org/1999/02/22-rdf-syntax-ns#": b"rdf", - b"http://schemas.xmlsoap.org/wsdl/": b"wsdl", - # xml schema - b"http://www.w3.org/2001/XMLSchema": b"xs", - b"http://www.w3.org/2001/XMLSchema-instance": b"xsi", - # dublin core - b"http://purl.org/dc/elements/1.1/": b"dc", - # objectify - b"http://codespeak.net/lxml/objectify/pytype" : b"py", -} - -# To avoid runtime encoding overhead, we keep a Unicode copy -# of the uri-prefix mapping as (str, str) items view. -cdef object _DEFAULT_NAMESPACE_PREFIXES_ITEMS = [] - -cdef _update_default_namespace_prefixes_items(): - cdef bytes ns, prefix - global _DEFAULT_NAMESPACE_PREFIXES_ITEMS - _DEFAULT_NAMESPACE_PREFIXES_ITEMS = { - ns.decode('utf-8') : prefix.decode('utf-8') - for ns, prefix in _DEFAULT_NAMESPACE_PREFIXES.items() - }.items() - -_update_default_namespace_prefixes_items() - -cdef object _check_internal_prefix = re.compile(br"ns\d+$").match - -def register_namespace(prefix, uri): - """Registers a namespace prefix that newly created Elements in that - namespace will use. The registry is global, and any existing - mapping for either the given prefix or the namespace URI will be - removed. - """ - prefix_utf, uri_utf = _utf8(prefix), _utf8(uri) - if _check_internal_prefix(prefix_utf): - raise ValueError("Prefix format reserved for internal use") - _tagValidOrRaise(prefix_utf) - _uriValidOrRaise(uri_utf) - if (uri_utf == b"http://www.w3.org/XML/1998/namespace" and prefix_utf != b'xml' - or prefix_utf == b'xml' and uri_utf != b"http://www.w3.org/XML/1998/namespace"): - raise ValueError("Cannot change the 'xml' prefix of the XML namespace") - for k, v in list(_DEFAULT_NAMESPACE_PREFIXES.items()): - if k == uri_utf or v == prefix_utf: - del _DEFAULT_NAMESPACE_PREFIXES[k] - _DEFAULT_NAMESPACE_PREFIXES[uri_utf] = prefix_utf - _update_default_namespace_prefixes_items() - - -# Error superclass for ElementTree compatibility -cdef class Error(Exception): - pass - -# module level superclass for all exceptions -cdef class LxmlError(Error): - """Main exception base class for lxml. All other exceptions inherit from - this one. - """ - def __init__(self, message, error_log=None): - super(_Error, self).__init__(message) - if error_log is None: - self.error_log = __copyGlobalErrorLog() - else: - self.error_log = error_log.copy() - -cdef object _Error = Error - - -# superclass for all syntax errors -class LxmlSyntaxError(LxmlError, SyntaxError): - """Base class for all syntax errors. - """ - -cdef class C14NError(LxmlError): - """Error during C14N serialisation. - """ - -# version information -cdef tuple __unpackDottedVersion(version): - version_list = [] - l = (version.decode("ascii").replace('-', '.').split('.') + [0]*4)[:4] - for item in l: - try: - item = int(item) - except ValueError: - if item.startswith('dev'): - count = item[3:] - item = -300 - elif item.startswith('alpha'): - count = item[5:] - item = -200 - elif item.startswith('beta'): - count = item[4:] - item = -100 - else: - count = 0 - if count: - item += int(count) - version_list.append(item) - return tuple(version_list) - -cdef tuple __unpackIntVersion(int c_version, int base=100): - return ( - ((c_version // (base*base)) % base), - ((c_version // base) % base), - (c_version % base) - ) - -cdef int _LIBXML_VERSION_INT -try: - _LIBXML_VERSION_INT = int( - re.match('[0-9]+', (tree.xmlParserVersion).decode("ascii")).group(0)) -except Exception: - print("Unknown libxml2 version: " + (tree.xmlParserVersion).decode("latin1")) - _LIBXML_VERSION_INT = 0 - -LIBXML_VERSION = __unpackIntVersion(_LIBXML_VERSION_INT) -LIBXML_COMPILED_VERSION = __unpackIntVersion(tree.LIBXML_VERSION) -LXML_VERSION = __unpackDottedVersion(tree.LXML_VERSION_STRING) - -__version__ = tree.LXML_VERSION_STRING.decode("ascii") - -cdef extern from *: - """ - #ifdef ZLIB_VERNUM - #define __lxml_zlib_version (ZLIB_VERNUM >> 4) - #else - #define __lxml_zlib_version 0 - #endif - #ifdef _LIBICONV_VERSION - #define __lxml_iconv_version (_LIBICONV_VERSION << 8) - #else - #define __lxml_iconv_version 0 - #endif - """ - # zlib isn't included automatically by libxml2's headers - #long ZLIB_HEX_VERSION "__lxml_zlib_version" - long LIBICONV_HEX_VERSION "__lxml_iconv_version" - -#ZLIB_COMPILED_VERSION = __unpackIntVersion(ZLIB_HEX_VERSION, base=0x10) -ICONV_COMPILED_VERSION = __unpackIntVersion(LIBICONV_HEX_VERSION, base=0x100)[:2] - - -cdef extern from "libxml/xmlversion.h": - """ - static const char* const _lxml_lib_features[] = { -#ifdef LIBXML_HTML_ENABLED - "html", -#endif -#ifdef LIBXML_FTP_ENABLED - "ftp", -#endif -#ifdef LIBXML_HTTP_ENABLED - "http", -#endif -#ifdef LIBXML_CATALOG_ENABLED - "catalog", -#endif -#ifdef LIBXML_XPATH_ENABLED - "xpath", -#endif -#ifdef LIBXML_ICONV_ENABLED - "iconv", -#endif -#ifdef LIBXML_ICU_ENABLED - "icu", -#endif -#ifdef LIBXML_REGEXP_ENABLED - "regexp", -#endif -#ifdef LIBXML_SCHEMAS_ENABLED - "xmlschema", -#endif -#ifdef LIBXML_SCHEMATRON_ENABLED - "schematron", -#endif -#ifdef LIBXML_ZLIB_ENABLED - "zlib", -#endif -#ifdef LIBXML_LZMA_ENABLED - "lzma", -#endif - 0 - }; - """ - const char* const* _LXML_LIB_FEATURES "_lxml_lib_features" - - -cdef set _copy_lib_features(): - features = set() - feature = _LXML_LIB_FEATURES - while feature[0]: - features.add(feature[0].decode('ASCII')) - feature += 1 - return features - -LIBXML_COMPILED_FEATURES = _copy_lib_features() -LIBXML_FEATURES = { - feature_name for feature_id, feature_name in [ - #XML_WITH_THREAD = 1 - #XML_WITH_TREE = 2 - #XML_WITH_OUTPUT = 3 - #XML_WITH_PUSH = 4 - #XML_WITH_READER = 5 - #XML_WITH_PATTERN = 6 - #XML_WITH_WRITER = 7 - #XML_WITH_SAX1 = 8 - (xmlparser.XML_WITH_FTP, "ftp"), # XML_WITH_FTP = 9 - (xmlparser.XML_WITH_HTTP, "http"), # XML_WITH_HTTP = 10 - #XML_WITH_VALID = 11 - (xmlparser.XML_WITH_HTML, "html"), # XML_WITH_HTML = 12 - #XML_WITH_LEGACY = 13 - #XML_WITH_C14N = 14 - (xmlparser.XML_WITH_CATALOG, "catalog"), # XML_WITH_CATALOG = 15 - (xmlparser.XML_WITH_XPATH, "xpath"), # XML_WITH_XPATH = 16 - #XML_WITH_XPTR = 17 - #XML_WITH_XINCLUDE = 18 - (xmlparser.XML_WITH_ICONV, "iconv"), # XML_WITH_ICONV = 19 - #XML_WITH_ISO8859X = 20 - #XML_WITH_UNICODE = 21 - (xmlparser.XML_WITH_REGEXP, "regexp"), # XML_WITH_REGEXP = 22 - #XML_WITH_AUTOMATA = 23 - #XML_WITH_EXPR = 24 - (xmlparser.XML_WITH_SCHEMAS, "xmlschema"), # XML_WITH_SCHEMAS = 25 - (xmlparser.XML_WITH_SCHEMATRON, "schematron"), # XML_WITH_SCHEMATRON = 26 - #XML_WITH_MODULES = 27 - #XML_WITH_DEBUG = 28 - #XML_WITH_DEBUG_MEM = 29 - #XML_WITH_DEBUG_RUN = 30 # unused - (xmlparser.XML_WITH_ZLIB, "zlib"), # XML_WITH_ZLIB = 31 - (xmlparser.XML_WITH_ICU, "icu"), # XML_WITH_ICU = 32 - (xmlparser.XML_WITH_LZMA, "lzma"), # XML_WITH_LZMA = 33 - ] if xmlparser.xmlHasFeature(feature_id) -} - -cdef bint HAS_ZLIB_COMPRESSION = xmlparser.xmlHasFeature(xmlparser.XML_WITH_ZLIB) - - -# class for temporary storage of Python references, -# used e.g. for XPath results -@cython.final -@cython.internal -cdef class _TempStore: - cdef list _storage - def __init__(self): - self._storage = [] - - cdef int add(self, obj) except -1: - self._storage.append(obj) - return 0 - - cdef int clear(self) except -1: - del self._storage[:] - return 0 - - -# class for temporarily storing exceptions raised in extensions -@cython.internal -cdef class _ExceptionContext: - cdef object _exc_info - cdef int clear(self) except -1: - self._exc_info = None - return 0 - - cdef void _store_raised(self) noexcept: - try: - self._exc_info = sys.exc_info() - except BaseException as e: - self._store_exception(e) - finally: - return # and swallow any further exceptions - - cdef int _store_exception(self, exception) except -1: - self._exc_info = (exception, None, None) - return 0 - - cdef bint _has_raised(self) except -1: - return self._exc_info is not None - - cdef int _raise_if_stored(self) except -1: - if self._exc_info is None: - return 0 - type, value, traceback = self._exc_info - self._exc_info = None - if value is None and traceback is None: - raise type - else: - raise type, value, traceback - - -# type of a function that steps from node to node -ctypedef public xmlNode* (*_node_to_node_function)(xmlNode*) - - -################################################################################ -# Include submodules - -include "proxy.pxi" # Proxy handling (element backpointers/memory/etc.) -include "apihelpers.pxi" # Private helper functions -include "xmlerror.pxi" # Error and log handling - - -################################################################################ -# Public Python API - -@cython.final -@cython.freelist(8) -cdef public class _Document [ type LxmlDocumentType, object LxmlDocument ]: - """Internal base class to reference a libxml document. - - When instances of this class are garbage collected, the libxml - document is cleaned up. - """ - cdef int _ns_counter - cdef bytes _prefix_tail - cdef xmlDoc* _c_doc - cdef _BaseParser _parser - - def __dealloc__(self): - # if there are no more references to the document, it is safe - # to clean the whole thing up, as all nodes have a reference to - # the document - tree.xmlFreeDoc(self._c_doc) - - @cython.final - cdef getroot(self): - # return an element proxy for the document root - cdef xmlNode* c_node - c_node = tree.xmlDocGetRootElement(self._c_doc) - if c_node is NULL: - return None - return _elementFactory(self, c_node) - - @cython.final - cdef bint hasdoctype(self) noexcept: - # DOCTYPE gets parsed into internal subset (xmlDTD*) - return self._c_doc is not NULL and self._c_doc.intSubset is not NULL - - @cython.final - cdef getdoctype(self): - # get doctype info: root tag, public/system ID (or None if not known) - cdef tree.xmlDtd* c_dtd - cdef xmlNode* c_root_node - public_id = None - sys_url = None - c_dtd = self._c_doc.intSubset - if c_dtd is not NULL: - if c_dtd.ExternalID is not NULL: - public_id = funicode(c_dtd.ExternalID) - if c_dtd.SystemID is not NULL: - sys_url = funicode(c_dtd.SystemID) - c_dtd = self._c_doc.extSubset - if c_dtd is not NULL: - if not public_id and c_dtd.ExternalID is not NULL: - public_id = funicode(c_dtd.ExternalID) - if not sys_url and c_dtd.SystemID is not NULL: - sys_url = funicode(c_dtd.SystemID) - c_root_node = tree.xmlDocGetRootElement(self._c_doc) - if c_root_node is NULL: - root_name = None - else: - root_name = funicode(c_root_node.name) - return root_name, public_id, sys_url - - @cython.final - cdef getxmlinfo(self): - # return XML version and encoding (or None if not known) - cdef xmlDoc* c_doc = self._c_doc - if c_doc.version is NULL: - version = None - else: - version = funicode(c_doc.version) - if c_doc.encoding is NULL: - encoding = None - else: - encoding = funicode(c_doc.encoding) - return version, encoding - - @cython.final - cdef isstandalone(self): - # returns True for "standalone=true", - # False for "standalone=false", None if not provided - if self._c_doc.standalone == -1: - return None - else: - return (self._c_doc.standalone == 1) - - @cython.final - cdef bytes buildNewPrefix(self): - # get a new unique prefix ("nsX") for this document - cdef bytes ns - if self._ns_counter < len(_PREFIX_CACHE): - ns = _PREFIX_CACHE[self._ns_counter] - else: - ns = python.PyBytes_FromFormat("ns%d", self._ns_counter) - if self._prefix_tail is not None: - ns += self._prefix_tail - self._ns_counter += 1 - if self._ns_counter < 0: - # overflow! - self._ns_counter = 0 - if self._prefix_tail is None: - self._prefix_tail = b"A" - else: - self._prefix_tail += b"A" - return ns - - @cython.final - cdef xmlNs* _findOrBuildNodeNs(self, xmlNode* c_node, - const_xmlChar* c_href, const_xmlChar* c_prefix, - bint is_attribute) except NULL: - """Get or create namespace structure for a node. Reuses the prefix if - possible. - """ - cdef xmlNs* c_ns - cdef xmlNs* c_doc_ns - cdef python.PyObject* dict_result - if c_node.type != tree.XML_ELEMENT_NODE: - assert c_node.type == tree.XML_ELEMENT_NODE, \ - "invalid node type %d, expected %d" % ( - c_node.type, tree.XML_ELEMENT_NODE) - # look for existing ns declaration - c_ns = _searchNsByHref(c_node, c_href, is_attribute) - if c_ns is not NULL: - if is_attribute and c_ns.prefix is NULL: - # do not put namespaced attributes into the default - # namespace as this would break serialisation - pass - else: - return c_ns - - # none found => determine a suitable new prefix - if c_prefix is NULL: - dict_result = python.PyDict_GetItem( - _DEFAULT_NAMESPACE_PREFIXES, c_href) - if dict_result is not NULL: - prefix = dict_result - else: - prefix = self.buildNewPrefix() - c_prefix = _xcstr(prefix) - - # make sure the prefix is not in use already - while tree.xmlSearchNs(self._c_doc, c_node, c_prefix) is not NULL: - prefix = self.buildNewPrefix() - c_prefix = _xcstr(prefix) - - # declare the namespace and return it - c_ns = tree.xmlNewNs(c_node, c_href, c_prefix) - if c_ns is NULL: - raise MemoryError() - return c_ns - - @cython.final - cdef int _setNodeNs(self, xmlNode* c_node, const_xmlChar* c_href) except -1: - "Lookup namespace structure and set it for the node." - c_ns = self._findOrBuildNodeNs(c_node, c_href, NULL, 0) - tree.xmlSetNs(c_node, c_ns) - - -cdef tuple __initPrefixCache(): - cdef int i - return tuple([ python.PyBytes_FromFormat("ns%d", i) - for i in range(26) ]) - -cdef tuple _PREFIX_CACHE = __initPrefixCache() - - -cdef _Document _documentFactory(xmlDoc* c_doc, _BaseParser parser): - cdef _Document result - result = _Document.__new__(_Document) - result._c_doc = c_doc - result._ns_counter = 0 - result._prefix_tail = None - if parser is None: - parser = __GLOBAL_PARSER_CONTEXT.getDefaultParser() - result._parser = parser - return result - - -cdef object _find_invalid_public_id_characters = re.compile( - ur"[^\x20\x0D\x0Aa-zA-Z0-9'()+,./:=?;!*#@$_%-]+").search - - -cdef class DocInfo: - "Document information provided by parser and DTD." - cdef _Document _doc - def __cinit__(self, tree): - "Create a DocInfo object for an ElementTree object or root Element." - self._doc = _documentOrRaise(tree) - root_name, public_id, system_url = self._doc.getdoctype() - if not root_name and (public_id or system_url): - raise ValueError, "Could not find root node" - - @property - def root_name(self): - """Returns the name of the root node as defined by the DOCTYPE.""" - root_name, public_id, system_url = self._doc.getdoctype() - return root_name - - @cython.final - cdef tree.xmlDtd* _get_c_dtd(self): - """"Return the DTD. Create it if it does not yet exist.""" - cdef xmlDoc* c_doc = self._doc._c_doc - cdef xmlNode* c_root_node - cdef const_xmlChar* c_name - - if c_doc.intSubset: - return c_doc.intSubset - - c_root_node = tree.xmlDocGetRootElement(c_doc) - c_name = c_root_node.name if c_root_node else NULL - return tree.xmlCreateIntSubset(c_doc, c_name, NULL, NULL) - - def clear(self): - """Removes DOCTYPE and internal subset from the document.""" - cdef xmlDoc* c_doc = self._doc._c_doc - cdef tree.xmlNode* c_dtd = c_doc.intSubset - if c_dtd is NULL: - return - tree.xmlUnlinkNode(c_dtd) - tree.xmlFreeNode(c_dtd) - - property public_id: - """Public ID of the DOCTYPE. - - Mutable. May be set to a valid string or None. If a DTD does not - exist, setting this variable (even to None) will create one. - """ - def __get__(self): - root_name, public_id, system_url = self._doc.getdoctype() - return public_id - - def __set__(self, value): - cdef xmlChar* c_value = NULL - if value is not None: - match = _find_invalid_public_id_characters(value) - if match: - raise ValueError, f'Invalid character(s) {match.group(0)!r} in public_id.' - value = _utf8(value) - c_value = tree.xmlStrdup(_xcstr(value)) - if not c_value: - raise MemoryError() - - c_dtd = self._get_c_dtd() - if not c_dtd: - tree.xmlFree(c_value) - raise MemoryError() - if c_dtd.ExternalID: - tree.xmlFree(c_dtd.ExternalID) - c_dtd.ExternalID = c_value - - property system_url: - """System ID of the DOCTYPE. - - Mutable. May be set to a valid string or None. If a DTD does not - exist, setting this variable (even to None) will create one. - """ - def __get__(self): - root_name, public_id, system_url = self._doc.getdoctype() - return system_url - - def __set__(self, value): - cdef xmlChar* c_value = NULL - if value is not None: - bvalue = _utf8(value) - # sys_url may be any valid unicode string that can be - # enclosed in single quotes or quotes. - if b"'" in bvalue and b'"' in bvalue: - raise ValueError( - 'System URL may not contain both single (\') and double quotes (").') - c_value = tree.xmlStrdup(_xcstr(bvalue)) - if not c_value: - raise MemoryError() - - c_dtd = self._get_c_dtd() - if not c_dtd: - tree.xmlFree(c_value) - raise MemoryError() - if c_dtd.SystemID: - tree.xmlFree(c_dtd.SystemID) - c_dtd.SystemID = c_value - - @property - def xml_version(self): - """Returns the XML version as declared by the document.""" - xml_version, encoding = self._doc.getxmlinfo() - return xml_version - - @property - def encoding(self): - """Returns the encoding name as declared by the document.""" - xml_version, encoding = self._doc.getxmlinfo() - return encoding - - @property - def standalone(self): - """Returns the standalone flag as declared by the document. The possible - values are True (``standalone='yes'``), False - (``standalone='no'`` or flag not provided in the declaration), - and None (unknown or no declaration found). Note that a - normal truth test on this value will always tell if the - ``standalone`` flag was set to ``'yes'`` or not. - """ - return self._doc.isstandalone() - - property URL: - "The source URL of the document (or None if unknown)." - def __get__(self): - if self._doc._c_doc.URL is NULL: - return None - return _decodeFilename(self._doc._c_doc.URL) - def __set__(self, url): - url = _encodeFilename(url) - c_oldurl = self._doc._c_doc.URL - if url is None: - self._doc._c_doc.URL = NULL - else: - self._doc._c_doc.URL = tree.xmlStrdup(_xcstr(url)) - if c_oldurl is not NULL: - tree.xmlFree(c_oldurl) - - @property - def doctype(self): - """Returns a DOCTYPE declaration string for the document.""" - root_name, public_id, system_url = self._doc.getdoctype() - if system_url: - # If '"' in system_url, we must escape it with single - # quotes, otherwise escape with double quotes. If url - # contains both a single quote and a double quote, XML - # standard is being violated. - if '"' in system_url: - quoted_system_url = f"'{system_url}'" - else: - quoted_system_url = f'"{system_url}"' - if public_id: - if system_url: - return f'' - else: - return f'' - elif system_url: - return f'' - elif self._doc.hasdoctype(): - return f'' - else: - return '' - - @property - def internalDTD(self): - """Returns a DTD validator based on the internal subset of the document.""" - return _dtdFactory(self._doc._c_doc.intSubset) - - @property - def externalDTD(self): - """Returns a DTD validator based on the external subset of the document.""" - return _dtdFactory(self._doc._c_doc.extSubset) - - -@cython.no_gc_clear -cdef public class _Element [ type LxmlElementType, object LxmlElement ]: - """Element class. - - References a document object and a libxml node. - - By pointing to a Document instance, a reference is kept to - _Document as long as there is some pointer to a node in it. - """ - cdef _Document _doc - cdef xmlNode* _c_node - cdef object _tag - - def _init(self): - """_init(self) - - Called after object initialisation. Custom subclasses may override - this if they recursively call _init() in the superclasses. - """ - - @cython.linetrace(False) - @cython.profile(False) - def __dealloc__(self): - #print("trying to free node:", self._c_node) - #displayNode(self._c_node, 0) - if self._c_node is not NULL: - _unregisterProxy(self) - attemptDeallocation(self._c_node) - - # MANIPULATORS - - def __setitem__(self, x, value): - """__setitem__(self, x, value) - - Replaces the given subelement index or slice. - """ - cdef xmlNode* c_node = NULL - cdef xmlNode* c_next - cdef xmlDoc* c_source_doc - cdef _Element element - cdef bint left_to_right - cdef Py_ssize_t slicelength = 0, step = 0 - _assertValidNode(self) - if value is None: - raise ValueError, "cannot assign None" - if isinstance(x, slice): - # slice assignment - _findChildSlice(x, self._c_node, &c_node, &step, &slicelength) - if step > 0: - left_to_right = 1 - else: - left_to_right = 0 - step = -step - _replaceSlice(self, c_node, slicelength, step, left_to_right, value) - return - else: - # otherwise: normal item assignment - element = value - _assertValidNode(element) - c_node = _findChild(self._c_node, x) - if c_node is NULL: - raise IndexError, "list index out of range" - c_source_doc = element._c_node.doc - c_next = element._c_node.next - _removeText(c_node.next) - tree.xmlReplaceNode(c_node, element._c_node) - _moveTail(c_next, element._c_node) - moveNodeToDocument(self._doc, c_source_doc, element._c_node) - if not attemptDeallocation(c_node): - moveNodeToDocument(self._doc, c_node.doc, c_node) - - def __delitem__(self, x): - """__delitem__(self, x) - - Deletes the given subelement or a slice. - """ - cdef xmlNode* c_node = NULL - cdef xmlNode* c_next - cdef Py_ssize_t step = 0, slicelength = 0 - _assertValidNode(self) - if isinstance(x, slice): - # slice deletion - if _isFullSlice(x): - c_node = self._c_node.children - if c_node is not NULL: - if not _isElement(c_node): - c_node = _nextElement(c_node) - while c_node is not NULL: - c_next = _nextElement(c_node) - _removeNode(self._doc, c_node) - c_node = c_next - else: - _findChildSlice(x, self._c_node, &c_node, &step, &slicelength) - _deleteSlice(self._doc, c_node, slicelength, step) - else: - # item deletion - c_node = _findChild(self._c_node, x) - if c_node is NULL: - raise IndexError, f"index out of range: {x}" - _removeNode(self._doc, c_node) - - def __deepcopy__(self, memo): - "__deepcopy__(self, memo)" - return self.__copy__() - - def __copy__(self): - "__copy__(self)" - cdef xmlDoc* c_doc - cdef xmlNode* c_node - cdef _Document new_doc - _assertValidNode(self) - c_doc = _copyDocRoot(self._doc._c_doc, self._c_node) # recursive - new_doc = _documentFactory(c_doc, self._doc._parser) - root = new_doc.getroot() - if root is not None: - return root - # Comment/PI - c_node = c_doc.children - while c_node is not NULL and c_node.type != self._c_node.type: - c_node = c_node.next - if c_node is NULL: - return None - return _elementFactory(new_doc, c_node) - - def set(self, key, value): - """set(self, key, value) - - Sets an element attribute. - In HTML documents (not XML or XHTML), the value None is allowed and creates - an attribute without value (just the attribute name). - """ - _assertValidNode(self) - _setAttributeValue(self, key, value) - - def append(self, _Element element not None): - """append(self, element) - - Adds a subelement to the end of this element. - """ - _assertValidNode(self) - _assertValidNode(element) - _appendChild(self, element) - - def addnext(self, _Element element not None): - """addnext(self, element) - - Adds the element as a following sibling directly after this - element. - - This is normally used to set a processing instruction or comment after - the root node of a document. Note that tail text is automatically - discarded when adding at the root level. - """ - _assertValidNode(self) - _assertValidNode(element) - if self._c_node.parent != NULL and not _isElement(self._c_node.parent): - if element._c_node.type not in (tree.XML_PI_NODE, tree.XML_COMMENT_NODE): - raise TypeError, "Only processing instructions and comments can be siblings of the root element" - element.tail = None - _appendSibling(self, element) - - def addprevious(self, _Element element not None): - """addprevious(self, element) - - Adds the element as a preceding sibling directly before this - element. - - This is normally used to set a processing instruction or comment - before the root node of a document. Note that tail text is - automatically discarded when adding at the root level. - """ - _assertValidNode(self) - _assertValidNode(element) - if self._c_node.parent != NULL and not _isElement(self._c_node.parent): - if element._c_node.type != tree.XML_PI_NODE: - if element._c_node.type != tree.XML_COMMENT_NODE: - raise TypeError, "Only processing instructions and comments can be siblings of the root element" - element.tail = None - _prependSibling(self, element) - - def extend(self, elements): - """extend(self, elements) - - Extends the current children by the elements in the iterable. - """ - cdef _Element element - _assertValidNode(self) - for element in elements: - if element is None: - raise TypeError, "Node must not be None" - _assertValidNode(element) - _appendChild(self, element) - - def clear(self, bint keep_tail=False): - """clear(self, keep_tail=False) - - Resets an element. This function removes all subelements, clears - all attributes and sets the text and tail properties to None. - - Pass ``keep_tail=True`` to leave the tail text untouched. - """ - cdef xmlAttr* c_attr - cdef xmlAttr* c_attr_next - cdef xmlNode* c_node - cdef xmlNode* c_node_next - _assertValidNode(self) - c_node = self._c_node - # remove self.text and self.tail - _removeText(c_node.children) - if not keep_tail: - _removeText(c_node.next) - # remove all attributes - c_attr = c_node.properties - if c_attr: - c_node.properties = NULL - tree.xmlFreePropList(c_attr) - # remove all subelements - c_node = c_node.children - if c_node and not _isElement(c_node): - c_node = _nextElement(c_node) - while c_node is not NULL: - c_node_next = _nextElement(c_node) - _removeNode(self._doc, c_node) - c_node = c_node_next - - def insert(self, index: int, _Element element not None): - """insert(self, index, element) - - Inserts a subelement at the given position in this element - """ - cdef xmlNode* c_node - cdef xmlNode* c_next - cdef xmlDoc* c_source_doc - _assertValidNode(self) - _assertValidNode(element) - c_node = _findChild(self._c_node, index) - if c_node is NULL: - _appendChild(self, element) - return - # prevent cycles - if _isAncestorOrSame(element._c_node, self._c_node): - raise ValueError("cannot append parent to itself") - c_source_doc = element._c_node.doc - c_next = element._c_node.next - tree.xmlAddPrevSibling(c_node, element._c_node) - _moveTail(c_next, element._c_node) - moveNodeToDocument(self._doc, c_source_doc, element._c_node) - - def remove(self, _Element element not None): - """remove(self, element) - - Removes a matching subelement. Unlike the find methods, this - method compares elements based on identity, not on tag value - or contents. - """ - cdef xmlNode* c_node - cdef xmlNode* c_next - _assertValidNode(self) - _assertValidNode(element) - c_node = element._c_node - if c_node.parent is not self._c_node: - raise ValueError, "Element is not a child of this node." - c_next = element._c_node.next - tree.xmlUnlinkNode(c_node) - _moveTail(c_next, c_node) - # fix namespace declarations - moveNodeToDocument(self._doc, c_node.doc, c_node) - - def replace(self, _Element old_element not None, - _Element new_element not None): - """replace(self, old_element, new_element) - - Replaces a subelement with the element passed as second argument. - """ - cdef xmlNode* c_old_node - cdef xmlNode* c_old_next - cdef xmlNode* c_new_node - cdef xmlNode* c_new_next - cdef xmlDoc* c_source_doc - _assertValidNode(self) - _assertValidNode(old_element) - _assertValidNode(new_element) - c_old_node = old_element._c_node - if c_old_node.parent is not self._c_node: - raise ValueError, "Element is not a child of this node." - c_new_node = new_element._c_node - # prevent cycles - if _isAncestorOrSame(c_new_node, self._c_node): - raise ValueError("cannot append parent to itself") - # replace node - c_old_next = c_old_node.next - c_new_next = c_new_node.next - c_source_doc = c_new_node.doc - tree.xmlReplaceNode(c_old_node, c_new_node) - _moveTail(c_new_next, c_new_node) - _moveTail(c_old_next, c_old_node) - moveNodeToDocument(self._doc, c_source_doc, c_new_node) - # fix namespace declarations - moveNodeToDocument(self._doc, c_old_node.doc, c_old_node) - - # PROPERTIES - property tag: - """Element tag - """ - def __get__(self): - if self._tag is not None: - return self._tag - _assertValidNode(self) - self._tag = _namespacedName(self._c_node) - return self._tag - - def __set__(self, value): - cdef _BaseParser parser - _assertValidNode(self) - ns, name = _getNsTag(value) - parser = self._doc._parser - if parser is not None and parser._for_html: - _htmlTagValidOrRaise(name) - else: - _tagValidOrRaise(name) - self._tag = value - tree.xmlNodeSetName(self._c_node, _xcstr(name)) - if ns is None: - self._c_node.ns = NULL - else: - self._doc._setNodeNs(self._c_node, _xcstr(ns)) - - @property - def attrib(self): - """Element attribute dictionary. Where possible, use get(), set(), - keys(), values() and items() to access element attributes. - """ - return _Attrib.__new__(_Attrib, self) - - property text: - """Text before the first subelement. This is either a string or - the value None, if there was no text. - """ - def __get__(self): - _assertValidNode(self) - return _collectText(self._c_node.children) - - def __set__(self, value): - _assertValidNode(self) - if isinstance(value, QName): - value = _resolveQNameText(self, value).decode('utf8') - _setNodeText(self._c_node, value) - - # using 'del el.text' is the wrong thing to do - #def __del__(self): - # _setNodeText(self._c_node, None) - - property tail: - """Text after this element's end tag, but before the next sibling - element's start tag. This is either a string or the value None, if - there was no text. - """ - def __get__(self): - _assertValidNode(self) - return _collectText(self._c_node.next) - - def __set__(self, value): - _assertValidNode(self) - _setTailText(self._c_node, value) - - # using 'del el.tail' is the wrong thing to do - #def __del__(self): - # _setTailText(self._c_node, None) - - # not in ElementTree, read-only - @property - def prefix(self): - """Namespace prefix or None. - """ - if self._c_node.ns is not NULL: - if self._c_node.ns.prefix is not NULL: - return funicode(self._c_node.ns.prefix) - return None - - # not in ElementTree, read-only - property sourceline: - """Original line number as found by the parser or None if unknown. - """ - def __get__(self): - cdef long line - _assertValidNode(self) - line = tree.xmlGetLineNo(self._c_node) - return line if line > 0 else None - - def __set__(self, line): - _assertValidNode(self) - if line <= 0: - self._c_node.line = 0 - else: - self._c_node.line = line - - # not in ElementTree, read-only - @property - def nsmap(self): - """Namespace prefix->URI mapping known in the context of this - Element. This includes all namespace declarations of the - parents. - - Note that changing the returned dict has no effect on the Element. - """ - _assertValidNode(self) - return _build_nsmap(self._c_node) - - # not in ElementTree, read-only - property base: - """The base URI of the Element (xml:base or HTML base URL). - None if the base URI is unknown. - - Note that the value depends on the URL of the document that - holds the Element if there is no xml:base attribute on the - Element or its ancestors. - - Setting this property will set an xml:base attribute on the - Element, regardless of the document type (XML or HTML). - """ - def __get__(self): - _assertValidNode(self) - c_base = tree.xmlNodeGetBase(self._doc._c_doc, self._c_node) - if c_base is NULL: - if self._doc._c_doc.URL is NULL: - return None - return _decodeFilename(self._doc._c_doc.URL) - try: - base = _decodeFilename(c_base) - finally: - tree.xmlFree(c_base) - return base - - def __set__(self, url): - _assertValidNode(self) - if url is None: - c_base = NULL - else: - url = _encodeFilename(url) - c_base = _xcstr(url) - tree.xmlNodeSetBase(self._c_node, c_base) - - # ACCESSORS - def __repr__(self): - "__repr__(self)" - return "" % (self.tag, id(self)) - - def __getitem__(self, x): - """Returns the subelement at the given position or the requested - slice. - """ - cdef xmlNode* c_node = NULL - cdef Py_ssize_t step = 0, slicelength = 0 - cdef Py_ssize_t c, i - cdef _node_to_node_function next_element - cdef list result - _assertValidNode(self) - if isinstance(x, slice): - # slicing - if _isFullSlice(x): - return _collectChildren(self) - _findChildSlice(x, self._c_node, &c_node, &step, &slicelength) - if c_node is NULL: - return [] - if step > 0: - next_element = _nextElement - else: - step = -step - next_element = _previousElement - result = [] - c = 0 - while c_node is not NULL and c < slicelength: - result.append(_elementFactory(self._doc, c_node)) - c += 1 - for i in range(step): - c_node = next_element(c_node) - if c_node is NULL: - break - return result - else: - # indexing - c_node = _findChild(self._c_node, x) - if c_node is NULL: - raise IndexError, "list index out of range" - return _elementFactory(self._doc, c_node) - - def __len__(self): - """__len__(self) - - Returns the number of subelements. - """ - _assertValidNode(self) - return _countElements(self._c_node.children) - - def __bool__(self): - """__bool__(self)""" - import warnings - warnings.warn( - "Truth-testing of elements was a source of confusion and will always " - "return True in future versions. " - "Use specific 'len(elem)' or 'elem is not None' test instead.", - FutureWarning - ) - # emulate old behaviour - _assertValidNode(self) - return _hasChild(self._c_node) - - def __contains__(self, element): - "__contains__(self, element)" - cdef xmlNode* c_node - _assertValidNode(self) - if not isinstance(element, _Element): - return 0 - c_node = (<_Element>element)._c_node - return c_node is not NULL and c_node.parent is self._c_node - - def __iter__(self): - "__iter__(self)" - return ElementChildIterator(self) - - def __reversed__(self): - "__reversed__(self)" - return ElementChildIterator(self, reversed=True) - - def index(self, child: _Element, start: int = None, stop: int = None): - """index(self, child, start=None, stop=None) - - Find the position of the child within the parent. - - This method is not part of the original ElementTree API. - """ - cdef Py_ssize_t k, l - cdef Py_ssize_t c_start, c_stop - cdef xmlNode* c_child - cdef xmlNode* c_start_node - _assertValidNode(self) - _assertValidNode(child) - c_child = child._c_node - if c_child.parent is not self._c_node: - raise ValueError, "Element is not a child of this node." - - # handle the unbounded search straight away (normal case) - if stop is None and (start is None or start == 0): - k = 0 - c_child = c_child.prev - while c_child is not NULL: - if _isElement(c_child): - k += 1 - c_child = c_child.prev - return k - - # check indices - if start is None: - c_start = 0 - else: - c_start = start - if stop is None: - c_stop = 0 - else: - c_stop = stop - if c_stop == 0 or \ - c_start >= c_stop and (c_stop > 0 or c_start < 0): - raise ValueError, "list.index(x): x not in slice" - - # for negative slice indices, check slice before searching index - if c_start < 0 or c_stop < 0: - # start from right, at most up to leftmost(c_start, c_stop) - if c_start < c_stop: - k = -c_start - else: - k = -c_stop - c_start_node = self._c_node.last - l = 1 - while c_start_node != c_child and l < k: - if _isElement(c_start_node): - l += 1 - c_start_node = c_start_node.prev - if c_start_node == c_child: - # found! before slice end? - if c_stop < 0 and l <= -c_stop: - raise ValueError, "list.index(x): x not in slice" - elif c_start < 0: - raise ValueError, "list.index(x): x not in slice" - - # now determine the index backwards from child - c_child = c_child.prev - k = 0 - if c_stop > 0: - # we can optimize: stop after c_stop elements if not found - while c_child != NULL and k < c_stop: - if _isElement(c_child): - k += 1 - c_child = c_child.prev - if k < c_stop: - return k - else: - # traverse all - while c_child != NULL: - if _isElement(c_child): - k = k + 1 - c_child = c_child.prev - if c_start > 0: - if k >= c_start: - return k - else: - return k - if c_start != 0 or c_stop != 0: - raise ValueError, "list.index(x): x not in slice" - else: - raise ValueError, "list.index(x): x not in list" - - def get(self, key, default=None): - """get(self, key, default=None) - - Gets an element attribute. - """ - _assertValidNode(self) - return _getAttributeValue(self, key, default) - - def keys(self): - """keys(self) - - Gets a list of attribute names. The names are returned in an - arbitrary order (just like for an ordinary Python dictionary). - """ - _assertValidNode(self) - return _collectAttributes(self._c_node, 1) - - def values(self): - """values(self) - - Gets element attribute values as a sequence of strings. The - attributes are returned in an arbitrary order. - """ - _assertValidNode(self) - return _collectAttributes(self._c_node, 2) - - def items(self): - """items(self) - - Gets element attributes, as a sequence. The attributes are returned in - an arbitrary order. - """ - _assertValidNode(self) - return _collectAttributes(self._c_node, 3) - - def getchildren(self): - """getchildren(self) - - Returns all direct children. The elements are returned in document - order. - - :deprecated: Note that this method has been deprecated as of - ElementTree 1.3 and lxml 2.0. New code should use - ``list(element)`` or simply iterate over elements. - """ - _assertValidNode(self) - return _collectChildren(self) - - def getparent(self): - """getparent(self) - - Returns the parent of this element or None for the root element. - """ - cdef xmlNode* c_node - #_assertValidNode(self) # not needed - c_node = _parentElement(self._c_node) - if c_node is NULL: - return None - return _elementFactory(self._doc, c_node) - - def getnext(self): - """getnext(self) - - Returns the following sibling of this element or None. - """ - cdef xmlNode* c_node - #_assertValidNode(self) # not needed - c_node = _nextElement(self._c_node) - if c_node is NULL: - return None - return _elementFactory(self._doc, c_node) - - def getprevious(self): - """getprevious(self) - - Returns the preceding sibling of this element or None. - """ - cdef xmlNode* c_node - #_assertValidNode(self) # not needed - c_node = _previousElement(self._c_node) - if c_node is NULL: - return None - return _elementFactory(self._doc, c_node) - - def itersiblings(self, tag=None, *tags, preceding=False): - """itersiblings(self, tag=None, *tags, preceding=False) - - Iterate over the following or preceding siblings of this element. - - The direction is determined by the 'preceding' keyword which - defaults to False, i.e. forward iteration over the following - siblings. When True, the iterator yields the preceding - siblings in reverse document order, i.e. starting right before - the current element and going backwards. - - Can be restricted to find only elements with specific tags, - see `iter`. - """ - if preceding: - if self._c_node and not self._c_node.prev: - return ITER_EMPTY - elif self._c_node and not self._c_node.next: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return SiblingsIterator(self, tags, preceding=preceding) - - def iterancestors(self, tag=None, *tags): - """iterancestors(self, tag=None, *tags) - - Iterate over the ancestors of this element (from parent to parent). - - Can be restricted to find only elements with specific tags, - see `iter`. - """ - if self._c_node and not self._c_node.parent: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return AncestorsIterator(self, tags) - - def iterdescendants(self, tag=None, *tags): - """iterdescendants(self, tag=None, *tags) - - Iterate over the descendants of this element in document order. - - As opposed to ``el.iter()``, this iterator does not yield the element - itself. The returned elements can be restricted to find only elements - with specific tags, see `iter`. - """ - if self._c_node and not self._c_node.children: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return ElementDepthFirstIterator(self, tags, inclusive=False) - - def iterchildren(self, tag=None, *tags, reversed=False): - """iterchildren(self, tag=None, *tags, reversed=False) - - Iterate over the children of this element. - - As opposed to using normal iteration on this element, the returned - elements can be reversed with the 'reversed' keyword and restricted - to find only elements with specific tags, see `iter`. - """ - if self._c_node and not self._c_node.children: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return ElementChildIterator(self, tags, reversed=reversed) - - def getroottree(self): - """getroottree(self) - - Return an ElementTree for the root node of the document that - contains this element. - - This is the same as following element.getparent() up the tree until it - returns None (for the root element) and then build an ElementTree for - the last parent that was returned.""" - _assertValidDoc(self._doc) - return _elementTreeFactory(self._doc, None) - - def getiterator(self, tag=None, *tags): - """getiterator(self, tag=None, *tags) - - Returns a sequence or iterator of all elements in the subtree in - document order (depth first pre-order), starting with this - element. - - Can be restricted to find only elements with specific tags, - see `iter`. - - :deprecated: Note that this method is deprecated as of - ElementTree 1.3 and lxml 2.0. It returns an iterator in - lxml, which diverges from the original ElementTree - behaviour. If you want an efficient iterator, use the - ``element.iter()`` method instead. You should only use this - method in new code if you require backwards compatibility - with older versions of lxml or ElementTree. - """ - if tag is not None: - tags += (tag,) - return ElementDepthFirstIterator(self, tags) - - def iter(self, tag=None, *tags): - """iter(self, tag=None, *tags) - - Iterate over all elements in the subtree in document order (depth - first pre-order), starting with this element. - - Can be restricted to find only elements with specific tags: - pass ``"{ns}localname"`` as tag. Either or both of ``ns`` and - ``localname`` can be ``*`` for a wildcard; ``ns`` can be empty - for no namespace. ``"localname"`` is equivalent to ``"{}localname"`` - (i.e. no namespace) but ``"*"`` is ``"{*}*"`` (any or no namespace), - not ``"{}*"``. - - You can also pass the Element, Comment, ProcessingInstruction and - Entity factory functions to look only for the specific element type. - - Passing multiple tags (or a sequence of tags) instead of a single tag - will let the iterator return all elements matching any of these tags, - in document order. - """ - if tag is not None: - tags += (tag,) - return ElementDepthFirstIterator(self, tags) - - def itertext(self, tag=None, *tags, with_tail=True): - """itertext(self, tag=None, *tags, with_tail=True) - - Iterates over the text content of a subtree. - - You can pass tag names to restrict text content to specific elements, - see `iter`. - - You can set the ``with_tail`` keyword argument to ``False`` to skip - over tail text. - """ - if tag is not None: - tags += (tag,) - return ElementTextIterator(self, tags, with_tail=with_tail) - - def makeelement(self, _tag, attrib=None, nsmap=None, **_extra): - """makeelement(self, _tag, attrib=None, nsmap=None, **_extra) - - Creates a new element associated with the same document. - """ - _assertValidDoc(self._doc) - return _makeElement(_tag, NULL, self._doc, None, None, None, - attrib, nsmap, _extra) - - def find(self, path, namespaces=None): - """find(self, path, namespaces=None) - - Finds the first matching subelement, by tag name or path. - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - if isinstance(path, QName): - path = (path).text - return _elementpath.find(self, path, namespaces, with_prefixes=not _isHtmlDocument(self)) - - def findtext(self, path, default=None, namespaces=None): - """findtext(self, path, default=None, namespaces=None) - - Finds text for the first matching subelement, by tag name or path. - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - if isinstance(path, QName): - path = (path).text - return _elementpath.findtext(self, path, default, namespaces, with_prefixes=not _isHtmlDocument(self)) - - def findall(self, path, namespaces=None): - """findall(self, path, namespaces=None) - - Finds all matching subelements, by tag name or path. - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - if isinstance(path, QName): - path = (path).text - return _elementpath.findall(self, path, namespaces, with_prefixes=not _isHtmlDocument(self)) - - def iterfind(self, path, namespaces=None): - """iterfind(self, path, namespaces=None) - - Iterates over all matching subelements, by tag name or path. - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - if isinstance(path, QName): - path = (path).text - return _elementpath.iterfind(self, path, namespaces, with_prefixes=not _isHtmlDocument(self)) - - def xpath(self, _path, *, namespaces=None, extensions=None, - smart_strings=True, **_variables): - """xpath(self, _path, namespaces=None, extensions=None, smart_strings=True, **_variables) - - Evaluate an xpath expression using the element as context node. - """ - evaluator = XPathElementEvaluator(self, namespaces=namespaces, - extensions=extensions, - smart_strings=smart_strings) - return evaluator(_path, **_variables) - - def cssselect(self, expr, *, translator='xml'): - """ - Run the CSS expression on this element and its children, - returning a list of the results. - - Equivalent to lxml.cssselect.CSSSelect(expr)(self) -- note - that pre-compiling the expression can provide a substantial - speedup. - """ - # Do the import here to make the dependency optional. - from lxml.cssselect import CSSSelector - return CSSSelector(expr, translator=translator)(self) - - -@cython.linetrace(False) -cdef _Element _elementFactory(_Document doc, xmlNode* c_node): - cdef _Element result - result = getProxy(c_node) - if result is not None: - return result - if c_node is NULL: - return None - - element_class = LOOKUP_ELEMENT_CLASS( - ELEMENT_CLASS_LOOKUP_STATE, doc, c_node) - if type(element_class) is not type: - if not isinstance(element_class, type): - raise TypeError(f"Element class is not a type, got {type(element_class)}") - if hasProxy(c_node): - # prevent re-entry race condition - we just called into Python - return getProxy(c_node) - result = element_class.__new__(element_class) - if hasProxy(c_node): - # prevent re-entry race condition - we just called into Python - result._c_node = NULL - return getProxy(c_node) - - _registerProxy(result, doc, c_node) - if element_class is not _Element: - result._init() - return result - - -@cython.internal -cdef class __ContentOnlyElement(_Element): - cdef int _raiseImmutable(self) except -1: - raise TypeError, "this element does not have children or attributes" - - def set(self, key, value): - "set(self, key, value)" - self._raiseImmutable() - - def append(self, value): - "append(self, value)" - self._raiseImmutable() - - def insert(self, index, value): - "insert(self, index, value)" - self._raiseImmutable() - - def __setitem__(self, index, value): - "__setitem__(self, index, value)" - self._raiseImmutable() - - @property - def attrib(self): - return IMMUTABLE_EMPTY_MAPPING - - property text: - def __get__(self): - _assertValidNode(self) - return funicodeOrEmpty(self._c_node.content) - - def __set__(self, value): - cdef tree.xmlDict* c_dict - _assertValidNode(self) - if value is None: - c_text = NULL - else: - value = _utf8(value) - c_text = _xcstr(value) - tree.xmlNodeSetContent(self._c_node, c_text) - - # ACCESSORS - def __getitem__(self, x): - "__getitem__(self, x)" - if isinstance(x, slice): - return [] - else: - raise IndexError, "list index out of range" - - def __len__(self): - "__len__(self)" - return 0 - - def get(self, key, default=None): - "get(self, key, default=None)" - return None - - def keys(self): - "keys(self)" - return [] - - def items(self): - "items(self)" - return [] - - def values(self): - "values(self)" - return [] - -cdef class _Comment(__ContentOnlyElement): - @property - def tag(self): - return Comment - - def __repr__(self): - return "" % self.text - -cdef class _ProcessingInstruction(__ContentOnlyElement): - @property - def tag(self): - return ProcessingInstruction - - property target: - # not in ElementTree - def __get__(self): - _assertValidNode(self) - return funicode(self._c_node.name) - - def __set__(self, value): - _assertValidNode(self) - value = _utf8(value) - c_text = _xcstr(value) - tree.xmlNodeSetName(self._c_node, c_text) - - def __repr__(self): - text = self.text - if text: - return "" % (self.target, text) - else: - return "" % self.target - - def get(self, key, default=None): - """get(self, key, default=None) - - Try to parse pseudo-attributes from the text content of the - processing instruction, search for one with the given key as - name and return its associated value. - - Note that this is only a convenience method for the most - common case that all text content is structured in - attribute-like name-value pairs with properly quoted values. - It is not guaranteed to work for all possible text content. - """ - return self.attrib.get(key, default) - - @property - def attrib(self): - """Returns a dict containing all pseudo-attributes that can be - parsed from the text content of this processing instruction. - Note that modifying the dict currently has no effect on the - XML node, although this is not guaranteed to stay this way. - """ - return { attr : (value1 or value2) - for attr, value1, value2 in _FIND_PI_ATTRIBUTES(' ' + self.text) } - -cdef object _FIND_PI_ATTRIBUTES = re.compile(r'\s+(\w+)\s*=\s*(?:\'([^\']*)\'|"([^"]*)")', re.U).findall - -cdef class _Entity(__ContentOnlyElement): - @property - def tag(self): - return Entity - - property name: - # not in ElementTree - def __get__(self): - _assertValidNode(self) - return funicode(self._c_node.name) - - def __set__(self, value): - _assertValidNode(self) - value_utf = _utf8(value) - if b'&' in value_utf or b';' in value_utf: - raise ValueError, f"Invalid entity name '{value}'" - tree.xmlNodeSetName(self._c_node, _xcstr(value_utf)) - - @property - def text(self): - # FIXME: should this be None or '&[VALUE];' or the resolved - # entity value ? - _assertValidNode(self) - return f'&{funicode(self._c_node.name)};' - - def __repr__(self): - return "&%s;" % self.name - - -cdef class QName: - """QName(text_or_uri_or_element, tag=None) - - QName wrapper for qualified XML names. - - Pass a tag name by itself or a namespace URI and a tag name to - create a qualified name. Alternatively, pass an Element to - extract its tag name. ``None`` as first argument is ignored in - order to allow for generic 2-argument usage. - - The ``text`` property holds the qualified name in - ``{namespace}tagname`` notation. The ``namespace`` and - ``localname`` properties hold the respective parts of the tag - name. - - You can pass QName objects wherever a tag name is expected. Also, - setting Element text from a QName will resolve the namespace prefix - on assignment and set a qualified text value. This is helpful in XML - languages like SOAP or XML-Schema that use prefixed tag names in - their text content. - """ - cdef readonly unicode text - cdef readonly unicode localname - cdef readonly unicode namespace - def __init__(self, text_or_uri_or_element, tag=None): - if text_or_uri_or_element is None: - # Allow None as no namespace. - text_or_uri_or_element, tag = tag, None - if not _isString(text_or_uri_or_element): - if isinstance(text_or_uri_or_element, _Element): - text_or_uri_or_element = (<_Element>text_or_uri_or_element).tag - if not _isString(text_or_uri_or_element): - raise ValueError, f"Invalid input tag of type {type(text_or_uri_or_element)!r}" - elif isinstance(text_or_uri_or_element, QName): - text_or_uri_or_element = (text_or_uri_or_element).text - elif text_or_uri_or_element is not None: - text_or_uri_or_element = unicode(text_or_uri_or_element) - else: - raise ValueError, f"Invalid input tag of type {type(text_or_uri_or_element)!r}" - - ns_utf, tag_utf = _getNsTag(text_or_uri_or_element) - if tag is not None: - # either ('ns', 'tag') or ('{ns}oldtag', 'newtag') - if ns_utf is None: - ns_utf = tag_utf # case 1: namespace ended up as tag name - tag_utf = _utf8(tag) - _tagValidOrRaise(tag_utf) - self.localname = (tag_utf).decode('utf8') - if ns_utf is None: - self.namespace = None - self.text = self.localname - else: - self.namespace = (ns_utf).decode('utf8') - self.text = "{%s}%s" % (self.namespace, self.localname) - def __str__(self): - return self.text - def __hash__(self): - return hash(self.text) - def __richcmp__(self, other, int op): - try: - if type(other) is QName: - other = (other).text - elif not isinstance(other, unicode): - other = unicode(other) - except (ValueError, UnicodeDecodeError): - return NotImplemented - return python.PyObject_RichCompare(self.text, other, op) - - -cdef public class _ElementTree [ type LxmlElementTreeType, - object LxmlElementTree ]: - cdef _Document _doc - cdef _Element _context_node - - # Note that _doc is only used to store the original document if we do not - # have a _context_node. All methods should prefer self._context_node._doc - # to honour tree restructuring. _doc can happily be None! - - @cython.final - cdef int _assertHasRoot(self) except -1: - """We have to take care here: the document may not have a root node! - This can happen if ElementTree() is called without any argument and - the caller 'forgets' to call parse() afterwards, so this is a bug in - the caller program. - """ - assert self._context_node is not None, \ - "ElementTree not initialized, missing root" - return 0 - - def parse(self, source, _BaseParser parser=None, *, base_url=None): - """parse(self, source, parser=None, base_url=None) - - Updates self with the content of source and returns its root. - """ - cdef _Document doc = None - try: - doc = _parseDocument(source, parser, base_url) - except _TargetParserResult as result_container: - # raises a TypeError if we don't get an _Element - self._context_node = result_container.result - else: - self._context_node = doc.getroot() - self._doc = None if self._context_node is not None else doc - return self._context_node - - def _setroot(self, _Element root not None): - """_setroot(self, root) - - Relocate the ElementTree to a new root node. - """ - _assertValidNode(root) - if root._c_node.type != tree.XML_ELEMENT_NODE: - raise TypeError, "Only elements can be the root of an ElementTree" - self._context_node = root - self._doc = None - - def getroot(self): - """getroot(self) - - Gets the root element for this tree. - """ - return self._context_node - - def __copy__(self): - return _elementTreeFactory(self._doc, self._context_node) - - def __deepcopy__(self, memo): - cdef _Element root - cdef _Document doc - cdef xmlDoc* c_doc - if self._context_node is not None: - root = self._context_node.__copy__() - assert root is not None - _assertValidNode(root) - _copyNonElementSiblings(self._context_node._c_node, root._c_node) - return _elementTreeFactory(None, root) - elif self._doc is not None: - _assertValidDoc(self._doc) - c_doc = tree.xmlCopyDoc(self._doc._c_doc, 1) - if c_doc is NULL: - raise MemoryError() - doc = _documentFactory(c_doc, self._doc._parser) - return _elementTreeFactory(doc, None) - else: - # so what ... - return self - - # not in ElementTree - @property - def docinfo(self) -> DocInfo: - """Information about the document provided by parser and DTD.""" - self._assertHasRoot() - return DocInfo(self._context_node._doc) - - # not in ElementTree, read-only - @property - def parser(self): - """The parser that was used to parse the document in this ElementTree. - """ - if self._context_node is not None and \ - self._context_node._doc is not None: - return self._context_node._doc._parser - if self._doc is not None: - return self._doc._parser - return None - - def write(self, file, *, encoding=None, method="xml", - bint pretty_print=False, xml_declaration=None, bint with_tail=True, - standalone=None, doctype=None, compression=0, - bint exclusive=False, inclusive_ns_prefixes=None, - bint with_comments=True, bint strip_text=False, - docstring=None): - """write(self, file, encoding=None, method="xml", - pretty_print=False, xml_declaration=None, with_tail=True, - standalone=None, doctype=None, compression=0, - exclusive=False, inclusive_ns_prefixes=None, - with_comments=True, strip_text=False) - - Write the tree to a filename, file or file-like object. - - Defaults to ASCII encoding and writing a declaration as needed. - - The keyword argument 'method' selects the output method: - 'xml', 'html', 'text', 'c14n' or 'c14n2'. Default is 'xml'. - - With ``method="c14n"`` (C14N version 1), the options ``exclusive``, - ``with_comments`` and ``inclusive_ns_prefixes`` request exclusive - C14N, include comments, and list the inclusive prefixes respectively. - - With ``method="c14n2"`` (C14N version 2), the ``with_comments`` and - ``strip_text`` options control the output of comments and text space - according to C14N 2.0. - - Passing a boolean value to the ``standalone`` option will - output an XML declaration with the corresponding - ``standalone`` flag. - - The ``doctype`` option allows passing in a plain string that will - be serialised before the XML tree. Note that passing in non - well-formed content here will make the XML output non well-formed. - Also, an existing doctype in the document tree will not be removed - when serialising an ElementTree instance. - - The ``compression`` option enables GZip compression level 1-9. - - The ``inclusive_ns_prefixes`` should be a list of namespace strings - (i.e. ['xs', 'xsi']) that will be promoted to the top-level element - during exclusive C14N serialisation. This parameter is ignored if - exclusive mode=False. - - If exclusive=True and no list is provided, a namespace will only be - rendered if it is used by the immediate parent or one of its attributes - and its prefix and values have not already been rendered by an ancestor - of the namespace node's parent element. - """ - cdef bint write_declaration - cdef int is_standalone - - self._assertHasRoot() - _assertValidNode(self._context_node) - if compression is None or compression < 0: - compression = 0 - - # C14N serialisation - if method in ('c14n', 'c14n2'): - if encoding is not None: - raise ValueError("Cannot specify encoding with C14N") - if xml_declaration: - raise ValueError("Cannot enable XML declaration in C14N") - - if method == 'c14n': - _tofilelikeC14N(file, self._context_node, exclusive, with_comments, - compression, inclusive_ns_prefixes) - else: # c14n2 - with _open_utf8_file(file, compression=compression) as f: - target = C14NWriterTarget( - f.write, with_comments=with_comments, strip_text=strip_text) - _tree_to_target(self, target) - return - - if not with_comments: - raise ValueError("Can only discard comments in C14N serialisation") - # suppress decl. in default case (purely for ElementTree compatibility) - if xml_declaration is not None: - write_declaration = xml_declaration - if encoding is None: - encoding = 'ASCII' - else: - encoding = encoding.upper() - elif encoding is None: - encoding = 'ASCII' - write_declaration = 0 - else: - encoding = encoding.upper() - write_declaration = encoding not in ( - 'US-ASCII', 'ASCII', 'UTF8', 'UTF-8') - if standalone is None: - is_standalone = -1 - elif standalone: - write_declaration = 1 - is_standalone = 1 - else: - write_declaration = 1 - is_standalone = 0 - - if docstring is not None and doctype is None: - import warnings - warnings.warn( - "The 'docstring' option is deprecated. Use 'doctype' instead.", - DeprecationWarning) - doctype = docstring - - _tofilelike(file, self._context_node, encoding, doctype, method, - write_declaration, 1, pretty_print, with_tail, - is_standalone, compression) - - def getpath(self, _Element element not None): - """getpath(self, element) - - Returns a structural, absolute XPath expression to find the element. - - For namespaced elements, the expression uses prefixes from the - document, which therefore need to be provided in order to make any - use of the expression in XPath. - - Also see the method getelementpath(self, element), which returns a - self-contained ElementPath expression. - """ - cdef _Document doc - cdef _Element root - cdef xmlDoc* c_doc - _assertValidNode(element) - if self._context_node is not None: - root = self._context_node - doc = root._doc - elif self._doc is not None: - doc = self._doc - root = doc.getroot() - else: - raise ValueError, "Element is not in this tree." - _assertValidDoc(doc) - _assertValidNode(root) - if element._doc is not doc: - raise ValueError, "Element is not in this tree." - - c_doc = _fakeRootDoc(doc._c_doc, root._c_node) - c_path = tree.xmlGetNodePath(element._c_node) - _destroyFakeDoc(doc._c_doc, c_doc) - if c_path is NULL: - raise MemoryError() - path = funicode(c_path) - tree.xmlFree(c_path) - return path - - def getelementpath(self, _Element element not None): - """getelementpath(self, element) - - Returns a structural, absolute ElementPath expression to find the - element. This path can be used in the .find() method to look up - the element, provided that the elements along the path and their - list of immediate children were not modified in between. - - ElementPath has the advantage over an XPath expression (as returned - by the .getpath() method) that it does not require additional prefix - declarations. It is always self-contained. - """ - cdef _Element root - cdef Py_ssize_t count - _assertValidNode(element) - if element._c_node.type != tree.XML_ELEMENT_NODE: - raise ValueError, "input is not an Element" - if self._context_node is not None: - root = self._context_node - elif self._doc is not None: - root = self._doc.getroot() - else: - raise ValueError, "Element is not in this tree" - _assertValidNode(root) - if element._doc is not root._doc: - raise ValueError, "Element is not in this tree" - - path = [] - c_element = element._c_node - while c_element is not root._c_node: - c_name = c_element.name - c_href = _getNs(c_element) - tag = _namespacedNameFromNsName(c_href, c_name) - if c_href is NULL: - c_href = b'' # no namespace (NULL is wildcard) - # use tag[N] if there are preceding siblings with the same tag - count = 0 - c_node = c_element.prev - while c_node is not NULL: - if c_node.type == tree.XML_ELEMENT_NODE: - if _tagMatches(c_node, c_href, c_name): - count += 1 - c_node = c_node.prev - if count: - tag = f'{tag}[{count+1}]' - else: - # use tag[1] if there are following siblings with the same tag - c_node = c_element.next - while c_node is not NULL: - if c_node.type == tree.XML_ELEMENT_NODE: - if _tagMatches(c_node, c_href, c_name): - tag += '[1]' - break - c_node = c_node.next - - path.append(tag) - c_element = c_element.parent - if c_element is NULL or c_element.type != tree.XML_ELEMENT_NODE: - raise ValueError, "Element is not in this tree." - if not path: - return '.' - path.reverse() - return '/'.join(path) - - def getiterator(self, tag=None, *tags): - """getiterator(self, *tags, tag=None) - - Returns a sequence or iterator of all elements in document order - (depth first pre-order), starting with the root element. - - Can be restricted to find only elements with specific tags, - see `_Element.iter`. - - :deprecated: Note that this method is deprecated as of - ElementTree 1.3 and lxml 2.0. It returns an iterator in - lxml, which diverges from the original ElementTree - behaviour. If you want an efficient iterator, use the - ``tree.iter()`` method instead. You should only use this - method in new code if you require backwards compatibility - with older versions of lxml or ElementTree. - """ - root = self.getroot() - if root is None: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return root.getiterator(*tags) - - def iter(self, tag=None, *tags): - """iter(self, tag=None, *tags) - - Creates an iterator for the root element. The iterator loops over - all elements in this tree, in document order. Note that siblings - of the root element (comments or processing instructions) are not - returned by the iterator. - - Can be restricted to find only elements with specific tags, - see `_Element.iter`. - """ - root = self.getroot() - if root is None: - return ITER_EMPTY - if tag is not None: - tags += (tag,) - return root.iter(*tags) - - def find(self, path, namespaces=None): - """find(self, path, namespaces=None) - - Finds the first toplevel element with given tag. Same as - ``tree.getroot().find(path)``. - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - self._assertHasRoot() - root = self.getroot() - if _isString(path): - if path[:1] == "/": - path = "." + path - from warnings import warn - warn( - "This search incorrectly ignores the root element, and will be " - "fixed in a future version. If you rely on the current " - f"behaviour, change it to {path!r}", - FutureWarning, stacklevel=1 - ) - return root.find(path, namespaces) - - def findtext(self, path, default=None, namespaces=None): - """findtext(self, path, default=None, namespaces=None) - - Finds the text for the first element matching the ElementPath - expression. Same as getroot().findtext(path) - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - self._assertHasRoot() - root = self.getroot() - if _isString(path): - if path[:1] == "/": - path = "." + path - from warnings import warn - warn( - "This search incorrectly ignores the root element, and will be " - "fixed in a future version. If you rely on the current " - f"behaviour, change it to {path!r}", - FutureWarning, stacklevel=1 - ) - return root.findtext(path, default, namespaces) - - def findall(self, path, namespaces=None): - """findall(self, path, namespaces=None) - - Finds all elements matching the ElementPath expression. Same as - getroot().findall(path). - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - self._assertHasRoot() - root = self.getroot() - if _isString(path): - if path[:1] == "/": - path = "." + path - from warnings import warn - warn( - "This search incorrectly ignores the root element, and will be " - "fixed in a future version. If you rely on the current " - f"behaviour, change it to {path!r}", - FutureWarning, stacklevel=1 - ) - return root.findall(path, namespaces) - - def iterfind(self, path, namespaces=None): - """iterfind(self, path, namespaces=None) - - Iterates over all elements matching the ElementPath expression. - Same as getroot().iterfind(path). - - The optional ``namespaces`` argument accepts a - prefix-to-namespace mapping that allows the usage of XPath - prefixes in the path expression. - """ - self._assertHasRoot() - root = self.getroot() - if _isString(path): - if path[:1] == "/": - path = "." + path - from warnings import warn - warn( - "This search incorrectly ignores the root element, and will be " - "fixed in a future version. If you rely on the current " - f"behaviour, change it to {path!r}", - FutureWarning, stacklevel=1 - ) - return root.iterfind(path, namespaces) - - def xpath(self, _path, *, namespaces=None, extensions=None, - smart_strings=True, **_variables): - """xpath(self, _path, namespaces=None, extensions=None, smart_strings=True, **_variables) - - XPath evaluate in context of document. - - ``namespaces`` is an optional dictionary with prefix to namespace URI - mappings, used by XPath. ``extensions`` defines additional extension - functions. - - Returns a list (nodeset), or bool, float or string. - - In case of a list result, return Element for element nodes, - string for text and attribute values. - - Note: if you are going to apply multiple XPath expressions - against the same document, it is more efficient to use - XPathEvaluator directly. - """ - self._assertHasRoot() - evaluator = XPathDocumentEvaluator(self, namespaces=namespaces, - extensions=extensions, - smart_strings=smart_strings) - return evaluator(_path, **_variables) - - def xslt(self, _xslt, extensions=None, access_control=None, **_kw): - """xslt(self, _xslt, extensions=None, access_control=None, **_kw) - - Transform this document using other document. - - xslt is a tree that should be XSLT - keyword parameters are XSLT transformation parameters. - - Returns the transformed tree. - - Note: if you are going to apply the same XSLT stylesheet against - multiple documents, it is more efficient to use the XSLT - class directly. - """ - self._assertHasRoot() - style = XSLT(_xslt, extensions=extensions, - access_control=access_control) - return style(self, **_kw) - - def relaxng(self, relaxng): - """relaxng(self, relaxng) - - Validate this document using other document. - - The relaxng argument is a tree that should contain a Relax NG schema. - - Returns True or False, depending on whether validation - succeeded. - - Note: if you are going to apply the same Relax NG schema against - multiple documents, it is more efficient to use the RelaxNG - class directly. - """ - self._assertHasRoot() - schema = RelaxNG(relaxng) - return schema.validate(self) - - def xmlschema(self, xmlschema): - """xmlschema(self, xmlschema) - - Validate this document using other document. - - The xmlschema argument is a tree that should contain an XML Schema. - - Returns True or False, depending on whether validation - succeeded. - - Note: If you are going to apply the same XML Schema against - multiple documents, it is more efficient to use the XMLSchema - class directly. - """ - self._assertHasRoot() - schema = XMLSchema(xmlschema) - return schema.validate(self) - - def xinclude(self): - """xinclude(self) - - Process the XInclude nodes in this document and include the - referenced XML fragments. - - There is support for loading files through the file system, HTTP and - FTP. - - Note that XInclude does not support custom resolvers in Python space - due to restrictions of libxml2 <= 2.6.29. - """ - self._assertHasRoot() - XInclude()(self._context_node) - - def write_c14n(self, file, *, bint exclusive=False, bint with_comments=True, - compression=0, inclusive_ns_prefixes=None): - """write_c14n(self, file, exclusive=False, with_comments=True, - compression=0, inclusive_ns_prefixes=None) - - C14N write of document. Always writes UTF-8. - - The ``compression`` option enables GZip compression level 1-9. - - The ``inclusive_ns_prefixes`` should be a list of namespace strings - (i.e. ['xs', 'xsi']) that will be promoted to the top-level element - during exclusive C14N serialisation. This parameter is ignored if - exclusive mode=False. - - If exclusive=True and no list is provided, a namespace will only be - rendered if it is used by the immediate parent or one of its attributes - and its prefix and values have not already been rendered by an ancestor - of the namespace node's parent element. - - NOTE: This method is deprecated as of lxml 4.4 and will be removed in a - future release. Use ``.write(f, method="c14n")`` instead. - """ - self._assertHasRoot() - _assertValidNode(self._context_node) - if compression is None or compression < 0: - compression = 0 - - _tofilelikeC14N(file, self._context_node, exclusive, with_comments, - compression, inclusive_ns_prefixes) - -cdef _ElementTree _elementTreeFactory(_Document doc, _Element context_node): - return _newElementTree(doc, context_node, _ElementTree) - -cdef _ElementTree _newElementTree(_Document doc, _Element context_node, - object baseclass): - cdef _ElementTree result - result = baseclass() - if context_node is None and doc is not None: - context_node = doc.getroot() - if context_node is None: - _assertValidDoc(doc) - result._doc = doc - else: - _assertValidNode(context_node) - result._context_node = context_node - return result - - -@cython.final -@cython.freelist(16) -cdef class _Attrib: - """A dict-like proxy for the ``Element.attrib`` property. - """ - cdef _Element _element - def __cinit__(self, _Element element not None): - _assertValidNode(element) - self._element = element - - # MANIPULATORS - def __setitem__(self, key, value): - _assertValidNode(self._element) - _setAttributeValue(self._element, key, value) - - def __delitem__(self, key): - _assertValidNode(self._element) - _delAttribute(self._element, key) - - def update(self, sequence_or_dict): - _assertValidNode(self._element) - if isinstance(sequence_or_dict, (dict, _Attrib)): - sequence_or_dict = sequence_or_dict.items() - for key, value in sequence_or_dict: - _setAttributeValue(self._element, key, value) - - def pop(self, key, *default): - if len(default) > 1: - raise TypeError, f"pop expected at most 2 arguments, got {len(default)+1}" - _assertValidNode(self._element) - result = _getAttributeValue(self._element, key, None) - if result is None: - if not default: - raise KeyError, key - result = default[0] - else: - _delAttribute(self._element, key) - return result - - def clear(self): - _assertValidNode(self._element) - c_attrs = self._element._c_node.properties - if c_attrs: - self._element._c_node.properties = NULL - tree.xmlFreePropList(c_attrs) - - # ACCESSORS - def __repr__(self): - _assertValidNode(self._element) - return repr(dict( _collectAttributes(self._element._c_node, 3) )) - - def __copy__(self): - _assertValidNode(self._element) - return dict(_collectAttributes(self._element._c_node, 3)) - - def __deepcopy__(self, memo): - _assertValidNode(self._element) - return dict(_collectAttributes(self._element._c_node, 3)) - - def __getitem__(self, key): - _assertValidNode(self._element) - result = _getAttributeValue(self._element, key, None) - if result is None: - raise KeyError, key - return result - - def __bool__(self): - _assertValidNode(self._element) - cdef xmlAttr* c_attr = self._element._c_node.properties - while c_attr is not NULL: - if c_attr.type == tree.XML_ATTRIBUTE_NODE: - return 1 - c_attr = c_attr.next - return 0 - - def __len__(self): - _assertValidNode(self._element) - cdef xmlAttr* c_attr = self._element._c_node.properties - cdef Py_ssize_t c = 0 - while c_attr is not NULL: - if c_attr.type == tree.XML_ATTRIBUTE_NODE: - c += 1 - c_attr = c_attr.next - return c - - def get(self, key, default=None): - _assertValidNode(self._element) - return _getAttributeValue(self._element, key, default) - - def keys(self): - _assertValidNode(self._element) - return _collectAttributes(self._element._c_node, 1) - - def __iter__(self): - _assertValidNode(self._element) - return iter(_collectAttributes(self._element._c_node, 1)) - - def iterkeys(self): - _assertValidNode(self._element) - return iter(_collectAttributes(self._element._c_node, 1)) - - def values(self): - _assertValidNode(self._element) - return _collectAttributes(self._element._c_node, 2) - - def itervalues(self): - _assertValidNode(self._element) - return iter(_collectAttributes(self._element._c_node, 2)) - - def items(self): - _assertValidNode(self._element) - return _collectAttributes(self._element._c_node, 3) - - def iteritems(self): - _assertValidNode(self._element) - return iter(_collectAttributes(self._element._c_node, 3)) - - def has_key(self, key): - _assertValidNode(self._element) - return key in self - - def __contains__(self, key): - _assertValidNode(self._element) - cdef xmlNode* c_node - ns, tag = _getNsTag(key) - c_node = self._element._c_node - c_href = NULL if ns is None else _xcstr(ns) - return 1 if tree.xmlHasNsProp(c_node, _xcstr(tag), c_href) else 0 - - def __richcmp__(self, other, int op): - try: - one = dict(self.items()) - if not isinstance(other, dict): - other = dict(other) - except (TypeError, ValueError): - return NotImplemented - return python.PyObject_RichCompare(one, other, op) - -MutableMapping.register(_Attrib) - - -@cython.final -@cython.internal -cdef class _AttribIterator: - """Attribute iterator - for internal use only! - """ - # XML attributes must not be removed while running! - cdef _Element _node - cdef xmlAttr* _c_attr - cdef int _keysvalues # 1 - keys, 2 - values, 3 - items (key, value) - def __iter__(self): - return self - - def __next__(self): - cdef xmlAttr* c_attr - if self._node is None: - raise StopIteration - c_attr = self._c_attr - while c_attr is not NULL and c_attr.type != tree.XML_ATTRIBUTE_NODE: - c_attr = c_attr.next - if c_attr is NULL: - self._node = None - raise StopIteration - - self._c_attr = c_attr.next - if self._keysvalues == 1: - return _namespacedName(c_attr) - elif self._keysvalues == 2: - return _attributeValue(self._node._c_node, c_attr) - else: - return (_namespacedName(c_attr), - _attributeValue(self._node._c_node, c_attr)) - -cdef object _attributeIteratorFactory(_Element element, int keysvalues): - cdef _AttribIterator attribs - if element._c_node.properties is NULL: - return ITER_EMPTY - attribs = _AttribIterator() - attribs._node = element - attribs._c_attr = element._c_node.properties - attribs._keysvalues = keysvalues - return attribs - - -cdef public class _ElementTagMatcher [ object LxmlElementTagMatcher, - type LxmlElementTagMatcherType ]: - """ - Dead but public. :) - """ - cdef object _pystrings - cdef int _node_type - cdef char* _href - cdef char* _name - cdef _initTagMatch(self, tag): - self._href = NULL - self._name = NULL - if tag is None: - self._node_type = 0 - elif tag is Comment: - self._node_type = tree.XML_COMMENT_NODE - elif tag is ProcessingInstruction: - self._node_type = tree.XML_PI_NODE - elif tag is Entity: - self._node_type = tree.XML_ENTITY_REF_NODE - elif tag is Element: - self._node_type = tree.XML_ELEMENT_NODE - else: - self._node_type = tree.XML_ELEMENT_NODE - self._pystrings = _getNsTag(tag) - if self._pystrings[0] is not None: - self._href = _cstr(self._pystrings[0]) - self._name = _cstr(self._pystrings[1]) - if self._name[0] == c'*' and self._name[1] == c'\0': - self._name = NULL - -cdef public class _ElementIterator(_ElementTagMatcher) [ - object LxmlElementIterator, type LxmlElementIteratorType ]: - """ - Dead but public. :) - """ - # we keep Python references here to control GC - cdef _Element _node - cdef _node_to_node_function _next_element - def __iter__(self): - return self - - cdef void _storeNext(self, _Element node): - cdef xmlNode* c_node - c_node = self._next_element(node._c_node) - while c_node is not NULL and \ - self._node_type != 0 and \ - (self._node_type != c_node.type or - not _tagMatches(c_node, self._href, self._name)): - c_node = self._next_element(c_node) - if c_node is NULL: - self._node = None - else: - # Python ref: - self._node = _elementFactory(node._doc, c_node) - - def __next__(self): - cdef xmlNode* c_node - cdef _Element current_node - if self._node is None: - raise StopIteration - # Python ref: - current_node = self._node - self._storeNext(current_node) - return current_node - -@cython.final -@cython.internal -cdef class _MultiTagMatcher: - """ - Match an xmlNode against a list of tags. - """ - cdef list _py_tags - cdef qname* _cached_tags - cdef size_t _tag_count - cdef size_t _cached_size - cdef _Document _cached_doc - cdef int _node_types - - def __cinit__(self, tags): - self._py_tags = [] - self.initTagMatch(tags) - - def __dealloc__(self): - self._clear() - - cdef bint rejectsAll(self) noexcept: - return not self._tag_count and not self._node_types - - cdef bint rejectsAllAttributes(self) noexcept: - return not self._tag_count - - cdef bint matchesType(self, int node_type) noexcept: - if node_type == tree.XML_ELEMENT_NODE and self._tag_count: - return True - return self._node_types & (1 << node_type) - - cdef void _clear(self) noexcept: - cdef size_t i, count - count = self._tag_count - self._tag_count = 0 - if self._cached_tags: - for i in range(count): - cpython.ref.Py_XDECREF(self._cached_tags[i].href) - python.lxml_free(self._cached_tags) - self._cached_tags = NULL - - cdef initTagMatch(self, tags): - self._cached_doc = None - del self._py_tags[:] - self._clear() - if tags is None or tags == (): - # no selection in tags argument => match anything - self._node_types = ( - 1 << tree.XML_COMMENT_NODE | - 1 << tree.XML_PI_NODE | - 1 << tree.XML_ENTITY_REF_NODE | - 1 << tree.XML_ELEMENT_NODE) - else: - self._node_types = 0 - self._storeTags(tags, set()) - - cdef _storeTags(self, tag, set seen): - if tag is Comment: - self._node_types |= 1 << tree.XML_COMMENT_NODE - elif tag is ProcessingInstruction: - self._node_types |= 1 << tree.XML_PI_NODE - elif tag is Entity: - self._node_types |= 1 << tree.XML_ENTITY_REF_NODE - elif tag is Element: - self._node_types |= 1 << tree.XML_ELEMENT_NODE - elif python._isString(tag): - if tag in seen: - return - seen.add(tag) - if tag in ('*', '{*}*'): - self._node_types |= 1 << tree.XML_ELEMENT_NODE - else: - href, name = _getNsTag(tag) - if name == b'*': - name = None - if href is None: - href = b'' # no namespace - elif href == b'*': - href = None # wildcard: any namespace, including none - self._py_tags.append((href, name)) - elif isinstance(tag, QName): - self._storeTags(tag.text, seen) - else: - # support a sequence of tags - for item in tag: - self._storeTags(item, seen) - - cdef inline int cacheTags(self, _Document doc, bint force_into_dict=False) except -1: - """ - Look up the tag names in the doc dict to enable string pointer comparisons. - """ - cdef size_t dict_size = tree.xmlDictSize(doc._c_doc.dict) - if doc is self._cached_doc and dict_size == self._cached_size: - # doc and dict didn't change => names already cached - return 0 - self._tag_count = 0 - if not self._py_tags: - self._cached_doc = doc - self._cached_size = dict_size - return 0 - if not self._cached_tags: - self._cached_tags = python.lxml_malloc(len(self._py_tags), sizeof(qname)) - if not self._cached_tags: - self._cached_doc = None - raise MemoryError() - self._tag_count = _mapTagsToQnameMatchArray( - doc._c_doc, self._py_tags, self._cached_tags, force_into_dict) - self._cached_doc = doc - self._cached_size = dict_size - return 0 - - cdef inline bint matches(self, xmlNode* c_node) noexcept: - cdef qname* c_qname - if self._node_types & (1 << c_node.type): - return True - elif c_node.type == tree.XML_ELEMENT_NODE: - for c_qname in self._cached_tags[:self._tag_count]: - if _tagMatchesExactly(c_node, c_qname): - return True - return False - - cdef inline bint matchesNsTag(self, const_xmlChar* c_href, - const_xmlChar* c_name) noexcept: - cdef qname* c_qname - if self._node_types & (1 << tree.XML_ELEMENT_NODE): - return True - for c_qname in self._cached_tags[:self._tag_count]: - if _nsTagMatchesExactly(c_href, c_name, c_qname): - return True - return False - - cdef inline bint matchesAttribute(self, xmlAttr* c_attr) noexcept: - """Attribute matches differ from Element matches in that they do - not care about node types. - """ - cdef qname* c_qname - for c_qname in self._cached_tags[:self._tag_count]: - if _tagMatchesExactly(c_attr, c_qname): - return True - return False - -cdef class _ElementMatchIterator: - cdef _Element _node - cdef _node_to_node_function _next_element - cdef _MultiTagMatcher _matcher - - @cython.final - cdef _initTagMatcher(self, tags): - self._matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, tags) - - def __iter__(self): - return self - - @cython.final - cdef int _storeNext(self, _Element node) except -1: - self._matcher.cacheTags(node._doc) - c_node = self._next_element(node._c_node) - while c_node is not NULL and not self._matcher.matches(c_node): - c_node = self._next_element(c_node) - # store Python ref to next node to make sure it's kept alive - self._node = _elementFactory(node._doc, c_node) if c_node is not NULL else None - return 0 - - def __next__(self): - cdef _Element current_node = self._node - if current_node is None: - raise StopIteration - self._storeNext(current_node) - return current_node - -cdef class ElementChildIterator(_ElementMatchIterator): - """ElementChildIterator(self, node, tag=None, reversed=False) - Iterates over the children of an element. - """ - def __cinit__(self, _Element node not None, tag=None, *, bint reversed=False): - cdef xmlNode* c_node - _assertValidNode(node) - self._initTagMatcher(tag) - if reversed: - c_node = _findChildBackwards(node._c_node, 0) - self._next_element = _previousElement - else: - c_node = _findChildForwards(node._c_node, 0) - self._next_element = _nextElement - self._matcher.cacheTags(node._doc) - while c_node is not NULL and not self._matcher.matches(c_node): - c_node = self._next_element(c_node) - # store Python ref to next node to make sure it's kept alive - self._node = _elementFactory(node._doc, c_node) if c_node is not NULL else None - -cdef class SiblingsIterator(_ElementMatchIterator): - """SiblingsIterator(self, node, tag=None, preceding=False) - Iterates over the siblings of an element. - - You can pass the boolean keyword ``preceding`` to specify the direction. - """ - def __cinit__(self, _Element node not None, tag=None, *, bint preceding=False): - _assertValidNode(node) - self._initTagMatcher(tag) - if preceding: - self._next_element = _previousElement - else: - self._next_element = _nextElement - self._storeNext(node) - -cdef class AncestorsIterator(_ElementMatchIterator): - """AncestorsIterator(self, node, tag=None) - Iterates over the ancestors of an element (from parent to parent). - """ - def __cinit__(self, _Element node not None, tag=None): - _assertValidNode(node) - self._initTagMatcher(tag) - self._next_element = _parentElement - self._storeNext(node) - -cdef class ElementDepthFirstIterator: - """ElementDepthFirstIterator(self, node, tag=None, inclusive=True) - Iterates over an element and its sub-elements in document order (depth - first pre-order). - - Note that this also includes comments, entities and processing - instructions. To filter them out, check if the ``tag`` property - of the returned element is a string (i.e. not None and not a - factory function), or pass the ``Element`` factory for the ``tag`` - argument to receive only Elements. - - If the optional ``tag`` argument is not None, the iterator returns only - the elements that match the respective name and namespace. - - The optional boolean argument 'inclusive' defaults to True and can be set - to False to exclude the start element itself. - - Note that the behaviour of this iterator is completely undefined if the - tree it traverses is modified during iteration. - """ - # we keep Python references here to control GC - # keep the next Element after the one we return, and the (s)top node - cdef _Element _next_node - cdef _Element _top_node - cdef _MultiTagMatcher _matcher - def __cinit__(self, _Element node not None, tag=None, *, bint inclusive=True): - _assertValidNode(node) - self._top_node = node - self._next_node = node - self._matcher = _MultiTagMatcher.__new__(_MultiTagMatcher, tag) - self._matcher.cacheTags(node._doc) - if not inclusive or not self._matcher.matches(node._c_node): - # find start node (this cannot raise StopIteration, self._next_node != None) - next(self) - - def __iter__(self): - return self - - def __next__(self): - cdef xmlNode* c_node - cdef _Element current_node = self._next_node - if current_node is None: - raise StopIteration - c_node = current_node._c_node - self._matcher.cacheTags(current_node._doc) - if not self._matcher._tag_count: - # no tag name was found in the dict => not in document either - # try to match by node type - c_node = self._nextNodeAnyTag(c_node) - else: - c_node = self._nextNodeMatchTag(c_node) - if c_node is NULL: - self._next_node = None - else: - self._next_node = _elementFactory(current_node._doc, c_node) - return current_node - - @cython.final - cdef xmlNode* _nextNodeAnyTag(self, xmlNode* c_node) noexcept: - cdef int node_types = self._matcher._node_types - if not node_types: - return NULL - tree.BEGIN_FOR_EACH_ELEMENT_FROM(self._top_node._c_node, c_node, 0) - if node_types & (1 << c_node.type): - return c_node - tree.END_FOR_EACH_ELEMENT_FROM(c_node) - return NULL - - @cython.final - cdef xmlNode* _nextNodeMatchTag(self, xmlNode* c_node) noexcept: - tree.BEGIN_FOR_EACH_ELEMENT_FROM(self._top_node._c_node, c_node, 0) - if self._matcher.matches(c_node): - return c_node - tree.END_FOR_EACH_ELEMENT_FROM(c_node) - return NULL - - -cdef class ElementTextIterator: - """ElementTextIterator(self, element, tag=None, with_tail=True) - Iterates over the text content of a subtree. - - You can pass the ``tag`` keyword argument to restrict text content to a - specific tag name. - - You can set the ``with_tail`` keyword argument to ``False`` to skip over - tail text (e.g. if you know that it's only whitespace from pretty-printing). - """ - cdef object _events - cdef _Element _start_element - def __cinit__(self, _Element element not None, tag=None, *, bint with_tail=True): - _assertValidNode(element) - if with_tail: - events = ("start", "comment", "pi", "end") - else: - events = ("start",) - self._start_element = element - self._events = iterwalk(element, events=events, tag=tag) - - def __iter__(self): - return self - - def __next__(self): - cdef _Element element - result = None - while result is None: - event, element = next(self._events) # raises StopIteration - if event == "start": - result = element.text - elif element is not self._start_element: - result = element.tail - return result - - -cdef xmlNode* _createElement(xmlDoc* c_doc, object name_utf) except NULL: - cdef xmlNode* c_node - c_node = tree.xmlNewDocNode(c_doc, NULL, _xcstr(name_utf), NULL) - return c_node - -cdef xmlNode* _createComment(xmlDoc* c_doc, const_xmlChar* text) noexcept: - cdef xmlNode* c_node - c_node = tree.xmlNewDocComment(c_doc, text) - return c_node - -cdef xmlNode* _createPI(xmlDoc* c_doc, const_xmlChar* target, const_xmlChar* text) noexcept: - cdef xmlNode* c_node - c_node = tree.xmlNewDocPI(c_doc, target, text) - return c_node - -cdef xmlNode* _createEntity(xmlDoc* c_doc, const_xmlChar* name) noexcept: - cdef xmlNode* c_node - c_node = tree.xmlNewReference(c_doc, name) - return c_node - -# module-level API for ElementTree - -from abc import ABC - -class Element(ABC): - """Element(_tag, attrib=None, nsmap=None, **_extra) - - Element factory, as a class. - - An instance of this class is an object implementing the - Element interface. - - >>> element = Element("test") - >>> type(element) - - >>> isinstance(element, Element) - True - >>> issubclass(_Element, Element) - True - - Also look at the `_Element.makeelement()` and - `_BaseParser.makeelement()` methods, which provide a faster way to - create an Element within a specific document or parser context. - """ - def __new__(cls, _tag, attrib=None, nsmap=None, **_extra): - return _makeElement(_tag, NULL, None, None, None, None, - attrib, nsmap, _extra) - -# Register _Element as a virtual subclass of Element -Element.register(_Element) - - -def Comment(text=None): - """Comment(text=None) - - Comment element factory. This factory function creates a special element that will - be serialized as an XML comment. - """ - cdef _Document doc - cdef xmlNode* c_node - cdef xmlDoc* c_doc - - if text is None: - text = b'' - else: - text = _utf8(text) - if b'--' in text or text.endswith(b'-'): - raise ValueError("Comment may not contain '--' or end with '-'") - - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - c_node = _createComment(c_doc, _xcstr(text)) - tree.xmlAddChild(c_doc, c_node) - return _elementFactory(doc, c_node) - - -def ProcessingInstruction(target, text=None): - """ProcessingInstruction(target, text=None) - - ProcessingInstruction element factory. This factory function creates a - special element that will be serialized as an XML processing instruction. - """ - cdef _Document doc - cdef xmlNode* c_node - cdef xmlDoc* c_doc - - target = _utf8(target) - _tagValidOrRaise(target) - if target.lower() == b'xml': - raise ValueError, f"Invalid PI name '{target}'" - - if text is None: - text = b'' - else: - text = _utf8(text) - if b'?>' in text: - raise ValueError, "PI text must not contain '?>'" - - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - c_node = _createPI(c_doc, _xcstr(target), _xcstr(text)) - tree.xmlAddChild(c_doc, c_node) - return _elementFactory(doc, c_node) - -PI = ProcessingInstruction - - -cdef class CDATA: - """CDATA(data) - - CDATA factory. This factory creates an opaque data object that - can be used to set Element text. The usual way to use it is:: - - >>> el = Element('content') - >>> el.text = CDATA('a string') - - >>> print(el.text) - a string - >>> print(tostring(el, encoding="unicode")) - - """ - cdef bytes _utf8_data - def __cinit__(self, data): - self._utf8_data = _utf8(data) - - -def Entity(name): - """Entity(name) - - Entity factory. This factory function creates a special element - that will be serialized as an XML entity reference or character - reference. Note, however, that entities will not be automatically - declared in the document. A document that uses entity references - requires a DTD to define the entities. - """ - cdef _Document doc - cdef xmlNode* c_node - cdef xmlDoc* c_doc - name_utf = _utf8(name) - c_name = _xcstr(name_utf) - if c_name[0] == c'#': - if not _characterReferenceIsValid(c_name + 1): - raise ValueError, f"Invalid character reference: '{name}'" - elif not _xmlNameIsValid(c_name): - raise ValueError, f"Invalid entity reference: '{name}'" - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, None) - c_node = _createEntity(c_doc, c_name) - tree.xmlAddChild(c_doc, c_node) - return _elementFactory(doc, c_node) - - -def SubElement(_Element _parent not None, _tag, - attrib=None, nsmap=None, **_extra): - """SubElement(_parent, _tag, attrib=None, nsmap=None, **_extra) - - Subelement factory. This function creates an element instance, and - appends it to an existing element. - """ - return _makeSubElement(_parent, _tag, None, None, attrib, nsmap, _extra) - -from typing import Generic, TypeVar - -T = TypeVar("T") - -class ElementTree(ABC, Generic[T]): - def __new__(cls, _Element element=None, *, file=None, _BaseParser parser=None): - """ElementTree(element=None, file=None, parser=None) - - ElementTree wrapper class. - """ - cdef xmlNode* c_next - cdef xmlNode* c_node - cdef xmlNode* c_node_copy - cdef xmlDoc* c_doc - cdef _ElementTree etree - cdef _Document doc - - if element is not None: - doc = element._doc - elif file is not None: - try: - doc = _parseDocument(file, parser, None) - except _TargetParserResult as result_container: - return result_container.result - else: - c_doc = _newXMLDoc() - doc = _documentFactory(c_doc, parser) - - return _elementTreeFactory(doc, element) - -# Register _ElementTree as a virtual subclass of ElementTree -ElementTree.register(_ElementTree) - -# Remove "ABC" and typing helpers from module dict -del ABC, Generic, TypeVar, T - -def HTML(text, _BaseParser parser=None, *, base_url=None): - """HTML(text, parser=None, base_url=None) - - Parses an HTML document from a string constant. Returns the root - node (or the result returned by a parser target). This function - can be used to embed "HTML literals" in Python code. - - To override the parser with a different ``HTMLParser`` you can pass it to - the ``parser`` keyword argument. - - The ``base_url`` keyword argument allows to set the original base URL of - the document to support relative Paths when looking up external entities - (DTD, XInclude, ...). - """ - cdef _Document doc - if parser is None: - parser = __GLOBAL_PARSER_CONTEXT.getDefaultParser() - if not isinstance(parser, HTMLParser): - parser = __DEFAULT_HTML_PARSER - try: - doc = _parseMemoryDocument(text, base_url, parser) - return doc.getroot() - except _TargetParserResult as result_container: - return result_container.result - - -def XML(text, _BaseParser parser=None, *, base_url=None): - """XML(text, parser=None, base_url=None) - - Parses an XML document or fragment from a string constant. - Returns the root node (or the result returned by a parser target). - This function can be used to embed "XML literals" in Python code, - like in - - >>> root = XML("") - >>> print(root.tag) - root - - To override the parser with a different ``XMLParser`` you can pass it to - the ``parser`` keyword argument. - - The ``base_url`` keyword argument allows to set the original base URL of - the document to support relative Paths when looking up external entities - (DTD, XInclude, ...). - """ - cdef _Document doc - if parser is None: - parser = __GLOBAL_PARSER_CONTEXT.getDefaultParser() - if not isinstance(parser, XMLParser): - parser = __DEFAULT_XML_PARSER - try: - doc = _parseMemoryDocument(text, base_url, parser) - return doc.getroot() - except _TargetParserResult as result_container: - return result_container.result - - -def fromstring(text, _BaseParser parser=None, *, base_url=None): - """fromstring(text, parser=None, base_url=None) - - Parses an XML document or fragment from a string. Returns the - root node (or the result returned by a parser target). - - To override the default parser with a different parser you can pass it to - the ``parser`` keyword argument. - - The ``base_url`` keyword argument allows to set the original base URL of - the document to support relative Paths when looking up external entities - (DTD, XInclude, ...). - """ - cdef _Document doc - try: - doc = _parseMemoryDocument(text, base_url, parser) - return doc.getroot() - except _TargetParserResult as result_container: - return result_container.result - - -def fromstringlist(strings, _BaseParser parser=None): - """fromstringlist(strings, parser=None) - - Parses an XML document from a sequence of strings. Returns the - root node (or the result returned by a parser target). - - To override the default parser with a different parser you can pass it to - the ``parser`` keyword argument. - """ - cdef _Document doc - if isinstance(strings, (bytes, unicode)): - raise ValueError("passing a single string into fromstringlist() is not" - " efficient, use fromstring() instead") - if parser is None: - parser = __GLOBAL_PARSER_CONTEXT.getDefaultParser() - feed = parser.feed - for data in strings: - feed(data) - return parser.close() - - -def iselement(element): - """iselement(element) - - Checks if an object appears to be a valid element object. - """ - return isinstance(element, _Element) and (<_Element>element)._c_node is not NULL - - -def indent(tree, space=" ", *, Py_ssize_t level=0): - """indent(tree, space=" ", level=0) - - Indent an XML document by inserting newlines and indentation space - after elements. - - *tree* is the ElementTree or Element to modify. The (root) element - itself will not be changed, but the tail text of all elements in its - subtree will be adapted. - - *space* is the whitespace to insert for each indentation level, two - space characters by default. - - *level* is the initial indentation level. Setting this to a higher - value than 0 can be used for indenting subtrees that are more deeply - nested inside of a document. - """ - root = _rootNodeOrRaise(tree) - if level < 0: - raise ValueError(f"Initial indentation level must be >= 0, got {level}") - if _hasChild(root._c_node): - space = _utf8(space) - indent = b"\n" + level * space - _indent_children(root._c_node, 1, space, [indent, indent + space]) - - -cdef int _indent_children(xmlNode* c_node, Py_ssize_t level, bytes one_space, list indentations) except -1: - # Reuse indentation strings for speed. - if len(indentations) <= level: - indentations.append(indentations[-1] + one_space) - - # Start a new indentation level for the first child. - child_indentation = indentations[level] - if not _hasNonWhitespaceText(c_node): - _setNodeText(c_node, child_indentation) - - # Recursively indent all children. - cdef xmlNode* c_child = _findChildForwards(c_node, 0) - while c_child is not NULL: - if _hasChild(c_child): - _indent_children(c_child, level+1, one_space, indentations) - c_next_child = _nextElement(c_child) - if not _hasNonWhitespaceTail(c_child): - if c_next_child is NULL: - # Dedent after the last child. - child_indentation = indentations[level-1] - _setTailText(c_child, child_indentation) - c_child = c_next_child - return 0 - - -def dump(_Element elem not None, *, bint pretty_print=True, bint with_tail=True): - """dump(elem, pretty_print=True, with_tail=True) - - Writes an element tree or element structure to sys.stdout. This function - should be used for debugging only. - """ - xml = tostring(elem, pretty_print=pretty_print, with_tail=with_tail, encoding='unicode') - if not pretty_print: - xml += '\n' - sys.stdout.write(xml) - - -def tostring(element_or_tree, *, encoding=None, method="xml", - xml_declaration=None, bint pretty_print=False, bint with_tail=True, - standalone=None, doctype=None, - # method='c14n' - bint exclusive=False, inclusive_ns_prefixes=None, - # method='c14n2' - bint with_comments=True, bint strip_text=False, - ): - """tostring(element_or_tree, encoding=None, method="xml", - xml_declaration=None, pretty_print=False, with_tail=True, - standalone=None, doctype=None, - exclusive=False, inclusive_ns_prefixes=None, - with_comments=True, strip_text=False, - ) - - Serialize an element to an encoded string representation of its XML - tree. - - Defaults to ASCII encoding without XML declaration. This - behaviour can be configured with the keyword arguments 'encoding' - (string) and 'xml_declaration' (bool). Note that changing the - encoding to a non UTF-8 compatible encoding will enable a - declaration by default. - - You can also serialise to a Unicode string without declaration by - passing the name ``'unicode'`` as encoding (or the ``str`` function - in Py3 or ``unicode`` in Py2). This changes the return value from - a byte string to an unencoded unicode string. - - The keyword argument 'pretty_print' (bool) enables formatted XML. - - The keyword argument 'method' selects the output method: 'xml', - 'html', plain 'text' (text content without tags), 'c14n' or 'c14n2'. - Default is 'xml'. - - With ``method="c14n"`` (C14N version 1), the options ``exclusive``, - ``with_comments`` and ``inclusive_ns_prefixes`` request exclusive - C14N, include comments, and list the inclusive prefixes respectively. - - With ``method="c14n2"`` (C14N version 2), the ``with_comments`` and - ``strip_text`` options control the output of comments and text space - according to C14N 2.0. - - Passing a boolean value to the ``standalone`` option will output - an XML declaration with the corresponding ``standalone`` flag. - - The ``doctype`` option allows passing in a plain string that will - be serialised before the XML tree. Note that passing in non - well-formed content here will make the XML output non well-formed. - Also, an existing doctype in the document tree will not be removed - when serialising an ElementTree instance. - - You can prevent the tail text of the element from being serialised - by passing the boolean ``with_tail`` option. This has no impact - on the tail text of children, which will always be serialised. - """ - cdef bint write_declaration - cdef int is_standalone - # C14N serialisation - if method in ('c14n', 'c14n2'): - if encoding is not None: - raise ValueError("Cannot specify encoding with C14N") - if xml_declaration: - raise ValueError("Cannot enable XML declaration in C14N") - if method == 'c14n': - return _tostringC14N(element_or_tree, exclusive, with_comments, inclusive_ns_prefixes) - else: - out = BytesIO() - target = C14NWriterTarget( - utf8_writer(out).write, - with_comments=with_comments, strip_text=strip_text) - _tree_to_target(element_or_tree, target) - return out.getvalue() - if not with_comments: - raise ValueError("Can only discard comments in C14N serialisation") - if strip_text: - raise ValueError("Can only strip text in C14N 2.0 serialisation") - if encoding is unicode or (encoding is not None and encoding.lower() == 'unicode'): - if xml_declaration: - raise ValueError, \ - "Serialisation to unicode must not request an XML declaration" - write_declaration = 0 - encoding = unicode - elif xml_declaration is None: - # by default, write an XML declaration only for non-standard encodings - write_declaration = encoding is not None and encoding.upper() not in \ - ('ASCII', 'UTF-8', 'UTF8', 'US-ASCII') - else: - write_declaration = xml_declaration - if encoding is None: - encoding = 'ASCII' - if standalone is None: - is_standalone = -1 - elif standalone: - write_declaration = 1 - is_standalone = 1 - else: - write_declaration = 1 - is_standalone = 0 - - if isinstance(element_or_tree, _Element): - return _tostring(<_Element>element_or_tree, encoding, doctype, method, - write_declaration, 0, pretty_print, with_tail, - is_standalone) - elif isinstance(element_or_tree, _ElementTree): - return _tostring((<_ElementTree>element_or_tree)._context_node, - encoding, doctype, method, write_declaration, 1, - pretty_print, with_tail, is_standalone) - else: - raise TypeError, f"Type '{python._fqtypename(element_or_tree).decode('utf8')}' cannot be serialized." - - - -def tostringlist(element_or_tree, *args, **kwargs): - """tostringlist(element_or_tree, *args, **kwargs) - - Serialize an element to an encoded string representation of its XML - tree, stored in a list of partial strings. - - This is purely for ElementTree 1.3 compatibility. The result is a - single string wrapped in a list. - """ - return [tostring(element_or_tree, *args, **kwargs)] - - -def tounicode(element_or_tree, *, method="xml", bint pretty_print=False, - bint with_tail=True, doctype=None): - """tounicode(element_or_tree, method="xml", pretty_print=False, - with_tail=True, doctype=None) - - Serialize an element to the Python unicode representation of its XML - tree. - - :deprecated: use ``tostring(el, encoding='unicode')`` instead. - - Note that the result does not carry an XML encoding declaration and is - therefore not necessarily suited for serialization to byte streams without - further treatment. - - The boolean keyword argument 'pretty_print' enables formatted XML. - - The keyword argument 'method' selects the output method: 'xml', - 'html' or plain 'text'. - - You can prevent the tail text of the element from being serialised - by passing the boolean ``with_tail`` option. This has no impact - on the tail text of children, which will always be serialised. - """ - if isinstance(element_or_tree, _Element): - return _tostring(<_Element>element_or_tree, unicode, doctype, method, - 0, 0, pretty_print, with_tail, -1) - elif isinstance(element_or_tree, _ElementTree): - return _tostring((<_ElementTree>element_or_tree)._context_node, - unicode, doctype, method, 0, 1, pretty_print, - with_tail, -1) - else: - raise TypeError, f"Type '{type(element_or_tree)}' cannot be serialized." - - -def parse(source, _BaseParser parser=None, *, base_url=None): - """parse(source, parser=None, base_url=None) - - Return an ElementTree object loaded with source elements. If no parser - is provided as second argument, the default parser is used. - - The ``source`` can be any of the following: - - - a file name/path - - a file object - - a file-like object - - a URL using the HTTP or FTP protocol - - To parse from a string, use the ``fromstring()`` function instead. - - Note that it is generally faster to parse from a file path or URL - than from an open file object or file-like object. Transparent - decompression from gzip compressed sources is supported (unless - explicitly disabled in libxml2). - - The ``base_url`` keyword allows setting a URL for the document - when parsing from a file-like object. This is needed when looking - up external entities (DTD, XInclude, ...) with relative paths. - """ - cdef _Document doc - try: - doc = _parseDocument(source, parser, base_url) - return _elementTreeFactory(doc, None) - except _TargetParserResult as result_container: - return result_container.result - - -def adopt_external_document(capsule, _BaseParser parser=None): - """adopt_external_document(capsule, parser=None) - - Unpack a libxml2 document pointer from a PyCapsule and wrap it in an - lxml ElementTree object. - - This allows external libraries to build XML/HTML trees using libxml2 - and then pass them efficiently into lxml for further processing. - - If a ``parser`` is provided, it will be used for configuring the - lxml document. No parsing will be done. - - The capsule must have the name ``"libxml2:xmlDoc"`` and its pointer - value must reference a correct libxml2 document of type ``xmlDoc*``. - The creator of the capsule must take care to correctly clean up the - document using an appropriate capsule destructor. By default, the - libxml2 document will be copied to let lxml safely own the memory - of the internal tree that it uses. - - If the capsule context is non-NULL, it must point to a C string that - can be compared using ``strcmp()``. If the context string equals - ``"destructor:xmlFreeDoc"``, the libxml2 document will not be copied - but the capsule invalidated instead by clearing its destructor and - name. That way, lxml takes ownership of the libxml2 document in memory - without creating a copy first, and the capsule destructor will not be - called. The document will then eventually be cleaned up by lxml using - the libxml2 API function ``xmlFreeDoc()`` once it is no longer used. - - If no copy is made, later modifications of the tree outside of lxml - should not be attempted after transferring the ownership. - """ - cdef xmlDoc* c_doc - cdef bint is_owned = False - c_doc = python.lxml_unpack_xmldoc_capsule(capsule, &is_owned) - doc = _adoptForeignDoc(c_doc, parser, is_owned) - return _elementTreeFactory(doc, None) - - -################################################################################ -# Include submodules - -include "readonlytree.pxi" # Read-only implementation of Element proxies -include "classlookup.pxi" # Element class lookup mechanisms -include "nsclasses.pxi" # Namespace implementation and registry -include "docloader.pxi" # Support for custom document loaders -include "parser.pxi" # XML and HTML parsers -include "saxparser.pxi" # SAX-like Parser interface and tree builder -include "parsertarget.pxi" # ET Parser target -include "serializer.pxi" # XML output functions -include "iterparse.pxi" # incremental XML parsing -include "xmlid.pxi" # XMLID and IDDict -include "xinclude.pxi" # XInclude -include "cleanup.pxi" # Cleanup and recursive element removal functions - - -################################################################################ -# Include submodules for XPath and XSLT - -include "extensions.pxi" # XPath/XSLT extension functions -include "xpath.pxi" # XPath evaluation -include "xslt.pxi" # XSL transformations -include "xsltext.pxi" # XSL extension elements - - -################################################################################ -# Validation - -cdef class DocumentInvalid(LxmlError): - """Validation error. - - Raised by all document validators when their ``assertValid(tree)`` - method fails. - """ - - -cdef class _Validator: - "Base class for XML validators." - cdef _ErrorLog _error_log - def __cinit__(self): - self._error_log = _ErrorLog() - - def validate(self, etree): - """validate(self, etree) - - Validate the document using this schema. - - Returns true if document is valid, false if not. - """ - return self(etree) - - def assertValid(self, etree): - """assertValid(self, etree) - - Raises `DocumentInvalid` if the document does not comply with the schema. - """ - if not self(etree): - raise DocumentInvalid(self._error_log._buildExceptionMessage( - "Document does not comply with schema"), - self._error_log) - - def assert_(self, etree): - """assert_(self, etree) - - Raises `AssertionError` if the document does not comply with the schema. - """ - if not self(etree): - raise AssertionError, self._error_log._buildExceptionMessage( - "Document does not comply with schema") - - cpdef _append_log_message(self, int domain, int type, int level, int line, - message, filename): - self._error_log._receiveGeneric(domain, type, level, line, message, - filename) - - cpdef _clear_error_log(self): - self._error_log.clear() - - @property - def error_log(self): - """The log of validation errors and warnings.""" - assert self._error_log is not None, "XPath evaluator not initialised" - return self._error_log.copy() - -include "dtd.pxi" # DTD -include "relaxng.pxi" # RelaxNG -include "xmlschema.pxi" # XMLSchema -include "schematron.pxi" # Schematron (requires libxml2 2.6.21+) - -################################################################################ -# Public C API - -include "public-api.pxi" - -################################################################################ -# Other stuff - -include "debug.pxi" diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree_api.h b/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree_api.h deleted file mode 100644 index bbbb86b..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/etree_api.h +++ /dev/null @@ -1,204 +0,0 @@ -/* Generated by Cython 3.1.4 */ - -#ifndef __PYX_HAVE_API__lxml__etree -#define __PYX_HAVE_API__lxml__etree -#ifdef __MINGW64__ -#define MS_WIN64 -#endif -#include "Python.h" -#include "etree.h" - -static struct LxmlElement *(*__pyx_api_f_4lxml_5etree_deepcopyNodeToDocument)(struct LxmlDocument *, xmlNode *) = 0; -#define deepcopyNodeToDocument __pyx_api_f_4lxml_5etree_deepcopyNodeToDocument -static struct LxmlElementTree *(*__pyx_api_f_4lxml_5etree_elementTreeFactory)(struct LxmlElement *) = 0; -#define elementTreeFactory __pyx_api_f_4lxml_5etree_elementTreeFactory -static struct LxmlElementTree *(*__pyx_api_f_4lxml_5etree_newElementTree)(struct LxmlElement *, PyObject *) = 0; -#define newElementTree __pyx_api_f_4lxml_5etree_newElementTree -static struct LxmlElementTree *(*__pyx_api_f_4lxml_5etree_adoptExternalDocument)(xmlDoc *, PyObject *, int) = 0; -#define adoptExternalDocument __pyx_api_f_4lxml_5etree_adoptExternalDocument -static struct LxmlElement *(*__pyx_api_f_4lxml_5etree_elementFactory)(struct LxmlDocument *, xmlNode *) = 0; -#define elementFactory __pyx_api_f_4lxml_5etree_elementFactory -static struct LxmlElement *(*__pyx_api_f_4lxml_5etree_makeElement)(PyObject *, struct LxmlDocument *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *) = 0; -#define makeElement __pyx_api_f_4lxml_5etree_makeElement -static struct LxmlElement *(*__pyx_api_f_4lxml_5etree_makeSubElement)(struct LxmlElement *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *) = 0; -#define makeSubElement __pyx_api_f_4lxml_5etree_makeSubElement -static void (*__pyx_api_f_4lxml_5etree_setElementClassLookupFunction)(_element_class_lookup_function, PyObject *) = 0; -#define setElementClassLookupFunction __pyx_api_f_4lxml_5etree_setElementClassLookupFunction -static PyObject *(*__pyx_api_f_4lxml_5etree_lookupDefaultElementClass)(PyObject *, PyObject *, xmlNode *) = 0; -#define lookupDefaultElementClass __pyx_api_f_4lxml_5etree_lookupDefaultElementClass -static PyObject *(*__pyx_api_f_4lxml_5etree_lookupNamespaceElementClass)(PyObject *, PyObject *, xmlNode *) = 0; -#define lookupNamespaceElementClass __pyx_api_f_4lxml_5etree_lookupNamespaceElementClass -static PyObject *(*__pyx_api_f_4lxml_5etree_callLookupFallback)(struct LxmlFallbackElementClassLookup *, struct LxmlDocument *, xmlNode *) = 0; -#define callLookupFallback __pyx_api_f_4lxml_5etree_callLookupFallback -static int (*__pyx_api_f_4lxml_5etree_tagMatches)(xmlNode *, const xmlChar *, const xmlChar *) = 0; -#define tagMatches __pyx_api_f_4lxml_5etree_tagMatches -static struct LxmlDocument *(*__pyx_api_f_4lxml_5etree_documentOrRaise)(PyObject *) = 0; -#define documentOrRaise __pyx_api_f_4lxml_5etree_documentOrRaise -static struct LxmlElement *(*__pyx_api_f_4lxml_5etree_rootNodeOrRaise)(PyObject *) = 0; -#define rootNodeOrRaise __pyx_api_f_4lxml_5etree_rootNodeOrRaise -static int (*__pyx_api_f_4lxml_5etree_hasText)(xmlNode *) = 0; -#define hasText __pyx_api_f_4lxml_5etree_hasText -static int (*__pyx_api_f_4lxml_5etree_hasTail)(xmlNode *) = 0; -#define hasTail __pyx_api_f_4lxml_5etree_hasTail -static PyObject *(*__pyx_api_f_4lxml_5etree_textOf)(xmlNode *) = 0; -#define textOf __pyx_api_f_4lxml_5etree_textOf -static PyObject *(*__pyx_api_f_4lxml_5etree_tailOf)(xmlNode *) = 0; -#define tailOf __pyx_api_f_4lxml_5etree_tailOf -static int (*__pyx_api_f_4lxml_5etree_setNodeText)(xmlNode *, PyObject *) = 0; -#define setNodeText __pyx_api_f_4lxml_5etree_setNodeText -static int (*__pyx_api_f_4lxml_5etree_setTailText)(xmlNode *, PyObject *) = 0; -#define setTailText __pyx_api_f_4lxml_5etree_setTailText -static PyObject *(*__pyx_api_f_4lxml_5etree_attributeValue)(xmlNode *, xmlAttr *) = 0; -#define attributeValue __pyx_api_f_4lxml_5etree_attributeValue -static PyObject *(*__pyx_api_f_4lxml_5etree_attributeValueFromNsName)(xmlNode *, const xmlChar *, const xmlChar *) = 0; -#define attributeValueFromNsName __pyx_api_f_4lxml_5etree_attributeValueFromNsName -static PyObject *(*__pyx_api_f_4lxml_5etree_getAttributeValue)(struct LxmlElement *, PyObject *, PyObject *) = 0; -#define getAttributeValue __pyx_api_f_4lxml_5etree_getAttributeValue -static PyObject *(*__pyx_api_f_4lxml_5etree_iterattributes)(struct LxmlElement *, int) = 0; -#define iterattributes __pyx_api_f_4lxml_5etree_iterattributes -static PyObject *(*__pyx_api_f_4lxml_5etree_collectAttributes)(xmlNode *, int) = 0; -#define collectAttributes __pyx_api_f_4lxml_5etree_collectAttributes -static int (*__pyx_api_f_4lxml_5etree_setAttributeValue)(struct LxmlElement *, PyObject *, PyObject *) = 0; -#define setAttributeValue __pyx_api_f_4lxml_5etree_setAttributeValue -static int (*__pyx_api_f_4lxml_5etree_delAttribute)(struct LxmlElement *, PyObject *) = 0; -#define delAttribute __pyx_api_f_4lxml_5etree_delAttribute -static int (*__pyx_api_f_4lxml_5etree_delAttributeFromNsName)(xmlNode *, const xmlChar *, const xmlChar *) = 0; -#define delAttributeFromNsName __pyx_api_f_4lxml_5etree_delAttributeFromNsName -static int (*__pyx_api_f_4lxml_5etree_hasChild)(xmlNode *) = 0; -#define hasChild __pyx_api_f_4lxml_5etree_hasChild -static xmlNode *(*__pyx_api_f_4lxml_5etree_findChild)(xmlNode *, Py_ssize_t) = 0; -#define findChild __pyx_api_f_4lxml_5etree_findChild -static xmlNode *(*__pyx_api_f_4lxml_5etree_findChildForwards)(xmlNode *, Py_ssize_t) = 0; -#define findChildForwards __pyx_api_f_4lxml_5etree_findChildForwards -static xmlNode *(*__pyx_api_f_4lxml_5etree_findChildBackwards)(xmlNode *, Py_ssize_t) = 0; -#define findChildBackwards __pyx_api_f_4lxml_5etree_findChildBackwards -static xmlNode *(*__pyx_api_f_4lxml_5etree_nextElement)(xmlNode *) = 0; -#define nextElement __pyx_api_f_4lxml_5etree_nextElement -static xmlNode *(*__pyx_api_f_4lxml_5etree_previousElement)(xmlNode *) = 0; -#define previousElement __pyx_api_f_4lxml_5etree_previousElement -static void (*__pyx_api_f_4lxml_5etree_appendChild)(struct LxmlElement *, struct LxmlElement *) = 0; -#define appendChild __pyx_api_f_4lxml_5etree_appendChild -static int (*__pyx_api_f_4lxml_5etree_appendChildToElement)(struct LxmlElement *, struct LxmlElement *) = 0; -#define appendChildToElement __pyx_api_f_4lxml_5etree_appendChildToElement -static PyObject *(*__pyx_api_f_4lxml_5etree_pyunicode)(const xmlChar *) = 0; -#define pyunicode __pyx_api_f_4lxml_5etree_pyunicode -static PyObject *(*__pyx_api_f_4lxml_5etree_utf8)(PyObject *) = 0; -#define utf8 __pyx_api_f_4lxml_5etree_utf8 -static PyObject *(*__pyx_api_f_4lxml_5etree_getNsTag)(PyObject *) = 0; -#define getNsTag __pyx_api_f_4lxml_5etree_getNsTag -static PyObject *(*__pyx_api_f_4lxml_5etree_getNsTagWithEmptyNs)(PyObject *) = 0; -#define getNsTagWithEmptyNs __pyx_api_f_4lxml_5etree_getNsTagWithEmptyNs -static PyObject *(*__pyx_api_f_4lxml_5etree_namespacedName)(xmlNode *) = 0; -#define namespacedName __pyx_api_f_4lxml_5etree_namespacedName -static PyObject *(*__pyx_api_f_4lxml_5etree_namespacedNameFromNsName)(const xmlChar *, const xmlChar *) = 0; -#define namespacedNameFromNsName __pyx_api_f_4lxml_5etree_namespacedNameFromNsName -static void (*__pyx_api_f_4lxml_5etree_iteratorStoreNext)(struct LxmlElementIterator *, struct LxmlElement *) = 0; -#define iteratorStoreNext __pyx_api_f_4lxml_5etree_iteratorStoreNext -static void (*__pyx_api_f_4lxml_5etree_initTagMatch)(struct LxmlElementTagMatcher *, PyObject *) = 0; -#define initTagMatch __pyx_api_f_4lxml_5etree_initTagMatch -static xmlNs *(*__pyx_api_f_4lxml_5etree_findOrBuildNodeNsPrefix)(struct LxmlDocument *, xmlNode *, const xmlChar *, const xmlChar *) = 0; -#define findOrBuildNodeNsPrefix __pyx_api_f_4lxml_5etree_findOrBuildNodeNsPrefix -static int __Pyx_ImportFunction_3_1_4(PyObject *module, const char *funcname, void (**f)(void), const char *sig); - -#ifndef __PYX_HAVE_RT_ImportFunction_3_1_4 -#define __PYX_HAVE_RT_ImportFunction_3_1_4 -static int __Pyx_ImportFunction_3_1_4(PyObject *module, const char *funcname, void (**f)(void), const char *sig) { - PyObject *d = 0; - PyObject *cobj = 0; - union { - void (*fp)(void); - void *p; - } tmp; - d = PyObject_GetAttrString(module, "__pyx_capi__"); - if (!d) - goto bad; -#if (defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030d0000) || (!defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030d0000) - PyDict_GetItemStringRef(d, funcname, &cobj); -#else - cobj = PyDict_GetItemString(d, funcname); - Py_XINCREF(cobj); -#endif - if (!cobj) { - PyErr_Format(PyExc_ImportError, - "%.200s does not export expected C function %.200s", - PyModule_GetName(module), funcname); - goto bad; - } - if (!PyCapsule_IsValid(cobj, sig)) { - PyErr_Format(PyExc_TypeError, - "C function %.200s.%.200s has wrong signature (expected %.500s, got %.500s)", - PyModule_GetName(module), funcname, sig, PyCapsule_GetName(cobj)); - goto bad; - } - tmp.p = PyCapsule_GetPointer(cobj, sig); - *f = tmp.fp; - if (!(*f)) - goto bad; - Py_DECREF(d); - Py_DECREF(cobj); - return 0; -bad: - Py_XDECREF(d); - Py_XDECREF(cobj); - return -1; -} -#endif - - -static int import_lxml__etree(void) { - PyObject *module = 0; - module = PyImport_ImportModule("lxml.etree"); - if (!module) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "deepcopyNodeToDocument", (void (**)(void))&__pyx_api_f_4lxml_5etree_deepcopyNodeToDocument, "struct LxmlElement *(struct LxmlDocument *, xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "elementTreeFactory", (void (**)(void))&__pyx_api_f_4lxml_5etree_elementTreeFactory, "struct LxmlElementTree *(struct LxmlElement *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "newElementTree", (void (**)(void))&__pyx_api_f_4lxml_5etree_newElementTree, "struct LxmlElementTree *(struct LxmlElement *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "adoptExternalDocument", (void (**)(void))&__pyx_api_f_4lxml_5etree_adoptExternalDocument, "struct LxmlElementTree *(xmlDoc *, PyObject *, int)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "elementFactory", (void (**)(void))&__pyx_api_f_4lxml_5etree_elementFactory, "struct LxmlElement *(struct LxmlDocument *, xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "makeElement", (void (**)(void))&__pyx_api_f_4lxml_5etree_makeElement, "struct LxmlElement *(PyObject *, struct LxmlDocument *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "makeSubElement", (void (**)(void))&__pyx_api_f_4lxml_5etree_makeSubElement, "struct LxmlElement *(struct LxmlElement *, PyObject *, PyObject *, PyObject *, PyObject *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "setElementClassLookupFunction", (void (**)(void))&__pyx_api_f_4lxml_5etree_setElementClassLookupFunction, "void (_element_class_lookup_function, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "lookupDefaultElementClass", (void (**)(void))&__pyx_api_f_4lxml_5etree_lookupDefaultElementClass, "PyObject *(PyObject *, PyObject *, xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "lookupNamespaceElementClass", (void (**)(void))&__pyx_api_f_4lxml_5etree_lookupNamespaceElementClass, "PyObject *(PyObject *, PyObject *, xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "callLookupFallback", (void (**)(void))&__pyx_api_f_4lxml_5etree_callLookupFallback, "PyObject *(struct LxmlFallbackElementClassLookup *, struct LxmlDocument *, xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "tagMatches", (void (**)(void))&__pyx_api_f_4lxml_5etree_tagMatches, "int (xmlNode *, const xmlChar *, const xmlChar *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "documentOrRaise", (void (**)(void))&__pyx_api_f_4lxml_5etree_documentOrRaise, "struct LxmlDocument *(PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "rootNodeOrRaise", (void (**)(void))&__pyx_api_f_4lxml_5etree_rootNodeOrRaise, "struct LxmlElement *(PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "hasText", (void (**)(void))&__pyx_api_f_4lxml_5etree_hasText, "int (xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "hasTail", (void (**)(void))&__pyx_api_f_4lxml_5etree_hasTail, "int (xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "textOf", (void (**)(void))&__pyx_api_f_4lxml_5etree_textOf, "PyObject *(xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "tailOf", (void (**)(void))&__pyx_api_f_4lxml_5etree_tailOf, "PyObject *(xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "setNodeText", (void (**)(void))&__pyx_api_f_4lxml_5etree_setNodeText, "int (xmlNode *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "setTailText", (void (**)(void))&__pyx_api_f_4lxml_5etree_setTailText, "int (xmlNode *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "attributeValue", (void (**)(void))&__pyx_api_f_4lxml_5etree_attributeValue, "PyObject *(xmlNode *, xmlAttr *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "attributeValueFromNsName", (void (**)(void))&__pyx_api_f_4lxml_5etree_attributeValueFromNsName, "PyObject *(xmlNode *, const xmlChar *, const xmlChar *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "getAttributeValue", (void (**)(void))&__pyx_api_f_4lxml_5etree_getAttributeValue, "PyObject *(struct LxmlElement *, PyObject *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "iterattributes", (void (**)(void))&__pyx_api_f_4lxml_5etree_iterattributes, "PyObject *(struct LxmlElement *, int)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "collectAttributes", (void (**)(void))&__pyx_api_f_4lxml_5etree_collectAttributes, "PyObject *(xmlNode *, int)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "setAttributeValue", (void (**)(void))&__pyx_api_f_4lxml_5etree_setAttributeValue, "int (struct LxmlElement *, PyObject *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "delAttribute", (void (**)(void))&__pyx_api_f_4lxml_5etree_delAttribute, "int (struct LxmlElement *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "delAttributeFromNsName", (void (**)(void))&__pyx_api_f_4lxml_5etree_delAttributeFromNsName, "int (xmlNode *, const xmlChar *, const xmlChar *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "hasChild", (void (**)(void))&__pyx_api_f_4lxml_5etree_hasChild, "int (xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "findChild", (void (**)(void))&__pyx_api_f_4lxml_5etree_findChild, "xmlNode *(xmlNode *, Py_ssize_t)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "findChildForwards", (void (**)(void))&__pyx_api_f_4lxml_5etree_findChildForwards, "xmlNode *(xmlNode *, Py_ssize_t)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "findChildBackwards", (void (**)(void))&__pyx_api_f_4lxml_5etree_findChildBackwards, "xmlNode *(xmlNode *, Py_ssize_t)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "nextElement", (void (**)(void))&__pyx_api_f_4lxml_5etree_nextElement, "xmlNode *(xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "previousElement", (void (**)(void))&__pyx_api_f_4lxml_5etree_previousElement, "xmlNode *(xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "appendChild", (void (**)(void))&__pyx_api_f_4lxml_5etree_appendChild, "void (struct LxmlElement *, struct LxmlElement *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "appendChildToElement", (void (**)(void))&__pyx_api_f_4lxml_5etree_appendChildToElement, "int (struct LxmlElement *, struct LxmlElement *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "pyunicode", (void (**)(void))&__pyx_api_f_4lxml_5etree_pyunicode, "PyObject *(const xmlChar *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "utf8", (void (**)(void))&__pyx_api_f_4lxml_5etree_utf8, "PyObject *(PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "getNsTag", (void (**)(void))&__pyx_api_f_4lxml_5etree_getNsTag, "PyObject *(PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "getNsTagWithEmptyNs", (void (**)(void))&__pyx_api_f_4lxml_5etree_getNsTagWithEmptyNs, "PyObject *(PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "namespacedName", (void (**)(void))&__pyx_api_f_4lxml_5etree_namespacedName, "PyObject *(xmlNode *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "namespacedNameFromNsName", (void (**)(void))&__pyx_api_f_4lxml_5etree_namespacedNameFromNsName, "PyObject *(const xmlChar *, const xmlChar *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "iteratorStoreNext", (void (**)(void))&__pyx_api_f_4lxml_5etree_iteratorStoreNext, "void (struct LxmlElementIterator *, struct LxmlElement *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "initTagMatch", (void (**)(void))&__pyx_api_f_4lxml_5etree_initTagMatch, "void (struct LxmlElementTagMatcher *, PyObject *)") < 0) goto bad; - if (__Pyx_ImportFunction_3_1_4(module, "findOrBuildNodeNsPrefix", (void (**)(void))&__pyx_api_f_4lxml_5etree_findOrBuildNodeNsPrefix, "xmlNs *(struct LxmlDocument *, xmlNode *, const xmlChar *, const xmlChar *)") < 0) goto bad; - Py_DECREF(module); module = 0; - return 0; - bad: - Py_XDECREF(module); - return -1; -} - -#endif /* !__PYX_HAVE_API__lxml__etree */ diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/extensions.pxi b/eeeeee/.venv/lib/python3.9/site-packages/lxml/extensions.pxi deleted file mode 100644 index ab687be..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/extensions.pxi +++ /dev/null @@ -1,830 +0,0 @@ -# support for extension functions in XPath and XSLT - -cdef class XPathError(LxmlError): - """Base class of all XPath errors. - """ - -cdef class XPathEvalError(XPathError): - """Error during XPath evaluation. - """ - -cdef class XPathFunctionError(XPathEvalError): - """Internal error looking up an XPath extension function. - """ - -cdef class XPathResultError(XPathEvalError): - """Error handling an XPath result. - """ - - -# forward declarations - -ctypedef int (*_register_function)(void* ctxt, name_utf, ns_uri_utf) -cdef class _ExsltRegExp - -################################################################################ -# Base class for XSLT and XPath evaluation contexts: functions, namespaces, ... - -@cython.internal -cdef class _BaseContext: - cdef xpath.xmlXPathContext* _xpathCtxt - cdef _Document _doc - cdef dict _extensions - cdef list _namespaces - cdef list _global_namespaces - cdef dict _utf_refs - cdef dict _function_cache - cdef dict _eval_context_dict - cdef bint _build_smart_strings - # for exception handling and temporary reference keeping: - cdef _TempStore _temp_refs - cdef set _temp_documents - cdef _ExceptionContext _exc - cdef _ErrorLog _error_log - - def __init__(self, namespaces, extensions, error_log, enable_regexp, - build_smart_strings): - cdef _ExsltRegExp _regexp - cdef dict new_extensions - cdef list ns - self._utf_refs = {} - self._global_namespaces = [] - self._function_cache = {} - self._eval_context_dict = None - self._error_log = error_log - - if extensions is not None: - # convert extensions to UTF-8 - if isinstance(extensions, dict): - extensions = (extensions,) - # format: [ {(ns, name):function} ] -> {(ns_utf, name_utf):function} - new_extensions = {} - for extension in extensions: - for (ns_uri, name), function in extension.items(): - if name is None: - raise ValueError, "extensions must have non empty names" - ns_utf = self._to_utf(ns_uri) - name_utf = self._to_utf(name) - new_extensions[(ns_utf, name_utf)] = function - extensions = new_extensions or None - - if namespaces is not None: - if isinstance(namespaces, dict): - namespaces = namespaces.items() - if namespaces: - ns = [] - for prefix, ns_uri in namespaces: - if prefix is None or not prefix: - raise TypeError, \ - "empty namespace prefix is not supported in XPath" - if ns_uri is None or not ns_uri: - raise TypeError, \ - "setting default namespace is not supported in XPath" - prefix_utf = self._to_utf(prefix) - ns_uri_utf = self._to_utf(ns_uri) - ns.append( (prefix_utf, ns_uri_utf) ) - namespaces = ns - else: - namespaces = None - - self._doc = None - self._exc = _ExceptionContext() - self._extensions = extensions - self._namespaces = namespaces - self._temp_refs = _TempStore() - self._temp_documents = set() - self._build_smart_strings = build_smart_strings - - if enable_regexp: - _regexp = _ExsltRegExp() - _regexp._register_in_context(self) - - cdef _BaseContext _copy(self): - cdef _BaseContext context - if self._namespaces is not None: - namespaces = self._namespaces[:] - else: - namespaces = None - context = self.__class__(namespaces, None, self._error_log, False, - self._build_smart_strings) - if self._extensions is not None: - context._extensions = self._extensions.copy() - return context - - cdef bytes _to_utf(self, s): - "Convert to UTF-8 and keep a reference to the encoded string" - cdef python.PyObject* dict_result - if s is None: - return None - dict_result = python.PyDict_GetItem(self._utf_refs, s) - if dict_result is not NULL: - return dict_result - utf = _utf8(s) - self._utf_refs[s] = utf - if python.IS_PYPY: - # use C level refs, PyPy refs are not enough! - python.Py_INCREF(utf) - return utf - - cdef void _set_xpath_context(self, xpath.xmlXPathContext* xpathCtxt) noexcept: - self._xpathCtxt = xpathCtxt - xpathCtxt.userData = self - # Need a cast here because older libxml2 releases do not use 'const' in the functype. - xpathCtxt.error = _receiveXPathError - - @cython.final - cdef _register_context(self, _Document doc): - self._doc = doc - self._exc.clear() - - @cython.final - cdef _cleanup_context(self): - #xpath.xmlXPathRegisteredNsCleanup(self._xpathCtxt) - #self.unregisterGlobalNamespaces() - if python.IS_PYPY: - # clean up double refs in PyPy (see "_to_utf()" method) - for ref in self._utf_refs.itervalues(): - python.Py_DECREF(ref) - self._utf_refs.clear() - self._eval_context_dict = None - self._doc = None - - @cython.final - cdef _release_context(self): - if self._xpathCtxt is not NULL: - self._xpathCtxt.userData = NULL - self._xpathCtxt = NULL - - # namespaces (internal UTF-8 methods with leading '_') - - cdef addNamespace(self, prefix, ns_uri): - cdef list namespaces - if prefix is None: - raise TypeError, "empty prefix is not supported in XPath" - prefix_utf = self._to_utf(prefix) - ns_uri_utf = self._to_utf(ns_uri) - new_item = (prefix_utf, ns_uri_utf) - if self._namespaces is None: - self._namespaces = [new_item] - else: - namespaces = [] - for item in self._namespaces: - if item[0] == prefix_utf: - item = new_item - new_item = None - namespaces.append(item) - if new_item is not None: - namespaces.append(new_item) - self._namespaces = namespaces - if self._xpathCtxt is not NULL: - xpath.xmlXPathRegisterNs( - self._xpathCtxt, _xcstr(prefix_utf), _xcstr(ns_uri_utf)) - - cdef registerNamespace(self, prefix, ns_uri): - if prefix is None: - raise TypeError, "empty prefix is not supported in XPath" - prefix_utf = self._to_utf(prefix) - ns_uri_utf = self._to_utf(ns_uri) - self._global_namespaces.append(prefix_utf) - xpath.xmlXPathRegisterNs(self._xpathCtxt, - _xcstr(prefix_utf), _xcstr(ns_uri_utf)) - - cdef registerLocalNamespaces(self): - if self._namespaces is None: - return - for prefix_utf, ns_uri_utf in self._namespaces: - xpath.xmlXPathRegisterNs( - self._xpathCtxt, _xcstr(prefix_utf), _xcstr(ns_uri_utf)) - - cdef registerGlobalNamespaces(self): - cdef list ns_prefixes = _find_all_extension_prefixes() - if python.PyList_GET_SIZE(ns_prefixes) > 0: - for prefix_utf, ns_uri_utf in ns_prefixes: - self._global_namespaces.append(prefix_utf) - xpath.xmlXPathRegisterNs( - self._xpathCtxt, _xcstr(prefix_utf), _xcstr(ns_uri_utf)) - - cdef unregisterGlobalNamespaces(self): - if python.PyList_GET_SIZE(self._global_namespaces) > 0: - for prefix_utf in self._global_namespaces: - xpath.xmlXPathRegisterNs(self._xpathCtxt, - _xcstr(prefix_utf), NULL) - del self._global_namespaces[:] - - cdef void _unregisterNamespace(self, prefix_utf) noexcept: - xpath.xmlXPathRegisterNs(self._xpathCtxt, - _xcstr(prefix_utf), NULL) - - # extension functions - - cdef int _addLocalExtensionFunction(self, ns_utf, name_utf, function) except -1: - if self._extensions is None: - self._extensions = {} - self._extensions[(ns_utf, name_utf)] = function - return 0 - - cdef registerGlobalFunctions(self, void* ctxt, - _register_function reg_func): - cdef python.PyObject* dict_result - cdef dict d - for ns_utf, ns_functions in __FUNCTION_NAMESPACE_REGISTRIES.iteritems(): - dict_result = python.PyDict_GetItem( - self._function_cache, ns_utf) - if dict_result is not NULL: - d = dict_result - else: - d = {} - self._function_cache[ns_utf] = d - for name_utf, function in ns_functions.iteritems(): - d[name_utf] = function - reg_func(ctxt, name_utf, ns_utf) - - cdef registerLocalFunctions(self, void* ctxt, - _register_function reg_func): - cdef python.PyObject* dict_result - cdef dict d - if self._extensions is None: - return # done - last_ns = None - d = None - for (ns_utf, name_utf), function in self._extensions.iteritems(): - if ns_utf is not last_ns or d is None: - last_ns = ns_utf - dict_result = python.PyDict_GetItem( - self._function_cache, ns_utf) - if dict_result is not NULL: - d = dict_result - else: - d = {} - self._function_cache[ns_utf] = d - d[name_utf] = function - reg_func(ctxt, name_utf, ns_utf) - - cdef unregisterAllFunctions(self, void* ctxt, - _register_function unreg_func): - for ns_utf, functions in self._function_cache.iteritems(): - for name_utf in functions: - unreg_func(ctxt, name_utf, ns_utf) - - cdef unregisterGlobalFunctions(self, void* ctxt, - _register_function unreg_func): - for ns_utf, functions in self._function_cache.items(): - for name_utf in functions: - if self._extensions is None or \ - (ns_utf, name_utf) not in self._extensions: - unreg_func(ctxt, name_utf, ns_utf) - - @cython.final - cdef _find_cached_function(self, const_xmlChar* c_ns_uri, const_xmlChar* c_name): - """Lookup an extension function in the cache and return it. - - Parameters: c_ns_uri may be NULL, c_name must not be NULL - """ - cdef python.PyObject* c_dict - cdef python.PyObject* dict_result - c_dict = python.PyDict_GetItem( - self._function_cache, None if c_ns_uri is NULL else c_ns_uri) - if c_dict is not NULL: - dict_result = python.PyDict_GetItem( - c_dict, c_name) - if dict_result is not NULL: - return dict_result - return None - - # Python access to the XPath context for extension functions - - @property - def context_node(self): - cdef xmlNode* c_node - if self._xpathCtxt is NULL: - raise XPathError, \ - "XPath context is only usable during the evaluation" - c_node = self._xpathCtxt.node - if c_node is NULL: - raise XPathError, "no context node" - if c_node.doc != self._xpathCtxt.doc: - raise XPathError, \ - "document-external context nodes are not supported" - if self._doc is None: - raise XPathError, "document context is missing" - return _elementFactory(self._doc, c_node) - - @property - def eval_context(self): - if self._eval_context_dict is None: - self._eval_context_dict = {} - return self._eval_context_dict - - # Python reference keeping during XPath function evaluation - - @cython.final - cdef _release_temp_refs(self): - "Free temporarily referenced objects from this context." - self._temp_refs.clear() - self._temp_documents.clear() - - @cython.final - cdef _hold(self, obj): - """A way to temporarily hold references to nodes in the evaluator. - - This is needed because otherwise nodes created in XPath extension - functions would be reference counted too soon, during the XPath - evaluation. This is most important in the case of exceptions. - """ - cdef _Element element - if isinstance(obj, _Element): - self._temp_refs.add(obj) - self._temp_documents.add((<_Element>obj)._doc) - return - elif _isString(obj) or not python.PySequence_Check(obj): - return - for o in obj: - if isinstance(o, _Element): - #print "Holding element:", element._c_node - self._temp_refs.add(o) - #print "Holding document:", element._doc._c_doc - self._temp_documents.add((<_Element>o)._doc) - - @cython.final - cdef _Document _findDocumentForNode(self, xmlNode* c_node): - """If an XPath expression returns an element from a different - document than the current context document, we call this to - see if it was possibly created by an extension and is a known - document instance. - """ - cdef _Document doc - for doc in self._temp_documents: - if doc is not None and doc._c_doc is c_node.doc: - return doc - return None - - -# libxml2 keeps these error messages in a static array in its code -# and doesn't give us access to them ... - -cdef tuple LIBXML2_XPATH_ERROR_MESSAGES = ( - b"Ok", - b"Number encoding", - b"Unfinished literal", - b"Start of literal", - b"Expected $ for variable reference", - b"Undefined variable", - b"Invalid predicate", - b"Invalid expression", - b"Missing closing curly brace", - b"Unregistered function", - b"Invalid operand", - b"Invalid type", - b"Invalid number of arguments", - b"Invalid context size", - b"Invalid context position", - b"Memory allocation error", - b"Syntax error", - b"Resource error", - b"Sub resource error", - b"Undefined namespace prefix", - b"Encoding error", - b"Char out of XML range", - b"Invalid or incomplete context", - b"Stack usage error", - b"Forbidden variable\n", - b"?? Unknown error ??\n", -) - -cdef void _forwardXPathError(void* c_ctxt, const xmlerror.xmlError* c_error) noexcept with gil: - cdef xmlerror.xmlError error - cdef int xpath_code - if c_error.message is not NULL: - error.message = c_error.message - else: - xpath_code = c_error.code - xmlerror.XML_XPATH_EXPRESSION_OK - if 0 <= xpath_code < len(LIBXML2_XPATH_ERROR_MESSAGES): - error.message = _cstr(LIBXML2_XPATH_ERROR_MESSAGES[xpath_code]) - else: - error.message = b"unknown error" - error.domain = c_error.domain - error.code = c_error.code - error.level = c_error.level - error.line = c_error.line - error.int2 = c_error.int1 # column - error.file = c_error.file - error.node = NULL - - (<_BaseContext>c_ctxt)._error_log._receive(&error) - -cdef void _receiveXPathError(void* c_context, const xmlerror.xmlError* error) noexcept nogil: - if not __DEBUG: - return - if c_context is NULL: - _forwardError(NULL, error) - else: - _forwardXPathError(c_context, error) - - -def Extension(module, function_mapping=None, *, ns=None): - """Extension(module, function_mapping=None, ns=None) - - Build a dictionary of extension functions from the functions - defined in a module or the methods of an object. - - As second argument, you can pass an additional mapping of - attribute names to XPath function names, or a list of function - names that should be taken. - - The ``ns`` keyword argument accepts a namespace URI for the XPath - functions. - """ - cdef dict functions = {} - if isinstance(function_mapping, dict): - for function_name, xpath_name in function_mapping.items(): - functions[(ns, xpath_name)] = getattr(module, function_name) - else: - if function_mapping is None: - function_mapping = [ name for name in dir(module) - if not name.startswith('_') ] - for function_name in function_mapping: - functions[(ns, function_name)] = getattr(module, function_name) - return functions - -################################################################################ -# EXSLT regexp implementation - -@cython.final -@cython.internal -cdef class _ExsltRegExp: - cdef dict _compile_map - def __cinit__(self): - self._compile_map = {} - - cdef _make_string(self, value): - if _isString(value): - return value - elif isinstance(value, list): - # node set: take recursive text concatenation of first element - if python.PyList_GET_SIZE(value) == 0: - return '' - firstnode = value[0] - if _isString(firstnode): - return firstnode - elif isinstance(firstnode, _Element): - c_text = tree.xmlNodeGetContent((<_Element>firstnode)._c_node) - if c_text is NULL: - raise MemoryError() - try: - return funicode(c_text) - finally: - tree.xmlFree(c_text) - else: - return unicode(firstnode) - else: - return unicode(value) - - cdef _compile(self, rexp, ignore_case): - cdef python.PyObject* c_result - rexp = self._make_string(rexp) - key = (rexp, ignore_case) - c_result = python.PyDict_GetItem(self._compile_map, key) - if c_result is not NULL: - return c_result - py_flags = re.UNICODE - if ignore_case: - py_flags = py_flags | re.IGNORECASE - rexp_compiled = re.compile(rexp, py_flags) - self._compile_map[key] = rexp_compiled - return rexp_compiled - - def test(self, ctxt, s, rexp, flags=''): - flags = self._make_string(flags) - s = self._make_string(s) - rexpc = self._compile(rexp, 'i' in flags) - if rexpc.search(s) is None: - return False - else: - return True - - def match(self, ctxt, s, rexp, flags=''): - cdef list result_list - flags = self._make_string(flags) - s = self._make_string(s) - rexpc = self._compile(rexp, 'i' in flags) - if 'g' in flags: - results = rexpc.findall(s) - if not results: - return () - else: - result = rexpc.search(s) - if not result: - return () - results = [ result.group() ] - results.extend( result.groups('') ) - result_list = [] - root = Element('matches') - for s_match in results: - if python.PyTuple_CheckExact(s_match): - s_match = ''.join(s_match) - elem = SubElement(root, 'match') - elem.text = s_match - result_list.append(elem) - return result_list - - def replace(self, ctxt, s, rexp, flags, replacement): - replacement = self._make_string(replacement) - flags = self._make_string(flags) - s = self._make_string(s) - rexpc = self._compile(rexp, 'i' in flags) - count: object = 0 if 'g' in flags else 1 - return rexpc.sub(replacement, s, count) - - cdef _register_in_context(self, _BaseContext context): - ns = b"http://exslt.org/regular-expressions" - context._addLocalExtensionFunction(ns, b"test", self.test) - context._addLocalExtensionFunction(ns, b"match", self.match) - context._addLocalExtensionFunction(ns, b"replace", self.replace) - - -################################################################################ -# helper functions - -cdef xpath.xmlXPathObject* _wrapXPathObject(object obj, _Document doc, - _BaseContext context) except NULL: - cdef xpath.xmlNodeSet* resultSet - cdef _Element fake_node = None - cdef xmlNode* c_node - - if isinstance(obj, unicode): - obj = _utf8(obj) - if isinstance(obj, bytes): - # libxml2 copies the string value - return xpath.xmlXPathNewCString(_cstr(obj)) - if isinstance(obj, bool): - return xpath.xmlXPathNewBoolean(obj) - if python.PyNumber_Check(obj): - return xpath.xmlXPathNewFloat(obj) - if obj is None: - resultSet = xpath.xmlXPathNodeSetCreate(NULL) - elif isinstance(obj, _Element): - resultSet = xpath.xmlXPathNodeSetCreate((<_Element>obj)._c_node) - elif python.PySequence_Check(obj): - resultSet = xpath.xmlXPathNodeSetCreate(NULL) - try: - for value in obj: - if isinstance(value, _Element): - if context is not None: - context._hold(value) - xpath.xmlXPathNodeSetAdd(resultSet, (<_Element>value)._c_node) - else: - if context is None or doc is None: - raise XPathResultError, \ - f"Non-Element values not supported at this point - got {value!r}" - # support strings by appending text nodes to an Element - if isinstance(value, unicode): - value = _utf8(value) - if isinstance(value, bytes): - if fake_node is None: - fake_node = _makeElement("text-root", NULL, doc, None, - None, None, None, None, None) - context._hold(fake_node) - else: - # append a comment node to keep the text nodes separate - c_node = tree.xmlNewDocComment(doc._c_doc, "") - if c_node is NULL: - raise MemoryError() - tree.xmlAddChild(fake_node._c_node, c_node) - context._hold(value) - c_node = tree.xmlNewDocText(doc._c_doc, _xcstr(value)) - if c_node is NULL: - raise MemoryError() - tree.xmlAddChild(fake_node._c_node, c_node) - xpath.xmlXPathNodeSetAdd(resultSet, c_node) - else: - raise XPathResultError, \ - f"This is not a supported node-set result: {value!r}" - except: - xpath.xmlXPathFreeNodeSet(resultSet) - raise - else: - raise XPathResultError, f"Unknown return type: {python._fqtypename(obj).decode('utf8')}" - return xpath.xmlXPathWrapNodeSet(resultSet) - -cdef object _unwrapXPathObject(xpath.xmlXPathObject* xpathObj, - _Document doc, _BaseContext context): - if xpathObj.type == xpath.XPATH_UNDEFINED: - raise XPathResultError, "Undefined xpath result" - elif xpathObj.type == xpath.XPATH_NODESET: - return _createNodeSetResult(xpathObj, doc, context) - elif xpathObj.type == xpath.XPATH_BOOLEAN: - return xpathObj.boolval - elif xpathObj.type == xpath.XPATH_NUMBER: - return xpathObj.floatval - elif xpathObj.type == xpath.XPATH_STRING: - stringval = funicode(xpathObj.stringval) - if context._build_smart_strings: - stringval = _elementStringResultFactory( - stringval, None, None, False) - return stringval - elif xpathObj.type == xpath.XPATH_POINT: - raise NotImplementedError, "XPATH_POINT" - elif xpathObj.type == xpath.XPATH_RANGE: - raise NotImplementedError, "XPATH_RANGE" - elif xpathObj.type == xpath.XPATH_LOCATIONSET: - raise NotImplementedError, "XPATH_LOCATIONSET" - elif xpathObj.type == xpath.XPATH_USERS: - raise NotImplementedError, "XPATH_USERS" - elif xpathObj.type == xpath.XPATH_XSLT_TREE: - return _createNodeSetResult(xpathObj, doc, context) - else: - raise XPathResultError, f"Unknown xpath result {xpathObj.type}" - -cdef object _createNodeSetResult(xpath.xmlXPathObject* xpathObj, _Document doc, - _BaseContext context): - cdef xmlNode* c_node - cdef int i - cdef list result - result = [] - if xpathObj.nodesetval is NULL: - return result - for i in range(xpathObj.nodesetval.nodeNr): - c_node = xpathObj.nodesetval.nodeTab[i] - _unpackNodeSetEntry(result, c_node, doc, context, - xpathObj.type == xpath.XPATH_XSLT_TREE) - return result - -cdef _unpackNodeSetEntry(list results, xmlNode* c_node, _Document doc, - _BaseContext context, bint is_fragment): - cdef xmlNode* c_child - if _isElement(c_node): - if c_node.doc != doc._c_doc and c_node.doc._private is NULL: - # XXX: works, but maybe not always the right thing to do? - # XPath: only runs when extensions create or copy trees - # -> we store Python refs to these, so that is OK - # XSLT: can it leak when merging trees from multiple sources? - c_node = tree.xmlDocCopyNode(c_node, doc._c_doc, 1) - # FIXME: call _instantiateElementFromXPath() instead? - results.append( - _fakeDocElementFactory(doc, c_node)) - elif c_node.type == tree.XML_TEXT_NODE or \ - c_node.type == tree.XML_CDATA_SECTION_NODE or \ - c_node.type == tree.XML_ATTRIBUTE_NODE: - results.append( - _buildElementStringResult(doc, c_node, context)) - elif c_node.type == tree.XML_NAMESPACE_DECL: - results.append( (funicodeOrNone((c_node).prefix), - funicodeOrNone((c_node).href)) ) - elif c_node.type == tree.XML_DOCUMENT_NODE or \ - c_node.type == tree.XML_HTML_DOCUMENT_NODE: - # ignored for everything but result tree fragments - if is_fragment: - c_child = c_node.children - while c_child is not NULL: - _unpackNodeSetEntry(results, c_child, doc, context, 0) - c_child = c_child.next - elif c_node.type == tree.XML_XINCLUDE_START or \ - c_node.type == tree.XML_XINCLUDE_END: - pass - else: - raise NotImplementedError, \ - f"Not yet implemented result node type: {c_node.type}" - -cdef void _freeXPathObject(xpath.xmlXPathObject* xpathObj) noexcept: - """Free the XPath object, but *never* free the *content* of node sets. - Python dealloc will do that for us. - """ - if xpathObj.nodesetval is not NULL: - xpath.xmlXPathFreeNodeSet(xpathObj.nodesetval) - xpathObj.nodesetval = NULL - xpath.xmlXPathFreeObject(xpathObj) - -cdef _Element _instantiateElementFromXPath(xmlNode* c_node, _Document doc, - _BaseContext context): - # NOTE: this may copy the element - only call this when it can't leak - if c_node.doc != doc._c_doc and c_node.doc._private is NULL: - # not from the context document and not from a fake document - # either => may still be from a known document, e.g. one - # created by an extension function - node_doc = context._findDocumentForNode(c_node) - if node_doc is None: - # not from a known document at all! => can only make a - # safety copy here - c_node = tree.xmlDocCopyNode(c_node, doc._c_doc, 1) - else: - doc = node_doc - return _fakeDocElementFactory(doc, c_node) - -################################################################################ -# special str/unicode subclasses - -@cython.final -cdef class _ElementUnicodeResult(unicode): - cdef _Element _parent - cdef readonly object attrname - cdef readonly bint is_tail - - def getparent(self): - return self._parent - - @property - def is_text(self): - return self._parent is not None and not (self.is_tail or self.attrname is not None) - - @property - def is_attribute(self): - return self.attrname is not None - -cdef object _elementStringResultFactory(string_value, _Element parent, - attrname, bint is_tail): - result = _ElementUnicodeResult(string_value) - result._parent = parent - result.is_tail = is_tail - result.attrname = attrname - return result - -cdef object _buildElementStringResult(_Document doc, xmlNode* c_node, - _BaseContext context): - cdef _Element parent = None - cdef object attrname = None - cdef xmlNode* c_element - cdef bint is_tail - - if c_node.type == tree.XML_ATTRIBUTE_NODE: - attrname = _namespacedName(c_node) - is_tail = 0 - s = tree.xmlNodeGetContent(c_node) - try: - value = funicode(s) - finally: - tree.xmlFree(s) - c_element = NULL - else: - #assert c_node.type == tree.XML_TEXT_NODE or c_node.type == tree.XML_CDATA_SECTION_NODE, "invalid node type" - # may be tail text or normal text - value = funicode(c_node.content) - c_element = _previousElement(c_node) - is_tail = c_element is not NULL - - if not context._build_smart_strings: - return value - - if c_element is NULL: - # non-tail text or attribute text - c_element = c_node.parent - while c_element is not NULL and not _isElement(c_element): - c_element = c_element.parent - - if c_element is not NULL: - parent = _instantiateElementFromXPath(c_element, doc, context) - - return _elementStringResultFactory( - value, parent, attrname, is_tail) - -################################################################################ -# callbacks for XPath/XSLT extension functions - -cdef void _extension_function_call(_BaseContext context, function, - xpath.xmlXPathParserContext* ctxt, int nargs) noexcept: - cdef _Document doc - cdef xpath.xmlXPathObject* obj - cdef list args - cdef int i - doc = context._doc - try: - args = [] - for i in range(nargs): - obj = xpath.valuePop(ctxt) - o = _unwrapXPathObject(obj, doc, context) - _freeXPathObject(obj) - args.append(o) - args.reverse() - - res = function(context, *args) - # wrap result for XPath consumption - obj = _wrapXPathObject(res, doc, context) - # prevent Python from deallocating elements handed to libxml2 - context._hold(res) - xpath.valuePush(ctxt, obj) - except: - xpath.xmlXPathErr(ctxt, xpath.XPATH_EXPR_ERROR) - context._exc._store_raised() - finally: - return # swallow any further exceptions - -# lookup the function by name and call it - -cdef void _xpath_function_call(xpath.xmlXPathParserContext* ctxt, - int nargs) noexcept with gil: - cdef _BaseContext context - cdef xpath.xmlXPathContext* rctxt = ctxt.context - context = <_BaseContext> rctxt.userData - try: - function = context._find_cached_function(rctxt.functionURI, rctxt.function) - if function is not None: - _extension_function_call(context, function, ctxt, nargs) - else: - xpath.xmlXPathErr(ctxt, xpath.XPATH_UNKNOWN_FUNC_ERROR) - context._exc._store_exception(XPathFunctionError( - f"XPath function '{_namespacedNameFromNsName(rctxt.functionURI, rctxt.function)}' not found")) - except: - # may not be the right error, but we need to tell libxml2 *something* - xpath.xmlXPathErr(ctxt, xpath.XPATH_UNKNOWN_FUNC_ERROR) - context._exc._store_raised() - finally: - return # swallow any further exceptions diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/ElementSoup.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/ElementSoup.py deleted file mode 100644 index c35365d..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/ElementSoup.py +++ /dev/null @@ -1,10 +0,0 @@ -__doc__ = """Legacy interface to the BeautifulSoup HTML parser. -""" - -__all__ = ["parse", "convert_tree"] - -from .soupparser import convert_tree, parse as _parse - -def parse(file, beautifulsoup=None, makeelement=None): - root = _parse(file, beautifulsoup=beautifulsoup, makeelement=makeelement) - return root.getroot() diff --git a/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/__init__.py b/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/__init__.py deleted file mode 100644 index 2cee9f4..0000000 --- a/eeeeee/.venv/lib/python3.9/site-packages/lxml/html/__init__.py +++ /dev/null @@ -1,1927 +0,0 @@ -# Copyright (c) 2004 Ian Bicking. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# 3. Neither the name of Ian Bicking nor the names of its contributors may -# be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IAN BICKING OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""The ``lxml.html`` tool set for HTML handling. -""" - - -__all__ = [ - 'document_fromstring', 'fragment_fromstring', 'fragments_fromstring', 'fromstring', - 'tostring', 'Element', 'defs', 'open_in_browser', 'submit_form', - 'find_rel_links', 'find_class', 'make_links_absolute', - 'resolve_base_href', 'iterlinks', 'rewrite_links', 'parse'] - - -import copy -import re - -from collections.abc import MutableMapping, MutableSet -from functools import partial -from urllib.parse import urljoin - -from .. import etree -from . import defs -from ._setmixin import SetMixin - - -def __fix_docstring(s): - # TODO: remove and clean up doctests - if not s: - return s - sub = re.compile(r"^(\s*)u'", re.M).sub - return sub(r"\1'", s) - - -XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml" - -_rel_links_xpath = etree.XPath("descendant-or-self::a[@rel]|descendant-or-self::x:a[@rel]", - namespaces={'x':XHTML_NAMESPACE}) -_options_xpath = etree.XPath("descendant-or-self::option|descendant-or-self::x:option", - namespaces={'x':XHTML_NAMESPACE}) -_forms_xpath = etree.XPath("descendant-or-self::form|descendant-or-self::x:form", - namespaces={'x':XHTML_NAMESPACE}) -#_class_xpath = etree.XPath(r"descendant-or-self::*[regexp:match(@class, concat('\b', $class_name, '\b'))]", {'regexp': 'http://exslt.org/regular-expressions'}) -_class_xpath = etree.XPath("descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), concat(' ', $class_name, ' '))]") -_id_xpath = etree.XPath("descendant-or-self::*[@id=$id]") -_collect_string_content = etree.XPath("string()", smart_strings=False) -_iter_css_urls = re.compile(r'url\(('+'["][^"]*["]|'+"['][^']*[']|"+r'[^)]*)\)', re.I).finditer -_iter_css_imports = re.compile(r'@import "(.*?)"').finditer -_label_xpath = etree.XPath("//label[@for=$id]|//x:label[@for=$id]", - namespaces={'x':XHTML_NAMESPACE}) -_archive_re = re.compile(r'[^ ]+') -_parse_meta_refresh_url = re.compile( - r'[^;=]*;\s*(?:url\s*=\s*)?(?P.*)$', re.I).search - - -def _unquote_match(s, pos): - if s[:1] == '"' and s[-1:] == '"' or s[:1] == "'" and s[-1:] == "'": - return s[1:-1], pos+1 - else: - return s,pos - - -def _transform_result(typ, result): - """Convert the result back into the input type. - """ - if issubclass(typ, bytes): - return tostring(result, encoding='utf-8') - elif issubclass(typ, str): - return tostring(result, encoding='unicode') - else: - return result - - -def _nons(tag): - if isinstance(tag, str): - if tag[0] == '{' and tag[1:len(XHTML_NAMESPACE)+1] == XHTML_NAMESPACE: - return tag.split('}')[-1] - return tag - - -class Classes(MutableSet): - """Provides access to an element's class attribute as a set-like collection. - Usage:: - - >>> el = fromstring('') - >>> classes = el.classes # or: classes = Classes(el.attrib) - >>> classes |= ['block', 'paragraph'] - >>> el.get('class') - 'hidden large block paragraph' - >>> classes.toggle('hidden') - False - >>> el.get('class') - 'large block paragraph' - >>> classes -= ('some', 'classes', 'block') - >>> el.get('class') - 'large paragraph' - """ - def __init__(self, attributes): - self._attributes = attributes - self._get_class_value = partial(attributes.get, 'class', '') - - def add(self, value): - """ - Add a class. - - This has no effect if the class is already present. - """ - if not value or re.search(r'\s', value): - raise ValueError("Invalid class name: %r" % value) - classes = self._get_class_value().split() - if value in classes: - return - classes.append(value) - self._attributes['class'] = ' '.join(classes) - - def discard(self, value): - """ - Remove a class if it is currently present. - - If the class is not present, do nothing. - """ - if not value or re.search(r'\s', value): - raise ValueError("Invalid class name: %r" % value) - classes = [name for name in self._get_class_value().split() - if name != value] - if classes: - self._attributes['class'] = ' '.join(classes) - elif 'class' in self._attributes: - del self._attributes['class'] - - def remove(self, value): - """ - Remove a class; it must currently be present. - - If the class is not present, raise a KeyError. - """ - if not value or re.search(r'\s', value): - raise ValueError("Invalid class name: %r" % value) - super().remove(value) - - def __contains__(self, name): - classes = self._get_class_value() - return name in classes and name in classes.split() - - def __iter__(self): - return iter(self._get_class_value().split()) - - def __len__(self): - return len(self._get_class_value().split()) - - # non-standard methods - - def update(self, values): - """ - Add all names from 'values'. - """ - classes = self._get_class_value().split() - extended = False - for value in values: - if value not in classes: - classes.append(value) - extended = True - if extended: - self._attributes['class'] = ' '.join(classes) - - def toggle(self, value): - """ - Add a class name if it isn't there yet, or remove it if it exists. - - Returns true if the class was added (and is now enabled) and - false if it was removed (and is now disabled). - """ - if not value or re.search(r'\s', value): - raise ValueError("Invalid class name: %r" % value) - classes = self._get_class_value().split() - try: - classes.remove(value) - enabled = False - except ValueError: - classes.append(value) - enabled = True - if classes: - self._attributes['class'] = ' '.join(classes) - else: - del self._attributes['class'] - return enabled - - -class HtmlMixin: - - def set(self, key, value=None): - """set(self, key, value=None) - - Sets an element attribute. If no value is provided, or if the value is None, - creates a 'boolean' attribute without value, e.g. "
" - for ``form.set('novalidate')``. - """ - super().set(key, value) - - @property - def classes(self): - """ - A set-like wrapper around the 'class' attribute. - """ - return Classes(self.attrib) - - @classes.setter - def classes(self, classes): - assert isinstance(classes, Classes) # only allow "el.classes |= ..." etc. - value = classes._get_class_value() - if value: - self.set('class', value) - elif self.get('class') is not None: - del self.attrib['class'] - - @property - def base_url(self): - """ - Returns the base URL, given when the page was parsed. - - Use with ``urlparse.urljoin(el.base_url, href)`` to get - absolute URLs. - """ - return self.getroottree().docinfo.URL - - @property - def forms(self): - """ - Return a list of all the forms - """ - return _forms_xpath(self) - - @property - def body(self): - """ - Return the element. Can be called from a child element - to get the document's head. - """ - for element in self.getroottree().iter("body", f"{{{XHTML_NAMESPACE}}}body"): - return element - return None - - @property - def head(self): - """ - Returns the element. Can be called from a child - element to get the document's head. - """ - for element in self.getroottree().iter("head", f"{{{XHTML_NAMESPACE}}}head"): - return element - return None - - @property - def label(self): - """ - Get or set any