From 03bb6aa3ee4cf86ba13a8702c12d9ff4bf2e380a Mon Sep 17 00:00:00 2001 From: rg3915 Date: Mon, 24 Jun 2019 16:27:01 -0300 Subject: [PATCH 01/40] Tutorial Django 2.2 --- content/tutorial-django-2.2.md | 702 +++++++++++++++++++++++++++++++++ 1 file changed, 702 insertions(+) create mode 100644 content/tutorial-django-2.2.md diff --git a/content/tutorial-django-2.2.md b/content/tutorial-django-2.2.md new file mode 100644 index 000000000..697529277 --- /dev/null +++ b/content/tutorial-django-2.2.md @@ -0,0 +1,702 @@ +title: Tutorial Django 2.2 +Slug: tutorial-django-2 +Date: 2019-06-24 22:00 +Tags: Python, Django +Author: Regis da Silva +Email: regis.santos.100@gmail.com +Github: rg3915 +Twitter: rg3915 +Category: Python, Django + + +Este tutorial é baseado no **Intro to Django** que fica na parte de baixo da página [start](https://www.djangoproject.com/start/) do Django project. + +Até a data deste post o Django está na versão 2.2.2, e requer Python 3. + + +## O que você precisa? + +Python 3, pip e virtualenv. + +Você vai precisar do [pip](https://pip.readthedocs.io/en/latest/) e do [virtualenv](https://virtualenv.pypa.io/en/latest/). + +* Instale primeiro o `pip` + +Primeira opção + +``` +$ wget https://bootstrap.pypa.io/get-pip.py +$ sudo python get-pip.py +``` + +Segunda opção + +`$ sudo apt-get install -y python-pip` + +* Depois instale o `virtualenv` + +``` +$ sudo pip install virtualenv +$ # ou +$ sudo apt-get install -y virtualenv +``` + + +## Criando o ambiente + +Crie uma pasta com o nome `django2-pythonclub` + +``` +$ mkdir django2-pythonclub +$ cd django2-pythonclub +``` + +A partir de agora vamos considerar esta como a nossa pasta principal. + +Considerando que você está usando **Python 3**, digite + +``` +python3 -m venv .venv +``` + +Lembre-se de colocar esta pasta no seu `.gitignore`, caso esteja usando. + +``` +echo .venv >> .gitignore +``` + +Depois ative o ambiente digitando + +``` +source .venv/bin/activate +``` + + +## Instalando Django 2.2.2 + +Basta digitar + +``` +pip install django==2.2.2 +``` + +Dica: se você digitar `pip freeze` você verá a versão dos programas instalados. + +É recomendável que você atualize a versão do `pip` + +``` +pip install -U pip +``` + +Se der erro então faça: + +``` +python -m pip install --upgrade pip +``` + + + +## Instalando mais dependências + +Eu gosto de usar o [django-extensions](https://django-extensions.readthedocs.io/en/latest/) e o [django-widget-tweaks](https://github.com/jazzband/django-widget-tweaks), então digite + +``` +pip install django-extensions django-widget-tweaks python-decouple +``` + +**Importante:** você precisa criar um arquivo `requirements.txt` para instalações futuras do projeto em outro lugar. + +``` +pip freeze > requirements.txt +``` + +Este é o resultado do meu até o dia deste post: + +``` +(.venv):$ cat requirements.txt + +django-extensions==2.1.6 +django-widget-tweaks==1.4.3 +python-decouple==3.1 +pytz==2018.9 +six==1.12.0 +``` + +## Escondendo a SECRET_KEY e trabalhando com variáveis de ambiente + +É muito importante que você não deixe sua SECRET_KEY exposta. Então remova-o imediatamente do seu settings.py ANTES mesmo do primeiro commit. Espero que você esteja usando Git. + +Vamos usar o [python-decouple](https://github.com/henriquebastos/python-decouple) escrito por [Henrique Bastos](https://henriquebastos.net/) para gerenciar nossas variáveis de ambiente. Repare que já instalamos ele logo acima. + +Em seguida você vai precisar criar um arquivo `.env`, para isso rode o comando a seguir, ele vai criar uma pasta contrib e dentro dele colocar um arquivo `env_gen.py` + +``` +if [ ! -d contrib ]; then mkdir contrib; fi; git clone https://gist.github.com/22626de522f5c045bc63acdb8fe67b24.git contrib/ +rm -rf contrib/.git/ # remova a pasta .git que está dentro de contrib. +``` + +Em seguida rode + +``` +python contrib/env_gen.py +``` + +que ele vai criar o arquivo `.env`. + +Supondo que você está versionando seu código com Git, é importante que você escreva isso dentro do seu arquivo `.gitignore`, faça direto pelo terminal + +``` +echo .env >> .gitignore +echo .venv >> .gitignore +echo '*.sqlite3' >> .gitignore +``` + +Pronto, agora você pode dar o primeiro commit. + + +## Criando o projeto e a App + +Para criar o projeto digite + +``` +$ django-admin startproject myproject . +``` + +repare no ponto no final do comando, isto permite que o arquivo `manage.py` fique nesta mesma pasta _django2-pythonclub_ . + +Agora vamos criar a _app_ **bands**, mas vamos deixar esta _app_ dentro da pasta _myproject_. Então entre na pasta + +``` +$ cd myproject +``` + +e digite + +``` +$ python ../manage.py startapp bands +``` + +A intenção é que os arquivos tenham a seguinte hierarquia nas pastas: + +``` +. +├── manage.py +├── myproject +│   ├── bands +│   │   ├── admin.py +│   │   ├── apps.py +│   │   ├── models.py +│   │   ├── tests.py +│   │   └── views.py +│   ├── settings.py +│   ├── urls.py +│   └── wsgi.py +└── requirements.txt +``` + +Agora permaneça sempre na pasta `django2-pythonclub` + +``` +cd .. +``` + +e digite + +``` +$ python manage.py migrate +``` + +para criar a primeira _migração_ (isto cria o banco de dados SQLite), e depois rode a aplicação com + +``` +$ python manage.py runserver +``` + +e veja que a aplicação já está funcionando. Veja o endereço da url aqui + +``` +Django version 2.2.2, using settings 'myproject.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. +``` + + + +## Editando settings.py + +Em `INSTALLED_APPS` acrescente as linhas abaixo. + +```python +INSTALLED_APPS = ( + ... + 'widget_tweaks', + 'django_extensions', + 'myproject.bands', +) +``` + +E mude também o idioma. + +`LANGUAGE_CODE = 'pt-br'` + +E caso você queira o mesmo horário de Brasília-BR + +`TIME_ZONE = 'America/Sao_Paulo'` + +Já que falamos do python-decouple, precisamos de mais alguns ajustes + +```python +from decouple import config, Csv + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = config('SECRET_KEY') + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = config('DEBUG', default=False, cast=bool) + +ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[], cast=Csv()) +``` + +Veja que é importante manter sua SECRET_KEY bem guardada (em outro lugar). + +Então crie um arquivo `.env` e guarde sua SECRET_KEY dentro dele, exemplo: + +``` +SECRET_KEY=your_secret_key +DEBUG=True +ALLOWED_HOSTS=127.0.0.1,.localhost +``` + + +## Editando models.py + + +```python +from django.db import models +from django.urls import reverse_lazy + + +class Band(models.Model): + + """A model of a rock band.""" + name = models.CharField(max_length=200) + can_rock = models.BooleanField(default=True) + + class Meta: + ordering = ('name',) + verbose_name = 'band' + verbose_name_plural = 'bands' + + def __str__(self): + return self.name + + def get_absolute_url(http://github.com/self): + # retorna a url no formato /bands/1/ + return reverse_lazy('band_detail', kwargs={'pk': self.pk}) + + def get_members_count(self): + # count members by band + # conta os membros por banda + return self.band.count() + + +class Member(models.Model): + + """A model of a rock band member.""" + name = models.CharField("Member's name", max_length=200) + instrument = models.CharField(choices=( + ('g', "Guitar"), + ('b', "Bass"), + ('d', "Drums"), + ('v', "Vocal"), + ('p', "Piano"), + ), + max_length=1 + ) + + band = models.ForeignKey("Band", related_name='band', on_delete=models.CASCADE) + + class Meta: + ordering = ('name',) + verbose_name = 'member' + verbose_name_plural = 'members' + + def __str__(self): + return self.name +``` + +Tem algumas coisas que eu não estou explicando aqui para o tutorial ficar curto, mas uma coisa importante é que, como nós editamos o models.py vamos precisar criar um arquivo de migração do novo modelo. Para isso digite + +``` +python manage.py makemigrations +python manage.py migrate +``` + +O primeiro comando cria o arquivo de migração e o segundo o executa, criando as tabelas no banco de dados. + + +## Editando urls.py + + +```python +from django.urls import include, path +from myproject.bands import views as v +from django.contrib import admin + +app_name = 'bands' + +urlpatterns = [ + path('', v.home, name='home'), + # path('bands/', v.band_list, name='bands'), + # path('bands//', v.band_detail, name='band_detail'), + # path('bandform/', v.BandCreate.as_view(), name='band_form'), + # path('memberform/', v.MemberCreate.as_view(), name='member_form'), + # path('contact/', v.band_contact, name='contact'), + # path('protected/', v.protected_view, name='protected'), + # path('accounts/login/', v.message), + path('admin/', admin.site.urls), +] +``` + +Obs: deixei as demais urls comentada porque precisa da função em views.py para que cada url funcione. Descomente cada url somente depois que você tiver definido a função em classe em views.py a seguir. + + +## Editando views.py + +```python +from django.shortcuts import render +from django.http import HttpResponse +from django.contrib.auth.decorators import login_required +from django.views.generic import CreateView +from django.urls import reverse_lazy +from .models import Band, Member +# from .forms import BandContactForm, BandForm, MemberForm +``` + +Obs: Deixei a última linha comentada porque ainda não chegamos em forms. + +A função a seguir retorna um __HttpResponse__, ou seja, uma mensagem simples no navegador. + +```python +def home(request): + return HttpResponse('Welcome to the site!') +``` +A próxima função (use uma ou outra) renderiza um template, uma página html no navegador. + +```python +def home(request): + return render(request, 'home.html') +``` + +A função `band_list` retorna todas as bandas. + +Para fazer a __busca__ por nome de banda usamos o comando `search = request.GET.get('search_box')`, onde `search_box` é o nome do campo no template __band_list.html__. + +E os nomes são retornados a partir do comando `bands = bands.filter(name__icontains=search)`. Onde `icontains` procura um texto que contém a palavra, ou seja, você pode digitar o nome incompleto (ignora maiúsculo ou minúsculo). + +```python +def band_list(request): + """ A view of all bands. """ + bands = Band.objects.all() + search = request.GET.get('search_box') + if search: + bands = bands.filter(name__icontains=search) + return render(request, 'bands/band_list.html', {'bands': bands}) +``` + +Em urls.py pode descomentar a linha a seguir: + +```python +path('bands/', v.band_list, name='bands'), +``` + +A função `band_contact` mostra como tratar um formulário na view. Esta função requer `BandContactForm`, explicado em forms.py. + +```python +def band_contact(request): + """ A example of form """ + if request.method == 'POST': + form = BandContactForm(request.POST) + else: + form = BandContactForm() + return render(request, 'bands/band_contact.html', {'form': form}) +``` + +Em urls.py pode descomentar a linha a seguir: + +```python +path('contact/', v.band_contact, name='contact'), +``` + +A função `band_detail` retorna todos os membros de cada banda, usando o `pk` da banda junto com o comando `filter` em members. + +```python +def band_detail(request, pk): + """ A view of all members by bands. """ + band = Band.objects.get(pk=pk) + members = Member.objects.all().filter(band=band) + context = {'members': members, 'band': band} + return render(request, 'bands/band_detail.html', context) +``` + +Em urls.py pode descomentar a linha a seguir: + +```python +path('bands//', v.band_detail, name='band_detail'), +``` + +`BandCreate` e `MemberCreate` usam o [Class Based View](https://docs.djangoproject.com/en/2.2/ref/class-based-views/) para tratar formulário de uma forma mais simplificada usando a classe `CreateView`. O `reverse_lazy` serve para tratar a url de retorno de página. + +As classes a seguir requerem `BandForm` e `MemberForm`, explicado em forms.py. + +```python +class BandCreate(CreateView): + model = Band + form_class = BandForm + template_name = 'bands/band_form.html' + success_url = reverse_lazy('bands') + + +class MemberCreate(CreateView): + model = Member + form_class = MemberForm + template_name = 'bands/member_form.html' + success_url = reverse_lazy('bands') +``` + +Em urls.py pode descomentar a linha a seguir: + +```python +path('bandform/', v.BandCreate.as_view(), name='band_form'), +path('memberform/', v.MemberCreate.as_view(), name='member_form'), +``` + + +A próxima função requer que você entre numa página somente quando estiver logado. + +`[@login_required](https://docs.djangoproject.com/en/2.2/topics/auth/default/#the-login-required-decorator)` é um __decorator__. + +`login_url='/accounts/login/'` é página de erro, ou seja, quando o usuário não conseguiu logar. + +E `render(request, 'bands/protected.html',...` é página de sucesso. + +```python +@login_required(login_url='/accounts/login/') +def protected_view(request): + """ A view that can only be accessed by logged-in users """ + return render(request, 'bands/protected.html', {'current_user': request.user}) +``` + +`HttpResponse` retorna uma mensagem simples no navegador sem a necessidade de um template. + +```python +def message(request): + """ Message if is not authenticated. Simple view! """ + return HttpResponse('Access denied!') +``` + +Em urls.py pode descomentar a linha a seguir: + +```python +path('protected/', v.protected_view, name='protected'), +path('accounts/login/', v.message), +``` + + +## Comandos básicos do manage.py + + +Para criar novas migrações com base nas alterações feitas nos seus modelos + +`$ python manage.py makemigrations bands` + +Obs: talvez dê erro porque está faltando coisas de forms.py, explicado mais abaixo. + + +Para aplicar as migrações + +`$ python manage.py migrate` + + +Para criar um usuário e senha para o admin + +`$ python manage.py createsuperuser` + +Para rodar a aplicação localmente + +`$ python manage.py runserver` + +Após criar um super usuário você pode entrar em localhost:8000/admin + +Obs: Se você entrar agora em localhost:8000 vai faltar o template home.html. Explicado mais abaixo. + + +## shell_plus + +É o __interpretador interativo do python__ rodando __via terminal__ direto na aplicação do django. + +Com o comando a seguir abrimos o shell do Django. + +`$ python manage.py shell` + +Mas se você está usando o django-extensions (mostrei como configurá-lo no settings.py), então basta digitar + +`$ python manage.py shell_plus` + + +Veja a seguir como inserir dados direto pelo shell. + +```python +>>> from myproject.bands.models import Band, Member +>>> # Com django-extensions não precisa fazer o import +>>> # criando o objeto e salvando +>>> band = Band.objects.create(name='Metallica') +>>> band.name +>>> band.can_rock +>>> band.id +>>> # criando uma instancia da banda a partir do id +>>> b = Band.objects.get(id=band.id) +>>> # criando uma instancia do Membro e associando o id da banda a ela +>>> m = Member(name='James Hetfield', instrument='b', band=b) +>>> m.name +>>> # retornando o instrumento +>>> m.instrument +>>> m.get_instrument_display() +>>> m.band +>>> # salvando +>>> m.save() +>>> # listando todas as bandas +>>> Band.objects.all() +>>> # listando todos os membros +>>> Member.objects.all() +>>> # criando mais uma banda +>>> band = Band.objects.create(name='The Beatles') +>>> band = Band.objects.get(name='The Beatles') +>>> band.id +>>> b = Band.objects.get(id=band.id) +>>> # criando mais um membro +>>> m = Member(name='John Lennon', instrument='v', band=b) +>>> m.save() +>>> # listando tudo novamente +>>> Band.objects.all() +>>> Member.objects.all() +>>> exit() +``` + + + + +## Criando os templates + +Você pode criar os templates com os comandos a seguir... + +``` +$ mkdir -p myproject/bands/templates/bands +$ touch myproject/bands/templates/{menu,base,home}.html +$ touch myproject/bands/templates/bands/{band_list,band_detail,band_form,band_contact,member_form,protected}.html +``` + +... ou pegar os templates já prontos direto do Github. + +``` +mkdir -p myproject/bands/templates/bands +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/base.html -P myproject/bands/templates/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/home.html -P myproject/bands/templates/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/menu.html -P myproject/bands/templates/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_contact.html -P myproject/bands/templates/bands/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_detail.html -P myproject/bands/templates/bands/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_form.html -P myproject/bands/templates/bands/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/band_list.html -P myproject/bands/templates/bands/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/member_form.html -P myproject/bands/templates/bands/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/myproject/bands/templates/bands/protected.html -P myproject/bands/templates/bands/ +``` + + + + +## forms.py + +`$ touch myproject/bands/forms.py` + +Edite o forms.py. + +```python +from django import forms +from .models import Band, Member + + +class BandContactForm(forms.Form): + subject = forms.CharField(max_length=100) + message = forms.CharField(widget=forms.Textarea) + sender = forms.EmailField() + cc_myself = forms.BooleanField(required=False) + + +class BandForm(forms.ModelForm): + + class Meta: + model = Band + fields = '__all__' + + +class MemberForm(forms.ModelForm): + + class Meta: + model = Member + fields = '__all__' +``` + +Lembra que eu deixei o código comentado em views.py? + +Descomente ele por favor + +```python +from .forms import BandContactForm, BandForm, MemberForm +``` + + +## admin.py + +Criamos uma customização para o admin onde em members aparece um filtro por bandas. + +```python +from django.contrib import admin +from .models import Band, Member + + +class MemberAdmin(admin.ModelAdmin): + """Customize the look of the auto-generated admin for the Member model.""" + list_display = ('name', 'instrument') + list_filter = ('band',) + + +admin.site.register(Band) # Use the default options +admin.site.register(Member, MemberAdmin) # Use the customized options +``` + + +## Carregando dados de um CSV + +Vamos baixar alguns arquivos para criar os dados no banco a partir de um CSV. + +``` +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/create_data.py +mkdir fix +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/fix/bands.csv -P fix/ +wget https://raw.githubusercontent.com/rg3915/django2-pythonclub/master/fix/members.csv -P fix/ +``` + +Estando na pasta principal, rode o comando + +``` +python create_data.py +``` + +que ele vai carregar alguns dados pra você. + +Veja o código de [create_data.py](https://github.com/rg3915/django2-pythonclub/blob/master/create_data.py). + +Veja o código completo em https://github.com/rg3915/django2-pythonclub + +`git clone https://github.com/rg3915/django2-pythonclub.git` + From 4e57c46c51a8bca1cce6959d1cb8d33aca54cf3e Mon Sep 17 00:00:00 2001 From: rg3915 Date: Mon, 24 Jun 2019 16:48:50 -0300 Subject: [PATCH 02/40] =?UTF-8?q?Ajustes=20na=20descri=C3=A7=C3=A3o=20"do?= =?UTF-8?q?=20que=20vc=20precisa"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/tutorial-django-2.2.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/content/tutorial-django-2.2.md b/content/tutorial-django-2.2.md index 697529277..3fe6957c9 100644 --- a/content/tutorial-django-2.2.md +++ b/content/tutorial-django-2.2.md @@ -18,28 +18,7 @@ Até a data deste post o Django está na versão 2.2.2, e requer Python 3. Python 3, pip e virtualenv. -Você vai precisar do [pip](https://pip.readthedocs.io/en/latest/) e do [virtualenv](https://virtualenv.pypa.io/en/latest/). - -* Instale primeiro o `pip` - -Primeira opção - -``` -$ wget https://bootstrap.pypa.io/get-pip.py -$ sudo python get-pip.py -``` - -Segunda opção - -`$ sudo apt-get install -y python-pip` - -* Depois instale o `virtualenv` - -``` -$ sudo pip install virtualenv -$ # ou -$ sudo apt-get install -y virtualenv -``` +Considere que você tenha instalado Python3, [pip](https://pip.readthedocs.io/en/latest/) e [virtualenv](https://virtualenv.pypa.io/en/latest/). ## Criando o ambiente From a6d3749464dde441b09a11a61fa552a450b7e0ba Mon Sep 17 00:00:00 2001 From: rg3915 Date: Mon, 24 Jun 2019 16:53:47 -0300 Subject: [PATCH 03/40] Python 3.6 ou superior --- content/tutorial-django-2.2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/tutorial-django-2.2.md b/content/tutorial-django-2.2.md index 3fe6957c9..df4797142 100644 --- a/content/tutorial-django-2.2.md +++ b/content/tutorial-django-2.2.md @@ -16,9 +16,9 @@ Até a data deste post o Django está na versão 2.2.2, e requer Python 3. ## O que você precisa? -Python 3, pip e virtualenv. +Python 3.6 ou superior, pip e virtualenv. -Considere que você tenha instalado Python3, [pip](https://pip.readthedocs.io/en/latest/) e [virtualenv](https://virtualenv.pypa.io/en/latest/). +Considere que você tenha instalado Python 3.6 ou superior, [pip](https://pip.readthedocs.io/en/latest/) e [virtualenv](https://virtualenv.pypa.io/en/latest/). ## Criando o ambiente From ad12cdae9156643056015c1b08fb0f9f6f0e88af Mon Sep 17 00:00:00 2001 From: rg3915 Date: Mon, 24 Jun 2019 17:06:39 -0300 Subject: [PATCH 04/40] =?UTF-8?q?Coment=C3=A1rios.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/tutorial-django-2.2.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/tutorial-django-2.2.md b/content/tutorial-django-2.2.md index df4797142..1c158f1aa 100644 --- a/content/tutorial-django-2.2.md +++ b/content/tutorial-django-2.2.md @@ -53,6 +53,10 @@ source .venv/bin/activate ## Instalando Django 2.2.2 +> Lembre-se, sempre quando você for mexer no projeto, tenha certeza de ter ativado o `virtualenv`, executando o comando `source .venv/bin/activate`. + +Você deve repetir esse comando toda a vez que você abrir um novo terminal. + Basta digitar ``` From 07d03e6bb251e4407dae175a81f99e1081d391e1 Mon Sep 17 00:00:00 2001 From: rg3915 Date: Mon, 24 Jun 2019 17:10:04 -0300 Subject: [PATCH 05/40] fix typo --- content/tutorial-django-2.2.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/tutorial-django-2.2.md b/content/tutorial-django-2.2.md index 1c158f1aa..e293f23ae 100644 --- a/content/tutorial-django-2.2.md +++ b/content/tutorial-django-2.2.md @@ -50,12 +50,10 @@ Depois ative o ambiente digitando source .venv/bin/activate ``` +> Lembre-se, sempre quando você for mexer no projeto, tenha certeza de ter ativado o `virtualenv`, executando o comando `source .venv/bin/activate`. Você deve repetir esse comando toda a vez que você abrir um novo terminal. ## Instalando Django 2.2.2 -> Lembre-se, sempre quando você for mexer no projeto, tenha certeza de ter ativado o `virtualenv`, executando o comando `source .venv/bin/activate`. - -Você deve repetir esse comando toda a vez que você abrir um novo terminal. Basta digitar From df64dc8e9cd9a3a6e71dcc6f8de0c95ec8ab7c62 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:00:24 -0300 Subject: [PATCH 06/40] Post sobre criacao de dicts em Python --- ...ndo-dict-a-partir-de-dois-ou-mais-dicts.md | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 content/criando-dict-a-partir-de-dois-ou-mais-dicts.md diff --git a/content/criando-dict-a-partir-de-dois-ou-mais-dicts.md b/content/criando-dict-a-partir-de-dois-ou-mais-dicts.md new file mode 100644 index 000000000..b07c0ef53 --- /dev/null +++ b/content/criando-dict-a-partir-de-dois-ou-mais-dicts.md @@ -0,0 +1,161 @@ +Title: Criando dicts a partir de outros dicts +Slug: crie_dict-a-partir-de-outros-dicts +Date: 2019-10-01 20:20:29 +Category: Python +Tags: Python, Dict +Author: Michell Stuttgart +Email: michellstut@gmail.com +Github: mstuttgart +Linkedin: mstuttgart +Site: https://mstuttgart.github.io +Summary: Crie dicts a partir de outros dicts + +Neste tutorial, será abordado o processo de criação de um *dict* ou dicionário, a partir de um ou mais *dicts* em Python. + +Como já é de costume da linguagem, isso pode ser feito de várias maneiras diferentes. + +## Abordagem inicial + +Pra começar, vamos supor que temos os seguintes dicionários: + +```python +dict_1 = { + 'a': 1, + 'b': 2, +} + +dict_2 = { + 'b': 3, + 'c': 4, +} +``` + +Como exemplo, vamos criar um novo dicionário chamado **new_dict** com os valores de **dict_1** e **dict_2** logo acima. Uma abordagem bem conhecida é utilizar o método *update*. + +```python +new_dict = {} + +new_dcit.update(dict_1) +new_dcit.update(dict_2) +``` + +Assim, temos que **new_dict** será: + +```python +>> print(new_dict) +{ + 'a': 1, + 'b': 3, + 'c': 4, +} +``` + +Este método funciona bem, porém temos de chamar o método *update* para cada *dict* que desejamos mesclar em **new_dict**. Não seria interessante se fosse possível passar todos os *dicts* necessários já na inicialização de **new_dict**? + +### Novidades do Python 3 + +O Python 3 introduziu uma maneira bem interessante de se fazer isso, utilizando os operadores `**`. + +```python +new_dict = { + **dict_1, + **dict_2, +} + +``` + +Assim, de maneira semelhante ao exemplo anterior, temos que **new_dict** será : + +```python +>> print(new_dict['a']) +1 +>> print(new_dict['b']) +3 +>> print(new_dict['c']) +4 +``` + +## Cópia real de *dicts* + +Ao utilizamos o procedimento de inicialização acima, devemos tomar conseiderar alguns fatores. Apenas os valores do primeiro nível serão realmente duplicados no novo dicionário. Como exemplo, vamos alterar uma chave presente em ambos os *dicts* e verificar se as mesmas possuem o mesmo valor: + +```python +>> dict_1['a'] = 10 +>> new_dict['a'] = 11 +>> print(dict_1['a']) +10 +>> print(new_dict['a']) +11 +``` + +Porém isso muda quando um dos valores de **dict_1** for uma *list*, outro *dict* ou algum objeto complexo. Por exemplo: + +```python +dict_3 = { + 'a': 1, + 'b': 2, + 'c': { + 'd': 5, + } +} +``` + +e agora, vamos criar um novo *dict* a partir desse: + +```python +new_dict = { + **dict_3, +} + +``` + +Como no exemplo anterior, podemos imaginar que foi realizado uma cópia de todos os elementos de **dict_3**, porém isso não é totalmente verdade. O que realmente aconteceu é que foi feita uma cópia *superficial* dos valores de **dict_3**, ou seja, apenas os valores de *primeiro nível* foram duplicados. Observe o que acontece quando alteramos o valor do *dict* presente na chave **c**. + +```python +>> new_dict['c']['d'] = 11 +>> print(new_dict['c']['d']) +11 +>> print(dict_3['c']['d']) +11 +# valor anterior era 5 + +``` + +No caso da chave **c**, ela contem uma referência para outra estrutura de dados (um *dict*, no caso). Quando alteramos algum valor de **dict_3['c']**, isso reflete em todos os *dict* que foram inicializados com **dict_3**. Em outras palavras, deve-se ter cuidado ao inicializar um *dict* a partir de outros **dicts** quando os mesmos possuírem valores complexos, como *list*, *dict* ou outros objetos (os atributos deste objeto não serão duplicados). + +De modo a contornar este inconveniente, podemos utilizar o método *deepcopy* da *lib* nativa [copy](https://docs.python.org/2/library/copy.html). Agora, ao inicializarmos **new_dict**: + +```python +import copy + +dict_3 = { + 'a': 1, + 'b': 2, + 'c': { + 'd': 5, + } +} + +new_dict = copy.deepcopy(dict_3) +``` + +O método *deepcopy* realiza uma cópia recursiva de cada elemento de **dict_3**, resolvendo nosso problema. Veja mais um exemplo: + +```python +>> new_dict['c']['d'] = 11 +>> print(new_dict['c']['d']) +11 +>> print(dict_3['c']['d']) +5 +# valor não foi alterado +``` + +## Conclusão + +Este artigo tenta demonstrar de maneira simples a criação de *dicts*, utilizando os diversos recursos que a linguagem oferece bem como os prós e contras de cada abordagem. + +## Referências + +Para mais detalhes e outros exemplos, deem uma olhada neste *post* do forum da Python Brasil [aqui](https://groups.google.com/forum/#!topic/python-brasil/OhUqYQ32M7E). + +É isso pessoal. Obrigado por ler! From eb0b92614e624467c511b6785f70a1e3ceec55f5 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:14:42 -0300 Subject: [PATCH 07/40] =?UTF-8?q?Atualiza=20cabe=C3=A7alho=20dos=20posts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/abrangencia-de-listas-e-dicionarios.md | 5 ++--- content/como-distribuir-seu-projeto-python-com-pypi.md | 5 ++--- content/gerando-relatorios-de-teste-com-coveralls.md | 5 ++--- content/peewee-um-orm-python-minimalista.md | 3 +-- ...-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md | 5 ++--- ...-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md | 5 ++--- .../python-com-unittest-travis-e-coveralls-parte-1-de-4.md | 5 ++--- .../python-com-unittest-travis-e-coveralls-parte-2-de-4.md | 5 ++--- 8 files changed, 15 insertions(+), 23 deletions(-) diff --git a/content/abrangencia-de-listas-e-dicionarios.md b/content/abrangencia-de-listas-e-dicionarios.md index a0d3ffde7..6b780e32e 100644 --- a/content/abrangencia-de-listas-e-dicionarios.md +++ b/content/abrangencia-de-listas-e-dicionarios.md @@ -6,9 +6,8 @@ Tags: python,tutorial,list comprehensions Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io A utilização de listas em Python é algo trivial. A facilidade provida pela linguagem aliada a simplicidade da estrutura de dados *list* a torna, ao lado dos dicionários *dict*, uma das estrutura de dados mais utilizadas em Python. Aqui neste tutorial irei compartilhar algo que aprendi trabalhando com listas e dicionário em Python, mais especificamente no que diz respeito a *abrangência* de listas (e dicionários). diff --git a/content/como-distribuir-seu-projeto-python-com-pypi.md b/content/como-distribuir-seu-projeto-python-com-pypi.md index d1ba1df42..d3e8ac050 100644 --- a/content/como-distribuir-seu-projeto-python-com-pypi.md +++ b/content/como-distribuir-seu-projeto-python-com-pypi.md @@ -6,9 +6,8 @@ Tags: python, pypi, tutorial, desenvolvimento, pypi, pip Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io Imagine a seguinte situação: você passou alguns dias (ou mesmo meses) desenvolvendo uma módulo python, escreveu testes, implementou funcionalidades e depois de alguns ajustes, chegou a hora de liberar seu software para que outros desenvolvedores possam utilizá-lo. Qual o melhor modo de distribuí-lo? diff --git a/content/gerando-relatorios-de-teste-com-coveralls.md b/content/gerando-relatorios-de-teste-com-coveralls.md index d720fc94d..bc005c6da 100644 --- a/content/gerando-relatorios-de-teste-com-coveralls.md +++ b/content/gerando-relatorios-de-teste-com-coveralls.md @@ -6,9 +6,8 @@ Tags: python, coveralls, coverage, relatório, test Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io/ Na [terceira parte](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.html) do tutorial sobre *unittest*, vimos como utilizar o serviço [Coveralls](https://coveralls.io/) para gerar relatórios sobre o testes do nosso projeto. Entretanto, uma "desvantagem" do serviço é que o processo de análise é iniciado apenas quando executarmos um *push* ou um *pull request*. Sendo assim, não seria interessante termos a liberdade de executar esses testes localmente? diff --git a/content/peewee-um-orm-python-minimalista.md b/content/peewee-um-orm-python-minimalista.md index 4c9312b80..d17292f45 100644 --- a/content/peewee-um-orm-python-minimalista.md +++ b/content/peewee-um-orm-python-minimalista.md @@ -7,8 +7,7 @@ Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart Linkedin: michell.stuttgart -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Site: https://mstuttgart.github.io/ Summary: Conheça o Peewee, um prático e minimalista ORM Python [Peewee](http://peewee.readthedocs.io/en/latest/index.html) é um ORM destinado a criar e gerenciar tabelas de banco de dados relacionais através de objetos Python. Segundo a [wikipedia](https://pt.wikipedia.org/wiki/Mapeamento_objeto-relacional), um ORM é: diff --git a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md index ea6e00d14..74b9d7860 100644 --- a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md +++ b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md @@ -6,9 +6,8 @@ Tags: git, travis-ci, python, coveralls, landscape, test, tutorial Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io Fala pessoal, tudo bem? diff --git a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md index dd633dc27..7f776bcb2 100644 --- a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md +++ b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md @@ -6,9 +6,8 @@ Tags: git, travis-ci, python, coveralls, landscape, test, tutorial Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io Fala pessoal, tudo bem? diff --git a/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md b/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md index 8129143c9..184414caf 100644 --- a/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md +++ b/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md @@ -6,9 +6,8 @@ Tags: git, travis-ci, python, coveralls, landscape, test, tutorial Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io Durante o desenvolvimento de um software, tão importante quanto escrever um código organizado e que siga as melhores práticas, é garantir que o mesmo cumpra os requisitos a que ele se propõe. Em outras palavras, garantir que o software funcione de maneira adequada. diff --git a/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md b/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md index 212578101..526b9384c 100644 --- a/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md +++ b/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md @@ -6,9 +6,8 @@ Tags: git, travis-ci, python, coveralls, landscape, test, tutorial Author: Michell Stuttgart Email: michellstut@gmail.com Github: mstuttgart -Linkedin: michellstut -Facebook: michell.stuttgart -Site: http://codigoavulso.com.br +Linkedin: mstuttgart +Site: https://mstuttgart.github.io Fala pessoal, tudo bem? From 84626fca7ca62e364c02871505737b8b860ef79f Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:24:10 -0300 Subject: [PATCH 08/40] Atualiza 'abrangencia-de-listas-e-dicionarios.md' --- .../abrangencia-de-listas-e-dicionarios.md | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/content/abrangencia-de-listas-e-dicionarios.md b/content/abrangencia-de-listas-e-dicionarios.md index 6b780e32e..fc6eff793 100644 --- a/content/abrangencia-de-listas-e-dicionarios.md +++ b/content/abrangencia-de-listas-e-dicionarios.md @@ -11,12 +11,12 @@ Site: https://mstuttgart.github.io A utilização de listas em Python é algo trivial. A facilidade provida pela linguagem aliada a simplicidade da estrutura de dados *list* a torna, ao lado dos dicionários *dict*, uma das estrutura de dados mais utilizadas em Python. Aqui neste tutorial irei compartilhar algo que aprendi trabalhando com listas e dicionário em Python, mais especificamente no que diz respeito a *abrangência* de listas (e dicionários). -### Abrangência de listas +## Abrangência de listas A abrangência de listas, ou do inglês *list comprehensions*, é um termo utilizado para descrever uma sintaxe compacta que o Python nos oferece para criamos uma lista baseada em outra lista. Pareceu confuso? Ok, vamos aos exemplos! -#### Exemplo 1 -Vamos suport que temos a seguinte lista de valores: +### Exemplo 1 +Vamos supor que temos a seguinte lista de valores: ```python valores = [1, 2, 3, 4, 5] @@ -49,7 +49,7 @@ valores_dobro = [valor*2 for valor in valores] ``` Bacana não? O exemplo seguinte podemos incrementar mais o exemplo acima. -#### Exemplo 2 +### Exemplo 2 Vamos supor que desejamos criar uma lista onde apenas os valores pares (resto da divisão por 2 é zero) serão multiplicados por 2. Abaixo temos a nossa lista de valores: @@ -85,7 +85,7 @@ valores_dobro = [valor * 2 for valor in valores if valor % 2 == 0] ``` Muito mais simples, não? Vamos para o próximo exemplo. -#### Exemplo 3 +### Exemplo 3 De maneira semelhante a lista, nós também podemos aplicar a abrangência em lista e dicionários. Segue um exemplo onde temos o seguinte dicionário: @@ -99,7 +99,7 @@ Vamos criar um segundo dicionário contendo apenas as chaves que são consoantes novo_dicionario = {'b': 4, 'c': 6, 'd': 8, 'f': 12} ``` -Utilizando um algoritmo genérico, podemos resolver o problema da seguinte maneira: +Utilizando um algoritmo genérico, podemos reslo o problema da seguinte maneira: ```python novo_dicionario = {} @@ -120,14 +120,12 @@ Aplicando agora a abrangência, conseguimos compactar o código acima de maneira novo_dicionario = {chave: 2 * valor for chave, valor in dicionario.items() if chave in ['b', 'c', 'd', 'f']} ``` -### Conclusão +## Conclusão Chegamos ao final de mais um tutorial! Sempre temos de ter em mente que tão importante quanto escrever um código que funciona, é mantê-lo (seja por você ou por outro programador). Neste ponto, a abrangência de lista (e outras estruturas de dados) nos ajudam a escrever um código claro e fácil de dar manutenção. Até o próximo tutorial pessoal! -**Publicado originalmente:** [Abrangencia de listas e dicionários com Python](http://codigoavulso.com.br/abrangencia-de-listas-e-dicionarios.html) +## Referências -### Referências - -* [Python eficaz: 59 maneiras de programar melhor em Python; Slatkin, Brett; Novatec Editora, 2016.](https://novatec.com.br/livros/python-eficaz/) +* [Python eficaz: 59 maneiras de programar melhor em Python; Slatkin, Brett; Novatec Editora, 2016.](https://novatec.com.br/livros/python-eficaz/) \ No newline at end of file From 4b3dfe90f60e5ce736da0e359d1fb53bc1b3fed5 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:24:34 -0300 Subject: [PATCH 09/40] Atualiza 'gerando-relatorios-de-teste-com-coveralls.md' --- content/gerando-relatorios-de-teste-com-coveralls.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/gerando-relatorios-de-teste-com-coveralls.md b/content/gerando-relatorios-de-teste-com-coveralls.md index bc005c6da..569baf09a 100644 --- a/content/gerando-relatorios-de-teste-com-coveralls.md +++ b/content/gerando-relatorios-de-teste-com-coveralls.md @@ -9,7 +9,7 @@ Github: mstuttgart Linkedin: mstuttgart Site: https://mstuttgart.github.io/ -Na [terceira parte](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.html) do tutorial sobre *unittest*, vimos como utilizar o serviço [Coveralls](https://coveralls.io/) para gerar relatórios sobre o testes do nosso projeto. Entretanto, uma "desvantagem" do serviço é que o processo de análise é iniciado apenas quando executarmos um *push* ou um *pull request*. Sendo assim, não seria interessante termos a liberdade de executar esses testes localmente? +Na [terceira parte](https://mstuttgart.github.io/2016/04/29/2016-04-29-python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4/) do tutorial sobre *unittest*, vimos como utilizar o serviço [Coveralls](https://coveralls.io/) para gerar relatórios sobre o testes do nosso projeto. Entretanto, uma "desvantagem" do serviço é que o processo de análise é iniciado apenas quando executarmos um *push* ou um *pull request*. Sendo assim, não seria interessante termos a liberdade de executar esses testes localmente? Felizmente, os desenvolvedores do [Coveralls](https://coveralls.io/) pensaram nisso e criaram um conjunto de comandos que nos permite executá-lo pelo terminal. @@ -143,4 +143,4 @@ Neste tutorial vimos um pouco mais sobre o `Coveralls`. Evitei colocar as inform É isso pessoal, obrigado pela leitura e até o próximo tutorial. -**Publicado originalmente:** [gerando-relatorios-de-testes-com-coveralls](http://codigoavulso.com.br/gerando-relatorios-de-testes-com-coveralls.html) +**Publicado originalmente:** [gerando-relatorios-de-testes-com-coveralls](https://mstuttgart.github.io/2016/05/18/2016-05-18-gerando-relatorios-de-teste-com-coveralls/) From e26ddb5a425af22dd7cdc2560b1c28d3cb73ccdb Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:25:37 -0300 Subject: [PATCH 10/40] Atualiza 'peewee-um-orm-python-minimalista.md' --- content/peewee-um-orm-python-minimalista.md | 225 ++++++++++++++------ 1 file changed, 159 insertions(+), 66 deletions(-) diff --git a/content/peewee-um-orm-python-minimalista.md b/content/peewee-um-orm-python-minimalista.md index d17292f45..a0ffc5b3e 100644 --- a/content/peewee-um-orm-python-minimalista.md +++ b/content/peewee-um-orm-python-minimalista.md @@ -11,147 +11,189 @@ Site: https://mstuttgart.github.io/ Summary: Conheça o Peewee, um prático e minimalista ORM Python [Peewee](http://peewee.readthedocs.io/en/latest/index.html) é um ORM destinado a criar e gerenciar tabelas de banco de dados relacionais através de objetos Python. Segundo a [wikipedia](https://pt.wikipedia.org/wiki/Mapeamento_objeto-relacional), um ORM é: ->>> Mapeamento objeto-relacional (ou ORM, do inglês: Object-relational mapping) é uma técnica de desenvolvimento utilizada para reduzir a impedância da programação orientada aos objetos utilizando bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registros de cada tabela são representados como instâncias das classes correspondentes. -O que o ORM faz é, basicamente, transformar classes Python em tabelas no banco de dados, além de permitir construir *querys* usando diretamente objetos Python ao invés de SQL. +> Mapeamento objeto-relacional (ou ORM, do inglês: Object-relational mapping) é uma técnica de desenvolvimento > utilizada para reduzir a impedância da programação orientada aos objetos utilizando bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registros de cada tabela são representados como instâncias das classes correspondentes. -O Peewee é destinado a projetos de pequeno/médio porte, se destacando pela simplicidade quando comparado a outros ORM mais conhecidos, como o SQLAlchemy. Uma analogia utilizada pelo autor da API e que acho muito interessante é que Peewee está para o SQLAlchemy assim como SQLite está para o PostgreSQL. +O que um ORM faz é, basicamente, transformar classes Python em tabelas no banco de dados, além de permitir construir *querys* usando diretamente objetos Python ao invés de SQL. -Em relação aos recursos por ele oferecidos, podemos citar que ele possui suporte nativo a SQLite, PostgreSQL e MySQL, embora seja necessário a instalação de *drivers* para utilizá-lo com PostgreSQL e MySQL e suporta tanto Python 2.6+ quanto Python 3.4+. +O Peewee é destinado a projetos de pequeno/médio porte e se destaca pela simplicidade quando comparado a outros ORM mais conhecidos, como o SQLAlchemy. Uma analogia utilizada pelo autor da API e que acho muito interessante é que Peewee está para o SQLAlchemy assim como SQLite está para o PostgreSQL. -Neste tutorial, utilizaremos o SQLite, por sua simplicidade de uso e por não precisar de nenhuma configuração. +Em relação aos recursos por ele oferecidos, podemos citar que ele possui suporte nativo a SQLite, PostgreSQL e MySQL, embora seja necessário a instalação de *drivers* para utilizá-lo com PostgreSQL e MySQL e suporta tanto Python 2.6+ quanto Python 3.4+. -### Instalação +Neste tutorial, utilizaremos o SQLite, por sua simplicidade de uso e pelo Python possuir suporte nativo ao mesmo (usaremos o Python 3.5). -O Peewee pode ser facilmente instalado com o gerenciador de pacotes *pip*: +## Instalação -```bash +O Peewee pode ser facilmente instalado com o gerenciador de pacotes *pip* (recomendo a instalação em um virtualenv): + +``` pip install peewee ``` -### Criando o banco de dados +## Criando o banco de dados -Para criar as tabelas é bem simples. Inicialmente passamos o nome do nosso banco de dados (a extensão `*.db` indica um arquivo do SQLite). +Para criar o banco de dados é bem simples. Inicialmente passamos o nome do nosso banco de dados (a extensão `*.db` indica um arquivo do SQLite). ```python import peewee +# Aqui criamos o banco de dados db = peewee.SqliteDatabase('codigo_avulso.db') ``` Diferente de outros bancos de dados que funcionam através um servidor, o SQLite cria um arquivo de extensão `*.db`, onde todos os nossos dados são armazenados. -**DICA**: caso deseje ver as tabelas existentes no arquivo `codigo_avulso.db`, instale o aplicativo `SQLiteBrowser`. Com ele fica fácil monitorar as tabelas criadas e acompanhar o tutorial. - -```bash +> Caso deseje ver as tabelas existentes no arquivo `codigo_avulso.db`, instale o aplicativo `SQLiteBrowser`. Com ele fica fácil monitorar as tabelas criadas e acompanhar o tutorial. +```shell sudo apt-get install sqlitebrowser ``` -A título de exemplo, vamos criar um banco destinado a armazenar nomes de livros e de seus respectivos autores. Comecemos primeiro com a classe que representa os autores. +A título de exemplo, vamos criar um banco destinado a armazenar nomes de livros e de seus respectivos autores. Iremos chamá-lo de `models.py`. + +Inicialmente, vamos criar a classe base para todos os nossos `models`. Esta é uma abordagem recomendada pela documentação e é considerada uma boa prática. Também adicionaremos um log para acompanharmos as mudanças que são feitas no banco: ```python +# models.py + import peewee +# Criamos o banco de dados db = peewee.SqliteDatabase('codigo_avulso.db') -class Author(peewee.Model): - """ - Classe que representa a tabela Author - """ - # A tabela possui apenas o campo 'name', que - # receberá o nome do autor - name = peewee.CharField() +class BaseModel(peewee.Model): + """Classe model base""" class Meta: # Indica em qual banco de dados a tabela # 'author' sera criada (obrigatorio). Neste caso, - # utilizamos o banco 'codigo_avulso.db' criado anteriormente. + # utilizamos o banco 'codigo_avulso.db' criado anteriormente database = db ``` -Em seguida, criamos a classe que representa os livros. Ela possui uma relação de "muitos para um" com a tabela de autores, ou seja, cada livro possui apenas um autor, mas um autor pode possuir vários livros. + +A class `BaseModel` é responsável por criar a conexão com nosso banco de dados. + +Agora, vamos criar a model que representa os autores: ```python -import peewee +# models.py -db = peewee.SqliteDatabase('codigo_avulso.db') +class Author(BaseModel): -class Book(peewee.Model): + """ + Classe que representa a tabela Author + """ + # A tabela possui apenas o campo 'name', que receberá o nome do autor sera unico + name = peewee.CharField(unique=True) + +``` + +Se observamos a model `Author`, veremos que não foi especificado nenhuma coluna como *primary key* (chave primaria), sendo assim o Peewee irá criar um campo chamado `id` do tipo inteiro com auto incremento para funcionar como chave primária. +Em seguida, no mesmo arquivo `models.py` criamos a classe que representa os livros. Ela possui uma relação de "muitos para um" com a tabela de autores, ou seja, cada livro possui apenas um autor, mas um autor pode possuir vários livros. + +```python +# models.py + +class Book(BaseModel): """ Classe que representa a tabela Book """ - # A tabela possui apenas o campo 'title', que - # receberá o nome do livro - title = peewee.CharField() + # A tabela possui apenas o campo 'title', que receberá o nome do livro + title = peewee.CharField(unique=True) # Chave estrangeira para a tabela Author author = peewee.ForeignKeyField(Author) - class Meta: - # Indica em qual banco de dados a tabela - # 'author' sera criada (obrigatorio). Neste caso, - # utilizamos o banco 'codigo_avulso.db' criado anteriormente. - database = db ``` -Agora, vamos reunir tudo em um único arquivo `model.py`. Como exemplo, eu criei um arquivo *main.py* para utilizarmos as classes que acabamos de criar. +Agora, adicionamos o código que cria as tabelas `Author` e `Book`. ```python - -import peewee -from model import Author, Book - +# models.py if __name__ == '__main__': try: Author.create_table() + print("Tabela 'Author' criada com sucesso!") except peewee.OperationalError: - print 'Tabela Author ja existe!' + print("Tabela 'Author' ja existe!") try: Book.create_table() + print("Tabela 'Book' criada com sucesso!") except peewee.OperationalError: - print 'Tabela Book ja existe!' + print("Tabela 'Book' ja existe!") +``` +excerpt +Agora executamos o `models.py`: +``` +python models.py ``` -Após executarmos o código, será criado um arquivo de nome `codigo_avulso.db` no mesmo diretório do nosso arquivo `main.py`, contendo as tabelas `Author` e `Book`. A estrutura do diretório ficou assim: +A estrutura do diretório ficou assim: -```bash +```shell . ├── codigo_avulso.db -├── main.py -├── model.py +├── models.py ``` -### Inserindo dados no banco +Após executarmos o código, será criado um arquivo de nome `codigo_avulso.db` no mesmo diretório do nosso arquivo `models.py`, contendo as tabelas `Author` e `Book`. -Agora, vamos popular nosso banco com alguns autores e seus respectivos livros. Isso pode ser feito de dois modos. Através do método `create`, quando desejamos inserir um registro apenas; ou pelo método `insert_many`, quando desejamos inserir vários registros de uma vez em uma mesma tabela. +## Realizando o CRUD + +Agora vamos seguir com as 4 principais operações que podemos realizar em um banco de dados, também conhecida como CRUD. + +A sigla `CRUD` é comumente utilizada para designar as quatro operações básicas que pode-se executar em um banco de dados, sendo elas: + + - Create (criar um novo registro no banco) + - Read (ler/consultar um registro) + - Update (atualizar um registro) + - Delete (excluir um registro do banco) + +Iremos abordar cada uma dessas operações. + +### Create: Inserindo dados no banco + +Agora, vamos popular nosso banco com alguns autores e seus respectivos livros. Para isso criamos um arquivo `create.py`. A estrutura do diretório ficou assim: + +```shell +. +├── codigo_avulso.db +├── models.py +├── create.py +``` + +A criação dos registros no banco pode ser feito através do método `create`, quando desejamos inserir um registro apenas; ou pelo método `insert_many`, quando desejamos inserir vários registros de uma vez em uma mesma tabela. ```python +# create.py + +from models import Author, Book # Inserimos um autor de nome "H. G. Wells" na tabela 'Author' author_1 = Author.create(name='H. G. Wells') +# Inserimos um autor de nome "Julio Verne" na tabela 'Author' +author_2 = Author.create(name='Julio Verne') + book_1 = { 'title': 'A Máquina do Tempo', - 'author': author_1, + 'author_id': author_1, } book_2 = { 'title': 'Guerra dos Mundos', - 'author': author_1, + 'author_id': author_1, } -# Inserimos um autor de nome "Julio Verne" na tabela 'Author' -author_2 = Author.create(name='Julio Verne') - book_3 = { 'title': 'Volta ao Mundo em 80 Dias', - 'author': author_2, + 'author_id': author_2, } book_4 = { @@ -166,24 +208,34 @@ Book.insert_many(books).execute() ``` -### Consultando dados no banco +### Read: Consultando dados no banco O Peewee possui comandos destinados a realizar consultas no banco. De maneira semelhante ao conhecido `SELECT`. Podemos fazer essa consulta de duas maneiras. Se desejamos o primeiro registro que corresponda a nossa pesquisa, podemos utilizar o método `get()`. ```python +# read.py + +from models import Author, Book + book = Book.get(Book.title == "Volta ao Mundo em 80 Dias").get() -book.title +print(book.title) + +# Resultado +# * Volta ao Munto em 80 Dias ``` + Porém, se desejamos mais de um registro, utilizamos o método `select`. Por exemplo, para consultar todos os livros escritos pelo autor "H. G. Wells". ```python +# read.py + books = Book.select().join(Author).where(Author.name=='H. G. Wells') # Exibe a quantidade de registros que corresponde a nossa pesquisa -print books.count() +print(books.count()) for book in books: - book.title + print(book.title) # Resultado: # * A Máquina do Tempo @@ -194,19 +246,36 @@ for book in books: Também podemos utilizar outras comandos do SQL como `limit` e `group` (para mais detalhes, ver a documentação [aqui](http://peewee.readthedocs.io/en/latest/index.html)). -### Alterando dados no banco +A estrutura do diretório ficou assim: + +```sh +. +├── codigo_avulso.db +├── models.py +├── create.py +├── read.py +``` + +### Update: Alterando dados no banco Alterar dados também é bem simples. No exemplo anterior, se observarmos o resultado da consulta dos livros do autor "H. G. Wells", iremos nos deparar com o livro de título "Vinte Mil Léguas Submarinas". Se você, caro leitor, gosta de contos de ficção-científica, sabe que esta obra foi escrito por "Julio Verne", coincidentemente um dos autores que também estão cadastrados em nosso banco. Sendo assim, vamos corrigir o autor do respectivo livro. Primeiro vamos buscar o registro do autor e do livro: ```python +# update.py + +from models import Author, Book + new_author = Author.get(Author.name == 'Julio Verne') book = Book.get(Book.title=="Vinte Mil Leguas Submarinas") ``` + Agora vamos alterar o autor e gravar essa alteração no banco. ```python +# update.py + # Alteramos o autor do livro book.author = new_author @@ -214,31 +283,55 @@ book.author = new_author book.save() ``` -### Deletando dados do banco +A estrutura do diretório ficou assim: + +```sh +. +├── codigo_avulso.db +├── models.py +├── create.py +├── read.py +├── update.py +``` + +### Delete: Deletando dados do banco Assim como as operações anteriores, também podemos deletar registros do banco de maneira bem prática. Como exemplo, vamos deletar o livro "Guerra dos Mundos" do nosso banco de dados. ```python +# delete.py + +from models import Author, Book + # Buscamos o livro que desejamos excluir do banco book = Book.get(Book.title=="Guerra dos Mundos") # Excluimos o livro do banco book.delete_instance() + ``` + Simples não? -### Conclusão +A estrutura do diretório ficou assim: -É isso pessoal. Este tutorial foi uma introdução bem enxuta sobre o Peewee. Ainda existem muitos tópicos que não abordei aqui, como a criação de *primary_key*, de campos *many2many* entre outros recursos, pois foge do escopo deste tutorial. Se você gostou do ORM, aconselho a dar uma olhada também na sua documentação, para conseguir extrair todo o potencial da ferramenta. A utilização de um ORM evita que o desenvolvedor perca tempo escrevendo *query* SQL e foque totalmente no desenolvimento de código. +```sh +. +├── codigo_avulso.db +├── models.py +├── create.py +├── read.py +├── update.py +├── delete.py +``` -O Peewee também possui suporte ao flamework *flask*, então dependendo do tamanho do projeto, pode ser uma alternativa interessante no lugar de ORM mais complexos como o SQLAlchemy. +## Conclusão -É isso pessoal. Obrigado pela leitura e até o próximo tutorial! +É isso pessoal. Este tutorial foi uma introdução bem enxuta sobre o Peewee. Ainda existem muitos tópicos que não abordei aqui, como a criação de *primary_key*, de campos *many2many* entre outros recursos, pois foge do escopo deste tutorial. Se você gostou do ORM, aconselho a dar uma olhada também na sua documentação, para conseguir extrair todo o potencial da ferramenta. A utilização de um ORM evita que o desenvolvedor perca tempo escrevendo *query* SQL e foque totalmente no desenvolvimento de código. -### Referências +## Referências * [Documentação do Peewee (em inglês)](http://peewee.readthedocs.io/en/latest/index.html) * [An Intro to peewee – Another Python ORM](https://www.blog.pythonlibrary.org/2014/07/17/an-intro-to-peewee-another-python-orm/) * [Introduction to peewee](http://jonathansoma.com/tutorials/webapps/intro-to-peewee/) -* [Introdução à Linguagem SQL](https://www.novatec.com.br/livros/introducao-sql/) - +* [Introdução à Linguagem SQL](https://www.novatec.com.br/livros/introducao-sql/) \ No newline at end of file From 8335850dd248a31a058876b027d5449bca4e15ef Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:26:03 -0300 Subject: [PATCH 11/40] Atualiza 'python-com-unittest-travis-e-coveralls-parte-1-de-4.md' --- content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md b/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md index 184414caf..8f026e6ab 100644 --- a/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md +++ b/content/python-com-unittest-travis-e-coveralls-parte-1-de-4.md @@ -389,4 +389,4 @@ Os testes que escrevemos foram bem simples, apenas para fim de exemplo. Porém e É isso pessoal. Obrigado por ler até aqui. Até a próxima postagem! -**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-1-de-4](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-1-de-4.html) +**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-1-de-4](https://mstuttgart.github.io/2016/04/12/2016-04-12-python-com-unittest-travis-e-coveralls-parte-1-de-4/) From 5ccde03fdeb7b96d269758ca23c2fc436a1fb112 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:26:25 -0300 Subject: [PATCH 12/40] Atualiza 'python-com-unittest-travis-e-coveralls-parte-2-de-4.md' --- content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md b/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md index 526b9384c..417bcee55 100644 --- a/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md +++ b/content/python-com-unittest-travis-e-coveralls-parte-2-de-4.md @@ -161,4 +161,4 @@ Aqui encerramos a segunda parte do nossa série de tutoriais sobre `Unittest`. E Até o próximo tutorial! -**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-2-de-4](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-2-de-4.html) +**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-2-de-4](https://mstuttgart.github.io/2016/04/19/2016-04-19-python-com-unittest-travis-e-coveralls-parte-2-de-4/) From 2b602f9d18833048c2c9efa4d1345d634392571e Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:26:49 -0300 Subject: [PATCH 13/40] Atualiza 'python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md' --- ...com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md index 74b9d7860..7cf33ddf6 100644 --- a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md +++ b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.md @@ -162,4 +162,4 @@ Aqui encerramos a terceira parte do nossa série de tutoriais sobre `Unittest`. É isso pessoal. Obrigado por ler até aqui e até o próximo tutorial! -**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4.html) +**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4](https://mstuttgart.github.io/2016/04/29/2016-04-29-python-com-unittest-travis-ci-coveralls-e-landscape-parte-3-de-4/) From 306b8921fcf9036ca4e1b2de0c9758ae59f4c2b2 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Mon, 30 Sep 2019 21:27:12 -0300 Subject: [PATCH 14/40] Atualiza 'python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md' --- ...com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md index 7f776bcb2..2ab7d0878 100644 --- a/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md +++ b/content/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.md @@ -113,4 +113,4 @@ Vale lembrar que todas essas ferramentas ajudam muito, mas nada substitui o sens Espero que tenham gostado desta série de tutoriais. Obrigado por ler até aqui e até o próximo *post*. -**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4](http://codigoavulso.com.br/python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4.html) +**Publicado originalmente:** [python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4](https://mstuttgart.github.io/2016/05/07/2016-05-07-python-com-unittest-travis-ci-coveralls-e-landscape-parte-4-de-4/) From d8985f2bb581579262f5bb965908c7d2a7920183 Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Tue, 1 Oct 2019 12:12:07 -0300 Subject: [PATCH 15/40] Update content/abrangencia-de-listas-e-dicionarios.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Fábio C. Barrionuevo da Luz --- content/abrangencia-de-listas-e-dicionarios.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/abrangencia-de-listas-e-dicionarios.md b/content/abrangencia-de-listas-e-dicionarios.md index fc6eff793..d025ac785 100644 --- a/content/abrangencia-de-listas-e-dicionarios.md +++ b/content/abrangencia-de-listas-e-dicionarios.md @@ -99,7 +99,7 @@ Vamos criar um segundo dicionário contendo apenas as chaves que são consoantes novo_dicionario = {'b': 4, 'c': 6, 'd': 8, 'f': 12} ``` -Utilizando um algoritmo genérico, podemos reslo o problema da seguinte maneira: +Utilizando um algoritmo genérico, podemos resolver o problema da seguinte maneira: ```python novo_dicionario = {} @@ -128,4 +128,4 @@ Até o próximo tutorial pessoal! ## Referências -* [Python eficaz: 59 maneiras de programar melhor em Python; Slatkin, Brett; Novatec Editora, 2016.](https://novatec.com.br/livros/python-eficaz/) \ No newline at end of file +* [Python eficaz: 59 maneiras de programar melhor em Python; Slatkin, Brett; Novatec Editora, 2016.](https://novatec.com.br/livros/python-eficaz/) From d5d74ea068b321feea5ee5049017a1cdc8d6deed Mon Sep 17 00:00:00 2001 From: Lucas Magnum Date: Fri, 24 Jan 2020 12:36:39 -0300 Subject: [PATCH 16/40] Add article about CI with Github Actions --- content/django-ci-github-actions.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 content/django-ci-github-actions.rst diff --git a/content/django-ci-github-actions.rst b/content/django-ci-github-actions.rst new file mode 100644 index 000000000..fb4bbdbab --- /dev/null +++ b/content/django-ci-github-actions.rst @@ -0,0 +1,21 @@ +Criando um CI de uma aplicação Django usando Github Actions +########################################################### + +:date: 2020-01-24 12:10 +:tags: python, django, github actions +:category: Python +:slug: django-ci-github-actions +:author: Lucas Magnum +:email: lucasmagnumlopes@gmail.com +:github: lucasmagnum +:linkedin: lucasmagnum + +Fala pessoal, tudo bom? + +Nos vídeo abaixo vou mostrar como podemos configurar um CI de uma aplicação Django usando Github Actions. + +`https://www.youtube.com/watch?v=KpSlY8leYFY `_. + + +.. youtube:: KpSlY8leYFY + From 3516b5338598e1372dbcb5490bd9edcf628c4ac4 Mon Sep 17 00:00:00 2001 From: JacksonOsvaldo Date: Wed, 28 Oct 2020 01:05:44 -0300 Subject: [PATCH 17/40] Initial post JacksonOsvaldo --- ...endo-backup-do-banco-de-dados-no-django.md | 122 + content/images/JacksonOsvaldo/django_db.png | Bin 0 -> 51134 bytes env/bin/activate | 84 + env/bin/activate.csh | 55 + env/bin/activate.fish | 100 + env/bin/activate.ps1 | 60 + env/bin/activate.xsh | 46 + env/bin/activate_this.py | 32 + env/bin/easy_install | 8 + env/bin/easy_install-3.8 | 8 + env/bin/easy_install3 | 8 + env/bin/markdown_py | 8 + env/bin/pelican | 8 + env/bin/pelican-import | 8 + env/bin/pelican-quickstart | 8 + env/bin/pelican-themes | 8 + env/bin/pip | 8 + env/bin/pip-3.8 | 8 + env/bin/pip3 | 8 + env/bin/pip3.8 | 8 + env/bin/pygmentize | 8 + env/bin/python | 1 + env/bin/python3 | 1 + env/bin/python3.8 | 1 + env/bin/rst2html.py | 23 + env/bin/rst2html4.py | 26 + env/bin/rst2html5.py | 35 + env/bin/rst2latex.py | 26 + env/bin/rst2man.py | 26 + env/bin/rst2odt.py | 30 + env/bin/rst2odt_prepstyles.py | 67 + env/bin/rst2pseudoxml.py | 23 + env/bin/rst2s5.py | 24 + env/bin/rst2xetex.py | 27 + env/bin/rst2xml.py | 23 + env/bin/rstpep2html.py | 25 + env/bin/unidecode | 8 + env/bin/wheel | 8 + env/bin/wheel-3.8 | 8 + env/bin/wheel3 | 8 + .../Jinja2-2.11.2.dist-info/INSTALLER | 1 + .../Jinja2-2.11.2.dist-info/LICENSE.rst | 28 + .../Jinja2-2.11.2.dist-info/METADATA | 106 + .../Jinja2-2.11.2.dist-info/RECORD | 61 + .../Jinja2-2.11.2.dist-info/WHEEL | 6 + .../Jinja2-2.11.2.dist-info/entry_points.txt | 3 + .../Jinja2-2.11.2.dist-info/top_level.txt | 1 + .../Markdown-3.3.3.dist-info/INSTALLER | 1 + .../Markdown-3.3.3.dist-info/LICENSE.md | 29 + .../Markdown-3.3.3.dist-info/METADATA | 98 + .../Markdown-3.3.3.dist-info/RECORD | 76 + .../Markdown-3.3.3.dist-info/WHEEL | 5 + .../Markdown-3.3.3.dist-info/entry_points.txt | 23 + .../Markdown-3.3.3.dist-info/top_level.txt | 1 + .../MarkupSafe-1.1.1.dist-info/INSTALLER | 1 + .../MarkupSafe-1.1.1.dist-info/LICENSE.txt | 28 + .../MarkupSafe-1.1.1.dist-info/METADATA | 105 + .../MarkupSafe-1.1.1.dist-info/RECORD | 16 + .../MarkupSafe-1.1.1.dist-info/WHEEL | 5 + .../MarkupSafe-1.1.1.dist-info/top_level.txt | 1 + .../Pygments-2.7.2.dist-info/AUTHORS | 238 + .../Pygments-2.7.2.dist-info/INSTALLER | 1 + .../Pygments-2.7.2.dist-info/LICENSE | 25 + .../Pygments-2.7.2.dist-info/METADATA | 49 + .../Pygments-2.7.2.dist-info/RECORD | 481 + .../Pygments-2.7.2.dist-info/WHEEL | 5 + .../Pygments-2.7.2.dist-info/entry_points.txt | 3 + .../Pygments-2.7.2.dist-info/top_level.txt | 1 + .../Unidecode-1.1.1.dist-info/DESCRIPTION.rst | 237 + .../Unidecode-1.1.1.dist-info/INSTALLER | 1 + .../Unidecode-1.1.1.dist-info/LICENSE.txt | 339 + .../Unidecode-1.1.1.dist-info/METADATA | 261 + .../Unidecode-1.1.1.dist-info/RECORD | 394 + .../Unidecode-1.1.1.dist-info/WHEEL | 6 + .../entry_points.txt | 3 + .../Unidecode-1.1.1.dist-info/metadata.json | 1 + .../Unidecode-1.1.1.dist-info/top_level.txt | 1 + .../python3.8/site-packages/_virtualenv.pth | 1 + .../python3.8/site-packages/_virtualenv.py | 115 + .../blinker-1.4.dist-info/AUTHORS | 8 + .../blinker-1.4.dist-info/INSTALLER | 1 + .../blinker-1.4.dist-info/LICENSE | 20 + .../blinker-1.4.dist-info/METADATA | 103 + .../blinker-1.4.dist-info/RECORD | 15 + .../site-packages/blinker-1.4.dist-info/WHEEL | 5 + .../blinker-1.4.dist-info/top_level.txt | 1 + .../site-packages/blinker/__init__.py | 22 + .../site-packages/blinker/_saferef.py | 234 + .../site-packages/blinker/_utilities.py | 163 + .../python3.8/site-packages/blinker/base.py | 455 + .../site-packages/dateutil/__init__.py | 8 + .../site-packages/dateutil/_common.py | 43 + .../site-packages/dateutil/_version.py | 4 + .../site-packages/dateutil/easter.py | 89 + .../site-packages/dateutil/parser/__init__.py | 61 + .../site-packages/dateutil/parser/_parser.py | 1609 ++++ .../dateutil/parser/isoparser.py | 411 + .../site-packages/dateutil/relativedelta.py | 599 ++ .../python3.8/site-packages/dateutil/rrule.py | 1735 ++++ .../site-packages/dateutil/tz/__init__.py | 12 + .../site-packages/dateutil/tz/_common.py | 419 + .../site-packages/dateutil/tz/_factories.py | 80 + .../python3.8/site-packages/dateutil/tz/tz.py | 1849 ++++ .../site-packages/dateutil/tz/win.py | 370 + .../python3.8/site-packages/dateutil/tzwin.py | 2 + .../python3.8/site-packages/dateutil/utils.py | 71 + .../dateutil/zoneinfo/__init__.py | 167 + .../zoneinfo/dateutil-zoneinfo.tar.gz | Bin 0 -> 153315 bytes .../dateutil/zoneinfo/rebuild.py | 53 + .../docutils-0.16.dist-info/COPYING.txt | 137 + .../docutils-0.16.dist-info/INSTALLER | 1 + .../docutils-0.16.dist-info/METADATA | 64 + .../docutils-0.16.dist-info/RECORD | 332 + .../docutils-0.16.dist-info/WHEEL | 6 + .../docutils-0.16.dist-info/top_level.txt | 1 + .../site-packages/docutils/__init__.py | 233 + .../python3.8/site-packages/docutils/core.py | 666 ++ .../site-packages/docutils/examples.py | 97 + .../site-packages/docutils/frontend.py | 863 ++ .../python3.8/site-packages/docutils/io.py | 481 + .../docutils/languages/__init__.py | 47 + .../site-packages/docutils/languages/af.py | 58 + .../site-packages/docutils/languages/ca.py | 60 + .../site-packages/docutils/languages/cs.py | 60 + .../site-packages/docutils/languages/da.py | 62 + .../site-packages/docutils/languages/de.py | 58 + .../site-packages/docutils/languages/en.py | 60 + .../site-packages/docutils/languages/eo.py | 61 + .../site-packages/docutils/languages/es.py | 59 + .../site-packages/docutils/languages/fa.py | 61 + .../site-packages/docutils/languages/fi.py | 60 + .../site-packages/docutils/languages/fr.py | 58 + .../site-packages/docutils/languages/gl.py | 63 + .../site-packages/docutils/languages/he.py | 60 + .../site-packages/docutils/languages/it.py | 58 + .../site-packages/docutils/languages/ja.py | 61 + .../site-packages/docutils/languages/ko.py | 61 + .../site-packages/docutils/languages/lt.py | 61 + .../site-packages/docutils/languages/lv.py | 60 + .../site-packages/docutils/languages/nl.py | 60 + .../site-packages/docutils/languages/pl.py | 62 + .../site-packages/docutils/languages/pt_br.py | 60 + .../site-packages/docutils/languages/ru.py | 59 + .../site-packages/docutils/languages/sk.py | 58 + .../site-packages/docutils/languages/sv.py | 60 + .../site-packages/docutils/languages/zh_cn.py | 67 + .../site-packages/docutils/languages/zh_tw.py | 66 + .../python3.8/site-packages/docutils/nodes.py | 2317 +++++ .../docutils/parsers/__init__.py | 51 + .../site-packages/docutils/parsers/null.py | 20 + .../docutils/parsers/rst/__init__.py | 416 + .../parsers/rst/directives/__init__.py | 419 + .../parsers/rst/directives/admonitions.py | 99 + .../docutils/parsers/rst/directives/body.py | 288 + .../docutils/parsers/rst/directives/html.py | 88 + .../docutils/parsers/rst/directives/images.py | 171 + .../docutils/parsers/rst/directives/misc.py | 556 ++ .../docutils/parsers/rst/directives/parts.py | 126 + .../parsers/rst/directives/references.py | 29 + .../docutils/parsers/rst/directives/tables.py | 513 + .../docutils/parsers/rst/include/README.txt | 17 + .../docutils/parsers/rst/include/isoamsa.txt | 162 + .../docutils/parsers/rst/include/isoamsb.txt | 126 + .../docutils/parsers/rst/include/isoamsc.txt | 29 + .../docutils/parsers/rst/include/isoamsn.txt | 96 + .../docutils/parsers/rst/include/isoamso.txt | 62 + .../docutils/parsers/rst/include/isoamsr.txt | 191 + .../docutils/parsers/rst/include/isobox.txt | 46 + .../docutils/parsers/rst/include/isocyr1.txt | 73 + .../docutils/parsers/rst/include/isocyr2.txt | 32 + .../docutils/parsers/rst/include/isodia.txt | 20 + .../docutils/parsers/rst/include/isogrk1.txt | 55 + .../docutils/parsers/rst/include/isogrk2.txt | 26 + .../docutils/parsers/rst/include/isogrk3.txt | 52 + .../parsers/rst/include/isogrk4-wide.txt | 49 + .../docutils/parsers/rst/include/isogrk4.txt | 8 + .../docutils/parsers/rst/include/isolat1.txt | 68 + .../docutils/parsers/rst/include/isolat2.txt | 128 + .../parsers/rst/include/isomfrk-wide.txt | 58 + .../docutils/parsers/rst/include/isomfrk.txt | 11 + .../parsers/rst/include/isomopf-wide.txt | 32 + .../docutils/parsers/rst/include/isomopf.txt | 13 + .../parsers/rst/include/isomscr-wide.txt | 58 + .../docutils/parsers/rst/include/isomscr.txt | 17 + .../docutils/parsers/rst/include/isonum.txt | 82 + .../docutils/parsers/rst/include/isopub.txt | 90 + .../docutils/parsers/rst/include/isotech.txt | 168 + .../docutils/parsers/rst/include/mmlalias.txt | 554 ++ .../parsers/rst/include/mmlextra-wide.txt | 113 + .../docutils/parsers/rst/include/mmlextra.txt | 87 + .../docutils/parsers/rst/include/s5defs.txt | 68 + .../parsers/rst/include/xhtml1-lat1.txt | 102 + .../parsers/rst/include/xhtml1-special.txt | 37 + .../parsers/rst/include/xhtml1-symbol.txt | 130 + .../parsers/rst/languages/__init__.py | 36 + .../docutils/parsers/rst/languages/af.py | 106 + .../docutils/parsers/rst/languages/ca.py | 125 + .../docutils/parsers/rst/languages/cs.py | 108 + .../docutils/parsers/rst/languages/da.py | 113 + .../docutils/parsers/rst/languages/de.py | 105 + .../docutils/parsers/rst/languages/en.py | 110 + .../docutils/parsers/rst/languages/eo.py | 118 + .../docutils/parsers/rst/languages/es.py | 125 + .../docutils/parsers/rst/languages/fa.py | 102 + .../docutils/parsers/rst/languages/fi.py | 98 + .../docutils/parsers/rst/languages/fr.py | 103 + .../docutils/parsers/rst/languages/gl.py | 111 + .../docutils/parsers/rst/languages/he.py | 108 + .../docutils/parsers/rst/languages/it.py | 97 + .../docutils/parsers/rst/languages/ja.py | 119 + .../docutils/parsers/rst/languages/ko.py | 111 + .../docutils/parsers/rst/languages/lt.py | 109 + .../docutils/parsers/rst/languages/lv.py | 108 + .../docutils/parsers/rst/languages/nl.py | 112 + .../docutils/parsers/rst/languages/pl.py | 102 + .../docutils/parsers/rst/languages/pt_br.py | 108 + .../docutils/parsers/rst/languages/ru.py | 89 + .../docutils/parsers/rst/languages/sk.py | 95 + .../docutils/parsers/rst/languages/sv.py | 95 + .../docutils/parsers/rst/languages/zh_cn.py | 104 + .../docutils/parsers/rst/languages/zh_tw.py | 109 + .../docutils/parsers/rst/roles.py | 399 + .../docutils/parsers/rst/states.py | 3116 ++++++ .../docutils/parsers/rst/tableparser.py | 542 ++ .../docutils/readers/__init__.py | 112 + .../site-packages/docutils/readers/doctree.py | 46 + .../site-packages/docutils/readers/pep.py | 48 + .../docutils/readers/standalone.py | 66 + .../site-packages/docutils/statemachine.py | 1539 +++ .../docutils/transforms/__init__.py | 172 + .../docutils/transforms/components.py | 52 + .../docutils/transforms/frontmatter.py | 548 ++ .../site-packages/docutils/transforms/misc.py | 144 + .../docutils/transforms/parts.py | 180 + .../site-packages/docutils/transforms/peps.py | 305 + .../docutils/transforms/references.py | 911 ++ .../docutils/transforms/universal.py | 320 + .../docutils/transforms/writer_aux.py | 88 + .../site-packages/docutils/utils/__init__.py | 797 ++ .../docutils/utils/code_analyzer.py | 142 + .../docutils/utils/error_reporting.py | 229 + .../docutils/utils/math/__init__.py | 48 + .../docutils/utils/math/latex2mathml.py | 568 ++ .../docutils/utils/math/math2html.py | 5383 +++++++++++ .../docutils/utils/math/tex2mathml_extern.py | 148 + .../docutils/utils/math/tex2unichar.py | 662 ++ .../docutils/utils/math/unichar2tex.py | 788 ++ .../docutils/utils/punctuation_chars.py | 122 + .../site-packages/docutils/utils/roman.py | 82 + .../docutils/utils/smartquotes.py | 1014 ++ .../docutils/utils/urischemes.py | 136 + .../docutils/writers/__init__.py | 143 + .../docutils/writers/_html_base.py | 1670 ++++ .../docutils/writers/docutils_xml.py | 199 + .../docutils/writers/html4css1/__init__.py | 824 ++ .../docutils/writers/html4css1/html4css1.css | 349 + .../docutils/writers/html4css1/template.txt | 8 + .../writers/html5_polyglot/__init__.py | 219 + .../docutils/writers/html5_polyglot/math.css | 276 + .../writers/html5_polyglot/minimal.css | 284 + .../docutils/writers/html5_polyglot/plain.css | 298 + .../writers/html5_polyglot/template.txt | 8 + .../docutils/writers/latex2e/__init__.py | 3216 +++++++ .../docutils/writers/latex2e/default.tex | 14 + .../docutils/writers/latex2e/titlepage.tex | 20 + .../docutils/writers/latex2e/xelatex.tex | 21 + .../site-packages/docutils/writers/manpage.py | 1178 +++ .../site-packages/docutils/writers/null.py | 21 + .../docutils/writers/odf_odt/__init__.py | 3534 +++++++ .../writers/odf_odt/pygmentsformatter.py | 109 + .../docutils/writers/odf_odt/styles.odt | Bin 0 -> 16500 bytes .../docutils/writers/pep_html/__init__.py | 105 + .../docutils/writers/pep_html/pep.css | 344 + .../docutils/writers/pep_html/template.txt | 29 + .../docutils/writers/pseudoxml.py | 31 + .../docutils/writers/s5_html/__init__.py | 353 + .../writers/s5_html/themes/README.txt | 6 + .../writers/s5_html/themes/big-black/__base__ | 2 + .../s5_html/themes/big-black/framing.css | 25 + .../s5_html/themes/big-black/pretty.css | 109 + .../s5_html/themes/big-white/framing.css | 24 + .../s5_html/themes/big-white/pretty.css | 107 + .../writers/s5_html/themes/default/blank.gif | Bin 0 -> 49 bytes .../s5_html/themes/default/framing.css | 25 + .../s5_html/themes/default/iepngfix.htc | 42 + .../writers/s5_html/themes/default/opera.css | 8 + .../s5_html/themes/default/outline.css | 16 + .../writers/s5_html/themes/default/pretty.css | 120 + .../writers/s5_html/themes/default/print.css | 24 + .../s5_html/themes/default/s5-core.css | 11 + .../writers/s5_html/themes/default/slides.css | 10 + .../writers/s5_html/themes/default/slides.js | 558 ++ .../s5_html/themes/medium-black/__base__ | 2 + .../s5_html/themes/medium-black/pretty.css | 115 + .../s5_html/themes/medium-white/framing.css | 24 + .../s5_html/themes/medium-white/pretty.css | 113 + .../s5_html/themes/small-black/__base__ | 2 + .../s5_html/themes/small-black/pretty.css | 116 + .../s5_html/themes/small-white/framing.css | 24 + .../s5_html/themes/small-white/pretty.css | 114 + .../docutils/writers/xetex/__init__.py | 150 + .../python3.8/site-packages/easy-install.pth | 1 + .../python3.8/site-packages/easy_install.py | 5 + .../feedgenerator-1.9.1.dist-info/INSTALLER | 1 + .../feedgenerator-1.9.1.dist-info/LICENSE | 28 + .../feedgenerator-1.9.1.dist-info/METADATA | 49 + .../feedgenerator-1.9.1.dist-info/RECORD | 26 + .../feedgenerator-1.9.1.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/feedgenerator/__init__.py | 24 + .../feedgenerator/django/__init__.py | 0 .../feedgenerator/django/utils/__init__.py | 0 .../django/utils/datetime_safe.py | 89 + .../feedgenerator/django/utils/encoding.py | 256 + .../django/utils/feedgenerator.py | 404 + .../feedgenerator/django/utils/functional.py | 370 + .../feedgenerator/django/utils/six.py | 370 + .../feedgenerator/django/utils/timezone.py | 292 + .../feedgenerator/django/utils/xmlutils.py | 23 + .../site-packages/jinja2/__init__.py | 44 + .../python3.8/site-packages/jinja2/_compat.py | 132 + .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/asyncfilters.py | 158 + .../site-packages/jinja2/asyncsupport.py | 264 + .../python3.8/site-packages/jinja2/bccache.py | 350 + .../site-packages/jinja2/compiler.py | 1843 ++++ .../site-packages/jinja2/constants.py | 21 + .../python3.8/site-packages/jinja2/debug.py | 268 + .../site-packages/jinja2/defaults.py | 44 + .../site-packages/jinja2/environment.py | 1362 +++ .../site-packages/jinja2/exceptions.py | 177 + env/lib/python3.8/site-packages/jinja2/ext.py | 704 ++ .../python3.8/site-packages/jinja2/filters.py | 1382 +++ .../site-packages/jinja2/idtracking.py | 290 + .../python3.8/site-packages/jinja2/lexer.py | 848 ++ .../python3.8/site-packages/jinja2/loaders.py | 504 + .../python3.8/site-packages/jinja2/meta.py | 101 + .../site-packages/jinja2/nativetypes.py | 94 + .../python3.8/site-packages/jinja2/nodes.py | 1088 +++ .../site-packages/jinja2/optimizer.py | 41 + .../python3.8/site-packages/jinja2/parser.py | 939 ++ .../python3.8/site-packages/jinja2/runtime.py | 1011 ++ .../python3.8/site-packages/jinja2/sandbox.py | 510 + .../python3.8/site-packages/jinja2/tests.py | 215 + .../python3.8/site-packages/jinja2/utils.py | 732 ++ .../python3.8/site-packages/jinja2/visitor.py | 81 + .../site-packages/markdown/__init__.py | 61 + .../site-packages/markdown/__main__.py | 151 + .../site-packages/markdown/__meta__.py | 49 + .../site-packages/markdown/blockparser.py | 125 + .../site-packages/markdown/blockprocessors.py | 621 ++ .../python3.8/site-packages/markdown/core.py | 407 + .../markdown/extensions/__init__.py | 107 + .../site-packages/markdown/extensions/abbr.py | 99 + .../markdown/extensions/admonition.py | 164 + .../markdown/extensions/attr_list.py | 166 + .../markdown/extensions/codehilite.py | 307 + .../markdown/extensions/def_list.py | 111 + .../markdown/extensions/extra.py | 58 + .../markdown/extensions/fenced_code.py | 179 + .../markdown/extensions/footnotes.py | 402 + .../markdown/extensions/legacy_attrs.py | 67 + .../markdown/extensions/legacy_em.py | 49 + .../markdown/extensions/md_in_html.py | 345 + .../site-packages/markdown/extensions/meta.py | 79 + .../markdown/extensions/nl2br.py | 33 + .../markdown/extensions/sane_lists.py | 54 + .../markdown/extensions/smarty.py | 263 + .../markdown/extensions/tables.py | 223 + .../site-packages/markdown/extensions/toc.py | 373 + .../markdown/extensions/wikilinks.py | 87 + .../site-packages/markdown/htmlparser.py | 285 + .../site-packages/markdown/inlinepatterns.py | 892 ++ .../site-packages/markdown/pep562.py | 245 + .../site-packages/markdown/postprocessors.py | 120 + .../site-packages/markdown/preprocessors.py | 82 + .../site-packages/markdown/serializers.py | 189 + .../site-packages/markdown/test_tools.py | 210 + .../site-packages/markdown/treeprocessors.py | 435 + .../python3.8/site-packages/markdown/util.py | 482 + .../site-packages/markupsafe/__init__.py | 327 + .../site-packages/markupsafe/_compat.py | 33 + .../site-packages/markupsafe/_constants.py | 264 + .../site-packages/markupsafe/_native.py | 69 + .../site-packages/markupsafe/_speedups.c | 423 + .../_speedups.cpython-38-x86_64-linux-gnu.so | Bin 0 -> 48016 bytes .../pelican-3.7.1.dist-info/DESCRIPTION.rst | 400 + .../pelican-3.7.1.dist-info/INSTALLER | 1 + .../pelican-3.7.1.dist-info/METADATA | 431 + .../pelican-3.7.1.dist-info/RECORD | 112 + .../pelican-3.7.1.dist-info/WHEEL | 6 + .../pelican-3.7.1.dist-info/entry_points.txt | 6 + .../pelican-3.7.1.dist-info/metadata.json | 1 + .../pelican-3.7.1.dist-info/top_level.txt | 1 + .../site-packages/pelican-alias.egg-link | 2 + .../site-packages/pelican/__init__.py | 495 + .../python3.8/site-packages/pelican/cache.py | 141 + .../site-packages/pelican/contents.py | 478 + .../site-packages/pelican/generators.py | 752 ++ .../python3.8/site-packages/pelican/log.py | 256 + .../site-packages/pelican/paginator.py | 157 + .../site-packages/pelican/readers.py | 679 ++ .../site-packages/pelican/rstdirectives.py | 93 + .../python3.8/site-packages/pelican/server.py | 74 + .../site-packages/pelican/settings.py | 432 + .../site-packages/pelican/signals.py | 50 + .../themes/notmyidea/static/css/main.css | 452 + .../themes/notmyidea/static/css/pygment.css | 205 + .../themes/notmyidea/static/css/reset.css | 52 + .../themes/notmyidea/static/css/typogrify.css | 3 + .../themes/notmyidea/static/css/wide.css | 48 + .../notmyidea/static/images/icons/aboutme.png | Bin 0 -> 751 bytes .../static/images/icons/bitbucket.png | Bin 0 -> 3714 bytes .../static/images/icons/delicious.png | Bin 0 -> 958 bytes .../static/images/icons/facebook.png | Bin 0 -> 202 bytes .../notmyidea/static/images/icons/github.png | Bin 0 -> 1714 bytes .../static/images/icons/gitorious.png | Bin 0 -> 227 bytes .../notmyidea/static/images/icons/gittip.png | Bin 0 -> 487 bytes .../static/images/icons/google-groups.png | Bin 0 -> 803 bytes .../static/images/icons/google-plus.png | Bin 0 -> 527 bytes .../static/images/icons/hackernews.png | Bin 0 -> 3273 bytes .../notmyidea/static/images/icons/lastfm.png | Bin 0 -> 975 bytes .../static/images/icons/linkedin.png | Bin 0 -> 896 bytes .../notmyidea/static/images/icons/reddit.png | Bin 0 -> 693 bytes .../notmyidea/static/images/icons/rss.png | Bin 0 -> 879 bytes .../static/images/icons/slideshare.png | Bin 0 -> 535 bytes .../static/images/icons/speakerdeck.png | Bin 0 -> 1049 bytes .../static/images/icons/stackoverflow.png | Bin 0 -> 916 bytes .../notmyidea/static/images/icons/twitter.png | Bin 0 -> 1509 bytes .../notmyidea/static/images/icons/vimeo.png | Bin 0 -> 544 bytes .../notmyidea/static/images/icons/youtube.png | Bin 0 -> 458 bytes .../themes/notmyidea/templates/analytics.html | 45 + .../themes/notmyidea/templates/archives.html | 13 + .../themes/notmyidea/templates/article.html | 37 + .../notmyidea/templates/article_infos.html | 23 + .../themes/notmyidea/templates/author.html | 2 + .../themes/notmyidea/templates/authors.html | 16 + .../themes/notmyidea/templates/base.html | 82 + .../themes/notmyidea/templates/category.html | 2 + .../themes/notmyidea/templates/comments.html | 1 + .../notmyidea/templates/disqus_script.html | 11 + .../themes/notmyidea/templates/github.html | 9 + .../themes/notmyidea/templates/index.html | 59 + .../themes/notmyidea/templates/page.html | 10 + .../notmyidea/templates/period_archives.html | 13 + .../themes/notmyidea/templates/tag.html | 2 + .../themes/notmyidea/templates/taglist.html | 1 + .../themes/notmyidea/templates/tags.html | 16 + .../notmyidea/templates/translations.html | 8 + .../themes/notmyidea/templates/twitter.html | 3 + .../themes/simple/templates/archives.html | 11 + .../themes/simple/templates/article.html | 44 + .../themes/simple/templates/author.html | 7 + .../themes/simple/templates/authors.html | 13 + .../pelican/themes/simple/templates/base.html | 63 + .../themes/simple/templates/categories.html | 8 + .../themes/simple/templates/category.html | 5 + .../themes/simple/templates/gosquared.html | 14 + .../themes/simple/templates/index.html | 28 + .../pelican/themes/simple/templates/page.html | 15 + .../themes/simple/templates/pagination.html | 11 + .../simple/templates/period_archives.html | 11 + .../pelican/themes/simple/templates/tag.html | 0 .../pelican/themes/simple/templates/tags.html | 10 + .../themes/simple/templates/translations.html | 9 + .../site-packages/pelican/tools/__init__.py | 0 .../pelican/tools/pelican_import.py | 896 ++ .../pelican/tools/pelican_quickstart.py | 416 + .../pelican/tools/pelican_themes.py | 260 + .../pelican/tools/templates/Makefile.in | 123 + .../tools/templates/develop_server.sh.in | 102 + .../pelican/tools/templates/fabfile.py.in | 92 + .../pelican/tools/templates/pelicanconf.py.in | 35 + .../pelican/tools/templates/publishconf.py.in | 24 + .../site-packages/pelican/urlwrappers.py | 144 + .../python3.8/site-packages/pelican/utils.py | 840 ++ .../site-packages/pelican/writers.py | 230 + .../DESCRIPTION.rst | 101 + .../pelican_vimeo-0.1.2.dist-info/INSTALLER | 1 + .../pelican_vimeo-0.1.2.dist-info/METADATA | 133 + .../pelican_vimeo-0.1.2.dist-info/RECORD | 12 + .../pelican_vimeo-0.1.2.dist-info/WHEEL | 6 + .../metadata.json | 1 + .../top_level.txt | 1 + .../pelican_vimeo-0.1.2.dist-info/zip-safe | 1 + .../site-packages/pelican_vimeo/__init__.py | 31 + .../site-packages/pelican_vimeo/vimeo.py | 151 + .../DESCRIPTION.rst | 133 + .../pelican_youtube-0.2.1.dist-info/INSTALLER | 1 + .../pelican_youtube-0.2.1.dist-info/METADATA | 165 + .../pelican_youtube-0.2.1.dist-info/RECORD | 12 + .../pelican_youtube-0.2.1.dist-info/WHEEL | 6 + .../metadata.json | 1 + .../top_level.txt | 1 + .../pelican_youtube-0.2.1.dist-info/zip-safe | 1 + .../site-packages/pelican_youtube/__init__.py | 31 + .../site-packages/pelican_youtube/youtube.py | 103 + .../pip-20.1.dist-info/INSTALLER | 1 + .../pip-20.1.dist-info/LICENSE.txt | 20 + .../site-packages/pip-20.1.dist-info/METADATA | 87 + .../site-packages/pip-20.1.dist-info/RECORD | 795 ++ .../site-packages/pip-20.1.dist-info/WHEEL | 6 + .../pip-20.1.dist-info/entry_points.txt | 5 + .../pip-20.1.dist-info/top_level.txt | 1 + .../site-packages/pip-20.1.virtualenv | 0 .../python3.8/site-packages/pip/__init__.py | 18 + .../python3.8/site-packages/pip/__main__.py | 26 + .../site-packages/pip/_internal/__init__.py | 17 + .../site-packages/pip/_internal/build_env.py | 219 + .../site-packages/pip/_internal/cache.py | 349 + .../pip/_internal/cli/__init__.py | 4 + .../pip/_internal/cli/autocompletion.py | 164 + .../pip/_internal/cli/base_command.py | 228 + .../pip/_internal/cli/cmdoptions.py | 962 ++ .../pip/_internal/cli/command_context.py | 36 + .../site-packages/pip/_internal/cli/main.py | 75 + .../pip/_internal/cli/main_parser.py | 99 + .../site-packages/pip/_internal/cli/parser.py | 266 + .../pip/_internal/cli/progress_bars.py | 277 + .../pip/_internal/cli/req_command.py | 408 + .../pip/_internal/cli/spinners.py | 173 + .../pip/_internal/cli/status_codes.py | 8 + .../pip/_internal/commands/__init__.py | 122 + .../pip/_internal/commands/cache.py | 181 + .../pip/_internal/commands/check.py | 51 + .../pip/_internal/commands/completion.py | 95 + .../pip/_internal/commands/configuration.py | 233 + .../pip/_internal/commands/debug.py | 237 + .../pip/_internal/commands/download.py | 142 + .../pip/_internal/commands/freeze.py | 99 + .../pip/_internal/commands/hash.py | 58 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/install.py | 691 ++ .../pip/_internal/commands/list.py | 309 + .../pip/_internal/commands/search.py | 146 + .../pip/_internal/commands/show.py | 180 + .../pip/_internal/commands/uninstall.py | 89 + .../pip/_internal/commands/wheel.py | 190 + .../pip/_internal/configuration.py | 426 + .../pip/_internal/distributions/__init__.py | 24 + .../pip/_internal/distributions/base.py | 45 + .../pip/_internal/distributions/installed.py | 24 + .../pip/_internal/distributions/sdist.py | 104 + .../pip/_internal/distributions/wheel.py | 36 + .../site-packages/pip/_internal/exceptions.py | 308 + .../pip/_internal/index/__init__.py | 2 + .../pip/_internal/index/collector.py | 661 ++ .../pip/_internal/index/package_finder.py | 1016 ++ .../site-packages/pip/_internal/locations.py | 194 + .../site-packages/pip/_internal/main.py | 16 + .../pip/_internal/models/__init__.py | 2 + .../pip/_internal/models/candidate.py | 36 + .../pip/_internal/models/direct_url.py | 245 + .../pip/_internal/models/format_control.py | 84 + .../pip/_internal/models/index.py | 31 + .../pip/_internal/models/link.py | 236 + .../pip/_internal/models/scheme.py | 25 + .../pip/_internal/models/search_scope.py | 133 + .../pip/_internal/models/selection_prefs.py | 47 + .../pip/_internal/models/target_python.py | 110 + .../pip/_internal/models/wheel.py | 78 + .../pip/_internal/network/__init__.py | 2 + .../pip/_internal/network/auth.py | 298 + .../pip/_internal/network/cache.py | 81 + .../pip/_internal/network/download.py | 200 + .../pip/_internal/network/session.py | 421 + .../pip/_internal/network/utils.py | 48 + .../pip/_internal/network/xmlrpc.py | 44 + .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../_internal/operations/build/metadata.py | 40 + .../operations/build/metadata_legacy.py | 77 + .../pip/_internal/operations/build/wheel.py | 46 + .../operations/build/wheel_legacy.py | 115 + .../pip/_internal/operations/check.py | 163 + .../pip/_internal/operations/freeze.py | 272 + .../_internal/operations/install/__init__.py | 2 + .../operations/install/editable_legacy.py | 52 + .../_internal/operations/install/legacy.py | 142 + .../pip/_internal/operations/install/wheel.py | 631 ++ .../pip/_internal/operations/prepare.py | 511 + .../site-packages/pip/_internal/pyproject.py | 196 + .../pip/_internal/req/__init__.py | 92 + .../pip/_internal/req/constructors.py | 464 + .../pip/_internal/req/req_file.py | 582 ++ .../pip/_internal/req/req_install.py | 850 ++ .../pip/_internal/req/req_set.py | 202 + .../pip/_internal/req/req_tracker.py | 151 + .../pip/_internal/req/req_uninstall.py | 649 ++ .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 459 + .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 52 + .../resolution/resolvelib/candidates.py | 450 + .../resolution/resolvelib/factory.py | 201 + .../resolution/resolvelib/provider.py | 54 + .../resolution/resolvelib/requirements.py | 119 + .../resolution/resolvelib/resolver.py | 174 + .../pip/_internal/self_outdated_check.py | 242 + .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/appdirs.py | 44 + .../pip/_internal/utils/compat.py | 270 + .../pip/_internal/utils/compatibility_tags.py | 169 + .../pip/_internal/utils/deprecation.py | 104 + .../pip/_internal/utils/direct_url_helpers.py | 130 + .../pip/_internal/utils/distutils_args.py | 48 + .../pip/_internal/utils/encoding.py | 42 + .../pip/_internal/utils/entrypoints.py | 31 + .../pip/_internal/utils/filesystem.py | 190 + .../pip/_internal/utils/filetypes.py | 16 + .../pip/_internal/utils/glibc.py | 98 + .../pip/_internal/utils/hashes.py | 133 + .../_internal/utils/inject_securetransport.py | 36 + .../pip/_internal/utils/logging.py | 399 + .../site-packages/pip/_internal/utils/misc.py | 913 ++ .../pip/_internal/utils/models.py | 42 + .../pip/_internal/utils/packaging.py | 94 + .../pip/_internal/utils/pkg_resources.py | 44 + .../pip/_internal/utils/setuptools_build.py | 181 + .../pip/_internal/utils/subprocess.py | 277 + .../pip/_internal/utils/temp_dir.py | 271 + .../pip/_internal/utils/typing.py | 38 + .../pip/_internal/utils/unpacking.py | 272 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 116 + .../pip/_internal/utils/wheel.py | 225 + .../pip/_internal/vcs/__init__.py | 15 + .../site-packages/pip/_internal/vcs/bazaar.py | 120 + .../site-packages/pip/_internal/vcs/git.py | 394 + .../pip/_internal/vcs/mercurial.py | 161 + .../pip/_internal/vcs/subversion.py | 334 + .../pip/_internal/vcs/versioncontrol.py | 723 ++ .../pip/_internal/wheel_builder.py | 309 + .../site-packages/pip/_vendor/__init__.py | 114 + .../site-packages/pip/_vendor/appdirs.py | 633 ++ .../pip/_vendor/cachecontrol/__init__.py | 11 + .../pip/_vendor/cachecontrol/_cmd.py | 57 + .../pip/_vendor/cachecontrol/adapter.py | 133 + .../pip/_vendor/cachecontrol/cache.py | 39 + .../_vendor/cachecontrol/caches/__init__.py | 2 + .../_vendor/cachecontrol/caches/file_cache.py | 146 + .../cachecontrol/caches/redis_cache.py | 33 + .../pip/_vendor/cachecontrol/compat.py | 29 + .../pip/_vendor/cachecontrol/controller.py | 376 + .../pip/_vendor/cachecontrol/filewrapper.py | 80 + .../pip/_vendor/cachecontrol/heuristics.py | 135 + .../pip/_vendor/cachecontrol/serialize.py | 188 + .../pip/_vendor/cachecontrol/wrapper.py | 29 + .../pip/_vendor/certifi/__init__.py | 3 + .../pip/_vendor/certifi/__main__.py | 12 + .../pip/_vendor/certifi/cacert.pem | 4641 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 30 + .../pip/_vendor/chardet/__init__.py | 39 + .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 233 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 145 + .../pip/_vendor/chardet/cli/__init__.py | 1 + .../pip/_vendor/chardet/cli/chardetect.py | 85 + .../pip/_vendor/chardet/codingstatemachine.py | 88 + .../pip/_vendor/chardet/compat.py | 34 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 76 + .../pip/_vendor/chardet/escprober.py | 101 + .../pip/_vendor/chardet/escsm.py | 246 + .../pip/_vendor/chardet/eucjpprober.py | 92 + .../pip/_vendor/chardet/euckrfreq.py | 195 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 387 + .../pip/_vendor/chardet/euctwprober.py | 46 + .../pip/_vendor/chardet/gb2312freq.py | 283 + .../pip/_vendor/chardet/gb2312prober.py | 46 + .../pip/_vendor/chardet/hebrewprober.py | 292 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/jpcntx.py | 233 + .../pip/_vendor/chardet/langbulgarianmodel.py | 228 + .../pip/_vendor/chardet/langcyrillicmodel.py | 333 + .../pip/_vendor/chardet/langgreekmodel.py | 225 + .../pip/_vendor/chardet/langhebrewmodel.py | 200 + .../pip/_vendor/chardet/langhungarianmodel.py | 225 + .../pip/_vendor/chardet/langthaimodel.py | 199 + .../pip/_vendor/chardet/langturkishmodel.py | 193 + .../pip/_vendor/chardet/latin1prober.py | 145 + .../pip/_vendor/chardet/mbcharsetprober.py | 91 + .../pip/_vendor/chardet/mbcsgroupprober.py | 54 + .../pip/_vendor/chardet/mbcssm.py | 572 ++ .../pip/_vendor/chardet/sbcharsetprober.py | 132 + .../pip/_vendor/chardet/sbcsgroupprober.py | 73 + .../pip/_vendor/chardet/sjisprober.py | 92 + .../pip/_vendor/chardet/universaldetector.py | 286 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 6 + .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 257 + .../pip/_vendor/colorama/initialise.py | 80 + .../pip/_vendor/colorama/win32.py | 152 + .../pip/_vendor/colorama/winterm.py | 169 + .../site-packages/pip/_vendor/contextlib2.py | 518 + .../pip/_vendor/distlib/__init__.py | 23 + .../pip/_vendor/distlib/_backport/__init__.py | 6 + .../pip/_vendor/distlib/_backport/misc.py | 41 + .../pip/_vendor/distlib/_backport/shutil.py | 761 ++ .../_vendor/distlib/_backport/sysconfig.cfg | 84 + .../_vendor/distlib/_backport/sysconfig.py | 786 ++ .../pip/_vendor/distlib/_backport/tarfile.py | 2607 ++++++ .../pip/_vendor/distlib/compat.py | 1120 +++ .../pip/_vendor/distlib/database.py | 1339 +++ .../pip/_vendor/distlib/index.py | 516 + .../pip/_vendor/distlib/locators.py | 1302 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 131 + .../pip/_vendor/distlib/metadata.py | 1096 +++ .../pip/_vendor/distlib/resources.py | 355 + .../pip/_vendor/distlib/scripts.py | 416 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 96768 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 105984 bytes .../site-packages/pip/_vendor/distlib/util.py | 1761 ++++ .../pip/_vendor/distlib/version.py | 736 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 90112 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 99840 bytes .../pip/_vendor/distlib/wheel.py | 1004 ++ .../site-packages/pip/_vendor/distro.py | 1230 +++ .../pip/_vendor/html5lib/__init__.py | 35 + .../pip/_vendor/html5lib/_ihatexml.py | 288 + .../pip/_vendor/html5lib/_inputstream.py | 923 ++ .../pip/_vendor/html5lib/_tokenizer.py | 1721 ++++ .../pip/_vendor/html5lib/_trie/__init__.py | 14 + .../pip/_vendor/html5lib/_trie/_base.py | 40 + .../pip/_vendor/html5lib/_trie/datrie.py | 44 + .../pip/_vendor/html5lib/_trie/py.py | 67 + .../pip/_vendor/html5lib/_utils.py | 124 + .../pip/_vendor/html5lib/constants.py | 2947 ++++++ .../pip/_vendor/html5lib/filters/__init__.py | 0 .../filters/alphabeticalattributes.py | 29 + .../pip/_vendor/html5lib/filters/base.py | 12 + .../html5lib/filters/inject_meta_charset.py | 73 + .../pip/_vendor/html5lib/filters/lint.py | 93 + .../_vendor/html5lib/filters/optionaltags.py | 207 + .../pip/_vendor/html5lib/filters/sanitizer.py | 896 ++ .../_vendor/html5lib/filters/whitespace.py | 38 + .../pip/_vendor/html5lib/html5parser.py | 2791 ++++++ .../pip/_vendor/html5lib/serializer.py | 409 + .../_vendor/html5lib/treeadapters/__init__.py | 30 + .../_vendor/html5lib/treeadapters/genshi.py | 54 + .../pip/_vendor/html5lib/treeadapters/sax.py | 50 + .../_vendor/html5lib/treebuilders/__init__.py | 88 + .../pip/_vendor/html5lib/treebuilders/base.py | 417 + .../pip/_vendor/html5lib/treebuilders/dom.py | 239 + .../_vendor/html5lib/treebuilders/etree.py | 340 + .../html5lib/treebuilders/etree_lxml.py | 366 + .../_vendor/html5lib/treewalkers/__init__.py | 154 + .../pip/_vendor/html5lib/treewalkers/base.py | 252 + .../pip/_vendor/html5lib/treewalkers/dom.py | 43 + .../pip/_vendor/html5lib/treewalkers/etree.py | 130 + .../html5lib/treewalkers/etree_lxml.py | 213 + .../_vendor/html5lib/treewalkers/genshi.py | 69 + .../pip/_vendor/idna/__init__.py | 2 + .../site-packages/pip/_vendor/idna/codec.py | 118 + .../site-packages/pip/_vendor/idna/compat.py | 12 + .../site-packages/pip/_vendor/idna/core.py | 398 + .../pip/_vendor/idna/idnadata.py | 1991 ++++ .../pip/_vendor/idna/intranges.py | 53 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8317 +++++++++++++++++ .../site-packages/pip/_vendor/ipaddress.py | 2420 +++++ .../pip/_vendor/msgpack/__init__.py | 54 + .../pip/_vendor/msgpack/_version.py | 1 + .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 191 + .../pip/_vendor/msgpack/fallback.py | 1063 +++ .../pip/_vendor/packaging/__about__.py | 27 + .../pip/_vendor/packaging/__init__.py | 26 + .../pip/_vendor/packaging/_compat.py | 38 + .../pip/_vendor/packaging/_structures.py | 86 + .../pip/_vendor/packaging/_typing.py | 39 + .../pip/_vendor/packaging/markers.py | 328 + .../pip/_vendor/packaging/requirements.py | 145 + .../pip/_vendor/packaging/specifiers.py | 849 ++ .../pip/_vendor/packaging/tags.py | 739 ++ .../pip/_vendor/packaging/utils.py | 62 + .../pip/_vendor/packaging/version.py | 535 ++ .../pip/_vendor/pep517/__init__.py | 4 + .../pip/_vendor/pep517/_in_process.py | 280 + .../site-packages/pip/_vendor/pep517/build.py | 124 + .../site-packages/pip/_vendor/pep517/check.py | 203 + .../pip/_vendor/pep517/colorlog.py | 115 + .../pip/_vendor/pep517/compat.py | 34 + .../pip/_vendor/pep517/dirtools.py | 44 + .../pip/_vendor/pep517/envbuild.py | 167 + .../site-packages/pip/_vendor/pep517/meta.py | 92 + .../pip/_vendor/pep517/wrappers.py | 308 + .../pip/_vendor/pkg_resources/__init__.py | 3296 +++++++ .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/progress/__init__.py | 177 + .../site-packages/pip/_vendor/progress/bar.py | 91 + .../pip/_vendor/progress/counter.py | 41 + .../pip/_vendor/progress/spinner.py | 43 + .../site-packages/pip/_vendor/pyparsing.py | 7107 ++++++++++++++ .../pip/_vendor/requests/__init__.py | 133 + .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 42 + .../pip/_vendor/requests/adapters.py | 533 ++ .../site-packages/pip/_vendor/requests/api.py | 161 + .../pip/_vendor/requests/auth.py | 305 + .../pip/_vendor/requests/certs.py | 18 + .../pip/_vendor/requests/compat.py | 76 + .../pip/_vendor/requests/cookies.py | 549 ++ .../pip/_vendor/requests/exceptions.py | 126 + .../pip/_vendor/requests/help.py | 119 + .../pip/_vendor/requests/hooks.py | 34 + .../pip/_vendor/requests/models.py | 954 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 767 ++ .../pip/_vendor/requests/status_codes.py | 123 + .../pip/_vendor/requests/structures.py | 105 + .../pip/_vendor/requests/utils.py | 982 ++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../pip/_vendor/resolvelib/providers.py | 121 + .../pip/_vendor/resolvelib/reporters.py | 36 + .../pip/_vendor/resolvelib/resolvers.py | 414 + .../pip/_vendor/resolvelib/structs.py | 68 + .../site-packages/pip/_vendor/retrying.py | 267 + .../site-packages/pip/_vendor/six.py | 980 ++ .../site-packages/pip/_vendor/toml.py | 1039 ++ .../pip/_vendor/toml/__init__.py | 21 + .../site-packages/pip/_vendor/toml/decoder.py | 945 ++ .../site-packages/pip/_vendor/toml/encoder.py | 250 + .../site-packages/pip/_vendor/toml/ordered.py | 15 + .../site-packages/pip/_vendor/toml/tz.py | 21 + .../pip/_vendor/urllib3/__init__.py | 86 + .../pip/_vendor/urllib3/_collections.py | 336 + .../pip/_vendor/urllib3/connection.py | 414 + .../pip/_vendor/urllib3/connectionpool.py | 1051 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 493 + .../contrib/_securetransport/low_level.py | 328 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 121 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 498 + .../urllib3/contrib/securetransport.py | 859 ++ .../pip/_vendor/urllib3/contrib/socks.py | 210 + .../pip/_vendor/urllib3/exceptions.py | 255 + .../pip/_vendor/urllib3/fields.py | 273 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 52 + .../pip/_vendor/urllib3/packages/six.py | 1021 ++ .../packages/ssl_match_hostname/__init__.py | 19 + .../ssl_match_hostname/_implementation.py | 160 + .../pip/_vendor/urllib3/poolmanager.py | 470 + .../pip/_vendor/urllib3/request.py | 171 + .../pip/_vendor/urllib3/response.py | 809 ++ .../pip/_vendor/urllib3/util/__init__.py | 46 + .../pip/_vendor/urllib3/util/connection.py | 138 + .../pip/_vendor/urllib3/util/queue.py | 21 + .../pip/_vendor/urllib3/util/request.py | 135 + .../pip/_vendor/urllib3/util/response.py | 86 + .../pip/_vendor/urllib3/util/retry.py | 450 + .../pip/_vendor/urllib3/util/ssl_.py | 407 + .../pip/_vendor/urllib3/util/timeout.py | 258 + .../pip/_vendor/urllib3/util/url.py | 430 + .../pip/_vendor/urllib3/util/wait.py | 153 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../site-packages/pkg_resources/__init__.py | 3304 +++++++ .../pkg_resources/_vendor/__init__.py | 0 .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/packaging/__about__.py | 21 + .../_vendor/packaging/__init__.py | 14 + .../_vendor/packaging/_compat.py | 30 + .../_vendor/packaging/_structures.py | 68 + .../_vendor/packaging/markers.py | 301 + .../_vendor/packaging/requirements.py | 127 + .../_vendor/packaging/specifiers.py | 774 ++ .../pkg_resources/_vendor/packaging/utils.py | 14 + .../_vendor/packaging/version.py | 393 + .../pkg_resources/_vendor/pyparsing.py | 5742 ++++++++++++ .../pkg_resources/_vendor/six.py | 868 ++ .../pkg_resources/extern/__init__.py | 66 + .../site-packages/pkg_resources/py2_warn.py | 21 + .../site-packages/pkg_resources/py31compat.py | 23 + .../site-packages/pygments/__init__.py | 85 + .../site-packages/pygments/__main__.py | 18 + .../site-packages/pygments/cmdline.py | 582 ++ .../site-packages/pygments/console.py | 71 + .../site-packages/pygments/filter.py | 72 + .../pygments/filters/__init__.py | 938 ++ .../site-packages/pygments/formatter.py | 95 + .../pygments/formatters/__init__.py | 154 + .../pygments/formatters/_mapping.py | 83 + .../pygments/formatters/bbcode.py | 109 + .../site-packages/pygments/formatters/html.py | 931 ++ .../site-packages/pygments/formatters/img.py | 615 ++ .../site-packages/pygments/formatters/irc.py | 182 + .../pygments/formatters/latex.py | 512 + .../pygments/formatters/other.py | 164 + .../site-packages/pygments/formatters/rtf.py | 147 + .../site-packages/pygments/formatters/svg.py | 187 + .../pygments/formatters/terminal.py | 130 + .../pygments/formatters/terminal256.py | 319 + .../python3.8/site-packages/pygments/lexer.py | 873 ++ .../site-packages/pygments/lexers/__init__.py | 342 + .../pygments/lexers/_asy_builtins.py | 1645 ++++ .../pygments/lexers/_cl_builtins.py | 232 + .../pygments/lexers/_cocoa_builtins.py | 71 + .../pygments/lexers/_csound_builtins.py | 1725 ++++ .../pygments/lexers/_lasso_builtins.py | 5327 +++++++++++ .../pygments/lexers/_lua_builtins.py | 293 + .../site-packages/pygments/lexers/_mapping.py | 551 ++ .../pygments/lexers/_mql_builtins.py | 1172 +++ .../pygments/lexers/_mysql_builtins.py | 1282 +++ .../pygments/lexers/_openedge_builtins.py | 2547 +++++ .../pygments/lexers/_php_builtins.py | 4753 ++++++++++ .../pygments/lexers/_postgres_builtins.py | 678 ++ .../pygments/lexers/_scilab_builtins.py | 3094 ++++++ .../pygments/lexers/_sourcemod_builtins.py | 1161 +++ .../pygments/lexers/_stan_builtins.py | 558 ++ .../pygments/lexers/_stata_builtins.py | 421 + .../pygments/lexers/_tsql_builtins.py | 1004 ++ .../pygments/lexers/_usd_builtins.py | 113 + .../pygments/lexers/_vbscript_builtins.py | 280 + .../pygments/lexers/_vim_builtins.py | 1939 ++++ .../pygments/lexers/actionscript.py | 245 + .../site-packages/pygments/lexers/agile.py | 24 + .../site-packages/pygments/lexers/algebra.py | 240 + .../site-packages/pygments/lexers/ambient.py | 76 + .../site-packages/pygments/lexers/ampl.py | 87 + .../site-packages/pygments/lexers/apl.py | 101 + .../pygments/lexers/archetype.py | 318 + .../site-packages/pygments/lexers/arrow.py | 117 + .../site-packages/pygments/lexers/asm.py | 1005 ++ .../pygments/lexers/automation.py | 374 + .../site-packages/pygments/lexers/bare.py | 104 + .../site-packages/pygments/lexers/basic.py | 662 ++ .../site-packages/pygments/lexers/bibtex.py | 160 + .../site-packages/pygments/lexers/boa.py | 102 + .../site-packages/pygments/lexers/business.py | 627 ++ .../site-packages/pygments/lexers/c_cpp.py | 344 + .../site-packages/pygments/lexers/c_like.py | 566 ++ .../pygments/lexers/capnproto.py | 78 + .../site-packages/pygments/lexers/chapel.py | 112 + .../site-packages/pygments/lexers/clean.py | 179 + .../site-packages/pygments/lexers/compiled.py | 34 + .../site-packages/pygments/lexers/configs.py | 984 ++ .../site-packages/pygments/lexers/console.py | 114 + .../site-packages/pygments/lexers/crystal.py | 392 + .../site-packages/pygments/lexers/csound.py | 467 + .../site-packages/pygments/lexers/css.py | 691 ++ .../site-packages/pygments/lexers/d.py | 256 + .../site-packages/pygments/lexers/dalvik.py | 125 + .../site-packages/pygments/lexers/data.py | 561 ++ .../pygments/lexers/devicetree.py | 109 + .../site-packages/pygments/lexers/diff.py | 165 + .../site-packages/pygments/lexers/dotnet.py | 707 ++ .../site-packages/pygments/lexers/dsls.py | 960 ++ .../site-packages/pygments/lexers/dylan.py | 287 + .../site-packages/pygments/lexers/ecl.py | 139 + .../site-packages/pygments/lexers/eiffel.py | 65 + .../site-packages/pygments/lexers/elm.py | 121 + .../site-packages/pygments/lexers/email.py | 151 + .../site-packages/pygments/lexers/erlang.py | 530 ++ .../site-packages/pygments/lexers/esoteric.py | 304 + .../site-packages/pygments/lexers/ezhil.py | 77 + .../site-packages/pygments/lexers/factor.py | 344 + .../site-packages/pygments/lexers/fantom.py | 250 + .../site-packages/pygments/lexers/felix.py | 273 + .../pygments/lexers/floscript.py | 83 + .../site-packages/pygments/lexers/forth.py | 178 + .../site-packages/pygments/lexers/fortran.py | 206 + .../site-packages/pygments/lexers/foxpro.py | 428 + .../site-packages/pygments/lexers/freefem.py | 898 ++ .../pygments/lexers/functional.py | 21 + .../site-packages/pygments/lexers/gdscript.py | 346 + .../site-packages/pygments/lexers/go.py | 101 + .../pygments/lexers/grammar_notation.py | 270 + .../site-packages/pygments/lexers/graph.py | 85 + .../site-packages/pygments/lexers/graphics.py | 800 ++ .../site-packages/pygments/lexers/haskell.py | 870 ++ .../site-packages/pygments/lexers/haxe.py | 936 ++ .../site-packages/pygments/lexers/hdl.py | 472 + .../site-packages/pygments/lexers/hexdump.py | 103 + .../site-packages/pygments/lexers/html.py | 602 ++ .../site-packages/pygments/lexers/idl.py | 281 + .../site-packages/pygments/lexers/igor.py | 420 + .../site-packages/pygments/lexers/inferno.py | 96 + .../pygments/lexers/installers.py | 322 + .../pygments/lexers/int_fiction.py | 1368 +++ .../site-packages/pygments/lexers/iolang.py | 63 + .../site-packages/pygments/lexers/j.py | 146 + .../pygments/lexers/javascript.py | 1540 +++ .../site-packages/pygments/lexers/julia.py | 331 + .../site-packages/pygments/lexers/jvm.py | 1665 ++++ .../site-packages/pygments/lexers/lisp.py | 2699 ++++++ .../site-packages/pygments/lexers/make.py | 206 + .../site-packages/pygments/lexers/markup.py | 765 ++ .../site-packages/pygments/lexers/math.py | 21 + .../site-packages/pygments/lexers/matlab.py | 720 ++ .../site-packages/pygments/lexers/mime.py | 226 + .../site-packages/pygments/lexers/ml.py | 958 ++ .../site-packages/pygments/lexers/modeling.py | 366 + .../site-packages/pygments/lexers/modula2.py | 1580 ++++ .../site-packages/pygments/lexers/monte.py | 204 + .../site-packages/pygments/lexers/mosel.py | 448 + .../site-packages/pygments/lexers/ncl.py | 894 ++ .../site-packages/pygments/lexers/nimrod.py | 159 + .../site-packages/pygments/lexers/nit.py | 64 + .../site-packages/pygments/lexers/nix.py | 136 + .../site-packages/pygments/lexers/oberon.py | 121 + .../pygments/lexers/objective.py | 504 + .../site-packages/pygments/lexers/ooc.py | 85 + .../site-packages/pygments/lexers/other.py | 41 + .../site-packages/pygments/lexers/parasail.py | 79 + .../site-packages/pygments/lexers/parsers.py | 800 ++ .../site-packages/pygments/lexers/pascal.py | 644 ++ .../site-packages/pygments/lexers/pawn.py | 205 + .../site-packages/pygments/lexers/perl.py | 732 ++ .../site-packages/pygments/lexers/php.py | 321 + .../pygments/lexers/pointless.py | 71 + .../site-packages/pygments/lexers/pony.py | 94 + .../site-packages/pygments/lexers/praat.py | 302 + .../site-packages/pygments/lexers/prolog.py | 306 + .../site-packages/pygments/lexers/promql.py | 183 + .../site-packages/pygments/lexers/python.py | 1151 +++ .../site-packages/pygments/lexers/qvt.py | 152 + .../site-packages/pygments/lexers/r.py | 191 + .../site-packages/pygments/lexers/rdf.py | 423 + .../site-packages/pygments/lexers/rebol.py | 431 + .../site-packages/pygments/lexers/resource.py | 85 + .../site-packages/pygments/lexers/ride.py | 139 + .../site-packages/pygments/lexers/rnc.py | 67 + .../site-packages/pygments/lexers/roboconf.py | 82 + .../pygments/lexers/robotframework.py | 552 ++ .../site-packages/pygments/lexers/ruby.py | 517 + .../site-packages/pygments/lexers/rust.py | 216 + .../site-packages/pygments/lexers/sas.py | 228 + .../site-packages/pygments/lexers/scdoc.py | 83 + .../pygments/lexers/scripting.py | 1284 +++ .../site-packages/pygments/lexers/sgf.py | 61 + .../site-packages/pygments/lexers/shell.py | 909 ++ .../site-packages/pygments/lexers/sieve.py | 69 + .../site-packages/pygments/lexers/slash.py | 185 + .../pygments/lexers/smalltalk.py | 195 + .../site-packages/pygments/lexers/smv.py | 79 + .../site-packages/pygments/lexers/snobol.py | 83 + .../site-packages/pygments/lexers/solidity.py | 92 + .../site-packages/pygments/lexers/special.py | 105 + .../site-packages/pygments/lexers/sql.py | 837 ++ .../site-packages/pygments/lexers/stata.py | 171 + .../pygments/lexers/supercollider.py | 95 + .../site-packages/pygments/lexers/tcl.py | 145 + .../pygments/lexers/templates.py | 2265 +++++ .../site-packages/pygments/lexers/teraterm.py | 335 + .../site-packages/pygments/lexers/testing.py | 207 + .../site-packages/pygments/lexers/text.py | 26 + .../site-packages/pygments/lexers/textedit.py | 169 + .../site-packages/pygments/lexers/textfmts.py | 430 + .../site-packages/pygments/lexers/theorem.py | 472 + .../site-packages/pygments/lexers/tnt.py | 263 + .../pygments/lexers/trafficscript.py | 54 + .../pygments/lexers/typoscript.py | 219 + .../site-packages/pygments/lexers/unicon.py | 412 + .../site-packages/pygments/lexers/urbi.py | 146 + .../site-packages/pygments/lexers/usd.py | 90 + .../site-packages/pygments/lexers/varnish.py | 190 + .../pygments/lexers/verification.py | 114 + .../site-packages/pygments/lexers/web.py | 24 + .../site-packages/pygments/lexers/webidl.py | 299 + .../site-packages/pygments/lexers/webmisc.py | 991 ++ .../site-packages/pygments/lexers/whiley.py | 116 + .../site-packages/pygments/lexers/x10.py | 69 + .../site-packages/pygments/lexers/xorg.py | 37 + .../site-packages/pygments/lexers/yang.py | 104 + .../site-packages/pygments/lexers/zig.py | 124 + .../site-packages/pygments/modeline.py | 44 + .../site-packages/pygments/plugin.py | 70 + .../site-packages/pygments/regexopt.py | 92 + .../site-packages/pygments/scanner.py | 105 + .../site-packages/pygments/sphinxext.py | 156 + .../python3.8/site-packages/pygments/style.py | 192 + .../site-packages/pygments/styles/__init__.py | 86 + .../site-packages/pygments/styles/abap.py | 29 + .../site-packages/pygments/styles/algol.py | 63 + .../site-packages/pygments/styles/algol_nu.py | 63 + .../site-packages/pygments/styles/arduino.py | 98 + .../site-packages/pygments/styles/autumn.py | 65 + .../site-packages/pygments/styles/borland.py | 51 + .../site-packages/pygments/styles/bw.py | 49 + .../site-packages/pygments/styles/colorful.py | 81 + .../site-packages/pygments/styles/default.py | 73 + .../site-packages/pygments/styles/emacs.py | 72 + .../site-packages/pygments/styles/friendly.py | 72 + .../site-packages/pygments/styles/fruity.py | 42 + .../site-packages/pygments/styles/igor.py | 29 + .../site-packages/pygments/styles/inkpot.py | 67 + .../site-packages/pygments/styles/lovelace.py | 97 + .../site-packages/pygments/styles/manni.py | 75 + .../site-packages/pygments/styles/monokai.py | 107 + .../site-packages/pygments/styles/murphy.py | 80 + .../site-packages/pygments/styles/native.py | 65 + .../pygments/styles/paraiso_dark.py | 125 + .../pygments/styles/paraiso_light.py | 125 + .../site-packages/pygments/styles/pastie.py | 75 + .../site-packages/pygments/styles/perldoc.py | 69 + .../pygments/styles/rainbow_dash.py | 89 + .../site-packages/pygments/styles/rrt.py | 33 + .../site-packages/pygments/styles/sas.py | 44 + .../pygments/styles/solarized.py | 134 + .../pygments/styles/stata_dark.py | 41 + .../pygments/styles/stata_light.py | 39 + .../site-packages/pygments/styles/tango.py | 141 + .../site-packages/pygments/styles/trac.py | 63 + .../site-packages/pygments/styles/vim.py | 63 + .../site-packages/pygments/styles/vs.py | 38 + .../site-packages/pygments/styles/xcode.py | 51 + .../python3.8/site-packages/pygments/token.py | 213 + .../site-packages/pygments/unistring.py | 156 + .../python3.8/site-packages/pygments/util.py | 311 + .../python_dateutil-2.8.1.dist-info/INSTALLER | 1 + .../python_dateutil-2.8.1.dist-info/LICENSE | 54 + .../python_dateutil-2.8.1.dist-info/METADATA | 200 + .../python_dateutil-2.8.1.dist-info/RECORD | 44 + .../python_dateutil-2.8.1.dist-info/WHEEL | 6 + .../top_level.txt | 1 + .../python_dateutil-2.8.1.dist-info/zip-safe | 1 + .../pytz-2020.1.dist-info/DESCRIPTION.rst | 598 ++ .../pytz-2020.1.dist-info/INSTALLER | 1 + .../pytz-2020.1.dist-info/LICENSE.txt | 19 + .../pytz-2020.1.dist-info/METADATA | 632 ++ .../pytz-2020.1.dist-info/RECORD | 621 ++ .../site-packages/pytz-2020.1.dist-info/WHEEL | 6 + .../pytz-2020.1.dist-info/metadata.json | 1 + .../pytz-2020.1.dist-info/top_level.txt | 1 + .../pytz-2020.1.dist-info/zip-safe | 1 + .../python3.8/site-packages/pytz/__init__.py | 1552 +++ .../site-packages/pytz/exceptions.py | 59 + env/lib/python3.8/site-packages/pytz/lazy.py | 172 + .../python3.8/site-packages/pytz/reference.py | 140 + .../python3.8/site-packages/pytz/tzfile.py | 134 + .../python3.8/site-packages/pytz/tzinfo.py | 577 ++ .../pytz/zoneinfo/Africa/Abidjan | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Accra | Bin 0 -> 816 bytes .../pytz/zoneinfo/Africa/Addis_Ababa | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Algiers | Bin 0 -> 735 bytes .../site-packages/pytz/zoneinfo/Africa/Asmara | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Asmera | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Bamako | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bangui | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Banjul | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bissau | Bin 0 -> 194 bytes .../pytz/zoneinfo/Africa/Blantyre | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Brazzaville | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Bujumbura | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Cairo | Bin 0 -> 1955 bytes .../pytz/zoneinfo/Africa/Casablanca | Bin 0 -> 2429 bytes .../site-packages/pytz/zoneinfo/Africa/Ceuta | Bin 0 -> 2036 bytes .../pytz/zoneinfo/Africa/Conakry | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Dakar | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Djibouti | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Africa/Douala | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/El_Aaiun | Bin 0 -> 2295 bytes .../pytz/zoneinfo/Africa/Freetown | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Gaborone | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Harare | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Johannesburg | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/Africa/Juba | Bin 0 -> 653 bytes .../pytz/zoneinfo/Africa/Kampala | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Khartoum | Bin 0 -> 679 bytes .../site-packages/pytz/zoneinfo/Africa/Kigali | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Kinshasa | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lagos | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Libreville | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lome | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Luanda | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Lubumbashi | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lusaka | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Malabo | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Maputo | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Maseru | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mbabane | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mogadishu | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Monrovia | Bin 0 -> 208 bytes .../pytz/zoneinfo/Africa/Nairobi | Bin 0 -> 251 bytes .../pytz/zoneinfo/Africa/Ndjamena | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Africa/Niamey | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Nouakchott | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Ouagadougou | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Porto-Novo | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Sao_Tome | Bin 0 -> 254 bytes .../pytz/zoneinfo/Africa/Timbuktu | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Tripoli | Bin 0 -> 625 bytes .../site-packages/pytz/zoneinfo/Africa/Tunis | Bin 0 -> 689 bytes .../pytz/zoneinfo/Africa/Windhoek | Bin 0 -> 955 bytes .../site-packages/pytz/zoneinfo/America/Adak | Bin 0 -> 2356 bytes .../pytz/zoneinfo/America/Anchorage | Bin 0 -> 2371 bytes .../pytz/zoneinfo/America/Anguilla | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Antigua | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Araguaina | Bin 0 -> 884 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/Mendoza | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Salta | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/San_Luis | Bin 0 -> 1102 bytes .../pytz/zoneinfo/America/Argentina/Tucuman | Bin 0 -> 1104 bytes .../pytz/zoneinfo/America/Argentina/Ushuaia | Bin 0 -> 1076 bytes .../site-packages/pytz/zoneinfo/America/Aruba | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Asuncion | Bin 0 -> 2044 bytes .../pytz/zoneinfo/America/Atikokan | Bin 0 -> 336 bytes .../site-packages/pytz/zoneinfo/America/Atka | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/America/Bahia | Bin 0 -> 1024 bytes .../pytz/zoneinfo/America/Bahia_Banderas | Bin 0 -> 1546 bytes .../pytz/zoneinfo/America/Barbados | Bin 0 -> 314 bytes .../site-packages/pytz/zoneinfo/America/Belem | Bin 0 -> 576 bytes .../pytz/zoneinfo/America/Belize | Bin 0 -> 948 bytes .../pytz/zoneinfo/America/Blanc-Sablon | Bin 0 -> 298 bytes .../pytz/zoneinfo/America/Boa_Vista | Bin 0 -> 632 bytes .../pytz/zoneinfo/America/Bogota | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/America/Boise | Bin 0 -> 2394 bytes .../pytz/zoneinfo/America/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cambridge_Bay | Bin 0 -> 2084 bytes .../pytz/zoneinfo/America/Campo_Grande | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Cancun | Bin 0 -> 782 bytes .../pytz/zoneinfo/America/Caracas | Bin 0 -> 264 bytes .../pytz/zoneinfo/America/Catamarca | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cayenne | Bin 0 -> 198 bytes .../pytz/zoneinfo/America/Cayman | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Chicago | Bin 0 -> 3576 bytes .../pytz/zoneinfo/America/Chihuahua | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Coral_Harbour | Bin 0 -> 336 bytes .../pytz/zoneinfo/America/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Costa_Rica | Bin 0 -> 316 bytes .../pytz/zoneinfo/America/Creston | Bin 0 -> 208 bytes .../pytz/zoneinfo/America/Cuiaba | Bin 0 -> 1416 bytes .../pytz/zoneinfo/America/Curacao | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Danmarkshavn | Bin 0 -> 698 bytes .../pytz/zoneinfo/America/Dawson | Bin 0 -> 1600 bytes .../pytz/zoneinfo/America/Dawson_Creek | Bin 0 -> 1050 bytes .../pytz/zoneinfo/America/Denver | Bin 0 -> 2444 bytes .../pytz/zoneinfo/America/Detroit | Bin 0 -> 2230 bytes .../pytz/zoneinfo/America/Dominica | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Edmonton | Bin 0 -> 2332 bytes .../pytz/zoneinfo/America/Eirunepe | Bin 0 -> 656 bytes .../pytz/zoneinfo/America/El_Salvador | Bin 0 -> 224 bytes .../pytz/zoneinfo/America/Ensenada | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Fort_Nelson | Bin 0 -> 2240 bytes .../pytz/zoneinfo/America/Fort_Wayne | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Fortaleza | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Glace_Bay | Bin 0 -> 2192 bytes .../pytz/zoneinfo/America/Godthab | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Goose_Bay | Bin 0 -> 3210 bytes .../pytz/zoneinfo/America/Grand_Turk | Bin 0 -> 1848 bytes .../pytz/zoneinfo/America/Grenada | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guadeloupe | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guatemala | Bin 0 -> 280 bytes .../pytz/zoneinfo/America/Guayaquil | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Guyana | Bin 0 -> 236 bytes .../pytz/zoneinfo/America/Halifax | Bin 0 -> 3424 bytes .../pytz/zoneinfo/America/Havana | Bin 0 -> 2416 bytes .../pytz/zoneinfo/America/Hermosillo | Bin 0 -> 416 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Indiana/Knox | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Indiana/Marengo | Bin 0 -> 1722 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 0 -> 1904 bytes .../pytz/zoneinfo/America/Indiana/Tell_City | Bin 0 -> 1684 bytes .../pytz/zoneinfo/America/Indiana/Vevay | Bin 0 -> 1414 bytes .../pytz/zoneinfo/America/Indiana/Vincennes | Bin 0 -> 1694 bytes .../pytz/zoneinfo/America/Indiana/Winamac | Bin 0 -> 1778 bytes .../pytz/zoneinfo/America/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Inuvik | Bin 0 -> 1894 bytes .../pytz/zoneinfo/America/Iqaluit | Bin 0 -> 2032 bytes .../pytz/zoneinfo/America/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/America/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Juneau | Bin 0 -> 2353 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 0 -> 2352 bytes .../pytz/zoneinfo/America/Knox_IN | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Kralendijk | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/La_Paz | Bin 0 -> 232 bytes .../site-packages/pytz/zoneinfo/America/Lima | Bin 0 -> 406 bytes .../pytz/zoneinfo/America/Los_Angeles | Bin 0 -> 2836 bytes .../pytz/zoneinfo/America/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Lower_Princes | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Maceio | Bin 0 -> 744 bytes .../pytz/zoneinfo/America/Managua | Bin 0 -> 430 bytes .../pytz/zoneinfo/America/Manaus | Bin 0 -> 604 bytes .../pytz/zoneinfo/America/Marigot | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Martinique | Bin 0 -> 232 bytes .../pytz/zoneinfo/America/Matamoros | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Mazatlan | Bin 0 -> 1526 bytes .../pytz/zoneinfo/America/Mendoza | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Menominee | Bin 0 -> 2274 bytes .../pytz/zoneinfo/America/Merida | Bin 0 -> 1422 bytes .../pytz/zoneinfo/America/Metlakatla | Bin 0 -> 1423 bytes .../pytz/zoneinfo/America/Mexico_City | Bin 0 -> 1584 bytes .../pytz/zoneinfo/America/Miquelon | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Moncton | Bin 0 -> 3154 bytes .../pytz/zoneinfo/America/Monterrey | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Montevideo | Bin 0 -> 1510 bytes .../pytz/zoneinfo/America/Montreal | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Montserrat | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Nassau | Bin 0 -> 2258 bytes .../pytz/zoneinfo/America/New_York | Bin 0 -> 3536 bytes .../pytz/zoneinfo/America/Nipigon | Bin 0 -> 2122 bytes .../site-packages/pytz/zoneinfo/America/Nome | Bin 0 -> 2367 bytes .../pytz/zoneinfo/America/Noronha | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/North_Dakota/Beulah | Bin 0 -> 2380 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 0 -> 2380 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 0 -> 2380 bytes .../site-packages/pytz/zoneinfo/America/Nuuk | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Ojinaga | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Panama | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Pangnirtung | Bin 0 -> 2094 bytes .../pytz/zoneinfo/America/Paramaribo | Bin 0 -> 262 bytes .../pytz/zoneinfo/America/Phoenix | Bin 0 -> 328 bytes .../pytz/zoneinfo/America/Port-au-Prince | Bin 0 -> 1434 bytes .../pytz/zoneinfo/America/Port_of_Spain | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Porto_Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Porto_Velho | Bin 0 -> 576 bytes .../pytz/zoneinfo/America/Puerto_Rico | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Punta_Arenas | Bin 0 -> 1902 bytes .../pytz/zoneinfo/America/Rainy_River | Bin 0 -> 2122 bytes .../pytz/zoneinfo/America/Rankin_Inlet | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Recife | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Regina | Bin 0 -> 980 bytes .../pytz/zoneinfo/America/Resolute | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Rio_Branco | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Rosario | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Santa_Isabel | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Santarem | Bin 0 -> 602 bytes .../pytz/zoneinfo/America/Santiago | Bin 0 -> 2529 bytes .../pytz/zoneinfo/America/Santo_Domingo | Bin 0 -> 458 bytes .../pytz/zoneinfo/America/Sao_Paulo | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Scoresbysund | Bin 0 -> 1916 bytes .../pytz/zoneinfo/America/Shiprock | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/America/Sitka | Bin 0 -> 2329 bytes .../pytz/zoneinfo/America/St_Barthelemy | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Johns | Bin 0 -> 3655 bytes .../pytz/zoneinfo/America/St_Kitts | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Lucia | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Thomas | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Vincent | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Swift_Current | Bin 0 -> 560 bytes .../pytz/zoneinfo/America/Tegucigalpa | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/America/Thule | Bin 0 -> 1502 bytes .../pytz/zoneinfo/America/Thunder_Bay | Bin 0 -> 2202 bytes .../pytz/zoneinfo/America/Tijuana | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Toronto | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Tortola | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Vancouver | Bin 0 -> 2892 bytes .../pytz/zoneinfo/America/Virgin | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Whitehorse | Bin 0 -> 1600 bytes .../pytz/zoneinfo/America/Winnipeg | Bin 0 -> 2868 bytes .../pytz/zoneinfo/America/Yakutat | Bin 0 -> 2305 bytes .../pytz/zoneinfo/America/Yellowknife | Bin 0 -> 1966 bytes .../pytz/zoneinfo/Antarctica/Casey | Bin 0 -> 297 bytes .../pytz/zoneinfo/Antarctica/Davis | Bin 0 -> 297 bytes .../pytz/zoneinfo/Antarctica/DumontDUrville | Bin 0 -> 194 bytes .../pytz/zoneinfo/Antarctica/Macquarie | Bin 0 -> 1520 bytes .../pytz/zoneinfo/Antarctica/Mawson | Bin 0 -> 199 bytes .../pytz/zoneinfo/Antarctica/McMurdo | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Palmer | Bin 0 -> 1418 bytes .../pytz/zoneinfo/Antarctica/Rothera | Bin 0 -> 164 bytes .../pytz/zoneinfo/Antarctica/South_Pole | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Syowa | Bin 0 -> 165 bytes .../pytz/zoneinfo/Antarctica/Troll | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Antarctica/Vostok | Bin 0 -> 165 bytes .../pytz/zoneinfo/Arctic/Longyearbyen | Bin 0 -> 2228 bytes .../site-packages/pytz/zoneinfo/Asia/Aden | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Almaty | Bin 0 -> 997 bytes .../site-packages/pytz/zoneinfo/Asia/Amman | Bin 0 -> 1853 bytes .../site-packages/pytz/zoneinfo/Asia/Anadyr | Bin 0 -> 1188 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtau | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtobe | Bin 0 -> 1011 bytes .../site-packages/pytz/zoneinfo/Asia/Ashgabat | Bin 0 -> 619 bytes .../pytz/zoneinfo/Asia/Ashkhabad | Bin 0 -> 619 bytes .../site-packages/pytz/zoneinfo/Asia/Atyrau | Bin 0 -> 991 bytes .../site-packages/pytz/zoneinfo/Asia/Baghdad | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Bahrain | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Baku | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Bangkok | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Barnaul | Bin 0 -> 1221 bytes .../site-packages/pytz/zoneinfo/Asia/Beirut | Bin 0 -> 2154 bytes .../site-packages/pytz/zoneinfo/Asia/Bishkek | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Brunei | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Calcutta | Bin 0 -> 285 bytes .../site-packages/pytz/zoneinfo/Asia/Chita | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Choibalsan | Bin 0 -> 949 bytes .../pytz/zoneinfo/Asia/Chongqing | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Chungking | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Colombo | Bin 0 -> 372 bytes .../site-packages/pytz/zoneinfo/Asia/Dacca | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Damascus | Bin 0 -> 2294 bytes .../site-packages/pytz/zoneinfo/Asia/Dhaka | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Dili | Bin 0 -> 227 bytes .../site-packages/pytz/zoneinfo/Asia/Dubai | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Dushanbe | Bin 0 -> 591 bytes .../pytz/zoneinfo/Asia/Famagusta | Bin 0 -> 2028 bytes .../site-packages/pytz/zoneinfo/Asia/Gaza | Bin 0 -> 2316 bytes .../site-packages/pytz/zoneinfo/Asia/Harbin | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Hebron | Bin 0 -> 2344 bytes .../pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 0 -> 351 bytes .../pytz/zoneinfo/Asia/Hong_Kong | Bin 0 -> 1203 bytes .../site-packages/pytz/zoneinfo/Asia/Hovd | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Irkutsk | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Asia/Jakarta | Bin 0 -> 355 bytes .../site-packages/pytz/zoneinfo/Asia/Jayapura | Bin 0 -> 221 bytes .../pytz/zoneinfo/Asia/Jerusalem | Bin 0 -> 2288 bytes .../site-packages/pytz/zoneinfo/Asia/Kabul | Bin 0 -> 208 bytes .../pytz/zoneinfo/Asia/Kamchatka | Bin 0 -> 1166 bytes .../site-packages/pytz/zoneinfo/Asia/Karachi | Bin 0 -> 379 bytes .../site-packages/pytz/zoneinfo/Asia/Kashgar | Bin 0 -> 165 bytes .../pytz/zoneinfo/Asia/Kathmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Katmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Khandyga | Bin 0 -> 1271 bytes .../site-packages/pytz/zoneinfo/Asia/Kolkata | Bin 0 -> 285 bytes .../pytz/zoneinfo/Asia/Krasnoyarsk | Bin 0 -> 1207 bytes .../pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Asia/Kuching | Bin 0 -> 483 bytes .../site-packages/pytz/zoneinfo/Asia/Kuwait | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Macao | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Macau | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Magadan | Bin 0 -> 1222 bytes .../site-packages/pytz/zoneinfo/Asia/Makassar | Bin 0 -> 254 bytes .../site-packages/pytz/zoneinfo/Asia/Manila | Bin 0 -> 328 bytes .../site-packages/pytz/zoneinfo/Asia/Muscat | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Nicosia | Bin 0 -> 2002 bytes .../pytz/zoneinfo/Asia/Novokuznetsk | Bin 0 -> 1165 bytes .../pytz/zoneinfo/Asia/Novosibirsk | Bin 0 -> 1221 bytes .../site-packages/pytz/zoneinfo/Asia/Omsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Oral | Bin 0 -> 1005 bytes .../pytz/zoneinfo/Asia/Phnom_Penh | Bin 0 -> 199 bytes .../pytz/zoneinfo/Asia/Pontianak | Bin 0 -> 353 bytes .../pytz/zoneinfo/Asia/Pyongyang | Bin 0 -> 237 bytes .../site-packages/pytz/zoneinfo/Asia/Qatar | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Qostanay | Bin 0 -> 1011 bytes .../pytz/zoneinfo/Asia/Qyzylorda | Bin 0 -> 1025 bytes .../site-packages/pytz/zoneinfo/Asia/Rangoon | Bin 0 -> 268 bytes .../site-packages/pytz/zoneinfo/Asia/Riyadh | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Saigon | Bin 0 -> 351 bytes .../site-packages/pytz/zoneinfo/Asia/Sakhalin | Bin 0 -> 1202 bytes .../pytz/zoneinfo/Asia/Samarkand | Bin 0 -> 577 bytes .../site-packages/pytz/zoneinfo/Asia/Seoul | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Asia/Shanghai | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Singapore | Bin 0 -> 383 bytes .../pytz/zoneinfo/Asia/Srednekolymsk | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Taipei | Bin 0 -> 761 bytes .../site-packages/pytz/zoneinfo/Asia/Tashkent | Bin 0 -> 591 bytes .../site-packages/pytz/zoneinfo/Asia/Tbilisi | Bin 0 -> 1035 bytes .../site-packages/pytz/zoneinfo/Asia/Tehran | Bin 0 -> 2582 bytes .../site-packages/pytz/zoneinfo/Asia/Tel_Aviv | Bin 0 -> 2288 bytes .../site-packages/pytz/zoneinfo/Asia/Thimbu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Thimphu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Tokyo | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Asia/Tomsk | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Ujung_Pandang | Bin 0 -> 254 bytes .../pytz/zoneinfo/Asia/Ulaanbaatar | Bin 0 -> 891 bytes .../pytz/zoneinfo/Asia/Ulan_Bator | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Urumqi | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Ust-Nera | Bin 0 -> 1252 bytes .../pytz/zoneinfo/Asia/Vientiane | Bin 0 -> 199 bytes .../pytz/zoneinfo/Asia/Vladivostok | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Yakutsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Yangon | Bin 0 -> 268 bytes .../pytz/zoneinfo/Asia/Yekaterinburg | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Yerevan | Bin 0 -> 1151 bytes .../pytz/zoneinfo/Atlantic/Azores | Bin 0 -> 3484 bytes .../pytz/zoneinfo/Atlantic/Bermuda | Bin 0 -> 1978 bytes .../pytz/zoneinfo/Atlantic/Canary | Bin 0 -> 1897 bytes .../pytz/zoneinfo/Atlantic/Cape_Verde | Bin 0 -> 270 bytes .../pytz/zoneinfo/Atlantic/Faeroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Faroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 0 -> 2228 bytes .../pytz/zoneinfo/Atlantic/Madeira | Bin 0 -> 3475 bytes .../pytz/zoneinfo/Atlantic/Reykjavik | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Atlantic/South_Georgia | Bin 0 -> 164 bytes .../pytz/zoneinfo/Atlantic/St_Helena | Bin 0 -> 148 bytes .../pytz/zoneinfo/Atlantic/Stanley | Bin 0 -> 1214 bytes .../site-packages/pytz/zoneinfo/Australia/ACT | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Adelaide | Bin 0 -> 2222 bytes .../pytz/zoneinfo/Australia/Brisbane | Bin 0 -> 433 bytes .../pytz/zoneinfo/Australia/Broken_Hill | Bin 0 -> 2243 bytes .../pytz/zoneinfo/Australia/Canberra | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Currie | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Darwin | Bin 0 -> 304 bytes .../pytz/zoneinfo/Australia/Eucla | Bin 0 -> 484 bytes .../pytz/zoneinfo/Australia/Hobart | Bin 0 -> 2316 bytes .../site-packages/pytz/zoneinfo/Australia/LHI | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Lindeman | Bin 0 -> 489 bytes .../pytz/zoneinfo/Australia/Lord_Howe | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Melbourne | Bin 0 -> 2204 bytes .../site-packages/pytz/zoneinfo/Australia/NSW | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/North | Bin 0 -> 304 bytes .../pytz/zoneinfo/Australia/Perth | Bin 0 -> 460 bytes .../pytz/zoneinfo/Australia/Queensland | Bin 0 -> 433 bytes .../pytz/zoneinfo/Australia/South | Bin 0 -> 2222 bytes .../pytz/zoneinfo/Australia/Sydney | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/Tasmania | Bin 0 -> 2316 bytes .../pytz/zoneinfo/Australia/Victoria | Bin 0 -> 2204 bytes .../pytz/zoneinfo/Australia/West | Bin 0 -> 460 bytes .../pytz/zoneinfo/Australia/Yancowinna | Bin 0 -> 2243 bytes .../site-packages/pytz/zoneinfo/Brazil/Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/Brazil/DeNoronha | Bin 0 -> 716 bytes .../site-packages/pytz/zoneinfo/Brazil/East | Bin 0 -> 1444 bytes .../site-packages/pytz/zoneinfo/Brazil/West | Bin 0 -> 604 bytes .../python3.8/site-packages/pytz/zoneinfo/CET | Bin 0 -> 2094 bytes .../site-packages/pytz/zoneinfo/CST6CDT | Bin 0 -> 2310 bytes .../pytz/zoneinfo/Canada/Atlantic | Bin 0 -> 3424 bytes .../pytz/zoneinfo/Canada/Central | Bin 0 -> 2868 bytes .../pytz/zoneinfo/Canada/Eastern | Bin 0 -> 3494 bytes .../pytz/zoneinfo/Canada/Mountain | Bin 0 -> 2332 bytes .../pytz/zoneinfo/Canada/Newfoundland | Bin 0 -> 3655 bytes .../pytz/zoneinfo/Canada/Pacific | Bin 0 -> 2892 bytes .../pytz/zoneinfo/Canada/Saskatchewan | Bin 0 -> 980 bytes .../site-packages/pytz/zoneinfo/Canada/Yukon | Bin 0 -> 1600 bytes .../pytz/zoneinfo/Chile/Continental | Bin 0 -> 2529 bytes .../pytz/zoneinfo/Chile/EasterIsland | Bin 0 -> 2233 bytes .../site-packages/pytz/zoneinfo/Cuba | Bin 0 -> 2416 bytes .../python3.8/site-packages/pytz/zoneinfo/EET | Bin 0 -> 1908 bytes .../python3.8/site-packages/pytz/zoneinfo/EST | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/EST5EDT | Bin 0 -> 2310 bytes .../site-packages/pytz/zoneinfo/Egypt | Bin 0 -> 1955 bytes .../site-packages/pytz/zoneinfo/Eire | Bin 0 -> 3492 bytes .../site-packages/pytz/zoneinfo/Etc/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+1 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+10 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+11 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+12 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+2 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+3 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+4 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+5 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+6 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+7 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+8 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+9 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-1 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-10 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-11 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-12 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-13 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-14 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-2 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-3 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-4 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-5 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-6 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-7 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-8 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-9 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Greenwich | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Zulu | Bin 0 -> 114 bytes .../pytz/zoneinfo/Europe/Amsterdam | Bin 0 -> 2910 bytes .../pytz/zoneinfo/Europe/Andorra | Bin 0 -> 1742 bytes .../pytz/zoneinfo/Europe/Astrakhan | Bin 0 -> 1165 bytes .../site-packages/pytz/zoneinfo/Europe/Athens | Bin 0 -> 2262 bytes .../pytz/zoneinfo/Europe/Belfast | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Belgrade | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Berlin | Bin 0 -> 2298 bytes .../pytz/zoneinfo/Europe/Bratislava | Bin 0 -> 2301 bytes .../pytz/zoneinfo/Europe/Brussels | Bin 0 -> 2933 bytes .../pytz/zoneinfo/Europe/Bucharest | Bin 0 -> 2184 bytes .../pytz/zoneinfo/Europe/Budapest | Bin 0 -> 2368 bytes .../pytz/zoneinfo/Europe/Busingen | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Chisinau | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Copenhagen | Bin 0 -> 2137 bytes .../site-packages/pytz/zoneinfo/Europe/Dublin | Bin 0 -> 3492 bytes .../pytz/zoneinfo/Europe/Gibraltar | Bin 0 -> 3052 bytes .../pytz/zoneinfo/Europe/Guernsey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Helsinki | Bin 0 -> 1900 bytes .../pytz/zoneinfo/Europe/Isle_of_Man | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Europe/Jersey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Kaliningrad | Bin 0 -> 1493 bytes .../site-packages/pytz/zoneinfo/Europe/Kiev | Bin 0 -> 2088 bytes .../site-packages/pytz/zoneinfo/Europe/Kirov | Bin 0 -> 1153 bytes .../site-packages/pytz/zoneinfo/Europe/Lisbon | Bin 0 -> 3469 bytes .../pytz/zoneinfo/Europe/Ljubljana | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/London | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Luxembourg | Bin 0 -> 2946 bytes .../site-packages/pytz/zoneinfo/Europe/Madrid | Bin 0 -> 2614 bytes .../site-packages/pytz/zoneinfo/Europe/Malta | Bin 0 -> 2620 bytes .../pytz/zoneinfo/Europe/Mariehamn | Bin 0 -> 1900 bytes .../site-packages/pytz/zoneinfo/Europe/Minsk | Bin 0 -> 1321 bytes .../site-packages/pytz/zoneinfo/Europe/Monaco | Bin 0 -> 2944 bytes .../site-packages/pytz/zoneinfo/Europe/Moscow | Bin 0 -> 1535 bytes .../pytz/zoneinfo/Europe/Nicosia | Bin 0 -> 2002 bytes .../site-packages/pytz/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes .../site-packages/pytz/zoneinfo/Europe/Paris | Bin 0 -> 2962 bytes .../pytz/zoneinfo/Europe/Podgorica | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Prague | Bin 0 -> 2301 bytes .../site-packages/pytz/zoneinfo/Europe/Riga | Bin 0 -> 2198 bytes .../site-packages/pytz/zoneinfo/Europe/Rome | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Samara | Bin 0 -> 1215 bytes .../pytz/zoneinfo/Europe/San_Marino | Bin 0 -> 2641 bytes .../pytz/zoneinfo/Europe/Sarajevo | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Saratov | Bin 0 -> 1183 bytes .../pytz/zoneinfo/Europe/Simferopol | Bin 0 -> 1453 bytes .../site-packages/pytz/zoneinfo/Europe/Skopje | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Sofia | Bin 0 -> 2077 bytes .../pytz/zoneinfo/Europe/Stockholm | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Tallinn | Bin 0 -> 2148 bytes .../site-packages/pytz/zoneinfo/Europe/Tirane | Bin 0 -> 2084 bytes .../pytz/zoneinfo/Europe/Tiraspol | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Ulyanovsk | Bin 0 -> 1267 bytes .../pytz/zoneinfo/Europe/Uzhgorod | Bin 0 -> 2050 bytes .../site-packages/pytz/zoneinfo/Europe/Vaduz | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Vatican | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Vienna | Bin 0 -> 2200 bytes .../pytz/zoneinfo/Europe/Vilnius | Bin 0 -> 2162 bytes .../pytz/zoneinfo/Europe/Volgograd | Bin 0 -> 1165 bytes .../site-packages/pytz/zoneinfo/Europe/Warsaw | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Europe/Zagreb | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Zaporozhye | Bin 0 -> 2106 bytes .../site-packages/pytz/zoneinfo/Europe/Zurich | Bin 0 -> 1909 bytes .../site-packages/pytz/zoneinfo/Factory | Bin 0 -> 116 bytes .../python3.8/site-packages/pytz/zoneinfo/GB | Bin 0 -> 3648 bytes .../site-packages/pytz/zoneinfo/GB-Eire | Bin 0 -> 3648 bytes .../python3.8/site-packages/pytz/zoneinfo/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Greenwich | Bin 0 -> 114 bytes .../python3.8/site-packages/pytz/zoneinfo/HST | Bin 0 -> 115 bytes .../site-packages/pytz/zoneinfo/Hongkong | Bin 0 -> 1203 bytes .../site-packages/pytz/zoneinfo/Iceland | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Indian/Antananarivo | Bin 0 -> 251 bytes .../site-packages/pytz/zoneinfo/Indian/Chagos | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Christmas | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Cocos | Bin 0 -> 174 bytes .../site-packages/pytz/zoneinfo/Indian/Comoro | Bin 0 -> 251 bytes .../pytz/zoneinfo/Indian/Kerguelen | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Mahe | Bin 0 -> 165 bytes .../pytz/zoneinfo/Indian/Maldives | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Mauritius | Bin 0 -> 241 bytes .../pytz/zoneinfo/Indian/Mayotte | Bin 0 -> 251 bytes .../pytz/zoneinfo/Indian/Reunion | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Iran | Bin 0 -> 2582 bytes .../site-packages/pytz/zoneinfo/Israel | Bin 0 -> 2288 bytes .../site-packages/pytz/zoneinfo/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/Japan | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Kwajalein | Bin 0 -> 316 bytes .../site-packages/pytz/zoneinfo/Libya | Bin 0 -> 625 bytes .../python3.8/site-packages/pytz/zoneinfo/MET | Bin 0 -> 2094 bytes .../python3.8/site-packages/pytz/zoneinfo/MST | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/MST7MDT | Bin 0 -> 2310 bytes .../pytz/zoneinfo/Mexico/BajaNorte | Bin 0 -> 2342 bytes .../pytz/zoneinfo/Mexico/BajaSur | Bin 0 -> 1526 bytes .../pytz/zoneinfo/Mexico/General | Bin 0 -> 1584 bytes .../python3.8/site-packages/pytz/zoneinfo/NZ | Bin 0 -> 2437 bytes .../site-packages/pytz/zoneinfo/NZ-CHAT | Bin 0 -> 2068 bytes .../site-packages/pytz/zoneinfo/Navajo | Bin 0 -> 2444 bytes .../python3.8/site-packages/pytz/zoneinfo/PRC | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/PST8PDT | Bin 0 -> 2310 bytes .../site-packages/pytz/zoneinfo/Pacific/Apia | Bin 0 -> 1097 bytes .../pytz/zoneinfo/Pacific/Auckland | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Pacific/Bougainville | Bin 0 -> 268 bytes .../pytz/zoneinfo/Pacific/Chatham | Bin 0 -> 2068 bytes .../site-packages/pytz/zoneinfo/Pacific/Chuuk | Bin 0 -> 269 bytes .../pytz/zoneinfo/Pacific/Easter | Bin 0 -> 2233 bytes .../site-packages/pytz/zoneinfo/Pacific/Efate | Bin 0 -> 466 bytes .../pytz/zoneinfo/Pacific/Enderbury | Bin 0 -> 234 bytes .../pytz/zoneinfo/Pacific/Fakaofo | Bin 0 -> 200 bytes .../site-packages/pytz/zoneinfo/Pacific/Fiji | Bin 0 -> 1077 bytes .../pytz/zoneinfo/Pacific/Funafuti | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Galapagos | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Gambier | Bin 0 -> 164 bytes .../pytz/zoneinfo/Pacific/Guadalcanal | Bin 0 -> 166 bytes .../site-packages/pytz/zoneinfo/Pacific/Guam | Bin 0 -> 494 bytes .../pytz/zoneinfo/Pacific/Honolulu | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Johnston | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Kiritimati | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Kosrae | Bin 0 -> 351 bytes .../pytz/zoneinfo/Pacific/Kwajalein | Bin 0 -> 316 bytes .../pytz/zoneinfo/Pacific/Majuro | Bin 0 -> 310 bytes .../pytz/zoneinfo/Pacific/Marquesas | Bin 0 -> 173 bytes .../pytz/zoneinfo/Pacific/Midway | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Nauru | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/Pacific/Niue | Bin 0 -> 241 bytes .../pytz/zoneinfo/Pacific/Norfolk | Bin 0 -> 880 bytes .../pytz/zoneinfo/Pacific/Noumea | Bin 0 -> 304 bytes .../pytz/zoneinfo/Pacific/Pago_Pago | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Palau | Bin 0 -> 180 bytes .../pytz/zoneinfo/Pacific/Pitcairn | Bin 0 -> 202 bytes .../pytz/zoneinfo/Pacific/Pohnpei | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Ponape | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Port_Moresby | Bin 0 -> 186 bytes .../pytz/zoneinfo/Pacific/Rarotonga | Bin 0 -> 577 bytes .../pytz/zoneinfo/Pacific/Saipan | Bin 0 -> 494 bytes .../site-packages/pytz/zoneinfo/Pacific/Samoa | Bin 0 -> 175 bytes .../pytz/zoneinfo/Pacific/Tahiti | Bin 0 -> 165 bytes .../pytz/zoneinfo/Pacific/Tarawa | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Tongatapu | Bin 0 -> 372 bytes .../site-packages/pytz/zoneinfo/Pacific/Truk | Bin 0 -> 269 bytes .../site-packages/pytz/zoneinfo/Pacific/Wake | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Wallis | Bin 0 -> 166 bytes .../site-packages/pytz/zoneinfo/Pacific/Yap | Bin 0 -> 269 bytes .../site-packages/pytz/zoneinfo/Poland | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Portugal | Bin 0 -> 3469 bytes .../python3.8/site-packages/pytz/zoneinfo/ROC | Bin 0 -> 761 bytes .../python3.8/site-packages/pytz/zoneinfo/ROK | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Singapore | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Turkey | Bin 0 -> 1947 bytes .../python3.8/site-packages/pytz/zoneinfo/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/US/Alaska | Bin 0 -> 2371 bytes .../site-packages/pytz/zoneinfo/US/Aleutian | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/US/Arizona | Bin 0 -> 328 bytes .../site-packages/pytz/zoneinfo/US/Central | Bin 0 -> 3576 bytes .../pytz/zoneinfo/US/East-Indiana | Bin 0 -> 1666 bytes .../site-packages/pytz/zoneinfo/US/Eastern | Bin 0 -> 3536 bytes .../site-packages/pytz/zoneinfo/US/Hawaii | Bin 0 -> 329 bytes .../pytz/zoneinfo/US/Indiana-Starke | Bin 0 -> 2428 bytes .../site-packages/pytz/zoneinfo/US/Michigan | Bin 0 -> 2230 bytes .../site-packages/pytz/zoneinfo/US/Mountain | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/US/Pacific | Bin 0 -> 2836 bytes .../site-packages/pytz/zoneinfo/US/Samoa | Bin 0 -> 175 bytes .../python3.8/site-packages/pytz/zoneinfo/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/W-SU | Bin 0 -> 1535 bytes .../python3.8/site-packages/pytz/zoneinfo/WET | Bin 0 -> 1905 bytes .../site-packages/pytz/zoneinfo/Zulu | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/iso3166.tab | 274 + .../site-packages/pytz/zoneinfo/leapseconds | 78 + .../site-packages/pytz/zoneinfo/posixrules | Bin 0 -> 3536 bytes .../site-packages/pytz/zoneinfo/tzdata.zi | 4410 +++++++++ .../site-packages/pytz/zoneinfo/zone.tab | 452 + .../site-packages/pytz/zoneinfo/zone1970.tab | 384 + .../setuptools-46.1.3.dist-info/INSTALLER | 1 + .../setuptools-46.1.3.dist-info/LICENSE | 19 + .../setuptools-46.1.3.dist-info/METADATA | 108 + .../setuptools-46.1.3.dist-info/RECORD | 208 + .../setuptools-46.1.3.dist-info/WHEEL | 5 + .../dependency_links.txt | 2 + .../entry_points.txt | 68 + .../setuptools-46.1.3.dist-info/top_level.txt | 3 + .../setuptools-46.1.3.dist-info/zip-safe | 1 + .../setuptools-46.1.3.virtualenv | 0 .../site-packages/setuptools/__init__.py | 232 + .../setuptools/_deprecation_warning.py | 7 + .../site-packages/setuptools/_imp.py | 82 + .../setuptools/_vendor/__init__.py | 0 .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 27 + .../setuptools/_vendor/packaging/__init__.py | 26 + .../setuptools/_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../setuptools/_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 ++ .../setuptools/_vendor/packaging/tags.py | 404 + .../setuptools/_vendor/packaging/utils.py | 57 + .../setuptools/_vendor/packaging/version.py | 420 + .../setuptools/_vendor/pyparsing.py | 5742 ++++++++++++ .../site-packages/setuptools/_vendor/six.py | 868 ++ .../site-packages/setuptools/archive_util.py | 175 + .../site-packages/setuptools/build_meta.py | 272 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 17 + .../site-packages/setuptools/command/alias.py | 80 + .../setuptools/command/bdist_egg.py | 509 + .../setuptools/command/bdist_rpm.py | 43 + .../setuptools/command/bdist_wininst.py | 21 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 330 + .../setuptools/command/build_py.py | 276 + .../setuptools/command/develop.py | 221 + .../setuptools/command/dist_info.py | 36 + .../setuptools/command/easy_install.py | 2355 +++++ .../setuptools/command/egg_info.py | 721 ++ .../setuptools/command/install.py | 125 + .../setuptools/command/install_egg_info.py | 62 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 68 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 136 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 66 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 252 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 280 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 206 + .../site-packages/setuptools/config.py | 659 ++ .../site-packages/setuptools/dep_util.py | 25 + .../site-packages/setuptools/depends.py | 176 + .../site-packages/setuptools/dist.py | 1031 ++ .../site-packages/setuptools/errors.py | 16 + .../site-packages/setuptools/extension.py | 57 + .../setuptools/extern/__init__.py | 66 + .../site-packages/setuptools/glob.py | 174 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 150 + .../site-packages/setuptools/launch.py | 35 + .../site-packages/setuptools/lib2to3_ex.py | 62 + .../site-packages/setuptools/monkey.py | 179 + .../site-packages/setuptools/msvc.py | 1825 ++++ .../site-packages/setuptools/namespaces.py | 111 + .../site-packages/setuptools/package_index.py | 1140 +++ .../site-packages/setuptools/py27compat.py | 60 + .../site-packages/setuptools/py31compat.py | 32 + .../site-packages/setuptools/py33compat.py | 59 + .../site-packages/setuptools/py34compat.py | 13 + .../site-packages/setuptools/sandbox.py | 492 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/site-patch.py | 76 + .../site-packages/setuptools/ssl_support.py | 265 + .../site-packages/setuptools/unicode_utils.py | 44 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 221 + .../setuptools/windows_support.py | 29 + .../six-1.15.0.dist-info/INSTALLER | 1 + .../six-1.15.0.dist-info/LICENSE | 18 + .../six-1.15.0.dist-info/METADATA | 49 + .../site-packages/six-1.15.0.dist-info/RECORD | 8 + .../site-packages/six-1.15.0.dist-info/WHEEL | 6 + .../six-1.15.0.dist-info/top_level.txt | 1 + env/lib/python3.8/site-packages/six.py | 982 ++ .../site-packages/unidecode/__init__.py | 103 + .../site-packages/unidecode/__main__.py | 3 + .../python3.8/site-packages/unidecode/util.py | 58 + .../python3.8/site-packages/unidecode/x000.py | 165 + .../python3.8/site-packages/unidecode/x001.py | 258 + .../python3.8/site-packages/unidecode/x002.py | 257 + .../python3.8/site-packages/unidecode/x003.py | 257 + .../python3.8/site-packages/unidecode/x004.py | 257 + .../python3.8/site-packages/unidecode/x005.py | 257 + .../python3.8/site-packages/unidecode/x006.py | 257 + .../python3.8/site-packages/unidecode/x007.py | 257 + .../python3.8/site-packages/unidecode/x009.py | 257 + .../python3.8/site-packages/unidecode/x00a.py | 257 + .../python3.8/site-packages/unidecode/x00b.py | 257 + .../python3.8/site-packages/unidecode/x00c.py | 257 + .../python3.8/site-packages/unidecode/x00d.py | 257 + .../python3.8/site-packages/unidecode/x00e.py | 257 + .../python3.8/site-packages/unidecode/x00f.py | 257 + .../python3.8/site-packages/unidecode/x010.py | 257 + .../python3.8/site-packages/unidecode/x011.py | 257 + .../python3.8/site-packages/unidecode/x012.py | 258 + .../python3.8/site-packages/unidecode/x013.py | 257 + .../python3.8/site-packages/unidecode/x014.py | 258 + .../python3.8/site-packages/unidecode/x015.py | 258 + .../python3.8/site-packages/unidecode/x016.py | 257 + .../python3.8/site-packages/unidecode/x017.py | 257 + .../python3.8/site-packages/unidecode/x018.py | 257 + .../python3.8/site-packages/unidecode/x01d.py | 257 + .../python3.8/site-packages/unidecode/x01e.py | 257 + .../python3.8/site-packages/unidecode/x01f.py | 257 + .../python3.8/site-packages/unidecode/x020.py | 257 + .../python3.8/site-packages/unidecode/x021.py | 257 + .../python3.8/site-packages/unidecode/x022.py | 257 + .../python3.8/site-packages/unidecode/x023.py | 257 + .../python3.8/site-packages/unidecode/x024.py | 258 + .../python3.8/site-packages/unidecode/x025.py | 257 + .../python3.8/site-packages/unidecode/x026.py | 257 + .../python3.8/site-packages/unidecode/x027.py | 257 + .../python3.8/site-packages/unidecode/x028.py | 258 + .../python3.8/site-packages/unidecode/x029.py | 257 + .../python3.8/site-packages/unidecode/x02a.py | 257 + .../python3.8/site-packages/unidecode/x02c.py | 257 + .../python3.8/site-packages/unidecode/x02e.py | 257 + .../python3.8/site-packages/unidecode/x02f.py | 257 + .../python3.8/site-packages/unidecode/x030.py | 257 + .../python3.8/site-packages/unidecode/x031.py | 257 + .../python3.8/site-packages/unidecode/x032.py | 257 + .../python3.8/site-packages/unidecode/x033.py | 258 + .../python3.8/site-packages/unidecode/x04d.py | 257 + .../python3.8/site-packages/unidecode/x04e.py | 258 + .../python3.8/site-packages/unidecode/x04f.py | 258 + .../python3.8/site-packages/unidecode/x050.py | 258 + .../python3.8/site-packages/unidecode/x051.py | 258 + .../python3.8/site-packages/unidecode/x052.py | 258 + .../python3.8/site-packages/unidecode/x053.py | 258 + .../python3.8/site-packages/unidecode/x054.py | 258 + .../python3.8/site-packages/unidecode/x055.py | 258 + .../python3.8/site-packages/unidecode/x056.py | 258 + .../python3.8/site-packages/unidecode/x057.py | 258 + .../python3.8/site-packages/unidecode/x058.py | 258 + .../python3.8/site-packages/unidecode/x059.py | 258 + .../python3.8/site-packages/unidecode/x05a.py | 258 + .../python3.8/site-packages/unidecode/x05b.py | 258 + .../python3.8/site-packages/unidecode/x05c.py | 258 + .../python3.8/site-packages/unidecode/x05d.py | 258 + .../python3.8/site-packages/unidecode/x05e.py | 258 + .../python3.8/site-packages/unidecode/x05f.py | 258 + .../python3.8/site-packages/unidecode/x060.py | 258 + .../python3.8/site-packages/unidecode/x061.py | 258 + .../python3.8/site-packages/unidecode/x062.py | 258 + .../python3.8/site-packages/unidecode/x063.py | 258 + .../python3.8/site-packages/unidecode/x064.py | 258 + .../python3.8/site-packages/unidecode/x065.py | 258 + .../python3.8/site-packages/unidecode/x066.py | 258 + .../python3.8/site-packages/unidecode/x067.py | 258 + .../python3.8/site-packages/unidecode/x068.py | 258 + .../python3.8/site-packages/unidecode/x069.py | 258 + .../python3.8/site-packages/unidecode/x06a.py | 258 + .../python3.8/site-packages/unidecode/x06b.py | 258 + .../python3.8/site-packages/unidecode/x06c.py | 258 + .../python3.8/site-packages/unidecode/x06d.py | 258 + .../python3.8/site-packages/unidecode/x06e.py | 258 + .../python3.8/site-packages/unidecode/x06f.py | 258 + .../python3.8/site-packages/unidecode/x070.py | 258 + .../python3.8/site-packages/unidecode/x071.py | 258 + .../python3.8/site-packages/unidecode/x072.py | 258 + .../python3.8/site-packages/unidecode/x073.py | 258 + .../python3.8/site-packages/unidecode/x074.py | 258 + .../python3.8/site-packages/unidecode/x075.py | 258 + .../python3.8/site-packages/unidecode/x076.py | 258 + .../python3.8/site-packages/unidecode/x077.py | 258 + .../python3.8/site-packages/unidecode/x078.py | 258 + .../python3.8/site-packages/unidecode/x079.py | 258 + .../python3.8/site-packages/unidecode/x07a.py | 258 + .../python3.8/site-packages/unidecode/x07b.py | 258 + .../python3.8/site-packages/unidecode/x07c.py | 258 + .../python3.8/site-packages/unidecode/x07d.py | 258 + .../python3.8/site-packages/unidecode/x07e.py | 258 + .../python3.8/site-packages/unidecode/x07f.py | 258 + .../python3.8/site-packages/unidecode/x080.py | 258 + .../python3.8/site-packages/unidecode/x081.py | 258 + .../python3.8/site-packages/unidecode/x082.py | 258 + .../python3.8/site-packages/unidecode/x083.py | 258 + .../python3.8/site-packages/unidecode/x084.py | 258 + .../python3.8/site-packages/unidecode/x085.py | 258 + .../python3.8/site-packages/unidecode/x086.py | 258 + .../python3.8/site-packages/unidecode/x087.py | 258 + .../python3.8/site-packages/unidecode/x088.py | 258 + .../python3.8/site-packages/unidecode/x089.py | 258 + .../python3.8/site-packages/unidecode/x08a.py | 258 + .../python3.8/site-packages/unidecode/x08b.py | 258 + .../python3.8/site-packages/unidecode/x08c.py | 258 + .../python3.8/site-packages/unidecode/x08d.py | 258 + .../python3.8/site-packages/unidecode/x08e.py | 258 + .../python3.8/site-packages/unidecode/x08f.py | 258 + .../python3.8/site-packages/unidecode/x090.py | 258 + .../python3.8/site-packages/unidecode/x091.py | 258 + .../python3.8/site-packages/unidecode/x092.py | 258 + .../python3.8/site-packages/unidecode/x093.py | 258 + .../python3.8/site-packages/unidecode/x094.py | 258 + .../python3.8/site-packages/unidecode/x095.py | 258 + .../python3.8/site-packages/unidecode/x096.py | 258 + .../python3.8/site-packages/unidecode/x097.py | 258 + .../python3.8/site-packages/unidecode/x098.py | 258 + .../python3.8/site-packages/unidecode/x099.py | 258 + .../python3.8/site-packages/unidecode/x09a.py | 258 + .../python3.8/site-packages/unidecode/x09b.py | 258 + .../python3.8/site-packages/unidecode/x09c.py | 258 + .../python3.8/site-packages/unidecode/x09d.py | 258 + .../python3.8/site-packages/unidecode/x09e.py | 258 + .../python3.8/site-packages/unidecode/x09f.py | 257 + .../python3.8/site-packages/unidecode/x0a0.py | 258 + .../python3.8/site-packages/unidecode/x0a1.py | 258 + .../python3.8/site-packages/unidecode/x0a2.py | 258 + .../python3.8/site-packages/unidecode/x0a3.py | 258 + .../python3.8/site-packages/unidecode/x0a4.py | 257 + .../python3.8/site-packages/unidecode/x0ac.py | 258 + .../python3.8/site-packages/unidecode/x0ad.py | 258 + .../python3.8/site-packages/unidecode/x0ae.py | 258 + .../python3.8/site-packages/unidecode/x0af.py | 258 + .../python3.8/site-packages/unidecode/x0b0.py | 258 + .../python3.8/site-packages/unidecode/x0b1.py | 258 + .../python3.8/site-packages/unidecode/x0b2.py | 258 + .../python3.8/site-packages/unidecode/x0b3.py | 258 + .../python3.8/site-packages/unidecode/x0b4.py | 258 + .../python3.8/site-packages/unidecode/x0b5.py | 258 + .../python3.8/site-packages/unidecode/x0b6.py | 258 + .../python3.8/site-packages/unidecode/x0b7.py | 258 + .../python3.8/site-packages/unidecode/x0b8.py | 258 + .../python3.8/site-packages/unidecode/x0b9.py | 258 + .../python3.8/site-packages/unidecode/x0ba.py | 258 + .../python3.8/site-packages/unidecode/x0bb.py | 258 + .../python3.8/site-packages/unidecode/x0bc.py | 258 + .../python3.8/site-packages/unidecode/x0bd.py | 258 + .../python3.8/site-packages/unidecode/x0be.py | 258 + .../python3.8/site-packages/unidecode/x0bf.py | 258 + .../python3.8/site-packages/unidecode/x0c0.py | 258 + .../python3.8/site-packages/unidecode/x0c1.py | 258 + .../python3.8/site-packages/unidecode/x0c2.py | 258 + .../python3.8/site-packages/unidecode/x0c3.py | 258 + .../python3.8/site-packages/unidecode/x0c4.py | 258 + .../python3.8/site-packages/unidecode/x0c5.py | 258 + .../python3.8/site-packages/unidecode/x0c6.py | 258 + .../python3.8/site-packages/unidecode/x0c7.py | 258 + .../python3.8/site-packages/unidecode/x0c8.py | 258 + .../python3.8/site-packages/unidecode/x0c9.py | 258 + .../python3.8/site-packages/unidecode/x0ca.py | 258 + .../python3.8/site-packages/unidecode/x0cb.py | 258 + .../python3.8/site-packages/unidecode/x0cc.py | 258 + .../python3.8/site-packages/unidecode/x0cd.py | 258 + .../python3.8/site-packages/unidecode/x0ce.py | 258 + .../python3.8/site-packages/unidecode/x0cf.py | 258 + .../python3.8/site-packages/unidecode/x0d0.py | 258 + .../python3.8/site-packages/unidecode/x0d1.py | 258 + .../python3.8/site-packages/unidecode/x0d2.py | 258 + .../python3.8/site-packages/unidecode/x0d3.py | 258 + .../python3.8/site-packages/unidecode/x0d4.py | 258 + .../python3.8/site-packages/unidecode/x0d5.py | 258 + .../python3.8/site-packages/unidecode/x0d6.py | 258 + .../python3.8/site-packages/unidecode/x0d7.py | 257 + .../python3.8/site-packages/unidecode/x0f9.py | 258 + .../python3.8/site-packages/unidecode/x0fa.py | 257 + .../python3.8/site-packages/unidecode/x0fb.py | 258 + .../python3.8/site-packages/unidecode/x0fc.py | 258 + .../python3.8/site-packages/unidecode/x0fd.py | 257 + .../python3.8/site-packages/unidecode/x0fe.py | 258 + .../python3.8/site-packages/unidecode/x0ff.py | 258 + .../python3.8/site-packages/unidecode/x1d4.py | 258 + .../python3.8/site-packages/unidecode/x1d5.py | 258 + .../python3.8/site-packages/unidecode/x1d6.py | 258 + .../python3.8/site-packages/unidecode/x1d7.py | 258 + .../python3.8/site-packages/unidecode/x1f1.py | 258 + .../wheel-0.34.2.dist-info/INSTALLER | 1 + .../wheel-0.34.2.dist-info/LICENSE.txt | 22 + .../wheel-0.34.2.dist-info/METADATA | 66 + .../wheel-0.34.2.dist-info/RECORD | 44 + .../wheel-0.34.2.dist-info/WHEEL | 6 + .../wheel-0.34.2.dist-info/entry_points.txt | 6 + .../wheel-0.34.2.dist-info/top_level.txt | 1 + .../site-packages/wheel-0.34.2.virtualenv | 0 .../python3.8/site-packages/wheel/__init__.py | 1 + .../python3.8/site-packages/wheel/__main__.py | 19 + .../python3.8/site-packages/wheel/_version.py | 4 + .../site-packages/wheel/bdist_wheel.py | 403 + .../site-packages/wheel/cli/__init__.py | 88 + .../site-packages/wheel/cli/convert.py | 269 + .../site-packages/wheel/cli/install.py | 0 .../python3.8/site-packages/wheel/cli/pack.py | 79 + .../site-packages/wheel/cli/unpack.py | 25 + .../site-packages/wheel/macosx_libfile.py | 341 + .../python3.8/site-packages/wheel/metadata.py | 138 + .../site-packages/wheel/pep425tags.py | 261 + .../python3.8/site-packages/wheel/pkginfo.py | 43 + env/lib/python3.8/site-packages/wheel/util.py | 46 + .../site-packages/wheel/wheelfile.py | 169 + env/pyvenv.cfg | 8 + 2062 files changed, 408102 insertions(+) create mode 100644 content/fazendo-backup-do-banco-de-dados-no-django.md create mode 100644 content/images/JacksonOsvaldo/django_db.png create mode 100644 env/bin/activate create mode 100644 env/bin/activate.csh create mode 100644 env/bin/activate.fish create mode 100644 env/bin/activate.ps1 create mode 100644 env/bin/activate.xsh create mode 100644 env/bin/activate_this.py create mode 100755 env/bin/easy_install create mode 100755 env/bin/easy_install-3.8 create mode 100755 env/bin/easy_install3 create mode 100755 env/bin/markdown_py create mode 100755 env/bin/pelican create mode 100755 env/bin/pelican-import create mode 100755 env/bin/pelican-quickstart create mode 100755 env/bin/pelican-themes create mode 100755 env/bin/pip create mode 100755 env/bin/pip-3.8 create mode 100755 env/bin/pip3 create mode 100755 env/bin/pip3.8 create mode 100755 env/bin/pygmentize create mode 120000 env/bin/python create mode 120000 env/bin/python3 create mode 120000 env/bin/python3.8 create mode 100755 env/bin/rst2html.py create mode 100755 env/bin/rst2html4.py create mode 100755 env/bin/rst2html5.py create mode 100755 env/bin/rst2latex.py create mode 100755 env/bin/rst2man.py create mode 100755 env/bin/rst2odt.py create mode 100755 env/bin/rst2odt_prepstyles.py create mode 100755 env/bin/rst2pseudoxml.py create mode 100755 env/bin/rst2s5.py create mode 100755 env/bin/rst2xetex.py create mode 100755 env/bin/rst2xml.py create mode 100755 env/bin/rstpep2html.py create mode 100755 env/bin/unidecode create mode 100755 env/bin/wheel create mode 100755 env/bin/wheel-3.8 create mode 100755 env/bin/wheel3 create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/LICENSE.md create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/AUTHORS create mode 100644 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/INSTALLER create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/LICENSE create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/RECORD create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/WHEEL create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/entry_points.txt create mode 100755 env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/DESCRIPTION.rst create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/LICENSE.txt create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/metadata.json create mode 100644 env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/_virtualenv.pth create mode 100644 env/lib/python3.8/site-packages/_virtualenv.py create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/AUTHORS create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/LICENSE create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/blinker-1.4.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/blinker/__init__.py create mode 100644 env/lib/python3.8/site-packages/blinker/_saferef.py create mode 100644 env/lib/python3.8/site-packages/blinker/_utilities.py create mode 100644 env/lib/python3.8/site-packages/blinker/base.py create mode 100644 env/lib/python3.8/site-packages/dateutil/__init__.py create mode 100644 env/lib/python3.8/site-packages/dateutil/_common.py create mode 100644 env/lib/python3.8/site-packages/dateutil/_version.py create mode 100644 env/lib/python3.8/site-packages/dateutil/easter.py create mode 100644 env/lib/python3.8/site-packages/dateutil/parser/__init__.py create mode 100644 env/lib/python3.8/site-packages/dateutil/parser/_parser.py create mode 100644 env/lib/python3.8/site-packages/dateutil/parser/isoparser.py create mode 100644 env/lib/python3.8/site-packages/dateutil/relativedelta.py create mode 100644 env/lib/python3.8/site-packages/dateutil/rrule.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tz/__init__.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tz/_common.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tz/_factories.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tz/tz.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tz/win.py create mode 100644 env/lib/python3.8/site-packages/dateutil/tzwin.py create mode 100644 env/lib/python3.8/site-packages/dateutil/utils.py create mode 100644 env/lib/python3.8/site-packages/dateutil/zoneinfo/__init__.py create mode 100644 env/lib/python3.8/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz create mode 100644 env/lib/python3.8/site-packages/dateutil/zoneinfo/rebuild.py create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/COPYING.txt create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/docutils-0.16.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/docutils/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/core.py create mode 100644 env/lib/python3.8/site-packages/docutils/examples.py create mode 100644 env/lib/python3.8/site-packages/docutils/frontend.py create mode 100644 env/lib/python3.8/site-packages/docutils/io.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/af.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/ca.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/cs.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/da.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/de.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/en.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/eo.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/es.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/fa.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/fi.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/fr.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/gl.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/he.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/it.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/ja.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/ko.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/lt.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/lv.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/nl.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/pl.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/pt_br.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/ru.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/sk.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/sv.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/zh_cn.py create mode 100644 env/lib/python3.8/site-packages/docutils/languages/zh_tw.py create mode 100644 env/lib/python3.8/site-packages/docutils/nodes.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/null.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/admonitions.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/body.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/html.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/images.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/misc.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/parts.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/references.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/directives/tables.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/README.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamsa.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamsb.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamsc.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamsn.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamso.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isoamsr.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isobox.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isocyr1.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isocyr2.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isodia.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isogrk1.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isogrk2.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isogrk3.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isogrk4-wide.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isogrk4.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isolat1.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isolat2.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomfrk-wide.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomfrk.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomopf-wide.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomopf.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomscr-wide.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isomscr.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isonum.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isopub.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/isotech.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/mmlalias.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/mmlextra-wide.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/mmlextra.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/s5defs.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/xhtml1-lat1.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/xhtml1-special.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/include/xhtml1-symbol.txt create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/af.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/ca.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/cs.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/da.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/de.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/en.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/eo.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/es.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/fa.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/fi.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/fr.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/gl.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/he.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/it.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/ja.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/ko.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/lt.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/lv.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/nl.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/pl.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/pt_br.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/ru.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/sk.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/sv.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/zh_cn.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/languages/zh_tw.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/roles.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/states.py create mode 100644 env/lib/python3.8/site-packages/docutils/parsers/rst/tableparser.py create mode 100644 env/lib/python3.8/site-packages/docutils/readers/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/readers/doctree.py create mode 100644 env/lib/python3.8/site-packages/docutils/readers/pep.py create mode 100644 env/lib/python3.8/site-packages/docutils/readers/standalone.py create mode 100644 env/lib/python3.8/site-packages/docutils/statemachine.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/components.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/frontmatter.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/misc.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/parts.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/peps.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/references.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/universal.py create mode 100644 env/lib/python3.8/site-packages/docutils/transforms/writer_aux.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/code_analyzer.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/error_reporting.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/latex2mathml.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/math2html.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/tex2mathml_extern.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/tex2unichar.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/math/unichar2tex.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/punctuation_chars.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/roman.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/smartquotes.py create mode 100644 env/lib/python3.8/site-packages/docutils/utils/urischemes.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/_html_base.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/docutils_xml.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html4css1/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html4css1/html4css1.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html4css1/template.txt create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html5_polyglot/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html5_polyglot/math.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html5_polyglot/minimal.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html5_polyglot/plain.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/html5_polyglot/template.txt create mode 100644 env/lib/python3.8/site-packages/docutils/writers/latex2e/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/latex2e/default.tex create mode 100644 env/lib/python3.8/site-packages/docutils/writers/latex2e/titlepage.tex create mode 100644 env/lib/python3.8/site-packages/docutils/writers/latex2e/xelatex.tex create mode 100644 env/lib/python3.8/site-packages/docutils/writers/manpage.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/null.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/odf_odt/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/odf_odt/pygmentsformatter.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/odf_odt/styles.odt create mode 100644 env/lib/python3.8/site-packages/docutils/writers/pep_html/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/pep_html/pep.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/pep_html/template.txt create mode 100644 env/lib/python3.8/site-packages/docutils/writers/pseudoxml.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/__init__.py create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/README.txt create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/big-black/__base__ create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/big-black/framing.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/big-black/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/big-white/framing.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/big-white/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/blank.gif create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/framing.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/iepngfix.htc create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/opera.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/outline.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/print.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/s5-core.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/slides.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/default/slides.js create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/medium-black/__base__ create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/medium-black/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/medium-white/framing.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/medium-white/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/small-black/__base__ create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/small-black/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/small-white/framing.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/s5_html/themes/small-white/pretty.css create mode 100644 env/lib/python3.8/site-packages/docutils/writers/xetex/__init__.py create mode 100644 env/lib/python3.8/site-packages/easy-install.pth create mode 100644 env/lib/python3.8/site-packages/easy_install.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/LICENSE create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/feedgenerator-1.9.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/feedgenerator/__init__.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/__init__.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/__init__.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/datetime_safe.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/encoding.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/feedgenerator.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/functional.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/six.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/timezone.py create mode 100644 env/lib/python3.8/site-packages/feedgenerator/django/utils/xmlutils.py create mode 100644 env/lib/python3.8/site-packages/jinja2/__init__.py create mode 100644 env/lib/python3.8/site-packages/jinja2/_compat.py create mode 100644 env/lib/python3.8/site-packages/jinja2/_identifier.py create mode 100644 env/lib/python3.8/site-packages/jinja2/asyncfilters.py create mode 100644 env/lib/python3.8/site-packages/jinja2/asyncsupport.py create mode 100644 env/lib/python3.8/site-packages/jinja2/bccache.py create mode 100644 env/lib/python3.8/site-packages/jinja2/compiler.py create mode 100644 env/lib/python3.8/site-packages/jinja2/constants.py create mode 100644 env/lib/python3.8/site-packages/jinja2/debug.py create mode 100644 env/lib/python3.8/site-packages/jinja2/defaults.py create mode 100644 env/lib/python3.8/site-packages/jinja2/environment.py create mode 100644 env/lib/python3.8/site-packages/jinja2/exceptions.py create mode 100644 env/lib/python3.8/site-packages/jinja2/ext.py create mode 100644 env/lib/python3.8/site-packages/jinja2/filters.py create mode 100644 env/lib/python3.8/site-packages/jinja2/idtracking.py create mode 100644 env/lib/python3.8/site-packages/jinja2/lexer.py create mode 100644 env/lib/python3.8/site-packages/jinja2/loaders.py create mode 100644 env/lib/python3.8/site-packages/jinja2/meta.py create mode 100644 env/lib/python3.8/site-packages/jinja2/nativetypes.py create mode 100644 env/lib/python3.8/site-packages/jinja2/nodes.py create mode 100644 env/lib/python3.8/site-packages/jinja2/optimizer.py create mode 100644 env/lib/python3.8/site-packages/jinja2/parser.py create mode 100644 env/lib/python3.8/site-packages/jinja2/runtime.py create mode 100644 env/lib/python3.8/site-packages/jinja2/sandbox.py create mode 100644 env/lib/python3.8/site-packages/jinja2/tests.py create mode 100644 env/lib/python3.8/site-packages/jinja2/utils.py create mode 100644 env/lib/python3.8/site-packages/jinja2/visitor.py create mode 100644 env/lib/python3.8/site-packages/markdown/__init__.py create mode 100644 env/lib/python3.8/site-packages/markdown/__main__.py create mode 100644 env/lib/python3.8/site-packages/markdown/__meta__.py create mode 100644 env/lib/python3.8/site-packages/markdown/blockparser.py create mode 100644 env/lib/python3.8/site-packages/markdown/blockprocessors.py create mode 100644 env/lib/python3.8/site-packages/markdown/core.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/__init__.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/abbr.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/admonition.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/attr_list.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/codehilite.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/def_list.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/extra.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/fenced_code.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/footnotes.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/legacy_attrs.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/legacy_em.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/md_in_html.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/meta.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/nl2br.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/sane_lists.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/smarty.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/tables.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/toc.py create mode 100644 env/lib/python3.8/site-packages/markdown/extensions/wikilinks.py create mode 100644 env/lib/python3.8/site-packages/markdown/htmlparser.py create mode 100644 env/lib/python3.8/site-packages/markdown/inlinepatterns.py create mode 100644 env/lib/python3.8/site-packages/markdown/pep562.py create mode 100644 env/lib/python3.8/site-packages/markdown/postprocessors.py create mode 100644 env/lib/python3.8/site-packages/markdown/preprocessors.py create mode 100644 env/lib/python3.8/site-packages/markdown/serializers.py create mode 100644 env/lib/python3.8/site-packages/markdown/test_tools.py create mode 100644 env/lib/python3.8/site-packages/markdown/treeprocessors.py create mode 100644 env/lib/python3.8/site-packages/markdown/util.py create mode 100644 env/lib/python3.8/site-packages/markupsafe/__init__.py create mode 100644 env/lib/python3.8/site-packages/markupsafe/_compat.py create mode 100644 env/lib/python3.8/site-packages/markupsafe/_constants.py create mode 100644 env/lib/python3.8/site-packages/markupsafe/_native.py create mode 100644 env/lib/python3.8/site-packages/markupsafe/_speedups.c create mode 100755 env/lib/python3.8/site-packages/markupsafe/_speedups.cpython-38-x86_64-linux-gnu.so create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/DESCRIPTION.rst create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/metadata.json create mode 100644 env/lib/python3.8/site-packages/pelican-3.7.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/pelican-alias.egg-link create mode 100644 env/lib/python3.8/site-packages/pelican/__init__.py create mode 100644 env/lib/python3.8/site-packages/pelican/cache.py create mode 100644 env/lib/python3.8/site-packages/pelican/contents.py create mode 100644 env/lib/python3.8/site-packages/pelican/generators.py create mode 100644 env/lib/python3.8/site-packages/pelican/log.py create mode 100644 env/lib/python3.8/site-packages/pelican/paginator.py create mode 100644 env/lib/python3.8/site-packages/pelican/readers.py create mode 100644 env/lib/python3.8/site-packages/pelican/rstdirectives.py create mode 100644 env/lib/python3.8/site-packages/pelican/server.py create mode 100644 env/lib/python3.8/site-packages/pelican/settings.py create mode 100644 env/lib/python3.8/site-packages/pelican/signals.py create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/css/main.css create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/css/pygment.css create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/css/reset.css create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/css/typogrify.css create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/css/wide.css create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/aboutme.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/bitbucket.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/delicious.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/facebook.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/github.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/gitorious.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/gittip.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/google-groups.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/google-plus.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/hackernews.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/lastfm.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/linkedin.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/reddit.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/rss.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/slideshare.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/speakerdeck.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/stackoverflow.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/twitter.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/vimeo.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/static/images/icons/youtube.png create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/analytics.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/archives.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/article.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/article_infos.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/author.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/authors.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/base.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/category.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/comments.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/disqus_script.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/github.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/index.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/page.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/period_archives.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/tag.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/taglist.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/tags.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/translations.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/notmyidea/templates/twitter.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/archives.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/article.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/author.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/authors.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/base.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/categories.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/category.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/gosquared.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/index.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/page.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/pagination.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/period_archives.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/tag.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/tags.html create mode 100644 env/lib/python3.8/site-packages/pelican/themes/simple/templates/translations.html create mode 100644 env/lib/python3.8/site-packages/pelican/tools/__init__.py create mode 100644 env/lib/python3.8/site-packages/pelican/tools/pelican_import.py create mode 100644 env/lib/python3.8/site-packages/pelican/tools/pelican_quickstart.py create mode 100644 env/lib/python3.8/site-packages/pelican/tools/pelican_themes.py create mode 100644 env/lib/python3.8/site-packages/pelican/tools/templates/Makefile.in create mode 100755 env/lib/python3.8/site-packages/pelican/tools/templates/develop_server.sh.in create mode 100644 env/lib/python3.8/site-packages/pelican/tools/templates/fabfile.py.in create mode 100644 env/lib/python3.8/site-packages/pelican/tools/templates/pelicanconf.py.in create mode 100755 env/lib/python3.8/site-packages/pelican/tools/templates/publishconf.py.in create mode 100644 env/lib/python3.8/site-packages/pelican/urlwrappers.py create mode 100644 env/lib/python3.8/site-packages/pelican/utils.py create mode 100644 env/lib/python3.8/site-packages/pelican/writers.py create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/DESCRIPTION.rst create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/metadata.json create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo-0.1.2.dist-info/zip-safe create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo/__init__.py create mode 100644 env/lib/python3.8/site-packages/pelican_vimeo/vimeo.py create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/DESCRIPTION.rst create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/metadata.json create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/pelican_youtube-0.2.1.dist-info/zip-safe create mode 100644 env/lib/python3.8/site-packages/pelican_youtube/__init__.py create mode 100644 env/lib/python3.8/site-packages/pelican_youtube/youtube.py create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/LICENSE.txt create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/pip-20.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/pip-20.1.virtualenv create mode 100644 env/lib/python3.8/site-packages/pip/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/__main__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/build_env.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/base_command.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/command_context.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/main.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/parser.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/req_command.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/spinners.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/check.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/completion.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/configuration.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/debug.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/download.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/freeze.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/hash.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/help.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/install.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/list.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/search.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/show.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/commands/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/configuration.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/distributions/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/distributions/installed.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/exceptions.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/index/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/index/collector.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/index/package_finder.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/locations.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/main.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/candidate.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/direct_url.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/format_control.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/index.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/link.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/scheme.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/search_scope.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/target_python.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/models/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/auth.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/download.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/session.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/utils.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/check.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/freeze.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/operations/prepare.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/pyproject.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/constructors.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/req_file.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/req_install.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/req_set.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/encoding.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/glibc.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/hashes.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/logging.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/misc.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/models.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/packaging.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/typing.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/urls.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/utils/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/git.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 env/lib/python3.8/site-packages/pip/_internal/wheel_builder.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/appdirs.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/certifi/core.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/enums.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langcyrillicmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/chardet/version.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/win32.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/contextlib2.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/misc.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/tarfile.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/database.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/index.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/markers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/resources.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/util.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/version.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/distro.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_tokenizer.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/_base.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/datrie.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/py.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/lint.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/optionaltags.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/whitespace.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/sax.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/dom.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/base.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/dom.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/genshi.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/codec.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/core.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/intranges.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/ipaddress.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/_typing.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/tags.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/packaging/version.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/build.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/check.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/meta.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/progress/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/progress/bar.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/progress/counter.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/progress/spinner.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/pyparsing.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/adapters.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/api.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/auth.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/certs.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/compat.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/cookies.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/help.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/hooks.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/models.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/packages.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/structures.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/requests/utils.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/retrying.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/six.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml/decoder.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml/encoder.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml/ordered.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/toml/tz.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/vendor.txt create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 env/lib/python3.8/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/__init__.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/_vendor/six.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/extern/__init__.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/py2_warn.py create mode 100644 env/lib/python3.8/site-packages/pkg_resources/py31compat.py create mode 100755 env/lib/python3.8/site-packages/pygments/__init__.py create mode 100755 env/lib/python3.8/site-packages/pygments/__main__.py create mode 100755 env/lib/python3.8/site-packages/pygments/cmdline.py create mode 100755 env/lib/python3.8/site-packages/pygments/console.py create mode 100755 env/lib/python3.8/site-packages/pygments/filter.py create mode 100755 env/lib/python3.8/site-packages/pygments/filters/__init__.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatter.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/__init__.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/_mapping.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/bbcode.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/html.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/img.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/irc.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/latex.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/other.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/rtf.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/svg.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/terminal.py create mode 100755 env/lib/python3.8/site-packages/pygments/formatters/terminal256.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexer.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/__init__.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_asy_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_cl_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_cocoa_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_csound_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_lasso_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_lua_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_mapping.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_mql_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_mysql_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_openedge_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_php_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_postgres_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_scilab_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_sourcemod_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_stan_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_stata_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_tsql_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_usd_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_vbscript_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/_vim_builtins.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/actionscript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/agile.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/algebra.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ambient.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ampl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/apl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/archetype.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/arrow.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/asm.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/automation.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/bare.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/basic.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/bibtex.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/boa.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/business.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/c_cpp.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/c_like.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/capnproto.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/chapel.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/clean.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/compiled.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/configs.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/console.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/crystal.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/csound.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/css.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/d.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/dalvik.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/data.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/devicetree.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/diff.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/dotnet.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/dsls.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/dylan.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ecl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/eiffel.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/elm.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/email.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/erlang.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/esoteric.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ezhil.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/factor.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/fantom.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/felix.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/floscript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/forth.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/fortran.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/foxpro.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/freefem.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/functional.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/gdscript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/go.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/grammar_notation.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/graph.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/graphics.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/haskell.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/haxe.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/hdl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/hexdump.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/html.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/idl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/igor.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/inferno.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/installers.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/int_fiction.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/iolang.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/j.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/javascript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/julia.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/jvm.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/lisp.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/make.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/markup.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/math.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/matlab.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/mime.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ml.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/modeling.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/modula2.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/monte.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/mosel.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ncl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/nimrod.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/nit.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/nix.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/oberon.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/objective.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ooc.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/other.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/parasail.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/parsers.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/pascal.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/pawn.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/perl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/php.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/pointless.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/pony.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/praat.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/prolog.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/promql.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/python.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/qvt.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/r.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/rdf.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/rebol.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/resource.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ride.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/rnc.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/roboconf.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/robotframework.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/ruby.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/rust.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/sas.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/scdoc.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/scripting.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/sgf.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/shell.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/sieve.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/slash.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/smalltalk.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/smv.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/snobol.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/solidity.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/special.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/sql.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/stata.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/supercollider.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/tcl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/templates.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/teraterm.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/testing.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/text.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/textedit.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/textfmts.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/theorem.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/tnt.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/trafficscript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/typoscript.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/unicon.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/urbi.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/usd.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/varnish.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/verification.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/web.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/webidl.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/webmisc.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/whiley.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/x10.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/xorg.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/yang.py create mode 100755 env/lib/python3.8/site-packages/pygments/lexers/zig.py create mode 100755 env/lib/python3.8/site-packages/pygments/modeline.py create mode 100755 env/lib/python3.8/site-packages/pygments/plugin.py create mode 100755 env/lib/python3.8/site-packages/pygments/regexopt.py create mode 100755 env/lib/python3.8/site-packages/pygments/scanner.py create mode 100755 env/lib/python3.8/site-packages/pygments/sphinxext.py create mode 100755 env/lib/python3.8/site-packages/pygments/style.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/__init__.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/abap.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/algol.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/algol_nu.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/arduino.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/autumn.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/borland.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/bw.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/colorful.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/default.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/emacs.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/friendly.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/fruity.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/igor.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/inkpot.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/lovelace.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/manni.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/monokai.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/murphy.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/native.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/paraiso_dark.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/paraiso_light.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/pastie.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/perldoc.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/rainbow_dash.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/rrt.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/sas.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/solarized.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/stata_dark.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/stata_light.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/tango.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/trac.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/vim.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/vs.py create mode 100755 env/lib/python3.8/site-packages/pygments/styles/xcode.py create mode 100755 env/lib/python3.8/site-packages/pygments/token.py create mode 100755 env/lib/python3.8/site-packages/pygments/unistring.py create mode 100755 env/lib/python3.8/site-packages/pygments/util.py create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/LICENSE create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/python_dateutil-2.8.1.dist-info/zip-safe create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/DESCRIPTION.rst create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/LICENSE.txt create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/metadata.json create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/pytz-2020.1.dist-info/zip-safe create mode 100644 env/lib/python3.8/site-packages/pytz/__init__.py create mode 100644 env/lib/python3.8/site-packages/pytz/exceptions.py create mode 100644 env/lib/python3.8/site-packages/pytz/lazy.py create mode 100644 env/lib/python3.8/site-packages/pytz/reference.py create mode 100644 env/lib/python3.8/site-packages/pytz/tzfile.py create mode 100644 env/lib/python3.8/site-packages/pytz/tzinfo.py create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Addis_Ababa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Banjul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bissau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bujumbura create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Casablanca create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/El_Aaiun create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Freetown create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Gaborone create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Juba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kampala create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lagos create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Libreville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lome create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Luanda create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lubumbashi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maputo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mbabane create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mogadishu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nairobi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Niamey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nouakchott create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ouagadougou create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Porto-Novo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Sao_Tome create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Timbuktu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tripoli create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tunis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Anguilla create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Antigua create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Araguaina create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Catamarca create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Jujuy create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Juan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia_Banderas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Blanc-Sablon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Bogota create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cambridge_Bay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Caracas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Coral_Harbour create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Costa_Rica create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Creston create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Cuiaba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson_Creek create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Detroit create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Ensenada create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Fortaleza create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Glace_Bay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Godthab create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Grand_Turk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Guyana create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Havana create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Knox create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Petersburg create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vevay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vincennes create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Inuvik create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Iqaluit create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Juneau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Louisville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Knox_IN create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Los_Angeles create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Louisville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Manaus create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Marigot create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Martinique create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Moncton create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Montevideo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Montreal create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Nome create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Panama create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Velho create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Punta_Arenas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Rainy_River create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Regina create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Rosario create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Santa_Isabel create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Sao_Paulo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Sitka create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Thunder_Bay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Tijuana create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Virgin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Whitehorse create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Macquarie create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Mawson create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/McMurdo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Rothera create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/South_Pole create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aden create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Almaty create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Anadyr create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtobe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bangkok create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Beirut create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bishkek create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Brunei create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Calcutta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chita create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Choibalsan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chongqing create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dubai create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Harbin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jayapura create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jerusalem create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kamchatka create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kashgar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Makassar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Muscat create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novosibirsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Oral create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qyzylorda create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Rangoon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Srednekolymsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Taipei create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tomsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulan_Bator create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Urumqi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yangon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yerevan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Azores create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faroe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Madeira create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/ACT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Brisbane create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Canberra create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Darwin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Eucla create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/LHI create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lindeman create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Melbourne create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/NSW create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Perth create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Sydney create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Victoria create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/West create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/Acre create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/DeNoronha create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/CET create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Central create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Saskatchewan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Cuba create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/EET create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/EST create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Egypt create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Eire create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Factory create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GB create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GMT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/HST create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Iceland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Iran create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Israel create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Japan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Libya create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/MET create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/MST create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/NZ create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Navajo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/PRC create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Poland create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Portugal create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/ROC create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/ROK create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Singapore create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Turkey create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/UCT create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Central create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/UTC create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Universal create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/W-SU create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/WET create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/Zulu create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/posixrules create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab create mode 100644 env/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/LICENSE create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/dependency_links.txt create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.dist-info/zip-safe create mode 100644 env/lib/python3.8/site-packages/setuptools-46.1.3.virtualenv create mode 100644 env/lib/python3.8/site-packages/setuptools/__init__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_deprecation_warning.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_imp.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/__init__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 env/lib/python3.8/site-packages/setuptools/_vendor/six.py create mode 100644 env/lib/python3.8/site-packages/setuptools/archive_util.py create mode 100644 env/lib/python3.8/site-packages/setuptools/build_meta.py create mode 100644 env/lib/python3.8/site-packages/setuptools/cli-32.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/cli-64.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/cli.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/command/__init__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/alias.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/bdist_egg.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/build_clib.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/build_ext.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/build_py.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/develop.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/dist_info.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/easy_install.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/egg_info.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/install.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/install_egg_info.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/install_lib.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/install_scripts.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml create mode 100644 env/lib/python3.8/site-packages/setuptools/command/py36compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/register.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/rotate.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/saveopts.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/sdist.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/setopt.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/test.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/upload.py create mode 100644 env/lib/python3.8/site-packages/setuptools/command/upload_docs.py create mode 100644 env/lib/python3.8/site-packages/setuptools/config.py create mode 100644 env/lib/python3.8/site-packages/setuptools/dep_util.py create mode 100644 env/lib/python3.8/site-packages/setuptools/depends.py create mode 100644 env/lib/python3.8/site-packages/setuptools/dist.py create mode 100644 env/lib/python3.8/site-packages/setuptools/errors.py create mode 100644 env/lib/python3.8/site-packages/setuptools/extension.py create mode 100644 env/lib/python3.8/site-packages/setuptools/extern/__init__.py create mode 100644 env/lib/python3.8/site-packages/setuptools/glob.py create mode 100644 env/lib/python3.8/site-packages/setuptools/gui-32.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/gui-64.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/gui.exe create mode 100644 env/lib/python3.8/site-packages/setuptools/installer.py create mode 100644 env/lib/python3.8/site-packages/setuptools/launch.py create mode 100644 env/lib/python3.8/site-packages/setuptools/lib2to3_ex.py create mode 100644 env/lib/python3.8/site-packages/setuptools/monkey.py create mode 100644 env/lib/python3.8/site-packages/setuptools/msvc.py create mode 100644 env/lib/python3.8/site-packages/setuptools/namespaces.py create mode 100644 env/lib/python3.8/site-packages/setuptools/package_index.py create mode 100644 env/lib/python3.8/site-packages/setuptools/py27compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/py31compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/py33compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/py34compat.py create mode 100644 env/lib/python3.8/site-packages/setuptools/sandbox.py create mode 100644 env/lib/python3.8/site-packages/setuptools/script (dev).tmpl create mode 100644 env/lib/python3.8/site-packages/setuptools/script.tmpl create mode 100644 env/lib/python3.8/site-packages/setuptools/site-patch.py create mode 100644 env/lib/python3.8/site-packages/setuptools/ssl_support.py create mode 100644 env/lib/python3.8/site-packages/setuptools/unicode_utils.py create mode 100644 env/lib/python3.8/site-packages/setuptools/version.py create mode 100644 env/lib/python3.8/site-packages/setuptools/wheel.py create mode 100644 env/lib/python3.8/site-packages/setuptools/windows_support.py create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/LICENSE create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/six-1.15.0.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/six.py create mode 100644 env/lib/python3.8/site-packages/unidecode/__init__.py create mode 100644 env/lib/python3.8/site-packages/unidecode/__main__.py create mode 100644 env/lib/python3.8/site-packages/unidecode/util.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x000.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x001.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x002.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x003.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x004.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x005.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x006.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x007.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x009.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x00f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x010.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x011.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x012.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x013.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x014.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x015.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x016.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x017.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x018.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x01d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x01e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x01f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x020.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x021.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x022.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x023.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x024.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x025.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x026.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x027.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x028.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x029.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x02a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x02c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x02e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x02f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x030.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x031.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x032.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x033.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x04d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x04e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x04f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x050.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x051.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x052.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x053.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x054.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x055.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x056.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x057.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x058.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x059.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x05f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x060.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x061.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x062.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x063.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x064.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x065.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x066.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x067.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x068.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x069.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x06f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x070.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x071.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x072.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x073.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x074.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x075.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x076.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x077.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x078.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x079.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x07f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x080.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x081.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x082.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x083.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x084.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x085.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x086.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x087.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x088.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x089.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x08f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x090.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x091.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x092.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x093.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x094.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x095.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x096.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x097.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x098.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x099.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09a.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09b.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09c.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09d.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09e.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x09f.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0a0.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0a1.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0a2.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0a3.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0a4.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ac.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ad.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ae.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0af.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b0.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b1.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b2.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b3.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b4.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b5.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b6.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b7.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b8.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0b9.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ba.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0bb.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0bc.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0bd.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0be.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0bf.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c0.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c1.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c2.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c3.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c4.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c5.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c6.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c7.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c8.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0c9.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ca.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0cb.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0cc.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0cd.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ce.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0cf.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d0.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d1.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d2.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d3.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d4.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d5.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d6.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0d7.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0f9.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0fa.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0fb.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0fc.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0fd.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0fe.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x0ff.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x1d4.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x1d5.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x1d6.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x1d7.py create mode 100644 env/lib/python3.8/site-packages/unidecode/x1f1.py create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/INSTALLER create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/LICENSE.txt create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/METADATA create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/RECORD create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/WHEEL create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/entry_points.txt create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.dist-info/top_level.txt create mode 100644 env/lib/python3.8/site-packages/wheel-0.34.2.virtualenv create mode 100644 env/lib/python3.8/site-packages/wheel/__init__.py create mode 100644 env/lib/python3.8/site-packages/wheel/__main__.py create mode 100644 env/lib/python3.8/site-packages/wheel/_version.py create mode 100644 env/lib/python3.8/site-packages/wheel/bdist_wheel.py create mode 100644 env/lib/python3.8/site-packages/wheel/cli/__init__.py create mode 100644 env/lib/python3.8/site-packages/wheel/cli/convert.py create mode 100644 env/lib/python3.8/site-packages/wheel/cli/install.py create mode 100644 env/lib/python3.8/site-packages/wheel/cli/pack.py create mode 100644 env/lib/python3.8/site-packages/wheel/cli/unpack.py create mode 100644 env/lib/python3.8/site-packages/wheel/macosx_libfile.py create mode 100644 env/lib/python3.8/site-packages/wheel/metadata.py create mode 100644 env/lib/python3.8/site-packages/wheel/pep425tags.py create mode 100644 env/lib/python3.8/site-packages/wheel/pkginfo.py create mode 100644 env/lib/python3.8/site-packages/wheel/util.py create mode 100644 env/lib/python3.8/site-packages/wheel/wheelfile.py create mode 100644 env/pyvenv.cfg diff --git a/content/fazendo-backup-do-banco-de-dados-no-django.md b/content/fazendo-backup-do-banco-de-dados-no-django.md new file mode 100644 index 000000000..7c0ec8a4b --- /dev/null +++ b/content/fazendo-backup-do-banco-de-dados-no-django.md @@ -0,0 +1,122 @@ +Title: Fazendo backup do banco de dados no Django +Date: 2020-10-27 22:19 +Tags: Python,Django,backup +Category: Python +Slug: fazendo-backup-do-banco-de-dados-no-django +Author: Jackson Osvaldo +Email: jacksonosvaldo@live.com +Github: JacksonOsvaldo +About_author: Um curioso apaixonado por livros, tecnologia e programação. + +## Apresentação + +Em algum momento, durante o seu processo de desenvolvimento com Django, pode ser que surja a necessidade de criar e restaurar o banco de dados da aplicação. Pensando nisso, resolvi fazer um pequeno tutorial, básico, de como realizar essa operação. + +Nesse tutorial, usaremos o [django-dbbackup](https://github.com/django-dbbackup/django-dbbackup), um pacote desenvolvido especificamente para isso. + +## Configurando nosso ambiente + +Primeiro, partindo do início, vamos criar uma pasta para o nosso projeto e, nela, isolar o nosso ambiente de desenvolvimento usando uma [virtualenv](https://virtualenv.pypa.io/en/latest/index.html): + +```shell +mkdir projeto_db && cd projeto_db #criando a pasta do nosso projeto + +virtualenv -p python3.8 env && source env/bin/activate #criando e ativando a nossa virtualenv +``` + +Depois disso e com o nosso ambiente já ativo, vamos realizar os seguintes procedimentos: + +```shell +pip install -U pip #com isso, atualizamos a verão do pip instalado +``` + +## Instalando as dependências + +Agora, vamos instalar o [Django](https://www.djangoproject.com/) e o pacote que usaremos para fazer nossos backups. + +```shell +pip install Django==3.1.2 #instalando o Django + +pip install django-dbbackup #instalando o django-dbbackup +``` + +## Criando e configurando projeto + +Depois de instaladas nossas dependências, vamos criar o nosso projeto e configurar o nosso pacote nas configurações do Django. + +```shell +django-admin startproject django_db . #dentro da nossa pasta projeto_db, criamos um projeto Django com o nome de django_db. +``` + +Depois de criado nosso projeto, vamos criar e popular o nosso banco de dados. + +```shell +python manage.py migrate #com isso, sincronizamos o estado do banco de dados com o conjunto atual de modelos e migrações. +``` + +Criado nosso banco de dados, vamos criar um superusuário para podemos o painel admin do nosso projeto. + +```shell +python manage.py createsuperuser +``` + +Perfeito. Já temos tudo que precisamos para executar nosso projeto. Para execução dele, é só fazermos: + +```shell +python manage.py runserver +``` + +Você terá uma imagem assim do seu projeto: + +![](https://jacksonosvaldo.github.io/img/django_db.png) + +## Configurando o django-dbbackup + +Dentro do seu projeto, vamos acessar o arquivo settings.py, como expresso abaixo: + +```shell +django_db/ +├── settings.py +``` + +Dentro desse arquivos iremos, primeiro, adiconar o django-dbbackup às apps do projeto: + +```python +INSTALLED_APPS = ( + ... + 'dbbackup', # adicionando django-dbbackup +) +``` + +Depois de adicionado às apps, vamos dizer para o Django o que vamos salvar no backup e, depois, indicar a pasta para onde será encaminhado esse arquivo. Essa inserção deve ou pode ser feita no final do arquivo _settings.py_: + +```python +DBBACKUP_STORAGE = 'django.core.files.storage.FileSystemStorage' #o que salvar +DBBACKUP_STORAGE_OPTIONS = {'location': 'backups/'} # onde salvar +``` + +Percebam que dissemos para o Django salvar o backup na pasta _backups_, mas essa pasta ainda não existe no nosso projeto. Por isso, precisamos criá-la [fora da pasta do projeto]: + +```shell +mkdir backups +``` + +## Criando e restaurando nosso backup + +Já temos tudo pronto. Agora, vamos criar o nosso primeiro backup: + +```shell +python manage.py dbbackup +``` + +Depois de exetudado, será criado um arquivo -- no nosso exemplo, esse arquivo terá uma extensão .dump --, salvo na pasta _backups_. Esse arquivo contem todo backup do nosso banco de dados. + +Para recuperarmos nosso banco, vamos supor que migramos nosso sistema de um servidor antigo para um novo e, por algum motivo, nossa base de dados foi corrompida, inviabilizando seu uso. Ou seja, estamos com o sistema/projeto sem banco de dados -- ou seja, exlua ou mova a a sua base dados .sqlite3 para que esse exemplo seja útil --, mas temos os backups. Com isso, vamos restaurar o banco: + +```shell +python manage.py dbrestore +``` + +Prontinho, restauramos nosso banco de dados. O interessante do django-dbbackup, dentre outras coisas, é que ele gera os backups com datas e horários específicos, facilitando o processo de recuperação das informações mais recentes. + +Por hoje é isso, pessoal. Até a próxima. ;) diff --git a/content/images/JacksonOsvaldo/django_db.png b/content/images/JacksonOsvaldo/django_db.png new file mode 100644 index 0000000000000000000000000000000000000000..ff3828743bac5fc8fdee9c99b7e080917a6e351d GIT binary patch literal 51134 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

1ORS*G#3_@mlPKM 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

Utyd$}*gLhYqTM=LtMGsn6hp^* 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 Fe*o%Re2f49 literal 0 HcmV?d00001 diff --git a/env/bin/activate b/env/bin/activate new file mode 100644 index 000000000..7a6a72737 --- /dev/null +++ b/env/bin/activate @@ -0,0 +1,84 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + + +if [ "${BASH_SOURCE-}" = "$0" ]; then + echo "You must source this script: \$ source $0" >&2 + exit 33 +fi + +deactivate () { + unset -f pydoc >/dev/null 2>&1 + + # reset old environment variables + # ! [ -z ${VAR+_} ] returns true if VAR is declared at all + if ! [ -z "${_OLD_VIRTUAL_PATH:+_}" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if ! [ -z "${_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-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null + fi + + if ! [ -z "${_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='/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env' +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +if ! [ -z "${PYTHONHOME+_}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1-}" + if [ "x" != x ] ; then + PS1="${PS1-}" + else + PS1="(`basename \"$VIRTUAL_ENV\"`) ${PS1-}" + fi + export PS1 +fi + +# Make sure to unalias pydoc if it's already there +alias pydoc 2>/dev/null >/dev/null && unalias pydoc || true + +pydoc () { + python -m pydoc "$@" +} + +# 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-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null +fi diff --git a/env/bin/activate.csh b/env/bin/activate.csh new file mode 100644 index 000000000..d2f808e1c --- /dev/null +++ b/env/bin/activate.csh @@ -0,0 +1,55 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . + +set newline='\ +' + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH:q" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT:q" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV '/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env' + +set _OLD_VIRTUAL_PATH="$PATH:q" +setenv PATH "$VIRTUAL_ENV:q/bin:$PATH:q" + + + +if ('' != "") then + set env_name = '' +else + set env_name = '('"$VIRTUAL_ENV:t:q"') ' +endif + +if ( $?VIRTUAL_ENV_DISABLE_PROMPT ) then + if ( $VIRTUAL_ENV_DISABLE_PROMPT == "" ) then + set do_prompt = "1" + else + set do_prompt = "0" + endif +else + set do_prompt = "1" +endif + +if ( $do_prompt == "1" ) then + # Could be in a non-interactive environment, + # in which case, $prompt is undefined and we wouldn't + # care about the prompt anyway. + if ( $?prompt ) then + set _OLD_VIRTUAL_PROMPT="$prompt:q" + if ( "$prompt:q" =~ *"$newline:q"* ) then + : + else + set prompt = "$env_name:q$prompt:q" + endif + endif +endif + +unset env_name +unset do_prompt + +alias pydoc python -m pydoc + +rehash diff --git a/env/bin/activate.fish b/env/bin/activate.fish new file mode 100644 index 000000000..70888e373 --- /dev/null +++ b/env/bin/activate.fish @@ -0,0 +1,100 @@ +# This file must be used using `source bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. +# Do not run it directly. + +function _bashify_path -d "Converts a fish path to something bash can recognize" + set fishy_path $argv + set bashy_path $fishy_path[1] + for path_part in $fishy_path[2..-1] + set bashy_path "$bashy_path:$path_part" + end + echo $bashy_path +end + +function _fishify_path -d "Converts a bash path to something fish can recognize" + echo $argv | tr ':' '\n' +end + +function deactivate -d 'Exit virtualenv mode and return to the normal environment.' + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + # https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling + if test (echo $FISH_VERSION | head -c 1) -lt 3 + set -gx PATH (_fishify_path "$_OLD_VIRTUAL_PATH") + else + set -gx PATH "$_OLD_VIRTUAL_PATH" + end + 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" + and functions -q _old_fish_prompt + # Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. + set -l fish_function_path + + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + end + + set -e VIRTUAL_ENV + + if test "$argv[1]" != 'nondestructive' + # Self-destruct! + functions -e pydoc + functions -e deactivate + functions -e _bashify_path + functions -e _fishify_path + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV '/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env' + +# https://github.com/fish-shell/fish-shell/issues/436 altered PATH handling +if test (echo $FISH_VERSION | head -c 1) -lt 3 + set -gx _OLD_VIRTUAL_PATH (_bashify_path $PATH) +else + set -gx _OLD_VIRTUAL_PATH "$PATH" +end +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 + +function pydoc + python -m pydoc $argv +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # Copy the current `fish_prompt` function as `_old_fish_prompt`. + functions -c fish_prompt _old_fish_prompt + + function fish_prompt + # Run the user's prompt first; it might depend on (pipe)status. + set -l prompt (_old_fish_prompt) + + # Prompt override provided? + # If not, just prepend the environment name. + if test -n '' + printf '%s%s' '' (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") + end + + string join -- \n $prompt # handle multi-line prompts + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/env/bin/activate.ps1 b/env/bin/activate.ps1 new file mode 100644 index 000000000..95504d395 --- /dev/null +++ b/env/bin/activate.ps1 @@ -0,0 +1,60 @@ +$script:THIS_PATH = $myinvocation.mycommand.path +$script:BASE_DIR = Split-Path (Resolve-Path "$THIS_PATH/..") -Parent + +function global:deactivate([switch] $NonDestructive) { + if (Test-Path variable:_OLD_VIRTUAL_PATH) { + $env:PATH = $variable:_OLD_VIRTUAL_PATH + Remove-Variable "_OLD_VIRTUAL_PATH" -Scope global + } + + if (Test-Path function:_old_virtual_prompt) { + $function:prompt = $function:_old_virtual_prompt + Remove-Item function:\_old_virtual_prompt + } + + if ($env:VIRTUAL_ENV) { + Remove-Item env:VIRTUAL_ENV -ErrorAction SilentlyContinue + } + + if (!$NonDestructive) { + # Self destruct! + Remove-Item function:deactivate + Remove-Item function:pydoc + } +} + +function global:pydoc { + python -m pydoc $args +} + +# unset irrelevant variables +deactivate -nondestructive + +$VIRTUAL_ENV = $BASE_DIR +$env:VIRTUAL_ENV = $VIRTUAL_ENV + +New-Variable -Scope global -Name _OLD_VIRTUAL_PATH -Value $env:PATH + +$env:PATH = "$env:VIRTUAL_ENV/bin:" + $env:PATH +if (!$env:VIRTUAL_ENV_DISABLE_PROMPT) { + function global:_old_virtual_prompt { + "" + } + $function:_old_virtual_prompt = $function:prompt + + if ("" -ne "") { + function global:prompt { + # Add the custom prefix to the existing prompt + $previous_prompt_value = & $function:_old_virtual_prompt + ("" + $previous_prompt_value) + } + } + else { + function global:prompt { + # Add a prefix to the current prompt, but don't discard it. + $previous_prompt_value = & $function:_old_virtual_prompt + $new_prompt_value = "($( Split-Path $env:VIRTUAL_ENV -Leaf )) " + ($new_prompt_value + $previous_prompt_value) + } + } +} diff --git a/env/bin/activate.xsh b/env/bin/activate.xsh new file mode 100644 index 000000000..4e62fa575 --- /dev/null +++ b/env/bin/activate.xsh @@ -0,0 +1,46 @@ +"""Xonsh activate script for virtualenv""" +from xonsh.tools import get_sep as _get_sep + +def _deactivate(args): + if "pydoc" in aliases: + del aliases["pydoc"] + + if ${...}.get("_OLD_VIRTUAL_PATH", ""): + $PATH = $_OLD_VIRTUAL_PATH + del $_OLD_VIRTUAL_PATH + + if ${...}.get("_OLD_VIRTUAL_PYTHONHOME", ""): + $PYTHONHOME = $_OLD_VIRTUAL_PYTHONHOME + del $_OLD_VIRTUAL_PYTHONHOME + + if "VIRTUAL_ENV" in ${...}: + del $VIRTUAL_ENV + + if "VIRTUAL_ENV_PROMPT" in ${...}: + del $VIRTUAL_ENV_PROMPT + + if "nondestructive" not in args: + # Self destruct! + del aliases["deactivate"] + + +# unset irrelevant variables +_deactivate(["nondestructive"]) +aliases["deactivate"] = _deactivate + +$VIRTUAL_ENV = r"/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env" + +$_OLD_VIRTUAL_PATH = $PATH +$PATH = $PATH[:] +$PATH.add($VIRTUAL_ENV + _get_sep() + "bin", front=True, replace=True) + +if ${...}.get("PYTHONHOME", ""): + # unset PYTHONHOME if set + $_OLD_VIRTUAL_PYTHONHOME = $PYTHONHOME + del $PYTHONHOME + +$VIRTUAL_ENV_PROMPT = "" +if not $VIRTUAL_ENV_PROMPT: + del $VIRTUAL_ENV_PROMPT + +aliases["pydoc"] = ["python", "-m", "pydoc"] diff --git a/env/bin/activate_this.py b/env/bin/activate_this.py new file mode 100644 index 000000000..447998698 --- /dev/null +++ b/env/bin/activate_this.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +"""Activate virtualenv for current interpreter: + +Use exec(open(this_file).read(), {'__file__': this_file}). + +This can be used when you must use an existing Python interpreter, not the virtualenv bin/python. +""" +import os +import site +import sys + +try: + abs_file = os.path.abspath(__file__) +except NameError: + raise AssertionError("You must use exec(open(this_file).read(), {'__file__': this_file}))") + +bin_dir = os.path.dirname(abs_file) +base = bin_dir[: -len("bin") - 1] # strip away the bin part from the __file__, plus the path separator + +# prepend bin to PATH (this file is inside the bin directory) +os.environ["PATH"] = os.pathsep.join([bin_dir] + os.environ.get("PATH", "").split(os.pathsep)) +os.environ["VIRTUAL_ENV"] = base # virtual env is right above bin directory + +# add the virtual environments libraries to the host python import mechanism +prev_length = len(sys.path) +for lib in "../lib/python3.8/site-packages".split(os.pathsep): + path = os.path.realpath(os.path.join(bin_dir, lib)) + site.addsitedir(path.decode("utf-8") if "" else path) +sys.path[:] = sys.path[prev_length:] + sys.path[0:prev_length] + +sys.real_prefix = sys.prefix +sys.prefix = base diff --git a/env/bin/easy_install b/env/bin/easy_install new file mode 100755 index 000000000..9aa78f0e3 --- /dev/null +++ b/env/bin/easy_install @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/easy_install-3.8 b/env/bin/easy_install-3.8 new file mode 100755 index 000000000..9aa78f0e3 --- /dev/null +++ b/env/bin/easy_install-3.8 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/easy_install3 b/env/bin/easy_install3 new file mode 100755 index 000000000..9aa78f0e3 --- /dev/null +++ b/env/bin/easy_install3 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/markdown_py b/env/bin/markdown_py new file mode 100755 index 000000000..977daded8 --- /dev/null +++ b/env/bin/markdown_py @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from markdown.__main__ import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/env/bin/pelican b/env/bin/pelican new file mode 100755 index 000000000..a997ef4ed --- /dev/null +++ b/env/bin/pelican @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pelican import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/pelican-import b/env/bin/pelican-import new file mode 100755 index 000000000..3c786d5e7 --- /dev/null +++ b/env/bin/pelican-import @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pelican.tools.pelican_import import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/pelican-quickstart b/env/bin/pelican-quickstart new file mode 100755 index 000000000..237221d3c --- /dev/null +++ b/env/bin/pelican-quickstart @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pelican.tools.pelican_quickstart import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/pelican-themes b/env/bin/pelican-themes new file mode 100755 index 000000000..853d4ac6c --- /dev/null +++ b/env/bin/pelican-themes @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pelican.tools.pelican_themes import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/pip b/env/bin/pip new file mode 100755 index 000000000..fdf3c7162 --- /dev/null +++ b/env/bin/pip @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- 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/env/bin/pip-3.8 b/env/bin/pip-3.8 new file mode 100755 index 000000000..fdf3c7162 --- /dev/null +++ b/env/bin/pip-3.8 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- 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/env/bin/pip3 b/env/bin/pip3 new file mode 100755 index 000000000..fdf3c7162 --- /dev/null +++ b/env/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- 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/env/bin/pip3.8 b/env/bin/pip3.8 new file mode 100755 index 000000000..fdf3c7162 --- /dev/null +++ b/env/bin/pip3.8 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- 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/env/bin/pygmentize b/env/bin/pygmentize new file mode 100755 index 000000000..c31ca241f --- /dev/null +++ b/env/bin/pygmentize @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pygments.cmdline import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/python b/env/bin/python new file mode 120000 index 000000000..02a138965 --- /dev/null +++ b/env/bin/python @@ -0,0 +1 @@ +/usr/bin/python3.8 \ No newline at end of file diff --git a/env/bin/python3 b/env/bin/python3 new file mode 120000 index 000000000..d8654aa0e --- /dev/null +++ b/env/bin/python3 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/env/bin/python3.8 b/env/bin/python3.8 new file mode 120000 index 000000000..d8654aa0e --- /dev/null +++ b/env/bin/python3.8 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/env/bin/rst2html.py b/env/bin/rst2html.py new file mode 100755 index 000000000..d1cc1373d --- /dev/null +++ b/env/bin/rst2html.py @@ -0,0 +1,23 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2html.py 4564 2006-05-21 20:44:42Z wiemann $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing HTML. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates (X)HTML documents from standalone reStructuredText ' + 'sources. ' + default_description) + +publish_cmdline(writer_name='html', description=description) diff --git a/env/bin/rst2html4.py b/env/bin/rst2html4.py new file mode 100755 index 000000000..4b039cea9 --- /dev/null +++ b/env/bin/rst2html4.py @@ -0,0 +1,26 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2html4.py 7994 2016-12-10 17:41:45Z milde $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing (X)HTML. + +The output conforms to XHTML 1.0 transitional +and almost to HTML 4.01 transitional (except for closing empty tags). +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates (X)HTML documents from standalone reStructuredText ' + 'sources. ' + default_description) + +publish_cmdline(writer_name='html4', description=description) diff --git a/env/bin/rst2html5.py b/env/bin/rst2html5.py new file mode 100755 index 000000000..ff3e82af4 --- /dev/null +++ b/env/bin/rst2html5.py @@ -0,0 +1,35 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf8 -*- +# :Copyright: © 2015 Günter Milde. +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause +# +# Revision: $Revision: 8410 $ +# Date: $Date: 2019-11-04 22:14:43 +0100 (Mo, 04. Nov 2019) $ + +""" +A minimal front end to the Docutils Publisher, producing HTML 5 documents. + +The output also conforms to XHTML 1.0 transitional +(except for the doctype declaration). +""" + +try: + import locale # module missing in Jython + locale.setlocale(locale.LC_ALL, '') +except locale.Error: + pass + +from docutils.core import publish_cmdline, default_description + +description = (u'Generates HTML 5 documents from standalone ' + u'reStructuredText sources ' + + default_description) + +publish_cmdline(writer_name='html5', description=description) diff --git a/env/bin/rst2latex.py b/env/bin/rst2latex.py new file mode 100755 index 000000000..8ac116a09 --- /dev/null +++ b/env/bin/rst2latex.py @@ -0,0 +1,26 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2latex.py 5905 2009-04-16 12:04:49Z milde $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing LaTeX. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline + +description = ('Generates LaTeX documents from standalone reStructuredText ' + 'sources. ' + 'Reads from (default is stdin) and writes to ' + ' (default is stdout). See ' + ' for ' + 'the full reference.') + +publish_cmdline(writer_name='latex', description=description) diff --git a/env/bin/rst2man.py b/env/bin/rst2man.py new file mode 100755 index 000000000..f081ad8bf --- /dev/null +++ b/env/bin/rst2man.py @@ -0,0 +1,26 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# Author: +# Contact: grubert@users.sf.net +# Copyright: This module has been placed in the public domain. + +""" +man.py +====== + +This module provides a simple command line interface that uses the +man page writer to output from ReStructuredText source. +""" + +import locale +try: + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description +from docutils.writers import manpage + +description = ("Generates plain unix manual documents. " + default_description) + +publish_cmdline(writer=manpage.Writer(), description=description) diff --git a/env/bin/rst2odt.py b/env/bin/rst2odt.py new file mode 100755 index 000000000..64f4942d2 --- /dev/null +++ b/env/bin/rst2odt.py @@ -0,0 +1,30 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2odt.py 5839 2009-01-07 19:09:28Z dkuhlman $ +# Author: Dave Kuhlman +# Copyright: This module has been placed in the public domain. + +""" +A front end to the Docutils Publisher, producing OpenOffice documents. +""" + +import sys +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline_to_binary, default_description +from docutils.writers.odf_odt import Writer, Reader + + +description = ('Generates OpenDocument/OpenOffice/ODF documents from ' + 'standalone reStructuredText sources. ' + default_description) + + +writer = Writer() +reader = Reader() +output = publish_cmdline_to_binary(reader=reader, writer=writer, + description=description) + diff --git a/env/bin/rst2odt_prepstyles.py b/env/bin/rst2odt_prepstyles.py new file mode 100755 index 000000000..c77da35d0 --- /dev/null +++ b/env/bin/rst2odt_prepstyles.py @@ -0,0 +1,67 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2odt_prepstyles.py 8346 2019-08-26 12:11:32Z milde $ +# Author: Dave Kuhlman +# Copyright: This module has been placed in the public domain. + +""" +Fix a word-processor-generated styles.odt for odtwriter use: Drop page size +specifications from styles.xml in STYLE_FILE.odt. +""" + +# Author: Michael Schutte + +from __future__ import print_function + +from lxml import etree +import sys +import zipfile +from tempfile import mkstemp +import shutil +import os + +NAMESPACES = { + "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0", + "fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" +} + + +def prepstyle(filename): + + zin = zipfile.ZipFile(filename) + styles = zin.read("styles.xml") + + root = etree.fromstring(styles) + for el in root.xpath("//style:page-layout-properties", + namespaces=NAMESPACES): + for attr in el.attrib: + if attr.startswith("{%s}" % NAMESPACES["fo"]): + del el.attrib[attr] + + tempname = mkstemp() + zout = zipfile.ZipFile(os.fdopen(tempname[0], "w"), "w", + zipfile.ZIP_DEFLATED) + + for item in zin.infolist(): + if item.filename == "styles.xml": + zout.writestr(item, etree.tostring(root)) + else: + zout.writestr(item, zin.read(item.filename)) + + zout.close() + zin.close() + shutil.move(tempname[1], filename) + + +def main(): + args = sys.argv[1:] + if len(args) != 1: + print(__doc__, file=sys.stderr) + print("Usage: %s STYLE_FILE.odt\n" % sys.argv[0], file=sys.stderr) + sys.exit(1) + filename = args[0] + prepstyle(filename) + + +if __name__ == '__main__': + main() diff --git a/env/bin/rst2pseudoxml.py b/env/bin/rst2pseudoxml.py new file mode 100755 index 000000000..74e29f70b --- /dev/null +++ b/env/bin/rst2pseudoxml.py @@ -0,0 +1,23 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2pseudoxml.py 4564 2006-05-21 20:44:42Z wiemann $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing pseudo-XML. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates pseudo-XML from standalone reStructuredText ' + 'sources (for testing purposes). ' + default_description) + +publish_cmdline(description=description) diff --git a/env/bin/rst2s5.py b/env/bin/rst2s5.py new file mode 100755 index 000000000..6a06496dd --- /dev/null +++ b/env/bin/rst2s5.py @@ -0,0 +1,24 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2s5.py 4564 2006-05-21 20:44:42Z wiemann $ +# Author: Chris Liechti +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing HTML slides using +the S5 template system. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates S5 (X)HTML slideshow documents from standalone ' + 'reStructuredText sources. ' + default_description) + +publish_cmdline(writer_name='s5', description=description) diff --git a/env/bin/rst2xetex.py b/env/bin/rst2xetex.py new file mode 100755 index 000000000..ce0e31ef1 --- /dev/null +++ b/env/bin/rst2xetex.py @@ -0,0 +1,27 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2xetex.py 7847 2015-03-17 17:30:47Z milde $ +# Author: Guenter Milde +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing Lua/XeLaTeX code. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline + +description = ('Generates LaTeX documents from standalone reStructuredText ' + 'sources for compilation with the Unicode-aware TeX variants ' + 'XeLaTeX or LuaLaTeX. ' + 'Reads from (default is stdin) and writes to ' + ' (default is stdout). See ' + ' for ' + 'the full reference.') + +publish_cmdline(writer_name='xetex', description=description) diff --git a/env/bin/rst2xml.py b/env/bin/rst2xml.py new file mode 100755 index 000000000..e0ff76570 --- /dev/null +++ b/env/bin/rst2xml.py @@ -0,0 +1,23 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rst2xml.py 4564 2006-05-21 20:44:42Z wiemann $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing Docutils XML. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates Docutils-native XML from standalone ' + 'reStructuredText sources. ' + default_description) + +publish_cmdline(writer_name='xml', description=description) diff --git a/env/bin/rstpep2html.py b/env/bin/rstpep2html.py new file mode 100755 index 000000000..92558f520 --- /dev/null +++ b/env/bin/rstpep2html.py @@ -0,0 +1,25 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python + +# $Id: rstpep2html.py 4564 2006-05-21 20:44:42Z wiemann $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing HTML from PEP +(Python Enhancement Proposal) documents. +""" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description + + +description = ('Generates (X)HTML from reStructuredText-format PEP files. ' + + default_description) + +publish_cmdline(reader_name='pep', writer_name='pep_html', + description=description) diff --git a/env/bin/unidecode b/env/bin/unidecode new file mode 100755 index 000000000..b4f7c6816 --- /dev/null +++ b/env/bin/unidecode @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from unidecode.util import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/wheel b/env/bin/wheel new file mode 100755 index 000000000..dfe29dd45 --- /dev/null +++ b/env/bin/wheel @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from wheel.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/wheel-3.8 b/env/bin/wheel-3.8 new file mode 100755 index 000000000..dfe29dd45 --- /dev/null +++ b/env/bin/wheel-3.8 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from wheel.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/bin/wheel3 b/env/bin/wheel3 new file mode 100755 index 000000000..dfe29dd45 --- /dev/null +++ b/env/bin/wheel3 @@ -0,0 +1,8 @@ +#!/home/jacksonosvaldo/Documentos/GitHub_Projetos/pythonclub.github.io/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from wheel.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst new file mode 100644 index 000000000..c37cae49e --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +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 the copyright holder 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 THE COPYRIGHT +HOLDER 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/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA new file mode 100644 index 000000000..55c0f8269 --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA @@ -0,0 +1,106 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 2.11.2 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/jinja +Project-URL: Issue tracker, https://github.com/pallets/jinja/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/x-rst +Requires-Dist: MarkupSafe (>=0.23) +Provides-Extra: i18n +Requires-Dist: Babel (>=0.8) ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} +

+ {% endblock %} + + +Links +----- + +- Website: https://palletsprojects.com/p/jinja/ +- Documentation: https://jinja.palletsprojects.com/ +- Releases: https://pypi.org/project/Jinja2/ +- Code: https://github.com/pallets/jinja +- Issue tracker: https://github.com/pallets/jinja/issues +- Test status: https://dev.azure.com/pallets/jinja/_build +- Official chat: https://discord.gg/t6rrQZH + + diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD new file mode 100644 index 000000000..413fef4bf --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD @@ -0,0 +1,61 @@ +Jinja2-2.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-2.11.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-2.11.2.dist-info/METADATA,sha256=5ZHRZoIRAMHsJPnqhlJ622_dRPsYePYJ-9EH4-Ry7yI,3535 +Jinja2-2.11.2.dist-info/RECORD,, +Jinja2-2.11.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +Jinja2-2.11.2.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61 +Jinja2-2.11.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=0QCM_jKKDM10yzSdHRVV4mQbCbDqf0GN0GirAqibn9Y,1549 +jinja2/__pycache__/__init__.cpython-38.pyc,, +jinja2/__pycache__/_compat.cpython-38.pyc,, +jinja2/__pycache__/_identifier.cpython-38.pyc,, +jinja2/__pycache__/asyncfilters.cpython-38.pyc,, +jinja2/__pycache__/asyncsupport.cpython-38.pyc,, +jinja2/__pycache__/bccache.cpython-38.pyc,, +jinja2/__pycache__/compiler.cpython-38.pyc,, +jinja2/__pycache__/constants.cpython-38.pyc,, +jinja2/__pycache__/debug.cpython-38.pyc,, +jinja2/__pycache__/defaults.cpython-38.pyc,, +jinja2/__pycache__/environment.cpython-38.pyc,, +jinja2/__pycache__/exceptions.cpython-38.pyc,, +jinja2/__pycache__/ext.cpython-38.pyc,, +jinja2/__pycache__/filters.cpython-38.pyc,, +jinja2/__pycache__/idtracking.cpython-38.pyc,, +jinja2/__pycache__/lexer.cpython-38.pyc,, +jinja2/__pycache__/loaders.cpython-38.pyc,, +jinja2/__pycache__/meta.cpython-38.pyc,, +jinja2/__pycache__/nativetypes.cpython-38.pyc,, +jinja2/__pycache__/nodes.cpython-38.pyc,, +jinja2/__pycache__/optimizer.cpython-38.pyc,, +jinja2/__pycache__/parser.cpython-38.pyc,, +jinja2/__pycache__/runtime.cpython-38.pyc,, +jinja2/__pycache__/sandbox.cpython-38.pyc,, +jinja2/__pycache__/tests.cpython-38.pyc,, +jinja2/__pycache__/utils.cpython-38.pyc,, +jinja2/__pycache__/visitor.cpython-38.pyc,, +jinja2/_compat.py,sha256=B6Se8HjnXVpzz9-vfHejn-DV2NjaVK-Iewupc5kKlu8,3191 +jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775 +jinja2/asyncfilters.py,sha256=XJtYXTxFvcJ5xwk6SaDL4S0oNnT0wPYvXBCSzc482fI,4250 +jinja2/asyncsupport.py,sha256=ZBFsDLuq3Gtji3Ia87lcyuDbqaHZJRdtShZcqwpFnSQ,7209 +jinja2/bccache.py,sha256=3Pmp4jo65M9FQuIxdxoDBbEDFwe4acDMQf77nEJfrHA,12139 +jinja2/compiler.py,sha256=Ta9W1Lit542wItAHXlDcg0sEOsFDMirCdlFPHAurg4o,66284 +jinja2/constants.py,sha256=RR1sTzNzUmKco6aZicw4JpQpJGCuPuqm1h1YmCNUEFY,1458 +jinja2/debug.py,sha256=neR7GIGGjZH3_ILJGVUYy3eLQCCaWJMXOb7o0kGInWc,8529 +jinja2/defaults.py,sha256=85B6YUUCyWPSdrSeVhcqFVuu_bHUAQXeey--FIwSeVQ,1126 +jinja2/environment.py,sha256=XDSLKc4SqNLMOwTSq3TbWEyA5WyXfuLuVD0wAVjEFwM,50629 +jinja2/exceptions.py,sha256=VjNLawcmf2ODffqVMCQK1cRmvFaUfQWF4u8ouP3QPcE,5425 +jinja2/ext.py,sha256=AtwL5O5enT_L3HR9-oBvhGyUTdGoyaqG_ICtnR_EVd4,26441 +jinja2/filters.py,sha256=_RpPgAlgIj7ExvyDzcHAC3B36cocfWK-1TEketbNeM0,41415 +jinja2/idtracking.py,sha256=J3O4VHsrbf3wzwiBc7Cro26kHb6_5kbULeIOzocchIU,9211 +jinja2/lexer.py,sha256=nUFLRKhhKmmEWkLI65nQePgcQs7qsRdjVYZETMt_v0g,30331 +jinja2/loaders.py,sha256=C-fST_dmFjgWkp0ZuCkrgICAoOsoSIF28wfAFink0oU,17666 +jinja2/meta.py,sha256=QjyYhfNRD3QCXjBJpiPl9KgkEkGXJbAkCUq4-Ur10EQ,4131 +jinja2/nativetypes.py,sha256=Ul__gtVw4xH-0qvUvnCNHedQeNDwmEuyLJztzzSPeRg,2753 +jinja2/nodes.py,sha256=Mk1oJPVgIjnQw9WOqILvcu3rLepcFZ0ahxQm2mbwDwc,31095 +jinja2/optimizer.py,sha256=gQLlMYzvQhluhzmAIFA1tXS0cwgWYOjprN-gTRcHVsc,1457 +jinja2/parser.py,sha256=fcfdqePNTNyvosIvczbytVA332qpsURvYnCGcjDHSkA,35660 +jinja2/runtime.py,sha256=0y-BRyIEZ9ltByL2Id6GpHe1oDRQAwNeQvI0SKobNMw,30618 +jinja2/sandbox.py,sha256=knayyUvXsZ-F0mk15mO2-ehK9gsw04UhB8td-iUOtLc,17127 +jinja2/tests.py,sha256=iO_Y-9Vo60zrVe1lMpSl5sKHqAxe2leZHC08OoZ8K24,4799 +jinja2/utils.py,sha256=OoVMlQe9S2-lWT6jJbTu9tDuDvGNyWUhHDcE51i5_Do,22522 +jinja2/visitor.py,sha256=DUHupl0a4PGp7nxRtZFttUzAi1ccxzqc2hzetPYUz8U,3240 diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL new file mode 100644 index 000000000..ef99c6cf3 --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt new file mode 100644 index 000000000..3619483fd --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract [i18n] + diff --git a/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt new file mode 100644 index 000000000..7f7afbf3b --- /dev/null +++ b/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/INSTALLER b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/LICENSE.md b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/LICENSE.md new file mode 100644 index 000000000..2652d97ad --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/LICENSE.md @@ -0,0 +1,29 @@ +Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later) +Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b) +Copyright 2004 Manfred Stienstra (the original version) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +* 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. +* Neither the name of the Python Markdown Project 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 PYTHON MARKDOWN PROJECT ''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 ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT +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/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/METADATA b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/METADATA new file mode 100644 index 000000000..39895cc3c --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/METADATA @@ -0,0 +1,98 @@ +Metadata-Version: 2.1 +Name: Markdown +Version: 3.3.3 +Summary: Python implementation of Markdown. +Home-page: https://Python-Markdown.github.io/ +Author: Manfred Stienstra, Yuri takhteyev and Waylan limberg +Author-email: waylan.limberg@icloud.com +Maintainer: Waylan Limberg +Maintainer-email: waylan.limberg@icloud.com +License: BSD License +Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-3.3.3-py2.py3-none-any.whl +Project-URL: Documentation, https://Python-Markdown.github.io/ +Project-URL: GitHub Project, https://github.com/Python-Markdown/markdown +Project-URL: Issue Tracker, https://github.com/Python-Markdown/markdown/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Communications :: Email :: Filters +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries +Classifier: Topic :: Internet :: WWW/HTTP :: Site Management +Classifier: Topic :: Software Development :: Documentation +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Filters +Classifier: Topic :: Text Processing :: Markup :: HTML +Classifier: Topic :: Text Processing :: Markup :: Markdown +Requires-Python: >=3.6 +Description-Content-Type: text/markdown +Requires-Dist: importlib-metadata ; python_version < "3.8" +Provides-Extra: testing +Requires-Dist: coverage ; extra == 'testing' +Requires-Dist: pyyaml ; extra == 'testing' + +[Python-Markdown][] +=================== + +[![Build Status][build-button]][build] +[![Coverage Status][codecov-button]][codecov] +[![Latest Version][mdversion-button]][md-pypi] +[![Python Versions][pyversion-button]][md-pypi] +[![BSD License][bsdlicense-button]][bsdlicense] +[![Code of Conduct][codeofconduct-button]][Code of Conduct] + +[build-button]: https://github.com/Python-Markdown/markdown/workflows/CI/badge.svg?event=push +[build]: https://github.com/Python-Markdown/markdown/actions?query=workflow%3ACI+event%3Apush +[codecov-button]: https://codecov.io/gh/Python-Markdown/markdown/branch/master/graph/badge.svg +[codecov]: https://codecov.io/gh/Python-Markdown/markdown +[mdversion-button]: https://img.shields.io/pypi/v/Markdown.svg +[md-pypi]: https://pypi.org/project/Markdown/ +[pyversion-button]: https://img.shields.io/pypi/pyversions/Markdown.svg +[bsdlicense-button]: https://img.shields.io/badge/license-BSD-yellow.svg +[bsdlicense]: https://opensource.org/licenses/BSD-3-Clause +[codeofconduct-button]: https://img.shields.io/badge/code%20of%20conduct-contributor%20covenant-green.svg?style=flat-square +[Code of Conduct]: https://github.com/Python-Markdown/markdown/blob/master/CODE_OF_CONDUCT.md + +This is a Python implementation of John Gruber's [Markdown][]. +It is almost completely compliant with the reference implementation, +though there are a few known issues. See [Features][] for information +on what exactly is supported and what is not. Additional features are +supported by the [Available Extensions][]. + +[Python-Markdown]: https://Python-Markdown.github.io/ +[Markdown]: https://daringfireball.net/projects/markdown/ +[Features]: https://Python-Markdown.github.io#Features +[Available Extensions]: https://Python-Markdown.github.io/extensions + +Documentation +------------- + +Installation and usage documentation is available in the `docs/` directory +of the distribution and on the project website at +. + +See the change log at . + +Support +------- + +You may report bugs, ask for help, and discuss various other issues on the [bug tracker][]. + +[bug tracker]: https://github.com/Python-Markdown/markdown/issues + +Code of Conduct +--------------- + +Everyone interacting in the Python-Markdown project's codebases, issue trackers, +and mailing lists is expected to follow the [Code of Conduct]. + + diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/RECORD b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/RECORD new file mode 100644 index 000000000..c5433d221 --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/RECORD @@ -0,0 +1,76 @@ +../../../bin/markdown_py,sha256=cf9aVbTIhdY_OkToV_UDqzCZen_5Y3bi79n5CS14PWk,281 +Markdown-3.3.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Markdown-3.3.3.dist-info/LICENSE.md,sha256=bxGTy2NHGOZcOlN9biXr1hSCDsDvaTz8EiSBEmONZNo,1645 +Markdown-3.3.3.dist-info/METADATA,sha256=WHalEShUS2T2w0axy9BTbQBrS03UkpFE3vE0Ew4g_dU,4416 +Markdown-3.3.3.dist-info/RECORD,, +Markdown-3.3.3.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +Markdown-3.3.3.dist-info/entry_points.txt,sha256=j4jiKg-iwZGImvi8OzotZePWoFbJJ4GrfzDqH03u3SQ,1103 +Markdown-3.3.3.dist-info/top_level.txt,sha256=IAxs8x618RXoH1uCqeLLxXsDefJvE_mIibr_M4sOlyk,9 +markdown/__init__.py,sha256=002-LuHviYzROW2rg_gBGai81nMouUNO9UFj5nSsTSk,2065 +markdown/__main__.py,sha256=MpVK3zlwQ-4AzDzZmIScPB90PpunMGVgS5KBmJuHYTw,5802 +markdown/__meta__.py,sha256=7JKFgvYGgDfauq4ZK8nEMnIAbVKOg64uR7D-xt14fM0,1630 +markdown/__pycache__/__init__.cpython-38.pyc,, +markdown/__pycache__/__main__.cpython-38.pyc,, +markdown/__pycache__/__meta__.cpython-38.pyc,, +markdown/__pycache__/blockparser.cpython-38.pyc,, +markdown/__pycache__/blockprocessors.cpython-38.pyc,, +markdown/__pycache__/core.cpython-38.pyc,, +markdown/__pycache__/htmlparser.cpython-38.pyc,, +markdown/__pycache__/inlinepatterns.cpython-38.pyc,, +markdown/__pycache__/pep562.cpython-38.pyc,, +markdown/__pycache__/postprocessors.cpython-38.pyc,, +markdown/__pycache__/preprocessors.cpython-38.pyc,, +markdown/__pycache__/serializers.cpython-38.pyc,, +markdown/__pycache__/test_tools.cpython-38.pyc,, +markdown/__pycache__/treeprocessors.cpython-38.pyc,, +markdown/__pycache__/util.cpython-38.pyc,, +markdown/blockparser.py,sha256=JpBhOokOoBUGCXolftOc5m1hPcR2y9s9hVd9WSuhHzo,4285 +markdown/blockprocessors.py,sha256=U7IjfwJ4WWldfWW4Ia1epEWJKk_7g1B6GqJzB8tN4MU,24821 +markdown/core.py,sha256=4ASA3Wvs4rgk6HBiT3ScKnIyx3oVz86_-5kGe5Vs5nU,15390 +markdown/extensions/__init__.py,sha256=nw2VtafIf5zHjAcUuykQbaNY6taOmNn7ARn11-Pe080,3661 +markdown/extensions/__pycache__/__init__.cpython-38.pyc,, +markdown/extensions/__pycache__/abbr.cpython-38.pyc,, +markdown/extensions/__pycache__/admonition.cpython-38.pyc,, +markdown/extensions/__pycache__/attr_list.cpython-38.pyc,, +markdown/extensions/__pycache__/codehilite.cpython-38.pyc,, +markdown/extensions/__pycache__/def_list.cpython-38.pyc,, +markdown/extensions/__pycache__/extra.cpython-38.pyc,, +markdown/extensions/__pycache__/fenced_code.cpython-38.pyc,, +markdown/extensions/__pycache__/footnotes.cpython-38.pyc,, +markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc,, +markdown/extensions/__pycache__/legacy_em.cpython-38.pyc,, +markdown/extensions/__pycache__/md_in_html.cpython-38.pyc,, +markdown/extensions/__pycache__/meta.cpython-38.pyc,, +markdown/extensions/__pycache__/nl2br.cpython-38.pyc,, +markdown/extensions/__pycache__/sane_lists.cpython-38.pyc,, +markdown/extensions/__pycache__/smarty.cpython-38.pyc,, +markdown/extensions/__pycache__/tables.cpython-38.pyc,, +markdown/extensions/__pycache__/toc.cpython-38.pyc,, +markdown/extensions/__pycache__/wikilinks.cpython-38.pyc,, +markdown/extensions/abbr.py,sha256=5TNU5ml6-H1n-fztEkgUphSTvp5yKCXaiPZMrVuRFvo,3186 +markdown/extensions/admonition.py,sha256=Zn53VydoDM4HtCZdVKT2Zf0Kp3Dbt6E6FJiyU-tCRvc,5534 +markdown/extensions/attr_list.py,sha256=nhKFY_u6BVyKW2oMUeC4wEjqFNGpDSnNXqaohuF6M7I,5988 +markdown/extensions/codehilite.py,sha256=AVbP0Ze37v0FRmySXcsJWmGzaulKdL8w_g-HS1gr4Ag,11628 +markdown/extensions/def_list.py,sha256=p-JT64hKqMkfxlmhETMVRPxjrdnBIPDW8k3S05S-qNM,3634 +markdown/extensions/extra.py,sha256=udRN8OvSWcq3UwkPygvsFl1RlCVtCJ-ARVg2IwVH6VY,1831 +markdown/extensions/fenced_code.py,sha256=rrqPzFvxeVJpitoIXy0qMkNe53gJ0PWHoLZS44yIfeM,7305 +markdown/extensions/footnotes.py,sha256=xvT6etWuTWTHLNHXYQWQGV-35RHTCvH9kBp2xJA6Jdg,15481 +markdown/extensions/legacy_attrs.py,sha256=2EaVQkxQoNnP8_lMPvGRBdNda8L4weUQroiyEuVdS-w,2547 +markdown/extensions/legacy_em.py,sha256=18j4L6zdScy9k18y-U2zaIhYsKVTxCaPurjqLFZmWkI,1582 +markdown/extensions/md_in_html.py,sha256=XD8Mui_u2c5qUyAtkSMyiH9nSB4-t4ACrf67x7HR6Mk,14521 +markdown/extensions/meta.py,sha256=EUfkzM7l7UpH__Or9K3pl8ldVddwndlCZWA3d712RAE,2331 +markdown/extensions/nl2br.py,sha256=wAqTNOuf2L1NzlEvEqoID70n9y-aiYaGLkuyQk3CD0w,783 +markdown/extensions/sane_lists.py,sha256=ZQmCf-247KBexVG0fc62nDvokGkV6W1uavYbieNKSG4,1505 +markdown/extensions/smarty.py,sha256=0padzkVCNACainKw-Xj1S5UfT0125VCTfNejmrCZItA,10238 +markdown/extensions/tables.py,sha256=bicFx_wqhnEx6Y_8MJqA56rh71pt5fOe94oiWbvcobY,7685 +markdown/extensions/toc.py,sha256=9f0QS5K2BE-Rn0RqZ8xZO8s_xX0U8fgKajx6Jl7goiE,13681 +markdown/extensions/wikilinks.py,sha256=GkgT9BY7b1-qW--dIwFAhC9V20RoeF13b7CFdw_V21Q,2812 +markdown/htmlparser.py,sha256=gRk_Ai7w7U46Oo2xbhkLdQCjRqFp5Y8wouIJBzvo0Ts,11276 +markdown/inlinepatterns.py,sha256=cZZdzEWZhVMerELC6KGlgKUi1AEZosOmw_uJNnPscRw,29762 +markdown/pep562.py,sha256=5UkqT7sb-cQufgbOl_jF-RYUVVHS7VThzlMzR9vrd3I,8917 +markdown/postprocessors.py,sha256=o5WpNIImALhyRB40k6TQeVao9eRN_8jOz4Oe7s6nYqA,3844 +markdown/preprocessors.py,sha256=-s8QGHGlX7JAIJTfCivuc-CVwTLWs0IyEU94YUT2IvQ,2742 +markdown/serializers.py,sha256=_wQl-iJrPSUEQ4Q1owWYqN9qceVh6TOlAOH_i44BKAQ,6540 +markdown/test_tools.py,sha256=ZnDwyELUmiyYa0oQgQ31phQrWI1-X6KyRuPkPbnXan4,7750 +markdown/treeprocessors.py,sha256=gSFoKa_ec-9iPzczsOvHxlkPBvhih5AcA4Q45ZrVJeQ,15407 +markdown/util.py,sha256=CfRNpS13QDxokl7SAqmkAih6IdPoK2OcPOY8_vgUZHI,16063 diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/WHEEL b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/WHEEL new file mode 100644 index 000000000..83ff02e96 --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/entry_points.txt b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/entry_points.txt new file mode 100644 index 000000000..f49693d43 --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/entry_points.txt @@ -0,0 +1,23 @@ +[console_scripts] +markdown_py = markdown.__main__:run + +[markdown.extensions] +abbr = markdown.extensions.abbr:AbbrExtension +admonition = markdown.extensions.admonition:AdmonitionExtension +attr_list = markdown.extensions.attr_list:AttrListExtension +codehilite = markdown.extensions.codehilite:CodeHiliteExtension +def_list = markdown.extensions.def_list:DefListExtension +extra = markdown.extensions.extra:ExtraExtension +fenced_code = markdown.extensions.fenced_code:FencedCodeExtension +footnotes = markdown.extensions.footnotes:FootnoteExtension +legacy_attrs = markdown.extensions.legacy_attrs:LegacyAttrExtension +legacy_em = markdown.extensions.legacy_em:LegacyEmExtension +md_in_html = markdown.extensions.md_in_html:MarkdownInHtmlExtension +meta = markdown.extensions.meta:MetaExtension +nl2br = markdown.extensions.nl2br:Nl2BrExtension +sane_lists = markdown.extensions.sane_lists:SaneListExtension +smarty = markdown.extensions.smarty:SmartyExtension +tables = markdown.extensions.tables:TableExtension +toc = markdown.extensions.toc:TocExtension +wikilinks = markdown.extensions.wikilinks:WikiLinkExtension + diff --git a/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/top_level.txt b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/top_level.txt new file mode 100644 index 000000000..0918c9768 --- /dev/null +++ b/env/lib/python3.8/site-packages/Markdown-3.3.3.dist-info/top_level.txt @@ -0,0 +1 @@ +markdown diff --git a/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt new file mode 100644 index 000000000..9d227a0cc --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +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 the copyright holder 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 THE COPYRIGHT +HOLDER 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/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA new file mode 100644 index 000000000..c50370d6e --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA @@ -0,0 +1,105 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 1.1.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: The Pallets Team +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/markupsafe +Project-URL: Issue tracker, https://github.com/pallets/markupsafe/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* +Description-Content-Type: text/x-rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + >>> # escape replaces special characters and wraps in Markup + >>> escape('') + Markup(u'<script>alert(document.cookie);</script>') + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup('Hello') + Markup('hello') + >>> escape(Markup('Hello')) + Markup('hello') + >>> # Markup is a text subclass (str on Python 3, unicode on Python 2) + >>> # methods and operators escape their arguments + >>> template = Markup("Hello %s") + >>> template % '"World"' + Markup('Hello "World"') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +libraries that use it. In order to grow the community of contributors +and users, and allow the maintainers to devote more time to the +projects, `please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +* Website: https://palletsprojects.com/p/markupsafe/ +* Documentation: https://markupsafe.palletsprojects.com/ +* License: `BSD-3-Clause `_ +* Releases: https://pypi.org/project/MarkupSafe/ +* Code: https://github.com/pallets/markupsafe +* Issue tracker: https://github.com/pallets/markupsafe/issues +* Test status: + + * Linux, Mac: https://travis-ci.org/pallets/markupsafe + * Windows: https://ci.appveyor.com/project/pallets/markupsafe + +* Test coverage: https://codecov.io/gh/pallets/markupsafe +* Official chat: https://discord.gg/t6rrQZH + + diff --git a/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD new file mode 100644 index 000000000..95c333990 --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD @@ -0,0 +1,16 @@ +MarkupSafe-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-1.1.1.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-1.1.1.dist-info/METADATA,sha256=IFCP4hCNGjXJgMoSvdjPiKDLAMUTTWoxKXQsQvmyMNU,3653 +MarkupSafe-1.1.1.dist-info/RECORD,, +MarkupSafe-1.1.1.dist-info/WHEEL,sha256=VEyGcIFAmk_1KbI6gaZGw_mMiT-pdGweASQLX-DzYaY,108 +MarkupSafe-1.1.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=oTblO5f9KFM-pvnq9bB0HgElnqkJyqHnFN1Nx2NIvnY,10126 +markupsafe/__pycache__/__init__.cpython-38.pyc,, +markupsafe/__pycache__/_compat.cpython-38.pyc,, +markupsafe/__pycache__/_constants.cpython-38.pyc,, +markupsafe/__pycache__/_native.cpython-38.pyc,, +markupsafe/_compat.py,sha256=uEW1ybxEjfxIiuTbRRaJpHsPFf4yQUMMKaPgYEC5XbU,558 +markupsafe/_constants.py,sha256=zo2ajfScG-l1Sb_52EP3MlDCqO7Y1BVHUXXKRsVDRNk,4690 +markupsafe/_native.py,sha256=d-8S_zzYt2y512xYcuSxq0NeG2DUUvG80wVdTn-4KI8,1873 +markupsafe/_speedups.c,sha256=k0fzEIK3CP6MmMqeY0ob43TP90mVN0DTyn7BAl3RqSg,9884 +markupsafe/_speedups.cpython-38-x86_64-linux-gnu.so,sha256=SbJwN321Xn7OPYGv5a6Ghzga75uT8RHQUGkoQUASF-o,48016 diff --git a/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL new file mode 100644 index 000000000..ae40efdd2 --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: false +Tag: cp38-cp38-manylinux1_x86_64 + diff --git a/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt new file mode 100644 index 000000000..75bf72925 --- /dev/null +++ b/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/AUTHORS b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/AUTHORS new file mode 100755 index 000000000..f209a8acb --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/AUTHORS @@ -0,0 +1,238 @@ +Pygments is written and maintained by Georg Brandl . + +Major developers are Tim Hatch and Armin Ronacher +. + +Other contributors, listed alphabetically, are: + +* Sam Aaron -- Ioke lexer +* Ali Afshar -- image formatter +* Thomas Aglassinger -- Easytrieve, JCL, Rexx, Transact-SQL and VBScript + lexers +* Muthiah Annamalai -- Ezhil lexer +* Kumar Appaiah -- Debian control lexer +* Andreas Amann -- AppleScript lexer +* Timothy Armstrong -- Dart lexer fixes +* Jeffrey Arnold -- R/S, Rd, BUGS, Jags, and Stan lexers +* Jeremy Ashkenas -- CoffeeScript lexer +* José Joaquín Atria -- Praat lexer +* Stefan Matthias Aust -- Smalltalk lexer +* Lucas Bajolet -- Nit lexer +* Ben Bangert -- Mako lexers +* Max Battcher -- Darcs patch lexer +* Thomas Baruchel -- APL lexer +* Tim Baumann -- (Literate) Agda lexer +* Paul Baumgart, 280 North, Inc. -- Objective-J lexer +* Michael Bayer -- Myghty lexers +* Thomas Beale -- Archetype lexers +* John Benediktsson -- Factor lexer +* Trevor Bergeron -- mIRC formatter +* Vincent Bernat -- LessCSS lexer +* Christopher Bertels -- Fancy lexer +* Sébastien Bigaret -- QVT Operational lexer +* Jarrett Billingsley -- MiniD lexer +* Adam Blinkinsop -- Haskell, Redcode lexers +* Stéphane Blondon -- SGF and Sieve lexers +* Frits van Bommel -- assembler lexers +* Pierre Bourdon -- bugfixes +* Martijn Braam -- Kernel log lexer, BARE lexer +* Matthias Bussonnier -- ANSI style handling for terminal-256 formatter +* chebee7i -- Python traceback lexer improvements +* Hiram Chirino -- Scaml and Jade lexers +* Mauricio Caceres -- SAS and Stata lexers. +* Ian Cooper -- VGL lexer +* David Corbett -- Inform, Jasmin, JSGF, Snowball, and TADS 3 lexers +* Leaf Corcoran -- MoonScript lexer +* Christopher Creutzig -- MuPAD lexer +* Daniël W. Crompton -- Pike lexer +* Pete Curry -- bugfixes +* Bryan Davis -- EBNF lexer +* Bruno Deferrari -- Shen lexer +* Giedrius Dubinskas -- HTML formatter improvements +* Owen Durni -- Haxe lexer +* Alexander Dutton, Oxford University Computing Services -- SPARQL lexer +* James Edwards -- Terraform lexer +* Nick Efford -- Python 3 lexer +* Sven Efftinge -- Xtend lexer +* Artem Egorkine -- terminal256 formatter +* Matthew Fernandez -- CAmkES lexer +* Paweł Fertyk -- GDScript lexer, HTML formatter improvements +* Michael Ficarra -- CPSA lexer +* James H. Fisher -- PostScript lexer +* William S. Fulton -- SWIG lexer +* Carlos Galdino -- Elixir and Elixir Console lexers +* Michael Galloy -- IDL lexer +* Naveen Garg -- Autohotkey lexer +* Simon Garnotel -- FreeFem++ lexer +* Laurent Gautier -- R/S lexer +* Alex Gaynor -- PyPy log lexer +* Richard Gerkin -- Igor Pro lexer +* Alain Gilbert -- TypeScript lexer +* Alex Gilding -- BlitzBasic lexer +* GitHub, Inc -- DASM16, Augeas, TOML, and Slash lexers +* Bertrand Goetzmann -- Groovy lexer +* Krzysiek Goj -- Scala lexer +* Rostyslav Golda -- FloScript lexer +* Andrey Golovizin -- BibTeX lexers +* Matt Good -- Genshi, Cheetah lexers +* Michał Górny -- vim modeline support +* Alex Gosse -- TrafficScript lexer +* Patrick Gotthardt -- PHP namespaces support +* Olivier Guibe -- Asymptote lexer +* Phil Hagelberg -- Fennel lexer +* Florian Hahn -- Boogie lexer +* Martin Harriman -- SNOBOL lexer +* Matthew Harrison -- SVG formatter +* Steven Hazel -- Tcl lexer +* Dan Michael Heggø -- Turtle lexer +* Aslak Hellesøy -- Gherkin lexer +* Greg Hendershott -- Racket lexer +* Justin Hendrick -- ParaSail lexer +* Jordi Gutiérrez Hermoso -- Octave lexer +* David Hess, Fish Software, Inc. -- Objective-J lexer +* Ken Hilton -- Typographic Number Theory and Arrow lexers +* Varun Hiremath -- Debian control lexer +* Rob Hoelz -- Perl 6 lexer +* Doug Hogan -- Mscgen lexer +* Ben Hollis -- Mason lexer +* Max Horn -- GAP lexer +* Alastair Houghton -- Lexer inheritance facility +* Tim Howard -- BlitzMax lexer +* Dustin Howett -- Logos lexer +* Ivan Inozemtsev -- Fantom lexer +* Hiroaki Itoh -- Shell console rewrite, Lexers for PowerShell session, + MSDOS session, BC, WDiff +* Brian R. Jackson -- Tea lexer +* Christian Jann -- ShellSession lexer +* Dennis Kaarsemaker -- sources.list lexer +* Dmitri Kabak -- Inferno Limbo lexer +* Igor Kalnitsky -- vhdl lexer +* Colin Kennedy - USD lexer +* Alexander Kit -- MaskJS lexer +* Pekka Klärck -- Robot Framework lexer +* Gerwin Klein -- Isabelle lexer +* Eric Knibbe -- Lasso lexer +* Stepan Koltsov -- Clay lexer +* Adam Koprowski -- Opa lexer +* Benjamin Kowarsch -- Modula-2 lexer +* Domen Kožar -- Nix lexer +* Oleh Krekel -- Emacs Lisp lexer +* Alexander Kriegisch -- Kconfig and AspectJ lexers +* Marek Kubica -- Scheme lexer +* Jochen Kupperschmidt -- Markdown processor +* Gerd Kurzbach -- Modelica lexer +* Jon Larimer, Google Inc. -- Smali lexer +* Olov Lassus -- Dart lexer +* Matt Layman -- TAP lexer +* Kristian Lyngstøl -- Varnish lexers +* Sylvestre Ledru -- Scilab lexer +* Chee Sing Lee -- Flatline lexer +* Mark Lee -- Vala lexer +* Valentin Lorentz -- C++ lexer improvements +* Ben Mabey -- Gherkin lexer +* Angus MacArthur -- QML lexer +* Louis Mandel -- X10 lexer +* Louis Marchand -- Eiffel lexer +* Simone Margaritelli -- Hybris lexer +* Kirk McDonald -- D lexer +* Gordon McGregor -- SystemVerilog lexer +* Stephen McKamey -- Duel/JBST lexer +* Brian McKenna -- F# lexer +* Charles McLaughlin -- Puppet lexer +* Kurt McKee -- Tera Term macro lexer, PostgreSQL updates, MySQL overhaul +* Lukas Meuser -- BBCode formatter, Lua lexer +* Cat Miller -- Pig lexer +* Paul Miller -- LiveScript lexer +* Hong Minhee -- HTTP lexer +* Michael Mior -- Awk lexer +* Bruce Mitchener -- Dylan lexer rewrite +* Reuben Morais -- SourcePawn lexer +* Jon Morton -- Rust lexer +* Paulo Moura -- Logtalk lexer +* Mher Movsisyan -- DTD lexer +* Dejan Muhamedagic -- Crmsh lexer +* Ana Nelson -- Ragel, ANTLR, R console lexers +* Kurt Neufeld -- Markdown lexer +* Nam T. Nguyen -- Monokai style +* Jesper Noehr -- HTML formatter "anchorlinenos" +* Mike Nolta -- Julia lexer +* Avery Nortonsmith -- Pointless lexer +* Jonas Obrist -- BBCode lexer +* Edward O'Callaghan -- Cryptol lexer +* David Oliva -- Rebol lexer +* Pat Pannuto -- nesC lexer +* Jon Parise -- Protocol buffers and Thrift lexers +* Benjamin Peterson -- Test suite refactoring +* Ronny Pfannschmidt -- BBCode lexer +* Dominik Picheta -- Nimrod lexer +* Andrew Pinkham -- RTF Formatter Refactoring +* Clément Prévost -- UrbiScript lexer +* Tanner Prynn -- cmdline -x option and loading lexers from files +* Oleh Prypin -- Crystal lexer (based on Ruby lexer) +* Xidorn Quan -- Web IDL lexer +* Elias Rabel -- Fortran fixed form lexer +* raichoo -- Idris lexer +* Daniel Ramirez -- GDScript lexer +* Kashif Rasul -- CUDA lexer +* Nathan Reed -- HLSL lexer +* Justin Reidy -- MXML lexer +* Norman Richards -- JSON lexer +* Corey Richardson -- Rust lexer updates +* Lubomir Rintel -- GoodData MAQL and CL lexers +* Andre Roberge -- Tango style +* Georg Rollinger -- HSAIL lexer +* Michiel Roos -- TypoScript lexer +* Konrad Rudolph -- LaTeX formatter enhancements +* Mario Ruggier -- Evoque lexers +* Miikka Salminen -- Lovelace style, Hexdump lexer, lexer enhancements +* Stou Sandalski -- NumPy, FORTRAN, tcsh and XSLT lexers +* Matteo Sasso -- Common Lisp lexer +* Joe Schafer -- Ada lexer +* Max Schillinger -- TiddlyWiki5 lexer +* Ken Schutte -- Matlab lexers +* René Schwaiger -- Rainbow Dash style +* Sebastian Schweizer -- Whiley lexer +* Tassilo Schweyer -- Io, MOOCode lexers +* Pablo Seminario -- PromQL lexer +* Ted Shaw -- AutoIt lexer +* Joerg Sieker -- ABAP lexer +* Robert Simmons -- Standard ML lexer +* Kirill Simonov -- YAML lexer +* Corbin Simpson -- Monte lexer +* Alexander Smishlajev -- Visual FoxPro lexer +* Steve Spigarelli -- XQuery lexer +* Jerome St-Louis -- eC lexer +* Camil Staps -- Clean and NuSMV lexers; Solarized style +* James Strachan -- Kotlin lexer +* Tom Stuart -- Treetop lexer +* Colin Sullivan -- SuperCollider lexer +* Ben Swift -- Extempore lexer +* Edoardo Tenani -- Arduino lexer +* Tiberius Teng -- default style overhaul +* Jeremy Thurgood -- Erlang, Squid config lexers +* Brian Tiffin -- OpenCOBOL lexer +* Bob Tolbert -- Hy lexer +* Matthias Trute -- Forth lexer +* Erick Tryzelaar -- Felix lexer +* Alexander Udalov -- Kotlin lexer improvements +* Thomas Van Doren -- Chapel lexer +* Daniele Varrazzo -- PostgreSQL lexers +* Abe Voelker -- OpenEdge ABL lexer +* Pepijn de Vos -- HTML formatter CTags support +* Matthias Vallentin -- Bro lexer +* Benoît Vinot -- AMPL lexer +* Linh Vu Hong -- RSL lexer +* Nathan Weizenbaum -- Haml and Sass lexers +* Nathan Whetsell -- Csound lexers +* Dietmar Winkler -- Modelica lexer +* Nils Winter -- Smalltalk lexer +* Davy Wybiral -- Clojure lexer +* Whitney Young -- ObjectiveC lexer +* Diego Zamboni -- CFengine3 lexer +* Enrique Zamudio -- Ceylon lexer +* Alex Zimin -- Nemerle lexer +* Rob Zimmerman -- Kal lexer +* Vincent Zurczak -- Roboconf lexer +* Hubert Gruniaux -- C and C++ lexer improvements + +Many thanks for all contributions! diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/INSTALLER b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/LICENSE b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/LICENSE new file mode 100755 index 000000000..085810ec6 --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2006-2020 by the respective authors (see AUTHORS file). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +* Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +* 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. + +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 THE COPYRIGHT +OWNER 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/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/METADATA b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/METADATA new file mode 100755 index 000000000..f48338548 --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/METADATA @@ -0,0 +1,49 @@ +Metadata-Version: 2.1 +Name: Pygments +Version: 2.7.2 +Summary: Pygments is a syntax highlighting package written in Python. +Home-page: https://pygments.org/ +Author: Georg Brandl +Author-email: georg@python.org +License: BSD License +Keywords: syntax highlighting +Platform: any +Classifier: License :: OSI Approved :: BSD License +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: End Users/Desktop +Classifier: Intended Audience :: System Administrators +Classifier: Development Status :: 6 - Mature +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Operating System :: OS Independent +Classifier: Topic :: Text Processing :: Filters +Classifier: Topic :: Utilities +Requires-Python: >=3.5 + + +Pygments +~~~~~~~~ + +Pygments is a syntax highlighting package written in Python. + +It is a generic syntax highlighter suitable for use in code hosting, forums, +wikis or other applications that need to prettify source code. Highlights +are: + +* a wide range of over 500 languages and other text formats is supported +* special attention is paid to details, increasing quality by a fair amount +* support for new languages and formats are added easily +* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image formats that PIL supports and ANSI sequences +* it is usable as a command-line tool and as a library + +:copyright: Copyright 2006-2020 by the Pygments team, see AUTHORS. +:license: BSD, see LICENSE for details. + + diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/RECORD b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/RECORD new file mode 100644 index 000000000..6b0500815 --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/RECORD @@ -0,0 +1,481 @@ +../../../bin/pygmentize,sha256=LU6WgFvWzVFfoNRTZX7Rl5GtMVtvGl-Jp4fsq79qsZg,282 +Pygments-2.7.2.dist-info/AUTHORS,sha256=1mUfNwQuHYn3VfjI0Tn7IK1O9F3FlcOsdsAqb4_OrU0,8816 +Pygments-2.7.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Pygments-2.7.2.dist-info/LICENSE,sha256=pxHLiF_RqxTn72VQ8Vxrvs2F597_8ONjzQYyZFz_wAw,1331 +Pygments-2.7.2.dist-info/METADATA,sha256=DymyfMeHDNq_0heG20Cy945NoosgWXOkO1GZL4IB0HE,1883 +Pygments-2.7.2.dist-info/RECORD,, +Pygments-2.7.2.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92 +Pygments-2.7.2.dist-info/entry_points.txt,sha256=NXt9BRDRv6tAfDwqKM0bDHrrxaIt2f1nxH9CwjyjSKc,54 +Pygments-2.7.2.dist-info/top_level.txt,sha256=RjKKqrVIStoebLHdbs0yZ2Lk4rS7cxGguXsLCYvZ2Ak,9 +pygments/__init__.py,sha256=wAiRqfG0j_VmyVCFbHsqOrHjndiPqp8TM-syuXoSKQA,3036 +pygments/__main__.py,sha256=oQ4ArOR7zC8miVPsd2bapcI1-KZTlyXwlOULNBjxsPE,372 +pygments/__pycache__/__init__.cpython-38.pyc,, +pygments/__pycache__/__main__.cpython-38.pyc,, +pygments/__pycache__/cmdline.cpython-38.pyc,, +pygments/__pycache__/console.cpython-38.pyc,, +pygments/__pycache__/filter.cpython-38.pyc,, +pygments/__pycache__/formatter.cpython-38.pyc,, +pygments/__pycache__/lexer.cpython-38.pyc,, +pygments/__pycache__/modeline.cpython-38.pyc,, +pygments/__pycache__/plugin.cpython-38.pyc,, +pygments/__pycache__/regexopt.cpython-38.pyc,, +pygments/__pycache__/scanner.cpython-38.pyc,, +pygments/__pycache__/sphinxext.cpython-38.pyc,, +pygments/__pycache__/style.cpython-38.pyc,, +pygments/__pycache__/token.cpython-38.pyc,, +pygments/__pycache__/unistring.cpython-38.pyc,, +pygments/__pycache__/util.cpython-38.pyc,, +pygments/cmdline.py,sha256=PxLOXy9HiIqgFC7aB9t8hADgaDV6pJN14BZOQAnIKwo,19638 +pygments/console.py,sha256=GHMWt82HVCuR40DJc2TF5IySfIT8dNCf_wAqP1HtdnQ,1721 +pygments/filter.py,sha256=V1DG8n7qKkzrNtPT7tRL5ueMxQnRRj_2NsJSRtR_4DA,1962 +pygments/filters/__init__.py,sha256=Z2E8U02kWh1HdrFyL9e6ocfgMPjtKnnRlwP-z16Hxlw,40268 +pygments/filters/__pycache__/__init__.cpython-38.pyc,, +pygments/formatter.py,sha256=vIVM2tXsof3f9_r8Sp5RtU7JXHk5MoXPM3d01prTXK0,2917 +pygments/formatters/__init__.py,sha256=0ufgZTgnDmrv_4crK8LBU-IACoAeo4SN-L3pjTz7hKs,5107 +pygments/formatters/__pycache__/__init__.cpython-38.pyc,, +pygments/formatters/__pycache__/_mapping.cpython-38.pyc,, +pygments/formatters/__pycache__/bbcode.cpython-38.pyc,, +pygments/formatters/__pycache__/html.cpython-38.pyc,, +pygments/formatters/__pycache__/img.cpython-38.pyc,, +pygments/formatters/__pycache__/irc.cpython-38.pyc,, +pygments/formatters/__pycache__/latex.cpython-38.pyc,, +pygments/formatters/__pycache__/other.cpython-38.pyc,, +pygments/formatters/__pycache__/rtf.cpython-38.pyc,, +pygments/formatters/__pycache__/svg.cpython-38.pyc,, +pygments/formatters/__pycache__/terminal.cpython-38.pyc,, +pygments/formatters/__pycache__/terminal256.cpython-38.pyc,, +pygments/formatters/_mapping.py,sha256=ouDaDNlwp86jioBQ7F2Bt627IxdPGIyJ35QkzYq2YtE,6175 +pygments/formatters/bbcode.py,sha256=QgnkzhJJB3gnsqyY9XJeh-eJLUlMjY2eKVqftBFBMmc,3314 +pygments/formatters/html.py,sha256=hiR7VMFHC2utIIlddbKT09mjTIUgCgAT9YBz-OT-kBo,32980 +pygments/formatters/img.py,sha256=I2F4UcUjidbHfckrwm7MT1rlwPjm2X10o1ihOm1WIJE,20726 +pygments/formatters/irc.py,sha256=CQIvm_ifolFDgJXcfYtkpPTqpEZ4xxQMCXQgi8cEn_A,5869 +pygments/formatters/latex.py,sha256=TDKdGvi7izpq3pi_T7bhOuqwjghX0d_arlBc0EH3cdk,18900 +pygments/formatters/other.py,sha256=j5mpN8UaUex9pc-eLkatkQ6WKFYx_h9z-yhPotOX1JM,5136 +pygments/formatters/rtf.py,sha256=YkwGA06YiqE44LFLMXeQbX0OaDJ1C-rYZJmB6Tf1xO0,5014 +pygments/formatters/svg.py,sha256=oWihkdB6OeTiuWbtcxMDRTtsyZ7FCxLpGDHQqBBcATc,7279 +pygments/formatters/terminal.py,sha256=_sbgNMtb2aFvmJje8IylEPQJketWSyeYDTx0ZFPK-9w,4662 +pygments/formatters/terminal256.py,sha256=EN2qbjT-0fJG6M4sSBJp4HlSns_8H9h7_9IHp15aLNA,11126 +pygments/lexer.py,sha256=R0QJyQH3o_6VyLsicDjPt2f5k80AKYabjYkdtsy0jm0,31436 +pygments/lexers/__init__.py,sha256=tCqwSx3Z66ax64P0t5XE7XrhRur7sCLppcmMUsOoxgc,11283 +pygments/lexers/__pycache__/__init__.cpython-38.pyc,, +pygments/lexers/__pycache__/_asy_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_cl_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_cocoa_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_csound_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_lasso_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_lua_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_mapping.cpython-38.pyc,, +pygments/lexers/__pycache__/_mql_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_mysql_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_openedge_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_php_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_postgres_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_scilab_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_sourcemod_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_stan_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_stata_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_tsql_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_usd_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_vbscript_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/_vim_builtins.cpython-38.pyc,, +pygments/lexers/__pycache__/actionscript.cpython-38.pyc,, +pygments/lexers/__pycache__/agile.cpython-38.pyc,, +pygments/lexers/__pycache__/algebra.cpython-38.pyc,, +pygments/lexers/__pycache__/ambient.cpython-38.pyc,, +pygments/lexers/__pycache__/ampl.cpython-38.pyc,, +pygments/lexers/__pycache__/apl.cpython-38.pyc,, +pygments/lexers/__pycache__/archetype.cpython-38.pyc,, +pygments/lexers/__pycache__/arrow.cpython-38.pyc,, +pygments/lexers/__pycache__/asm.cpython-38.pyc,, +pygments/lexers/__pycache__/automation.cpython-38.pyc,, +pygments/lexers/__pycache__/bare.cpython-38.pyc,, +pygments/lexers/__pycache__/basic.cpython-38.pyc,, +pygments/lexers/__pycache__/bibtex.cpython-38.pyc,, +pygments/lexers/__pycache__/boa.cpython-38.pyc,, +pygments/lexers/__pycache__/business.cpython-38.pyc,, +pygments/lexers/__pycache__/c_cpp.cpython-38.pyc,, +pygments/lexers/__pycache__/c_like.cpython-38.pyc,, +pygments/lexers/__pycache__/capnproto.cpython-38.pyc,, +pygments/lexers/__pycache__/chapel.cpython-38.pyc,, +pygments/lexers/__pycache__/clean.cpython-38.pyc,, +pygments/lexers/__pycache__/compiled.cpython-38.pyc,, +pygments/lexers/__pycache__/configs.cpython-38.pyc,, +pygments/lexers/__pycache__/console.cpython-38.pyc,, +pygments/lexers/__pycache__/crystal.cpython-38.pyc,, +pygments/lexers/__pycache__/csound.cpython-38.pyc,, +pygments/lexers/__pycache__/css.cpython-38.pyc,, +pygments/lexers/__pycache__/d.cpython-38.pyc,, +pygments/lexers/__pycache__/dalvik.cpython-38.pyc,, +pygments/lexers/__pycache__/data.cpython-38.pyc,, +pygments/lexers/__pycache__/devicetree.cpython-38.pyc,, +pygments/lexers/__pycache__/diff.cpython-38.pyc,, +pygments/lexers/__pycache__/dotnet.cpython-38.pyc,, +pygments/lexers/__pycache__/dsls.cpython-38.pyc,, +pygments/lexers/__pycache__/dylan.cpython-38.pyc,, +pygments/lexers/__pycache__/ecl.cpython-38.pyc,, +pygments/lexers/__pycache__/eiffel.cpython-38.pyc,, +pygments/lexers/__pycache__/elm.cpython-38.pyc,, +pygments/lexers/__pycache__/email.cpython-38.pyc,, +pygments/lexers/__pycache__/erlang.cpython-38.pyc,, +pygments/lexers/__pycache__/esoteric.cpython-38.pyc,, +pygments/lexers/__pycache__/ezhil.cpython-38.pyc,, +pygments/lexers/__pycache__/factor.cpython-38.pyc,, +pygments/lexers/__pycache__/fantom.cpython-38.pyc,, +pygments/lexers/__pycache__/felix.cpython-38.pyc,, +pygments/lexers/__pycache__/floscript.cpython-38.pyc,, +pygments/lexers/__pycache__/forth.cpython-38.pyc,, +pygments/lexers/__pycache__/fortran.cpython-38.pyc,, +pygments/lexers/__pycache__/foxpro.cpython-38.pyc,, +pygments/lexers/__pycache__/freefem.cpython-38.pyc,, +pygments/lexers/__pycache__/functional.cpython-38.pyc,, +pygments/lexers/__pycache__/gdscript.cpython-38.pyc,, +pygments/lexers/__pycache__/go.cpython-38.pyc,, +pygments/lexers/__pycache__/grammar_notation.cpython-38.pyc,, +pygments/lexers/__pycache__/graph.cpython-38.pyc,, +pygments/lexers/__pycache__/graphics.cpython-38.pyc,, +pygments/lexers/__pycache__/haskell.cpython-38.pyc,, +pygments/lexers/__pycache__/haxe.cpython-38.pyc,, +pygments/lexers/__pycache__/hdl.cpython-38.pyc,, +pygments/lexers/__pycache__/hexdump.cpython-38.pyc,, +pygments/lexers/__pycache__/html.cpython-38.pyc,, +pygments/lexers/__pycache__/idl.cpython-38.pyc,, +pygments/lexers/__pycache__/igor.cpython-38.pyc,, +pygments/lexers/__pycache__/inferno.cpython-38.pyc,, +pygments/lexers/__pycache__/installers.cpython-38.pyc,, +pygments/lexers/__pycache__/int_fiction.cpython-38.pyc,, +pygments/lexers/__pycache__/iolang.cpython-38.pyc,, +pygments/lexers/__pycache__/j.cpython-38.pyc,, +pygments/lexers/__pycache__/javascript.cpython-38.pyc,, +pygments/lexers/__pycache__/julia.cpython-38.pyc,, +pygments/lexers/__pycache__/jvm.cpython-38.pyc,, +pygments/lexers/__pycache__/lisp.cpython-38.pyc,, +pygments/lexers/__pycache__/make.cpython-38.pyc,, +pygments/lexers/__pycache__/markup.cpython-38.pyc,, +pygments/lexers/__pycache__/math.cpython-38.pyc,, +pygments/lexers/__pycache__/matlab.cpython-38.pyc,, +pygments/lexers/__pycache__/mime.cpython-38.pyc,, +pygments/lexers/__pycache__/ml.cpython-38.pyc,, +pygments/lexers/__pycache__/modeling.cpython-38.pyc,, +pygments/lexers/__pycache__/modula2.cpython-38.pyc,, +pygments/lexers/__pycache__/monte.cpython-38.pyc,, +pygments/lexers/__pycache__/mosel.cpython-38.pyc,, +pygments/lexers/__pycache__/ncl.cpython-38.pyc,, +pygments/lexers/__pycache__/nimrod.cpython-38.pyc,, +pygments/lexers/__pycache__/nit.cpython-38.pyc,, +pygments/lexers/__pycache__/nix.cpython-38.pyc,, +pygments/lexers/__pycache__/oberon.cpython-38.pyc,, +pygments/lexers/__pycache__/objective.cpython-38.pyc,, +pygments/lexers/__pycache__/ooc.cpython-38.pyc,, +pygments/lexers/__pycache__/other.cpython-38.pyc,, +pygments/lexers/__pycache__/parasail.cpython-38.pyc,, +pygments/lexers/__pycache__/parsers.cpython-38.pyc,, +pygments/lexers/__pycache__/pascal.cpython-38.pyc,, +pygments/lexers/__pycache__/pawn.cpython-38.pyc,, +pygments/lexers/__pycache__/perl.cpython-38.pyc,, +pygments/lexers/__pycache__/php.cpython-38.pyc,, +pygments/lexers/__pycache__/pointless.cpython-38.pyc,, +pygments/lexers/__pycache__/pony.cpython-38.pyc,, +pygments/lexers/__pycache__/praat.cpython-38.pyc,, +pygments/lexers/__pycache__/prolog.cpython-38.pyc,, +pygments/lexers/__pycache__/promql.cpython-38.pyc,, +pygments/lexers/__pycache__/python.cpython-38.pyc,, +pygments/lexers/__pycache__/qvt.cpython-38.pyc,, +pygments/lexers/__pycache__/r.cpython-38.pyc,, +pygments/lexers/__pycache__/rdf.cpython-38.pyc,, +pygments/lexers/__pycache__/rebol.cpython-38.pyc,, +pygments/lexers/__pycache__/resource.cpython-38.pyc,, +pygments/lexers/__pycache__/ride.cpython-38.pyc,, +pygments/lexers/__pycache__/rnc.cpython-38.pyc,, +pygments/lexers/__pycache__/roboconf.cpython-38.pyc,, +pygments/lexers/__pycache__/robotframework.cpython-38.pyc,, +pygments/lexers/__pycache__/ruby.cpython-38.pyc,, +pygments/lexers/__pycache__/rust.cpython-38.pyc,, +pygments/lexers/__pycache__/sas.cpython-38.pyc,, +pygments/lexers/__pycache__/scdoc.cpython-38.pyc,, +pygments/lexers/__pycache__/scripting.cpython-38.pyc,, +pygments/lexers/__pycache__/sgf.cpython-38.pyc,, +pygments/lexers/__pycache__/shell.cpython-38.pyc,, +pygments/lexers/__pycache__/sieve.cpython-38.pyc,, +pygments/lexers/__pycache__/slash.cpython-38.pyc,, +pygments/lexers/__pycache__/smalltalk.cpython-38.pyc,, +pygments/lexers/__pycache__/smv.cpython-38.pyc,, +pygments/lexers/__pycache__/snobol.cpython-38.pyc,, +pygments/lexers/__pycache__/solidity.cpython-38.pyc,, +pygments/lexers/__pycache__/special.cpython-38.pyc,, +pygments/lexers/__pycache__/sql.cpython-38.pyc,, +pygments/lexers/__pycache__/stata.cpython-38.pyc,, +pygments/lexers/__pycache__/supercollider.cpython-38.pyc,, +pygments/lexers/__pycache__/tcl.cpython-38.pyc,, +pygments/lexers/__pycache__/templates.cpython-38.pyc,, +pygments/lexers/__pycache__/teraterm.cpython-38.pyc,, +pygments/lexers/__pycache__/testing.cpython-38.pyc,, +pygments/lexers/__pycache__/text.cpython-38.pyc,, +pygments/lexers/__pycache__/textedit.cpython-38.pyc,, +pygments/lexers/__pycache__/textfmts.cpython-38.pyc,, +pygments/lexers/__pycache__/theorem.cpython-38.pyc,, +pygments/lexers/__pycache__/tnt.cpython-38.pyc,, +pygments/lexers/__pycache__/trafficscript.cpython-38.pyc,, +pygments/lexers/__pycache__/typoscript.cpython-38.pyc,, +pygments/lexers/__pycache__/unicon.cpython-38.pyc,, +pygments/lexers/__pycache__/urbi.cpython-38.pyc,, +pygments/lexers/__pycache__/usd.cpython-38.pyc,, +pygments/lexers/__pycache__/varnish.cpython-38.pyc,, +pygments/lexers/__pycache__/verification.cpython-38.pyc,, +pygments/lexers/__pycache__/web.cpython-38.pyc,, +pygments/lexers/__pycache__/webidl.cpython-38.pyc,, +pygments/lexers/__pycache__/webmisc.cpython-38.pyc,, +pygments/lexers/__pycache__/whiley.cpython-38.pyc,, +pygments/lexers/__pycache__/x10.cpython-38.pyc,, +pygments/lexers/__pycache__/xorg.cpython-38.pyc,, +pygments/lexers/__pycache__/yang.cpython-38.pyc,, +pygments/lexers/__pycache__/zig.cpython-38.pyc,, +pygments/lexers/_asy_builtins.py,sha256=Ei70g-d9AXOU6wQBjesL2h-280R9YIGnYO9DxC003yg,27311 +pygments/lexers/_cl_builtins.py,sha256=LTVIJuSh0nBCur8ljIjDLSzGhCyF_LzKcAkZOqv1sLc,14018 +pygments/lexers/_cocoa_builtins.py,sha256=YZpBi9V-yPDtbjM5cw6i7wUtfbXRov1jMWCDHUI6zsA,39962 +pygments/lexers/_csound_builtins.py,sha256=7_tvwJzx14QLhRSVQsA19QXmBh6rFCrl8M5cXVj5oZE,17881 +pygments/lexers/_lasso_builtins.py,sha256=iEoj04k4d4dyf7PBoFLY0Tey2GOnQb_DcGBoH8NnkuI,134534 +pygments/lexers/_lua_builtins.py,sha256=tbv_gbsIiO0pc7s-j9Jw2_hCYqgZonn_KZbVtBfsXWY,8297 +pygments/lexers/_mapping.py,sha256=L_hLSkmoCWULsDu-eMj6OrRgcnmCAKFcOK3L6WhXVXk,60282 +pygments/lexers/_mql_builtins.py,sha256=OEXBxj8uE6e0TkX1CO0Yb1Pj66prdUQKBiqI1bLkqA8,24737 +pygments/lexers/_mysql_builtins.py,sha256=axUR5RAG7VX_37TPtTTal8WUK9vqc-aONcv8FJnfWwM,24517 +pygments/lexers/_openedge_builtins.py,sha256=PMI-RrLbh8ujI-KJQ6bMYi9dAVM1ifhMQjAXpDsCyEM,48362 +pygments/lexers/_php_builtins.py,sha256=i1UEjEHA0WrjHIvJoSXal1il6Vir0DjnUT3n2D01Rws,154365 +pygments/lexers/_postgres_builtins.py,sha256=Vtj_uSv7mtmq0spgqLLnzhNzhVHSyX7FOHxQTEgndMw,12208 +pygments/lexers/_scilab_builtins.py,sha256=yVzY4AJ6JHRXvhTFyrjiXCQhZlj-gQ3-t8IvMgS4Ym4,52401 +pygments/lexers/_sourcemod_builtins.py,sha256=7AxLGHSaCobNF_SKat_DQqO3LQBzJlrZuXHdI84P6IY,27074 +pygments/lexers/_stan_builtins.py,sha256=N1njvtRIR7vvPBHFF3LgseDUbBHv0SG9T08cvAyMsTE,10481 +pygments/lexers/_stata_builtins.py,sha256=SbyuHyolx1Qbkb5ZtwzFviczS60CS4gyot7jQwiD4DE,25228 +pygments/lexers/_tsql_builtins.py,sha256=kZKAPtbJNZH-wbJi67YcmprWe_ZgXlJyf8nnalcW55o,15484 +pygments/lexers/_usd_builtins.py,sha256=SNZINMPnOzbW9BpvZoMqpg8BdW5TjvTuitsGTLiObk4,1682 +pygments/lexers/_vbscript_builtins.py,sha256=N_8q3HGtvnwLfof1Xn-qkrYYubOYSCuJzHpLfGo5-Qk,4249 +pygments/lexers/_vim_builtins.py,sha256=CkSYvvRXbvB3RNEuSFlvx2KDxKouZB-BmyfQxk3KK5o,57090 +pygments/lexers/actionscript.py,sha256=RYESUKQqngLcN7_ySDKq8IW5iPTRDBxdjvDZ-Wx0fns,11441 +pygments/lexers/agile.py,sha256=_DQrIQFQZ-ZX0ykVgLYfKbJPDmErA9Kj_rn8nOz6_u8,900 +pygments/lexers/algebra.py,sha256=PQdhcdrnq4aapKC23Z5G7BOqiCiBYYzOcOAalogq0uE,7754 +pygments/lexers/ambient.py,sha256=ywtaINl8YM8VL5jY6UpKJg6sOA5aybxO6do_RzO4uCE,2557 +pygments/lexers/ampl.py,sha256=U5Sifn_aZXxn6zIwuqndyW8YZZMieAPk-g2MutK7klo,4123 +pygments/lexers/apl.py,sha256=BJH42vs8XDxpbCdGRW4MD8SmwavR0meqjOdMa8nambA,3272 +pygments/lexers/archetype.py,sha256=_ut4GxINOUz43OoTwW95nc16HXWc-2ONYu_rPBgJx74,11134 +pygments/lexers/arrow.py,sha256=m_KGZH572n0z1s3jpBNvA2tX_hF371CU8QTGpKSkQMc,3524 +pygments/lexers/asm.py,sha256=C2w8E4PACLz2xbpRQ5tZPbmcQylI6CR7sCSLNiTtnRw,39365 +pygments/lexers/automation.py,sha256=CpJUoTKl0Hygv7A_DkA9ClEN-suaUO4kKEUzk6CUnsw,19640 +pygments/lexers/bare.py,sha256=AAFlI5dpj0ZrZpK8C-5vOInWjuGo3WcKa0xsGvpNYyU,2909 +pygments/lexers/basic.py,sha256=hxSZfL8mwmnuf10ACVnby5-psJAzZIH82HlOoYZhckk,27620 +pygments/lexers/bibtex.py,sha256=7u6BPERHi1cojZdxY7_5ZwW93mEw1hR__Nn2xacu7ck,4725 +pygments/lexers/boa.py,sha256=NA5MFRE0JpiTQIU7_J1dESSqB462e-eo4BevSXGYIYU,3942 +pygments/lexers/business.py,sha256=TMqfqWbb8MGuQGRPMUAFDskBwJIkO71i6xEmnDknEG0,27993 +pygments/lexers/c_cpp.py,sha256=8t---CidRDfBrLXWGkpm_ZTE7_u1YKxKwYSrGnZ6LTk,15068 +pygments/lexers/c_like.py,sha256=kOSBqIpmt1p0bx4V9ZaFEDo0Xv117ZpR183ph5qQQFs,24916 +pygments/lexers/capnproto.py,sha256=qnK6pWsQyNAt372npsUYNTsXxMGJFxi8AeD3TEwGCgI,2194 +pygments/lexers/chapel.py,sha256=ox1VPgwOJsz78XgWLxxrW8ENrHfi0oSPaxpnmIw2DIw,3919 +pygments/lexers/clean.py,sha256=tHRMMxW3erotjZgvY37de6OhEK4ed7qc3mTNccLa5po,6385 +pygments/lexers/compiled.py,sha256=J-BVhR3XQp9Bsy1OBO3OAlBj4za_OZyeeIyHVc8vK_A,1385 +pygments/lexers/configs.py,sha256=SdKjRJPXLkEFFruA9g-qNrDOY1mHAHwTj9ZXN5FPhKo,33614 +pygments/lexers/console.py,sha256=SAm5Mza1PESvHqqW7uv7BeDCKvFb59ZPpQxSYwn_4WI,4120 +pygments/lexers/crystal.py,sha256=f88IpQ68bAKUHfD83DvmEVEhcSu7cG2aQ2NmX2zNfm0,16807 +pygments/lexers/csound.py,sha256=Bgf7_t72ohO3LXIiQfHIm3lvTFRrF28PhAUcGo6UDwQ,16845 +pygments/lexers/css.py,sha256=77YDnAVdH38bo-9lV7VwqvJXcRbHdDhUBzWaOoZxyS0,31457 +pygments/lexers/d.py,sha256=KhK8TTj6RpC6czETIG7uIyMcls8fXmrJhCilkULqliw,9686 +pygments/lexers/dalvik.py,sha256=AqEZMn-tQMU6PstJ5c2U8rqZzQNCKXXCB93DGnxt_JI,4420 +pygments/lexers/data.py,sha256=QZxRACMTXPBDw061-yLIOy-5BmfHwbP0yZMfW63cn_A,19085 +pygments/lexers/devicetree.py,sha256=dVQtvaWVtvNPYv5D-prdHy47PbmcYmrlb3MbTUe7Ah0,3991 +pygments/lexers/diff.py,sha256=q2fGVMit-_1w0RPgWvZWerDKR-8FcWxeE5u-53aWAGU,4885 +pygments/lexers/dotnet.py,sha256=vuHwIJovdP8TuSHWIZ64cd6si11gSp6gFtVqzffyx0o,27947 +pygments/lexers/dsls.py,sha256=NgnvZgYMux4q8SHUGKdbEZcmUuBw_8bpA8My5ax0nNo,35837 +pygments/lexers/dylan.py,sha256=Pq1FLtiD3fhV1gJ3gx5E9Enw681SUb3XWEOSP22XbK8,10334 +pygments/lexers/ecl.py,sha256=OypOCofX6D3IzVfX2sd5mc-1EFbk7IC2lTBFkVUnb1M,6261 +pygments/lexers/eiffel.py,sha256=gSmf2MGpTLjm5Olz-T9i5jcAND_IQjSAinaCobsjkfc,2482 +pygments/lexers/elm.py,sha256=ABONeDSrJisEk_IAgD6BfLYjYOKPYNyFfrjOR96z5kQ,3003 +pygments/lexers/email.py,sha256=p4oDi3-exlete4Q-PaChStUIe7ZujNpFx1xBV7WjBFo,5118 +pygments/lexers/erlang.py,sha256=-u-6VRkuN2pkmhwpE3rSAWBif0FUSP01r1AGDFEmG04,18987 +pygments/lexers/esoteric.py,sha256=CKJ-rmOpUiiPKZo1u6EG2Jcn9xXuWN_VTDB63O74rQo,10173 +pygments/lexers/ezhil.py,sha256=rdJz02xvHVNpFPiO13Ndxb2ejipIapT4rCSqsQsr3CQ,3343 +pygments/lexers/factor.py,sha256=j0JYAbY5QwpS09cOtiBW4QCviP2C2h8kNRPzfajcEoc,17864 +pygments/lexers/fantom.py,sha256=kuXHWxgSIXtQaf6pBLjQiAxANldFrwgHhVm4OEr2e8g,9982 +pygments/lexers/felix.py,sha256=GllAURWmio4FlNSF4Rb9eC7Dmbg_NONc5Ub-6694cfQ,9408 +pygments/lexers/floscript.py,sha256=AExO1k2FTYTQBG4xMQ7qZW3zI6kbNSj0u70dnBRuTaY,2667 +pygments/lexers/forth.py,sha256=6dveh6pPzQmMCvMtBoumaxK_VEarnjqmrVF9v3KEYUg,7142 +pygments/lexers/fortran.py,sha256=VXwEkqm27sgBHH11duCOc0zCQYMTHd9yvlw321C_zRo,9873 +pygments/lexers/foxpro.py,sha256=11_H_szfTUTBQLWZnsSo-uOo8WH7QfrkvfjuXJ9Mz5w,26237 +pygments/lexers/freefem.py,sha256=_bf7po-YnmMPYzwunVMqhY6Eyia_V0zS6QJ-AGhU45E,27086 +pygments/lexers/functional.py,sha256=NTv-uWrlFgILDlmqy1fIsnzM8um33axk5x0aexifSmU,698 +pygments/lexers/gdscript.py,sha256=VqgaFzzToiA_X4nYsNUskbrBEVAoS8on5e0cgru2tTs,11146 +pygments/lexers/go.py,sha256=absaMdNN6ziVq9bU3U3IbRKCVdlJAkcCZzRavIx4_Tg,3701 +pygments/lexers/grammar_notation.py,sha256=SphpeLE1L_f739TxdSIbdMF747Cvi7x1FOclpaaXhHc,7941 +pygments/lexers/graph.py,sha256=C-dldxSLMlM-dEyPO63RfBIznbeQxs0NF7WggAJ3LQs,2756 +pygments/lexers/graphics.py,sha256=ZX2a-aQhom0jYMu0xkUzEEIKhVkvvOuA4DI0jKfnWeY,38950 +pygments/lexers/haskell.py,sha256=axkEJTUkmmXtVzGSXZJb2DfWOrnCpwnotY1o3XbNx1U,32216 +pygments/lexers/haxe.py,sha256=QHJ9Kf8DFSrSUxKWq2llejQbhR5VqlfjZmj-xBwsOdY,30958 +pygments/lexers/hdl.py,sha256=NOQskJGgNJdxNGdhxW-BR7y6Rg2JtO1MRLhOw3UF4Io,22345 +pygments/lexers/hexdump.py,sha256=ifbxPZouMKlnJ3Q2EgdUnaVkjfoaLay4_iycLu5XgX4,3507 +pygments/lexers/html.py,sha256=jl5nKr1ljbg5AuwF4YXyzOeoY6JPlm7iHW5K4d0M74M,19280 +pygments/lexers/idl.py,sha256=-_oWrY0idh6W-T2-eiPIQonmEEAqhUzgmplAyTPERZU,15248 +pygments/lexers/igor.py,sha256=3PogVobCzHT3uarhKBRQ7PddyM0vTZKRR_4ymKoe68U,30609 +pygments/lexers/inferno.py,sha256=NgFh46sM6d8-Nk5juK5K_zeTIskhBXs84qHhAYYWH5s,3117 +pygments/lexers/installers.py,sha256=Yq0ghUKBuPkrvNdNhsXbTnRDxdnYF47INaRgEtYy5kA,12866 +pygments/lexers/int_fiction.py,sha256=WkNq56PzZoMM3OSdhVgos7mEXK1r6GzzhnpPIfYd-uQ,56670 +pygments/lexers/iolang.py,sha256=c589TWHaZCzUuygvNEzsSchIRTOQ8PUM8rThK9QJ-tM,1905 +pygments/lexers/j.py,sha256=hBwm5ahUh_MIhVjP5uRXsk4HalYl6SEH5WEbszfXQlg,4527 +pygments/lexers/javascript.py,sha256=LMclB-mfZ8oQ-W4H_INeZWkaBVVVDWRPCyr9e9KlcHg,60624 +pygments/lexers/julia.py,sha256=EASSH6BdAYUjCTLJbhS0ZkYoqvN5Pxol-Q6g5970B1s,13877 +pygments/lexers/jvm.py,sha256=7Hsi3Vd6bmI22wGyykD0dNpSRFKl8S3qtTlW7C7UAzw,70172 +pygments/lexers/lisp.py,sha256=HeDbVkbMWIVrncBUSVQMEB5oBzf6HipORjHqNeXmxMU,141336 +pygments/lexers/make.py,sha256=DsyiyVFbJGUp5cWQDVjkyAQjZTc29AjCK1_gclFPDJQ,7416 +pygments/lexers/markup.py,sha256=wOP1PDw0apnge8yblRdUmm8supgzy8QzWFVuOmYJBRk,26821 +pygments/lexers/math.py,sha256=GyLxeaWh2tV7HmrM3t0Zvdxakv4s2AlSSrgYmATG4tE,700 +pygments/lexers/matlab.py,sha256=t16WTFtUweeyrtGyLIo9iAF8aFwLTZM1eAZUSsSrwaU,31893 +pygments/lexers/mime.py,sha256=sep9hhFRV1253UiIE5T4cXMY9bf-4tAAn9dwqisd2UM,7958 +pygments/lexers/ml.py,sha256=ChX87kNOOL1fwNG8aEyHSfqoc0NhoNu2kLKy3wVyPCk,35320 +pygments/lexers/modeling.py,sha256=S1j5VUoKNP4NWfDAWOb40pn-148OlMX8F_Af9onlAzQ,13408 +pygments/lexers/modula2.py,sha256=ri_hf5eOny8XsAkH3hlXfsuxvPa-wnNaNLDK4TixHPo,53112 +pygments/lexers/monte.py,sha256=ItpvI84X2gKpV72Vt8aKxHpbd9MSGtf9rpWs5S2HGHs,6307 +pygments/lexers/mosel.py,sha256=r08MqDzRk5t-7Tc5eDj88tKSJxG68_awXSqvZTcmyDg,9211 +pygments/lexers/ncl.py,sha256=6KvuXENGXIOZPNVmxfj7x_XtaLanIgkbU1RyrK8bNQM,63986 +pygments/lexers/nimrod.py,sha256=KgnW7EShPCo-mvbddowOeXi70oxGKOhtyxnje9vHZLY,5144 +pygments/lexers/nit.py,sha256=a-uZfcXINw_offPjYC0kiphDiCJGR4NaJs8nS5Wp4-U,2743 +pygments/lexers/nix.py,sha256=9j56FayYLp3Y4Sp_rIP6YLZuWqDXbCemwdZBn3EwBT4,4031 +pygments/lexers/oberon.py,sha256=VJalye9D_oMeWy6zSmkjBV3-Ci2_0JUMkj3lxPavabY,4235 +pygments/lexers/objective.py,sha256=YvntERGB7t4H2DAiOQPihJZtB7l9ts1DYrZiI5iDNQc,22789 +pygments/lexers/ooc.py,sha256=Jl62wFLApZ_mJ6_8b4m2Jv0dL6I0QE5Bb2_O-amVPLk,2999 +pygments/lexers/other.py,sha256=eCu6YO21bCXcUfphNOWsuyjlcG4HvVNmdlqQl6Q9Mv4,1768 +pygments/lexers/parasail.py,sha256=8QCQx1XlRKuyaM4zXoDa06TBkEVuIpGAm3jKWyO8cgU,2737 +pygments/lexers/parsers.py,sha256=hacMcXL9RO21Y6z0Xps0g3R8RHddGqFfBGkb0h5Gw2s,26042 +pygments/lexers/pascal.py,sha256=ssC3QBAAypr2UtkPWWmfes0dMuz1nX0OhklH-ifOR98,32624 +pygments/lexers/pawn.py,sha256=fgH4xNwJvHzSJRe2SAF2HawAt9U8Vz4d7CXv5jUHSLk,8235 +pygments/lexers/perl.py,sha256=vfBzFw6wDR5dRg41LblKkE3h8TheWuU0l4bANMqYrHM,39103 +pygments/lexers/php.py,sha256=tNE49-ZO6hpH5JpAX97V1vF8OcqN9joVB6qSiGfBSdM,12559 +pygments/lexers/pointless.py,sha256=bI6_v8ieNvnA4qyWtzqG8AvJEoFsqAPjSyNrmkakVDc,1992 +pygments/lexers/pony.py,sha256=gQOMDwkt1FL_fREF8XSnbx6jCrlScy3E8pLkIXRhEEc,3268 +pygments/lexers/praat.py,sha256=g-XdmcFFCAPHDzE11GqWCGGZJ1_W5YdVJ2BKJfUJbtE,12297 +pygments/lexers/prolog.py,sha256=hEcN1SXa1uKq02pfPtfbdRda2TZgq59Zmxro92k0B50,12395 +pygments/lexers/promql.py,sha256=vPsqN9nOd-iI4womaRNW14Y1xvuQEm2jnLsdbczDf-E,4757 +pygments/lexers/python.py,sha256=hB_esfwFXCE2eN2D9590hzYk9pgaF25OcUek97BgRg8,51124 +pygments/lexers/qvt.py,sha256=Fdo9lCxMwaYdlUsNHEaO8ID5oPTYv1Fi5t6-PNviiZ0,6096 +pygments/lexers/r.py,sha256=W8hORRZ42qvQQmef6IT7uikMWND_LpEjgj-cgt4CVhU,6201 +pygments/lexers/rdf.py,sha256=XL3w1tVg74o4WK41pym1L73pv3cdR9PS807OYPvni4k,14611 +pygments/lexers/rebol.py,sha256=k720WWhrNBHbsF_whdiz0F2NCTEFZy0DvgAbn4mkUs4,18624 +pygments/lexers/resource.py,sha256=oGfMFzx8SHXb73YY_xTz8B9QolRW42h4cPS4fC1Bdf4,2926 +pygments/lexers/ride.py,sha256=jmR4KsIQJAsR7yaj7mfA4wEKpCrOPuD84Yk4AV8e9_w,5074 +pygments/lexers/rnc.py,sha256=GyQXOGP_egO181cL0Bkbg2P5Au3Wh3j4TFjncoiRDbg,1990 +pygments/lexers/roboconf.py,sha256=G1x2JYJkCQ9D7TPy5R3JiwRhh34WnQICeTADSo3bWrQ,2070 +pygments/lexers/robotframework.py,sha256=R7Whhj_o0b_98InwKSw_gevdEfzHKRudEThMur7ckYg,18436 +pygments/lexers/ruby.py,sha256=4ovMi7GW1xq_JC0dlE9c6LGBBmizUbI2VGp_RrVGazo,22149 +pygments/lexers/rust.py,sha256=AH2dXQ7O1fDrT6Q-EhIa_KwKb1M_o78Rtk5IWkFxBZg,7983 +pygments/lexers/sas.py,sha256=2Vf3ovl7sZQzfZNmQiA0YdEhTQi6-PutNh7EDH54-1s,9449 +pygments/lexers/scdoc.py,sha256=Qu50p5gneda-HcGSJAwanmW0D3FI5wI2YwHWm92IZm8,2268 +pygments/lexers/scripting.py,sha256=Ze7M-l6WBUq-PtsA5kuDX8xT1IzzAQnOEsSfQEmG2xg,70032 +pygments/lexers/sgf.py,sha256=6bE4cXOLeSKpAdlUJoAfvR6mH4jGmednFFNfZpauTKg,2024 +pygments/lexers/shell.py,sha256=xk2TiZvxjALx_SbDDex_LfFR7LIBecsN5EMUYk64zd4,35670 +pygments/lexers/sieve.py,sha256=5Ue2wTJIvvgDK70jRcyqF8yPK01vCjlQQl1v8MfTAXA,2313 +pygments/lexers/slash.py,sha256=KgirxzrH--yESOQvtBPyk3V3ND5cFgUTc51nmfLPm3M,8506 +pygments/lexers/smalltalk.py,sha256=JJRM6HzaONoiR4a70psRnj7b4boSl1ctXF8HYbH6Q8g,7216 +pygments/lexers/smv.py,sha256=oUWCeSt1akmL9DfYp6m-4vEXU4ofP0PZHWIGymKXd58,2793 +pygments/lexers/snobol.py,sha256=qf3z9UEgIKmhfPmdXoxTDMMgGKezvpSVCSc8KIrzcvc,2756 +pygments/lexers/solidity.py,sha256=wjLryJ27bVPzxK4xvueDBHDqI9BzDgWbD63x4-vIvcg,3195 +pygments/lexers/special.py,sha256=iKFES2yV6da2Jj3zz4Y0_ChJki3LMix4egYsuZm9t3I,3149 +pygments/lexers/sql.py,sha256=zDY8vE-NAiteCyevGBl4zQxDjvF2Y9yRbcN70ASmUCw,33998 +pygments/lexers/stata.py,sha256=1Bxumz2aU3FrQ7mip-Zj5KZBhzsx7IrujcxZbVYS-NE,6438 +pygments/lexers/supercollider.py,sha256=gu8hkk6NIcNwdru9dpFIhBquW_9JXTMxUeqTQyyPIP0,3705 +pygments/lexers/tcl.py,sha256=e6680bROf2aX1FyZYxX0FjW6b6Rn_Fx4EWz8cEU3aoo,5398 +pygments/lexers/templates.py,sha256=mff6O-8OieNVdrsbGpv2bzd3IHK0WBhi3v1O-iQUyLw,71552 +pygments/lexers/teraterm.py,sha256=3FE2CXP7XvNeEhsTuG0yw-n8CKzhVPCekQvIFXP8lKc,9909 +pygments/lexers/testing.py,sha256=E18rDKZnyoOqHPPkH2uHFkWiuN1E06xYVJniRCSUy9o,10749 +pygments/lexers/text.py,sha256=QaH6MtXTrFn6KshCt9Q66QsFG-9_RyzDyQSHDKudQUQ,1030 +pygments/lexers/textedit.py,sha256=z_U0CQoaMqPxSehFE8ER8mAM6UO2ed0gkUypHiW-ncs,6092 +pygments/lexers/textfmts.py,sha256=FJkSuNLhXYGWQKgHfe9X8jVxRneE1j6we7KqIWbpB9k,15182 +pygments/lexers/theorem.py,sha256=w6wyUlVUc6amM0BNvTWeVxEkdQsDzxYe5tYuVYROeys,19200 +pygments/lexers/tnt.py,sha256=Aq3P5C4fh4xf0_WCDapX83YClGJlQmMlXeqJQJ0s844,10178 +pygments/lexers/trafficscript.py,sha256=hdxeHmHVYsr-X8kYbp67TXNaPctMGY4XMtfw9a77vYc,1546 +pygments/lexers/typoscript.py,sha256=7P9WLLL3fZ-elxZfcAk1-yc7mpI9t5Y60cZVo2zfaTc,8224 +pygments/lexers/unicon.py,sha256=TwN-939AC_cgNra_9KxWZoaN_FVZ5nJVu0e4q8loUxk,18536 +pygments/lexers/urbi.py,sha256=LZ_7oB6haq9y-xAftnW4MZA-TrzTk2pxfJW5dsE28dw,6050 +pygments/lexers/usd.py,sha256=piPY4eZRXErtWUw25-Vq7huAB-0Lpt0N8npltBK84cs,3475 +pygments/lexers/varnish.py,sha256=q2mwM1lvU5GRghchv9Dizm7vFfMY6o6KsLBiWb3dthw,7265 +pygments/lexers/verification.py,sha256=IBL25WrAYSoyUkks6pwsARcx-mx2SEgUYzd_hTBH6MQ,3932 +pygments/lexers/web.py,sha256=pL0Fu8qAkOd5ji5Yw1pMArwdYzlviN8ThSK-ti5MG-U,918 +pygments/lexers/webidl.py,sha256=mrwGwSYPcS-Haefk0EaVEeWXqwoPNMxktP0dOGyIuqY,10497 +pygments/lexers/webmisc.py,sha256=zweu9m2OaVt7mXaft088SG0MKycxAA6-Vs91V-fyvQ0,39967 +pygments/lexers/whiley.py,sha256=jIvjyRVL45LiWuh04SmvDWK7QszC0-NGAlynB_KVhlI,4011 +pygments/lexers/x10.py,sha256=Nuc0p1KrpzFxXOzdXfF8_w_tK6oRZ9hWr9KMwg7XQiY,1965 +pygments/lexers/xorg.py,sha256=QiCLtHSD3Xwq-3df2fhfAoHtR2PIVB2-tWvoEiudaXQ,889 +pygments/lexers/yang.py,sha256=ofggZ1QhWq_337tlVl6hgbCvYyBrb0BfvofWLoaNkho,4547 +pygments/lexers/zig.py,sha256=2u9yHsBbI55VyW1JB0oWHBRWKRN5RiqKPxX6G32UNB0,3963 +pygments/modeline.py,sha256=WKYkQjwDWTYkEgfWqax_Wlke78VZwpt6uu8K7Z7ntzU,1010 +pygments/plugin.py,sha256=lXe7YiOpuvU419CZwJ5NkxW90AZ3gcKZ21NgnsSCIp0,1734 +pygments/regexopt.py,sha256=g040xCZx8kUcA2Bjze5Ep9jQ8g2qp3U4-K6vO-IBlUA,3094 +pygments/scanner.py,sha256=CC90S63YnKvebHkEvFxdamDlpgq8pgQWwQ_j5L-Dvy0,3115 +pygments/sphinxext.py,sha256=bSifWW8V7bzE01olNO7pNvT8Wpf2vPCrIWlAuWsyZ5w,4618 +pygments/style.py,sha256=3operzZJvawZUEg67_76GNbBHlyybRgsNteJ_e1pJvo,6031 +pygments/styles/__init__.py,sha256=xFezPfBTeW-rF2r7QfbBBkcPZeX9rnULKIWzUj92wpk,2872 +pygments/styles/__pycache__/__init__.cpython-38.pyc,, +pygments/styles/__pycache__/abap.cpython-38.pyc,, +pygments/styles/__pycache__/algol.cpython-38.pyc,, +pygments/styles/__pycache__/algol_nu.cpython-38.pyc,, +pygments/styles/__pycache__/arduino.cpython-38.pyc,, +pygments/styles/__pycache__/autumn.cpython-38.pyc,, +pygments/styles/__pycache__/borland.cpython-38.pyc,, +pygments/styles/__pycache__/bw.cpython-38.pyc,, +pygments/styles/__pycache__/colorful.cpython-38.pyc,, +pygments/styles/__pycache__/default.cpython-38.pyc,, +pygments/styles/__pycache__/emacs.cpython-38.pyc,, +pygments/styles/__pycache__/friendly.cpython-38.pyc,, +pygments/styles/__pycache__/fruity.cpython-38.pyc,, +pygments/styles/__pycache__/igor.cpython-38.pyc,, +pygments/styles/__pycache__/inkpot.cpython-38.pyc,, +pygments/styles/__pycache__/lovelace.cpython-38.pyc,, +pygments/styles/__pycache__/manni.cpython-38.pyc,, +pygments/styles/__pycache__/monokai.cpython-38.pyc,, +pygments/styles/__pycache__/murphy.cpython-38.pyc,, +pygments/styles/__pycache__/native.cpython-38.pyc,, +pygments/styles/__pycache__/paraiso_dark.cpython-38.pyc,, +pygments/styles/__pycache__/paraiso_light.cpython-38.pyc,, +pygments/styles/__pycache__/pastie.cpython-38.pyc,, +pygments/styles/__pycache__/perldoc.cpython-38.pyc,, +pygments/styles/__pycache__/rainbow_dash.cpython-38.pyc,, +pygments/styles/__pycache__/rrt.cpython-38.pyc,, +pygments/styles/__pycache__/sas.cpython-38.pyc,, +pygments/styles/__pycache__/solarized.cpython-38.pyc,, +pygments/styles/__pycache__/stata_dark.cpython-38.pyc,, +pygments/styles/__pycache__/stata_light.cpython-38.pyc,, +pygments/styles/__pycache__/tango.cpython-38.pyc,, +pygments/styles/__pycache__/trac.cpython-38.pyc,, +pygments/styles/__pycache__/vim.cpython-38.pyc,, +pygments/styles/__pycache__/vs.cpython-38.pyc,, +pygments/styles/__pycache__/xcode.cpython-38.pyc,, +pygments/styles/abap.py,sha256=Puy_JUcO5inS-CeLoZiGJXEeA0rmtVLARs3FqbWhrVQ,751 +pygments/styles/algol.py,sha256=HUhP1n6OwwEZpFsDrc7jbfez2Uth8TmBVHSqsZ9sPLw,2263 +pygments/styles/algol_nu.py,sha256=NmUH8Vy_2_Y23blUU6t25dqPVPAeU5aze_LG8tVvxZo,2278 +pygments/styles/arduino.py,sha256=x7FHaSifp6oB8Jr3iC0iEKIF2qXf0AE0K2D0_jY2Tqk,4491 +pygments/styles/autumn.py,sha256=77fy_b6oCa2-VnXekNUzZ9rdP2EAW9WNA40fVkg8rfI,2144 +pygments/styles/borland.py,sha256=5Q70Zw7POwClbjKtQw1x8iMhCsxl97KlLyp1auet_m4,1562 +pygments/styles/bw.py,sha256=RyuRaLctgh16DDoPrDQtC1jKTR88_tFS1z1ZlvkThto,1355 +pygments/styles/colorful.py,sha256=F0yrdvCdzOTRZ5TUfEUERuWBunLCUWxxPwmBWUquWEE,2778 +pygments/styles/default.py,sha256=sgVjggp8pKRk-1Cl8S_z67dqknhIvmSQh6mXydPHw_0,2532 +pygments/styles/emacs.py,sha256=PCEwqZvBJTmO0rG9ssObYDZgfgXT33Bm2kGtpLpDuEQ,2486 +pygments/styles/friendly.py,sha256=sFQgif6P49u4ga_fse5OYpUowNf_E3DMFJrw6RMj8xo,2515 +pygments/styles/fruity.py,sha256=h-b0u6sl6jmcX4svOwiuKixzaiEyX3fuhrEwzuL7ZxY,1298 +pygments/styles/igor.py,sha256=PDdaC_EFevDkl-OLX_Bogo2Otv54esWggGmsEs1KCyo,739 +pygments/styles/inkpot.py,sha256=wpBM53JGxHKPXKrdA9SPwJIfS1zSbuTG0hOvvLZcMxA,2347 +pygments/styles/lovelace.py,sha256=s8JZa5TfefMEYpMLcbLdX1vyTwg_O-pIC2JOy0ZbsaU,3173 +pygments/styles/manni.py,sha256=KTn9EUCYw40WtWCWr2zdAzBwZYqVOKZ_O2YEuSGpl4w,2374 +pygments/styles/monokai.py,sha256=A4XcbVcv7k31bRvbhvwACyBN5cOzLq3RJJbz85k5Sog,5086 +pygments/styles/murphy.py,sha256=0FBNX0oDCD9UbJf2JQTLA8Y54OPBZfTrSAILCMt2lxI,2751 +pygments/styles/native.py,sha256=QrdYd-l7IlNsfHNrx-yUSx_WO1lsuH-cVTPL_3gZlLY,1938 +pygments/styles/paraiso_dark.py,sha256=2iXjhXDRYXKdCnh1LEzybFgVtlBNZet3229iLFgtDMI,5641 +pygments/styles/paraiso_light.py,sha256=j-JQWJFKcIJL3xq5-gN8LRckGsJW76HOetsV5PjMAWQ,5645 +pygments/styles/pastie.py,sha256=SVW1Ps_4986cDHh3qQjaF4ojY4GO_ynNPJxjyq5l4I0,2473 +pygments/styles/perldoc.py,sha256=lkOpoKzlgiXe8megrbtEIA65_m513IGaczU4MMuKcgE,2175 +pygments/styles/rainbow_dash.py,sha256=-lQMaDtNjFWmLVrhQuffCgGZQ5_ks_AD685emIKMxvU,2480 +pygments/styles/rrt.py,sha256=8mSaCP0aojqknqqQ1Y-8pLlRsbNLF0gdJIHsGx3SqTc,852 +pygments/styles/sas.py,sha256=gf3bX-8VjGdA6QUFjTXnpvhDRBb3HRdL-7z-yCfjy1Q,1441 +pygments/styles/solarized.py,sha256=ALrL3SLzhBVcXxwT31CQH8DCb3fcCanHBGYGk7kj40I,3955 +pygments/styles/stata_dark.py,sha256=v-FS9nUZ-jVADhz6xe74mkIR_KYZs3MTbJa2DkkzDS4,1245 +pygments/styles/stata_light.py,sha256=mPAYH9C39Vdr7abxLQD2oQaXQ-xLgp2sSMPTnFPYivM,1274 +pygments/styles/tango.py,sha256=EDsd1iJGu8FjWnSzz77FZW23it_sJBmmS_9Hd0UmIHo,7096 +pygments/styles/trac.py,sha256=fHTdiJs5lmAfoafAdn8WMHFv2wBPpm0bkXwi86-bM2A,1933 +pygments/styles/vim.py,sha256=_uwfmO3BVd7Uel2VDBjKcMJqK35-04fwNfZBTmhDMmg,1976 +pygments/styles/vs.py,sha256=lyYET0_NApyjGpnclC99gAgy2xBjLhzvE3P1saRmyJI,1073 +pygments/styles/xcode.py,sha256=wLRFypEBYy_BdQ9LO2twts6iPL_n8zEjNBAAxxV-zk8,1501 +pygments/token.py,sha256=QXtd5XSRPXefPi3BksCfmdauNW_bKgMiCHmKvUChR5o,6167 +pygments/unistring.py,sha256=gNWJAXJgrA9oxLgk30mz3p5dSMHlfJENc6CVUtT6UkI,63224 +pygments/util.py,sha256=v_r5oo1rJzPyviVq2yvvgX62lloZUBqzpFJPmsmepXA,9178 diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/WHEEL b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/WHEEL new file mode 100755 index 000000000..83ff02e96 --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/entry_points.txt b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/entry_points.txt new file mode 100755 index 000000000..756d801bd --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +pygmentize = pygments.cmdline:main + diff --git a/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/top_level.txt b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/top_level.txt new file mode 100755 index 000000000..a9f49e01c --- /dev/null +++ b/env/lib/python3.8/site-packages/Pygments-2.7.2.dist-info/top_level.txt @@ -0,0 +1 @@ +pygments diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/DESCRIPTION.rst b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/DESCRIPTION.rst new file mode 100644 index 000000000..4b318b2f9 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,237 @@ +Unidecode, lossy ASCII transliterations of Unicode text +======================================================= + +It often happens that you have text data in Unicode, but you need to +represent it in ASCII. For example when integrating with legacy code that +doesn't support Unicode, or for ease of entry of non-Roman names on a US +keyboard, or when constructing ASCII machine identifiers from +human-readable Unicode strings that should still be somewhat intelligible +(a popular example of this is when making an URL slug from an article +title). + +In most of these examples you could represent Unicode characters as ``???`` or +``\\15BA\\15A0\\1610``, to mention two extreme cases. But that's nearly useless +to someone who actually wants to read what the text says. + +What Unidecode provides is a middle road: the function ``unidecode()`` takes +Unicode data and tries to represent it in ASCII characters (i.e., the +universally displayable characters between 0x00 and 0x7F), where the +compromises taken when mapping between two character sets are chosen to be +near what a human with a US keyboard would choose. + +The quality of resulting ASCII representation varies. For languages of +western origin it should be between perfect and good. On the other hand +transliteration (i.e., conveying, in Roman letters, the pronunciation +expressed by the text in some other writing system) of languages like +Chinese, Japanese or Korean is a very complex issue and this library does +not even attempt to address it. It draws the line at context-free +character-by-character mapping. So a good rule of thumb is that the further +the script you are transliterating is from Latin alphabet, the worse the +transliteration will be. + +Note that this module generally produces better results than simply +stripping accents from characters (which can be done in Python with +built-in functions). It is based on hand-tuned character mappings that for +example also contain ASCII approximations for symbols and non-Latin +alphabets. + +This is a Python port of ``Text::Unidecode`` Perl module by Sean M. Burke +. + + +Module content +-------------- + +The module exports a function that takes an Unicode object (Python 2.x) or +string (Python 3.x) and returns a string (that can be encoded to ASCII bytes in +Python 3.x):: + + >>> from unidecode import unidecode + >>> unidecode(u'ko\u017eu\u0161\u010dek') + 'kozuscek' + >>> unidecode(u'30 \U0001d5c4\U0001d5c6/\U0001d5c1') + '30 km/h' + >>> unidecode(u"\u5317\u4EB0") + 'Bei Jing ' + +A utility is also included that allows you to transliterate text from the +command line in several ways. Reading from standard input:: + + $ echo hello | unidecode + hello + +from a command line argument:: + + $ unidecode -c hello + hello + +or from a file:: + + $ unidecode hello.txt + hello + +The default encoding used by the utility depends on your system locale. You can +specify another encoding with the ``-e`` argument. See ``unidecode --help`` for +a full list of available options. + +Requirements +------------ + +Nothing except Python itself. Unidecode supports Python 2.7 and 3.4 or later. + +You need a Python build with "wide" Unicode characters (also called "UCS-4 +build") in order for Unidecode to work correctly with characters outside of +Basic Multilingual Plane (BMP). Common characters outside BMP are bold, italic, +script, etc. variants of the Latin alphabet intended for mathematical notation. +Surrogate pair encoding of "narrow" builds is not supported in Unidecode. + +If your Python build supports "wide" Unicode the following expression will +return True:: + + >>> import sys + >>> sys.maxunicode > 0xffff + True + +See `PEP 261 `_ for details +regarding support for "wide" Unicode characters in Python. + + +Installation +------------ + +To install the latest version of Unidecode from the Python package index, use +these commands:: + + $ pip install unidecode + +To install Unidecode from the source distribution and run unit tests, use:: + + $ python setup.py install + $ python setup.py test + +Frequently asked questions +-------------------------- + +German umlauts are transliterated incorrectly + Latin letters "a", "o" and "u" with diaeresis are transliterated by + Unidecode as "a", "o", "u", *not* according to German rules "ae", "oe", + "ue". This is intentional and will not be changed. Rationale is that these + letters are used in languages other than German (for example, Finnish and + Turkish). German text transliterated without the extra "e" is much more + readable than other languages transliterated using German rules. A + workaround is to do your own replacements of these characters before + passing the string to ``unidecode()``. + +Unidecode should support localization (e.g. a language or country parameter, inspecting system locale, etc.) + Language-specific transliteration is a complicated problem and beyond the + scope of this library. Changes related to this will not be accepted. Please + consider using other libraries which do provide this capability, such as + `Unihandecode `_. + +Unidecode should use a permissive license such as MIT or the BSD license. + The maintainer of Unidecode believes that providing access to source code + on redistribution is a fair and reasonable request when basing products on + voluntary work of many contributors. If the license is not suitable for + you, please consider using other libraries, such as `text-unidecode + `_. + +Unidecode produces completely wrong results (e.g. "u" with diaeresis transliterating as "A 1/4 ") + The strings you are passing to Unidecode have been wrongly decoded + somewhere in your program. For example, you might be decoding utf-8 encoded + strings as latin1. With a misconfigured terminal, locale and/or a text + editor this might not be immediately apparent. Inspect your strings with + ``repr()`` and consult the + `Unicode HOWTO `_. + +I've upgraded Unidecode and now some URLs on my website return 404 Not Found. + This is an issue with the software that is running your website, not + Unidecode. Occasionally, new versions of Unidecode library are released + which contain improvements to the transliteration tables. This means that + you cannot rely that ``unidecode()`` output will not change across + different versions of Unidecode library. If you use ``unidecode()`` to + generate URLs for your website, either generate the URL slug once and store + it in the database or lock your dependency of Unidecode to one specific + version. + +Some of the issues in this section are discussed in more detail in `this blog +post `_. + + +Performance notes +----------------- + +By default, ``unidecode()`` optimizes for the use case where most of the strings +passed to it are already ASCII-only and no transliteration is necessary (this +default might change in future versions). + +For performance critical applications, two additional functions are exposed: + +``unidecode_expect_ascii()`` is optimized for ASCII-only inputs (approximately +5 times faster than ``unidecode_expect_nonascii()`` on 10 character strings, +more on longer strings), but slightly slower for non-ASCII inputs. + +``unidecode_expect_nonascii()`` takes approximately the same amount of time on +ASCII and non-ASCII inputs, but is slightly faster for non-ASCII inputs than +``unidecode_expect_ascii()``. + +Apart from differences in run time, both functions produce identical results. +For most users of Unidecode, the difference in performance should be +negligible. + + +Source +------ + +You can get the latest development version of Unidecode with:: + + $ git clone https://www.tablix.org/~avian/git/unidecode.git + +There is also an official mirror of this repository on GitHub at +https://github.com/avian2/unidecode + + +Contact +------- + +Please make sure to read the `Frequently asked questions`_ section above before +contacting the maintainer. + +Bug reports, patches and suggestions for Unidecode can be sent to +tomaz.solc@tablix.org. + +Alternatively, you can also open a ticket or pull request at +https://github.com/avian2/unidecode + + +Copyright +--------- + +Original character transliteration tables: + +Copyright 2001, Sean M. Burke , all rights reserved. + +Python code and later additions: + +Copyright 2019, Tomaz Solc + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. The programs and +documentation in this dist are distributed in the hope that they will be +useful, but without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +.. + vim: set filetype=rst: + + diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/INSTALLER b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/LICENSE.txt b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/LICENSE.txt new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/METADATA b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/METADATA new file mode 100644 index 000000000..c73f056b3 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/METADATA @@ -0,0 +1,261 @@ +Metadata-Version: 2.0 +Name: Unidecode +Version: 1.1.1 +Summary: ASCII transliterations of Unicode text +Home-page: UNKNOWN +Author: Tomaz Solc +Author-email: tomaz.solc@tablix.org +License: GPL +Platform: UNKNOWN +Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+) +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Text Processing +Classifier: Topic :: Text Processing :: Filters +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* + +Unidecode, lossy ASCII transliterations of Unicode text +======================================================= + +It often happens that you have text data in Unicode, but you need to +represent it in ASCII. For example when integrating with legacy code that +doesn't support Unicode, or for ease of entry of non-Roman names on a US +keyboard, or when constructing ASCII machine identifiers from +human-readable Unicode strings that should still be somewhat intelligible +(a popular example of this is when making an URL slug from an article +title). + +In most of these examples you could represent Unicode characters as ``???`` or +``\\15BA\\15A0\\1610``, to mention two extreme cases. But that's nearly useless +to someone who actually wants to read what the text says. + +What Unidecode provides is a middle road: the function ``unidecode()`` takes +Unicode data and tries to represent it in ASCII characters (i.e., the +universally displayable characters between 0x00 and 0x7F), where the +compromises taken when mapping between two character sets are chosen to be +near what a human with a US keyboard would choose. + +The quality of resulting ASCII representation varies. For languages of +western origin it should be between perfect and good. On the other hand +transliteration (i.e., conveying, in Roman letters, the pronunciation +expressed by the text in some other writing system) of languages like +Chinese, Japanese or Korean is a very complex issue and this library does +not even attempt to address it. It draws the line at context-free +character-by-character mapping. So a good rule of thumb is that the further +the script you are transliterating is from Latin alphabet, the worse the +transliteration will be. + +Note that this module generally produces better results than simply +stripping accents from characters (which can be done in Python with +built-in functions). It is based on hand-tuned character mappings that for +example also contain ASCII approximations for symbols and non-Latin +alphabets. + +This is a Python port of ``Text::Unidecode`` Perl module by Sean M. Burke +. + + +Module content +-------------- + +The module exports a function that takes an Unicode object (Python 2.x) or +string (Python 3.x) and returns a string (that can be encoded to ASCII bytes in +Python 3.x):: + + >>> from unidecode import unidecode + >>> unidecode(u'ko\u017eu\u0161\u010dek') + 'kozuscek' + >>> unidecode(u'30 \U0001d5c4\U0001d5c6/\U0001d5c1') + '30 km/h' + >>> unidecode(u"\u5317\u4EB0") + 'Bei Jing ' + +A utility is also included that allows you to transliterate text from the +command line in several ways. Reading from standard input:: + + $ echo hello | unidecode + hello + +from a command line argument:: + + $ unidecode -c hello + hello + +or from a file:: + + $ unidecode hello.txt + hello + +The default encoding used by the utility depends on your system locale. You can +specify another encoding with the ``-e`` argument. See ``unidecode --help`` for +a full list of available options. + +Requirements +------------ + +Nothing except Python itself. Unidecode supports Python 2.7 and 3.4 or later. + +You need a Python build with "wide" Unicode characters (also called "UCS-4 +build") in order for Unidecode to work correctly with characters outside of +Basic Multilingual Plane (BMP). Common characters outside BMP are bold, italic, +script, etc. variants of the Latin alphabet intended for mathematical notation. +Surrogate pair encoding of "narrow" builds is not supported in Unidecode. + +If your Python build supports "wide" Unicode the following expression will +return True:: + + >>> import sys + >>> sys.maxunicode > 0xffff + True + +See `PEP 261 `_ for details +regarding support for "wide" Unicode characters in Python. + + +Installation +------------ + +To install the latest version of Unidecode from the Python package index, use +these commands:: + + $ pip install unidecode + +To install Unidecode from the source distribution and run unit tests, use:: + + $ python setup.py install + $ python setup.py test + +Frequently asked questions +-------------------------- + +German umlauts are transliterated incorrectly + Latin letters "a", "o" and "u" with diaeresis are transliterated by + Unidecode as "a", "o", "u", *not* according to German rules "ae", "oe", + "ue". This is intentional and will not be changed. Rationale is that these + letters are used in languages other than German (for example, Finnish and + Turkish). German text transliterated without the extra "e" is much more + readable than other languages transliterated using German rules. A + workaround is to do your own replacements of these characters before + passing the string to ``unidecode()``. + +Unidecode should support localization (e.g. a language or country parameter, inspecting system locale, etc.) + Language-specific transliteration is a complicated problem and beyond the + scope of this library. Changes related to this will not be accepted. Please + consider using other libraries which do provide this capability, such as + `Unihandecode `_. + +Unidecode should use a permissive license such as MIT or the BSD license. + The maintainer of Unidecode believes that providing access to source code + on redistribution is a fair and reasonable request when basing products on + voluntary work of many contributors. If the license is not suitable for + you, please consider using other libraries, such as `text-unidecode + `_. + +Unidecode produces completely wrong results (e.g. "u" with diaeresis transliterating as "A 1/4 ") + The strings you are passing to Unidecode have been wrongly decoded + somewhere in your program. For example, you might be decoding utf-8 encoded + strings as latin1. With a misconfigured terminal, locale and/or a text + editor this might not be immediately apparent. Inspect your strings with + ``repr()`` and consult the + `Unicode HOWTO `_. + +I've upgraded Unidecode and now some URLs on my website return 404 Not Found. + This is an issue with the software that is running your website, not + Unidecode. Occasionally, new versions of Unidecode library are released + which contain improvements to the transliteration tables. This means that + you cannot rely that ``unidecode()`` output will not change across + different versions of Unidecode library. If you use ``unidecode()`` to + generate URLs for your website, either generate the URL slug once and store + it in the database or lock your dependency of Unidecode to one specific + version. + +Some of the issues in this section are discussed in more detail in `this blog +post `_. + + +Performance notes +----------------- + +By default, ``unidecode()`` optimizes for the use case where most of the strings +passed to it are already ASCII-only and no transliteration is necessary (this +default might change in future versions). + +For performance critical applications, two additional functions are exposed: + +``unidecode_expect_ascii()`` is optimized for ASCII-only inputs (approximately +5 times faster than ``unidecode_expect_nonascii()`` on 10 character strings, +more on longer strings), but slightly slower for non-ASCII inputs. + +``unidecode_expect_nonascii()`` takes approximately the same amount of time on +ASCII and non-ASCII inputs, but is slightly faster for non-ASCII inputs than +``unidecode_expect_ascii()``. + +Apart from differences in run time, both functions produce identical results. +For most users of Unidecode, the difference in performance should be +negligible. + + +Source +------ + +You can get the latest development version of Unidecode with:: + + $ git clone https://www.tablix.org/~avian/git/unidecode.git + +There is also an official mirror of this repository on GitHub at +https://github.com/avian2/unidecode + + +Contact +------- + +Please make sure to read the `Frequently asked questions`_ section above before +contacting the maintainer. + +Bug reports, patches and suggestions for Unidecode can be sent to +tomaz.solc@tablix.org. + +Alternatively, you can also open a ticket or pull request at +https://github.com/avian2/unidecode + + +Copyright +--------- + +Original character transliteration tables: + +Copyright 2001, Sean M. Burke , all rights reserved. + +Python code and later additions: + +Copyright 2019, Tomaz Solc + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., 51 +Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. The programs and +documentation in this dist are distributed in the hope that they will be +useful, but without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +.. + vim: set filetype=rst: + + diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/RECORD b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/RECORD new file mode 100644 index 000000000..06e92bc31 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/RECORD @@ -0,0 +1,394 @@ +../../../bin/unidecode,sha256=cCYDUTNdDj9MBGvIor6RPkPBqZmMltRbZ13u-uziMnA,280 +Unidecode-1.1.1.dist-info/DESCRIPTION.rst,sha256=1qgo-PnPYFf7RjSFGEnFbEL6FdtVq5GJMUDpysakI6A,9474 +Unidecode-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Unidecode-1.1.1.dist-info/LICENSE.txt,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092 +Unidecode-1.1.1.dist-info/METADATA,sha256=tYiBHi608dh-oJ4Eev65ipZFvIjgAVbj-peGVHYr73I,10442 +Unidecode-1.1.1.dist-info/RECORD,, +Unidecode-1.1.1.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +Unidecode-1.1.1.dist-info/entry_points.txt,sha256=ItDp7W6CoSJQAKqdiUkzmecugvKvWzjfN7MMK52GM10,51 +Unidecode-1.1.1.dist-info/metadata.json,sha256=uK7I5vPstQ58Y3hzy2i7dCLyq5GjVCJPIxQk1MZt8x0,1200 +Unidecode-1.1.1.dist-info/top_level.txt,sha256=4uYNG2l04s0dm0mEQmPLo2zrjLbhLPKUesLr2dOTdpo,10 +unidecode/__init__.py,sha256=OdPRbXia-xzzGelCHnVh_zmcHJA2s2wP6RGocPnCihU,3094 +unidecode/__main__.py,sha256=VWYWCclyJsdhtNMQtryMFbgsCZtNUsWcEuS7ZOlH1Jc,40 +unidecode/__pycache__/__init__.cpython-38.pyc,, +unidecode/__pycache__/__main__.cpython-38.pyc,, +unidecode/__pycache__/util.cpython-38.pyc,, +unidecode/__pycache__/x000.cpython-38.pyc,, +unidecode/__pycache__/x001.cpython-38.pyc,, +unidecode/__pycache__/x002.cpython-38.pyc,, +unidecode/__pycache__/x003.cpython-38.pyc,, +unidecode/__pycache__/x004.cpython-38.pyc,, +unidecode/__pycache__/x005.cpython-38.pyc,, +unidecode/__pycache__/x006.cpython-38.pyc,, +unidecode/__pycache__/x007.cpython-38.pyc,, +unidecode/__pycache__/x009.cpython-38.pyc,, +unidecode/__pycache__/x00a.cpython-38.pyc,, +unidecode/__pycache__/x00b.cpython-38.pyc,, +unidecode/__pycache__/x00c.cpython-38.pyc,, +unidecode/__pycache__/x00d.cpython-38.pyc,, +unidecode/__pycache__/x00e.cpython-38.pyc,, +unidecode/__pycache__/x00f.cpython-38.pyc,, +unidecode/__pycache__/x010.cpython-38.pyc,, +unidecode/__pycache__/x011.cpython-38.pyc,, +unidecode/__pycache__/x012.cpython-38.pyc,, +unidecode/__pycache__/x013.cpython-38.pyc,, +unidecode/__pycache__/x014.cpython-38.pyc,, +unidecode/__pycache__/x015.cpython-38.pyc,, +unidecode/__pycache__/x016.cpython-38.pyc,, +unidecode/__pycache__/x017.cpython-38.pyc,, +unidecode/__pycache__/x018.cpython-38.pyc,, +unidecode/__pycache__/x01d.cpython-38.pyc,, +unidecode/__pycache__/x01e.cpython-38.pyc,, +unidecode/__pycache__/x01f.cpython-38.pyc,, +unidecode/__pycache__/x020.cpython-38.pyc,, +unidecode/__pycache__/x021.cpython-38.pyc,, +unidecode/__pycache__/x022.cpython-38.pyc,, +unidecode/__pycache__/x023.cpython-38.pyc,, +unidecode/__pycache__/x024.cpython-38.pyc,, +unidecode/__pycache__/x025.cpython-38.pyc,, +unidecode/__pycache__/x026.cpython-38.pyc,, +unidecode/__pycache__/x027.cpython-38.pyc,, +unidecode/__pycache__/x028.cpython-38.pyc,, +unidecode/__pycache__/x029.cpython-38.pyc,, +unidecode/__pycache__/x02a.cpython-38.pyc,, +unidecode/__pycache__/x02c.cpython-38.pyc,, +unidecode/__pycache__/x02e.cpython-38.pyc,, +unidecode/__pycache__/x02f.cpython-38.pyc,, +unidecode/__pycache__/x030.cpython-38.pyc,, +unidecode/__pycache__/x031.cpython-38.pyc,, +unidecode/__pycache__/x032.cpython-38.pyc,, +unidecode/__pycache__/x033.cpython-38.pyc,, +unidecode/__pycache__/x04d.cpython-38.pyc,, +unidecode/__pycache__/x04e.cpython-38.pyc,, +unidecode/__pycache__/x04f.cpython-38.pyc,, +unidecode/__pycache__/x050.cpython-38.pyc,, +unidecode/__pycache__/x051.cpython-38.pyc,, +unidecode/__pycache__/x052.cpython-38.pyc,, +unidecode/__pycache__/x053.cpython-38.pyc,, +unidecode/__pycache__/x054.cpython-38.pyc,, +unidecode/__pycache__/x055.cpython-38.pyc,, +unidecode/__pycache__/x056.cpython-38.pyc,, +unidecode/__pycache__/x057.cpython-38.pyc,, +unidecode/__pycache__/x058.cpython-38.pyc,, +unidecode/__pycache__/x059.cpython-38.pyc,, +unidecode/__pycache__/x05a.cpython-38.pyc,, +unidecode/__pycache__/x05b.cpython-38.pyc,, +unidecode/__pycache__/x05c.cpython-38.pyc,, +unidecode/__pycache__/x05d.cpython-38.pyc,, +unidecode/__pycache__/x05e.cpython-38.pyc,, +unidecode/__pycache__/x05f.cpython-38.pyc,, +unidecode/__pycache__/x060.cpython-38.pyc,, +unidecode/__pycache__/x061.cpython-38.pyc,, +unidecode/__pycache__/x062.cpython-38.pyc,, +unidecode/__pycache__/x063.cpython-38.pyc,, +unidecode/__pycache__/x064.cpython-38.pyc,, +unidecode/__pycache__/x065.cpython-38.pyc,, +unidecode/__pycache__/x066.cpython-38.pyc,, +unidecode/__pycache__/x067.cpython-38.pyc,, +unidecode/__pycache__/x068.cpython-38.pyc,, +unidecode/__pycache__/x069.cpython-38.pyc,, +unidecode/__pycache__/x06a.cpython-38.pyc,, +unidecode/__pycache__/x06b.cpython-38.pyc,, +unidecode/__pycache__/x06c.cpython-38.pyc,, +unidecode/__pycache__/x06d.cpython-38.pyc,, +unidecode/__pycache__/x06e.cpython-38.pyc,, +unidecode/__pycache__/x06f.cpython-38.pyc,, +unidecode/__pycache__/x070.cpython-38.pyc,, +unidecode/__pycache__/x071.cpython-38.pyc,, +unidecode/__pycache__/x072.cpython-38.pyc,, +unidecode/__pycache__/x073.cpython-38.pyc,, +unidecode/__pycache__/x074.cpython-38.pyc,, +unidecode/__pycache__/x075.cpython-38.pyc,, +unidecode/__pycache__/x076.cpython-38.pyc,, +unidecode/__pycache__/x077.cpython-38.pyc,, +unidecode/__pycache__/x078.cpython-38.pyc,, +unidecode/__pycache__/x079.cpython-38.pyc,, +unidecode/__pycache__/x07a.cpython-38.pyc,, +unidecode/__pycache__/x07b.cpython-38.pyc,, +unidecode/__pycache__/x07c.cpython-38.pyc,, +unidecode/__pycache__/x07d.cpython-38.pyc,, +unidecode/__pycache__/x07e.cpython-38.pyc,, +unidecode/__pycache__/x07f.cpython-38.pyc,, +unidecode/__pycache__/x080.cpython-38.pyc,, +unidecode/__pycache__/x081.cpython-38.pyc,, +unidecode/__pycache__/x082.cpython-38.pyc,, +unidecode/__pycache__/x083.cpython-38.pyc,, +unidecode/__pycache__/x084.cpython-38.pyc,, +unidecode/__pycache__/x085.cpython-38.pyc,, +unidecode/__pycache__/x086.cpython-38.pyc,, +unidecode/__pycache__/x087.cpython-38.pyc,, +unidecode/__pycache__/x088.cpython-38.pyc,, +unidecode/__pycache__/x089.cpython-38.pyc,, +unidecode/__pycache__/x08a.cpython-38.pyc,, +unidecode/__pycache__/x08b.cpython-38.pyc,, +unidecode/__pycache__/x08c.cpython-38.pyc,, +unidecode/__pycache__/x08d.cpython-38.pyc,, +unidecode/__pycache__/x08e.cpython-38.pyc,, +unidecode/__pycache__/x08f.cpython-38.pyc,, +unidecode/__pycache__/x090.cpython-38.pyc,, +unidecode/__pycache__/x091.cpython-38.pyc,, +unidecode/__pycache__/x092.cpython-38.pyc,, +unidecode/__pycache__/x093.cpython-38.pyc,, +unidecode/__pycache__/x094.cpython-38.pyc,, +unidecode/__pycache__/x095.cpython-38.pyc,, +unidecode/__pycache__/x096.cpython-38.pyc,, +unidecode/__pycache__/x097.cpython-38.pyc,, +unidecode/__pycache__/x098.cpython-38.pyc,, +unidecode/__pycache__/x099.cpython-38.pyc,, +unidecode/__pycache__/x09a.cpython-38.pyc,, +unidecode/__pycache__/x09b.cpython-38.pyc,, +unidecode/__pycache__/x09c.cpython-38.pyc,, +unidecode/__pycache__/x09d.cpython-38.pyc,, +unidecode/__pycache__/x09e.cpython-38.pyc,, +unidecode/__pycache__/x09f.cpython-38.pyc,, +unidecode/__pycache__/x0a0.cpython-38.pyc,, +unidecode/__pycache__/x0a1.cpython-38.pyc,, +unidecode/__pycache__/x0a2.cpython-38.pyc,, +unidecode/__pycache__/x0a3.cpython-38.pyc,, +unidecode/__pycache__/x0a4.cpython-38.pyc,, +unidecode/__pycache__/x0ac.cpython-38.pyc,, +unidecode/__pycache__/x0ad.cpython-38.pyc,, +unidecode/__pycache__/x0ae.cpython-38.pyc,, +unidecode/__pycache__/x0af.cpython-38.pyc,, +unidecode/__pycache__/x0b0.cpython-38.pyc,, +unidecode/__pycache__/x0b1.cpython-38.pyc,, +unidecode/__pycache__/x0b2.cpython-38.pyc,, +unidecode/__pycache__/x0b3.cpython-38.pyc,, +unidecode/__pycache__/x0b4.cpython-38.pyc,, +unidecode/__pycache__/x0b5.cpython-38.pyc,, +unidecode/__pycache__/x0b6.cpython-38.pyc,, +unidecode/__pycache__/x0b7.cpython-38.pyc,, +unidecode/__pycache__/x0b8.cpython-38.pyc,, +unidecode/__pycache__/x0b9.cpython-38.pyc,, +unidecode/__pycache__/x0ba.cpython-38.pyc,, +unidecode/__pycache__/x0bb.cpython-38.pyc,, +unidecode/__pycache__/x0bc.cpython-38.pyc,, +unidecode/__pycache__/x0bd.cpython-38.pyc,, +unidecode/__pycache__/x0be.cpython-38.pyc,, +unidecode/__pycache__/x0bf.cpython-38.pyc,, +unidecode/__pycache__/x0c0.cpython-38.pyc,, +unidecode/__pycache__/x0c1.cpython-38.pyc,, +unidecode/__pycache__/x0c2.cpython-38.pyc,, +unidecode/__pycache__/x0c3.cpython-38.pyc,, +unidecode/__pycache__/x0c4.cpython-38.pyc,, +unidecode/__pycache__/x0c5.cpython-38.pyc,, +unidecode/__pycache__/x0c6.cpython-38.pyc,, +unidecode/__pycache__/x0c7.cpython-38.pyc,, +unidecode/__pycache__/x0c8.cpython-38.pyc,, +unidecode/__pycache__/x0c9.cpython-38.pyc,, +unidecode/__pycache__/x0ca.cpython-38.pyc,, +unidecode/__pycache__/x0cb.cpython-38.pyc,, +unidecode/__pycache__/x0cc.cpython-38.pyc,, +unidecode/__pycache__/x0cd.cpython-38.pyc,, +unidecode/__pycache__/x0ce.cpython-38.pyc,, +unidecode/__pycache__/x0cf.cpython-38.pyc,, +unidecode/__pycache__/x0d0.cpython-38.pyc,, +unidecode/__pycache__/x0d1.cpython-38.pyc,, +unidecode/__pycache__/x0d2.cpython-38.pyc,, +unidecode/__pycache__/x0d3.cpython-38.pyc,, +unidecode/__pycache__/x0d4.cpython-38.pyc,, +unidecode/__pycache__/x0d5.cpython-38.pyc,, +unidecode/__pycache__/x0d6.cpython-38.pyc,, +unidecode/__pycache__/x0d7.cpython-38.pyc,, +unidecode/__pycache__/x0f9.cpython-38.pyc,, +unidecode/__pycache__/x0fa.cpython-38.pyc,, +unidecode/__pycache__/x0fb.cpython-38.pyc,, +unidecode/__pycache__/x0fc.cpython-38.pyc,, +unidecode/__pycache__/x0fd.cpython-38.pyc,, +unidecode/__pycache__/x0fe.cpython-38.pyc,, +unidecode/__pycache__/x0ff.cpython-38.pyc,, +unidecode/__pycache__/x1d4.cpython-38.pyc,, +unidecode/__pycache__/x1d5.cpython-38.pyc,, +unidecode/__pycache__/x1d6.cpython-38.pyc,, +unidecode/__pycache__/x1d7.cpython-38.pyc,, +unidecode/__pycache__/x1f1.cpython-38.pyc,, +unidecode/util.py,sha256=qR0aGIMExGrFUGmojfAMdbRklcXrAPvXpU1evPXCa4g,1782 +unidecode/x000.py,sha256=dxTi7LcLTlbF3ZGGk9xPjx8sx2M6qPBIs2b5RS2DVNY,3041 +unidecode/x001.py,sha256=ylHh3UVaPtibVuUEEWvdSeDFK0OXrWt4-LnxAgYD6qo,3891 +unidecode/x002.py,sha256=Hoks5fu8uyhwDuJt93BiC6iYv_HVY4bIvKklyAtBoFI,3889 +unidecode/x003.py,sha256=UdskMuqktghKcjLeegwYkyfhDH3lgi_G5rr7ID5W0-s,3875 +unidecode/x004.py,sha256=85Sh4Rem7dRS7kIx6yGQqA7U7MxqCD40DGoqaob9MzI,4071 +unidecode/x005.py,sha256=qPEepEySMuoXFtVhrFw-y69wnVQGcFmk_0vtcUzDYTo,3997 +unidecode/x006.py,sha256=4fZWzc5DGZVFD1zvHtkywMHykQTiFgA7M6LMowpaGI0,3961 +unidecode/x007.py,sha256=k2kkTXdbKqMFOQy2TlGmRnoRYMCOvqTfjusGV76u9SE,4122 +unidecode/x009.py,sha256=aZrWpXwsS2yIyO8oZIIN3Uo4j0XdpaJq5VGdCu3e8cc,4075 +unidecode/x00a.py,sha256=UrXdvZ-qVMfWRSRW8HwrxfNXB-Jp0lgW2iPs6roZXz4,4121 +unidecode/x00b.py,sha256=MjqdSyCxXLZ6wUrgeS8A-wop9S78EEK9e-BJ4HpAqLA,4132 +unidecode/x00c.py,sha256=y-y0RqVolrIBfsj1DtT_rQUbmxxjoKnWlZDMPPC6Om4,4102 +unidecode/x00d.py,sha256=OVfHvb44WS_aMXSWrZt-693xJ70L4sepcyJFIkl23TY,4121 +unidecode/x00e.py,sha256=9N9w09V225dx1-e8w0HRaIoD66mpDhHgoQ-RlPZznmA,4092 +unidecode/x00f.py,sha256=Vak8Z6Dy6ucFysFSNBt24ZE4h2ZSXQcBLiWCSC27bSA,4061 +unidecode/x010.py,sha256=9vck5PTRcz5Q64F_2dIMQoPGEFTHWjvwq7ZE90nvOK4,4110 +unidecode/x011.py,sha256=8EN-PZS-ythtQlU3HZYNkGePm3oWFzSOgOorkeQUBV4,4135 +unidecode/x012.py,sha256=2onQfsL5e7X4RB9DKehMUcG81gaSav4UwGalXulnxOE,4318 +unidecode/x013.py,sha256=Nl9CnUVkJkXBux5TEia5Vq1nPjTICUUyT77GhkChbrQ,4247 +unidecode/x014.py,sha256=CkrW473dLq_AllpcK8teAUQSeglML_MZ6t9TsK5g9wE,4300 +unidecode/x015.py,sha256=TB6O4l2qPxbmF2dejlxXLqX5tTfjl95cMYx1770GHs0,4329 +unidecode/x016.py,sha256=M9kiUT0ScE5acj-tkomNZ0eND1lvau0i6tJOWepU1FA,4140 +unidecode/x017.py,sha256=nsZP_7vWKOTYY8LOE535g67qwwaMdGblZ-79MbfTNX8,4190 +unidecode/x018.py,sha256=_qBETpive71IdV6nD0md6KaSHaxaSpPUsTTHtVlE4KM,4099 +unidecode/x01d.py,sha256=EwAYkMVHAFvbKRzsQ-e4cRcvS_eia3kYCM2GcaqkBWY,3701 +unidecode/x01e.py,sha256=oVdWd4v85k-Slc3V0i2NZ4i5G866X6Qw7bKXJDmbXig,3853 +unidecode/x01f.py,sha256=pG-fs1iD7O3vSwIx6Ibz5MhpZI_NsQWEDlHiRpxgZC0,3899 +unidecode/x020.py,sha256=k9PWwEJiWl7yUFTVR89cl2XuYqWDEiVfrXvSqOaeJH4,4010 +unidecode/x021.py,sha256=Ns9H51Q51tDB-mRSERyMN1y2EiE7UPQx9K3BxwaFrQs,4012 +unidecode/x022.py,sha256=OzIXC-VMfUskTtEe5_m3zpmgtKtJSDY0XBZ5C0codi8,4329 +unidecode/x023.py,sha256=FFgn4hJ7Q4SbsxFtHUa8SuQ0VBJ9hkod5QTWaMmkk9U,4341 +unidecode/x024.py,sha256=pMZqUxkwfgz9n9NXpUaAaNr-p9ACNCyfTQKo2PFJ11w,4049 +unidecode/x025.py,sha256=-dvBV3byxxngHQcQx7Jjt9dwtehBaQwRoCnX3ZAzWe0,3871 +unidecode/x026.py,sha256=N7i11hEwuiW9mSEp0Dk4Aa9iIsHsxAYhLAplqZnUMs0,4020 +unidecode/x027.py,sha256=wZ1l328qv5BWbk-FPr34ayyJ4rWQG3EQIsPxd7GilFg,3783 +unidecode/x028.py,sha256=FZPCZ9w3N3WOI42h2gHEQgVOAlLBNTZjMu_KQQkIMdk,5069 +unidecode/x029.py,sha256=TlYRf7ym0R-L7DncmX4RNZX5kKctvGFLbtu8GPkxqpE,3584 +unidecode/x02a.py,sha256=WD3uhv1sNhQB45ugiKUk4Btj3aj8qcH_kpwrV3jRWJw,3589 +unidecode/x02c.py,sha256=zRG2Elxv5SlYrBpJb1NUz7WsJOFAkzwSi991cMyhnJs,3596 +unidecode/x02e.py,sha256=_ntc-U9pwAkGQkFC3zdQgJNUZSv9W4115ouIbINGyw4,4461 +unidecode/x02f.py,sha256=9cxem6MFm7acjUDcmYLk9lbxEyfP2xMjfE3c-6PUEbg,4572 +unidecode/x030.py,sha256=aHVHcoSl5FcxX9QQALaW5n1zYJ0Ymap-wgWuzojXLyY,4037 +unidecode/x031.py,sha256=vRlzxBKPo5s3ZDpUojrXelZKjTEwR8fsnm3vUeB5bp8,4125 +unidecode/x032.py,sha256=BSZV_t8jVsWX_RsoqajWAqigQaHh3wXmoMG5wUZtgos,4485 +unidecode/x033.py,sha256=ImTd4BRRPgCqWmrvJPoikoL0dJMKH8eQgd48vksi60A,4513 +unidecode/x04d.py,sha256=d5K-HbR3Gg1VBdMk1GO6PJdoseRRIV5ef4aQbslnsBo,4528 +unidecode/x04e.py,sha256=z04XMxt3y016alep4Xg8Zjh4cvBj6CddjD9Qv6sr6v4,4646 +unidecode/x04f.py,sha256=zEf_S6bDF755svnPRWyreVf2Q4SekYMxIpGf1Jb2alc,4607 +unidecode/x050.py,sha256=MNhEf7TRcQ2CdgkMcFloEGSbTtrsXK-6r6Ru7HDG6hU,4682 +unidecode/x051.py,sha256=VY0jC10xdU7bm21Cig5omd7L-4hiSk_rk2UTR_yTF3g,4685 +unidecode/x052.py,sha256=a09eo_5pL6jpU9TW-zG2w2iXTYp6awtQ4OxGnLdcwKg,4654 +unidecode/x053.py,sha256=so5U-CQ5jRbp7AYZZPCdmkdnNtfNn_-Nl_761eBMtIU,4616 +unidecode/x054.py,sha256=Htu6ZFPTTyBHUU1Ia-mc7Y3Dy4j1cp-fRwag0HGwmwk,4583 +unidecode/x055.py,sha256=WzgwsrHInE1H-O519FOIybJpofzdyfu7w5NZ5I2OtQI,4599 +unidecode/x056.py,sha256=t4ZVJlxic1vcqhrypLWRd3LyIfEuWoPIz343pCrfW7k,4615 +unidecode/x057.py,sha256=ndJuRj4TnvSe6aLX-yzDYHnWEl1JfqA6HnQvzsf2Fyo,4631 +unidecode/x058.py,sha256=nkaS7T1PVlhKlxVd-WrDw4Gx14mciLEZQrUt-9NpkD0,4678 +unidecode/x059.py,sha256=9wAKGpczWuyqMb89px7Ldy1McHecDXd8RMJ7lXwcBCU,4644 +unidecode/x05a.py,sha256=F150z3X248dkDgTq-0lyL-bLRqZZd7U0mkUI6PJRwwM,4636 +unidecode/x05b.py,sha256=LeJj8prX04qvLHFaeG-b2YE9LqIbnUec6pFD-7E918c,4668 +unidecode/x05c.py,sha256=Citt0KhdqvWkErFdpeSyg6x5CviH1opVRPSD6eBWjsA,4612 +unidecode/x05d.py,sha256=w1vKjN5RWPiwP535FCiqakz1IbeB4MGe2ANVM_bcdq4,4670 +unidecode/x05e.py,sha256=6Z7gnAXq9tVwvFIwh632oLQuEiHz1atcqIDREeoqldM,4668 +unidecode/x05f.py,sha256=Ho5tdX7JErho7LjeVCxf29XlWeEpDt5RUJC3nbw2j8M,4660 +unidecode/x060.py,sha256=2x6hmUwn_V3icd1kdfzkkDp5iEdmij7zpUWizfVIE7Q,4642 +unidecode/x061.py,sha256=hwSoPcP4PLy5zPITLdSVaYGwt_fIH9kJPpshKJZi-LA,4662 +unidecode/x062.py,sha256=rH9eYXX_t-Z4-pOy9-lyVm68zXt114X3lAIBI5JG_Qs,4620 +unidecode/x063.py,sha256=n8aXYOPurrEbBzz4DAl-tFOFiqMJ-r1Yt3WpM3ZGTq0,4656 +unidecode/x064.py,sha256=uBebjkUmgQVzK0tKWjxLZwQ1oC9KMEppv0W6caB8v1g,4655 +unidecode/x065.py,sha256=cFnHSLoNwMG6PJvxWWeWShSkHoB9IYTS2LJCc8W0l4I,4638 +unidecode/x066.py,sha256=gV2vx0TqIA44PBOzF02wetf3dxXcXmg8Jr2CtzxMDFU,4677 +unidecode/x067.py,sha256=9ck2UFSv8UL3c0RHPTdV4Rzq7ogZVedwsMAYhGE1lmM,4635 +unidecode/x068.py,sha256=aTAAeHLr5-VnMqNF0h9KC4tFOusV9PpWdywp7xllAA0,4674 +unidecode/x069.py,sha256=8_VMN2vGqNAPrP8iPxICRI9PN81Hts21FM1A4n1_7to,4673 +unidecode/x06a.py,sha256=e7ahJ-j5YvomZvQcIxfAMbHgijbKncYoTN9TakDQqig,4674 +unidecode/x06b.py,sha256=lBRWVhTMJPBKWAyAT23PueHtw9wXTuUG9S2UVWjosr4,4608 +unidecode/x06c.py,sha256=i8xXjlNwhXxvrHdnTbdy-jTfml_fD0uFURctA1BQKk0,4643 +unidecode/x06d.py,sha256=BvgJd7TNj6cL6I5bjPXngi3tJPo0YfhISCHSXvfmsTk,4651 +unidecode/x06e.py,sha256=jZ6VeQbASYGtx0QXySzZzRQf_LqtPAU6jhTo3U_nFTU,4640 +unidecode/x06f.py,sha256=W0A95toB7w7pLrohCaet_d0-S3V84fjzTKgZ6vhUtok,4650 +unidecode/x070.py,sha256=lVM1qXUltqIrKIi0WPH1F5Feuq4M007nm3lOkR_EB2s,4693 +unidecode/x071.py,sha256=v2V3WNKPVEhuJ_RX6rZA45rFIukgMCJ8rqPoUwj05zc,4670 +unidecode/x072.py,sha256=NhOkJEqApO9shkYgwdWVarVUDmWailI4N1vNiLGkOSM,4659 +unidecode/x073.py,sha256=loYg-ZrK1rdy2CkbQfd4qydW8lCeiNywEzT6gLTN-GI,4646 +unidecode/x074.py,sha256=FLIumUZcrCy9Y6eXL5BLpa_hE5HMGbPo-PWtFBh-rBs,4696 +unidecode/x075.py,sha256=P3SrhI5BQ5sJ66hyu_LWDONpuzLZJBKsl7f-A37sJXc,4675 +unidecode/x076.py,sha256=3enaJAMy951MK_yBnhJiOmoTdzU0eJ2uEgoRgZRTUn0,4639 +unidecode/x077.py,sha256=XH_TjHspGSnu4v3qgNOqFNMvZKZcA-HH6q_GWB48Cos,4675 +unidecode/x078.py,sha256=L9XOo8UH_x-prQC_edArnTs-j2asZR940sLaPST2iy0,4648 +unidecode/x079.py,sha256=6e29mgaXPmtMrU8_QRfmZpWZW8o-yEeeIOgAHOoepo8,4602 +unidecode/x07a.py,sha256=fMACYuAsIumgE8XkYnM2795HtFA6weH4YLn7jgJLbbw,4669 +unidecode/x07b.py,sha256=UH8ZXsR11pINz0AaxJ8etTTyaXiCawjuLcctzp4FwZc,4669 +unidecode/x07c.py,sha256=fpqGGsF0-rEVxBeVFf0RM8fjweUlg-9UduAtxAjL5vc,4663 +unidecode/x07d.py,sha256=EKFrTQTNFLGnsm3qI76ALxrxGCcDuyEbapi9j9jy1B4,4678 +unidecode/x07e.py,sha256=n2OG5xe8I-V0pn98Q2E-7PbXSQQI72ozNNUXFnMZHvM,4682 +unidecode/x07f.py,sha256=g455qjG3LBu9ujuuTt5xrRn2djK_iVXAJ4dUVl-bYfs,4664 +unidecode/x080.py,sha256=Fuqy0RgnvfvFFdmGiaHwK2B60UCU5Aw4fyF79kBfhr8,4651 +unidecode/x081.py,sha256=rQg3Hjqo61bEKCpb7TybHDLv2Hgu-_ghKdW6xk9xOhU,4673 +unidecode/x082.py,sha256=sRjOiGrYy2RtqqH_xQdL6_i17I-wJZI6ag7404mL4M8,4649 +unidecode/x083.py,sha256=8hCxGV2o1kFA6hMFvk4Ici_QKynDCYjDWjzCuMyfmHI,4643 +unidecode/x084.py,sha256=jIDgDPhwssUcLgA7N0ZINrB_qZn1P4C7lHyvP7yKA6o,4646 +unidecode/x085.py,sha256=5063XP5F72OEYuqjETqFlN_7IaU1A0feVuvIup9R0rI,4636 +unidecode/x086.py,sha256=ovNLdMRRHm4jngDGXmwG66zZH6l-V-uMtoYnXB_W_QY,4614 +unidecode/x087.py,sha256=-VmLJWGVMGF9BxYD8VcTc8TS83W27qcERuycKCfpLBc,4649 +unidecode/x088.py,sha256=E63aAVUF0B1f-5XL7fOUWqXL2juUJLU9TwO_LHKvd2Q,4645 +unidecode/x089.py,sha256=mrKWneiJ2hIFkM4cu4bU0IQMvTRWgXZ8rsDW575jp9A,4628 +unidecode/x08a.py,sha256=NjMp9ck824PXG2gcJXfi_9oQCFgXhhiallO3bYCtXCE,4647 +unidecode/x08b.py,sha256=W1kAtliqhm5x28Kxc6kUrjzqo-xc_HmYY0BjHhEV2x4,4643 +unidecode/x08c.py,sha256=aDhwugSrvtUhDdwbACfjS0EkBqGojwny-qbrQRJfPhA,4630 +unidecode/x08d.py,sha256=oyydBTJng0ip79lUTBHoTIqGjxmHTb0twkPZqE7LxeU,4636 +unidecode/x08e.py,sha256=w-FysLX-LgmggEuhmPZjyT67-i4_EB8Hx44i_X_Q3Nc,4659 +unidecode/x08f.py,sha256=adygkkCQn4W6YhJUknf2O-2eM_LzH1LfjjpgenbPh80,4651 +unidecode/x090.py,sha256=j-5qrCDDHYKJnbHL5A_fm5ISrdFVgDR5bXQbP18G-14,4631 +unidecode/x091.py,sha256=S8jlVjjPNLPCsSXK8qKXqGGoTLj-LWje5J-f-2AAEXY,4655 +unidecode/x092.py,sha256=uSF8NVYh_UGJE2pcl4JrVU2Prb-T2crGLCE4XQe7DfQ,4648 +unidecode/x093.py,sha256=oMiZM1VfvfKnwVKSJh28iynWJG8iQtKu_1zsrbPdPNs,4666 +unidecode/x094.py,sha256=MShhNv4E9bj9jmQEtWHi_8ZjeS4p2Iz6j3j9kJb5rK0,4661 +unidecode/x095.py,sha256=BQ1R6QwhWjC_Eb7zIbWP0A2ro7bI-t6fTAQWLFMmzAM,4671 +unidecode/x096.py,sha256=N9hLQrZhbTXC9boxDcWu3WESTIB6En82kJkBY-6qBRI,4610 +unidecode/x097.py,sha256=K4waHuw6tNchmcY7Glc-Su6cTG3-iF_X_egYuG-E4fA,4643 +unidecode/x098.py,sha256=CFFcb5gpK7FBqPsFwRoLP0YcYFJBGgh3l-Rf4PzXbjc,4645 +unidecode/x099.py,sha256=e9w1-tsa3tCYYQXn71Ey1bg_n2UYudMQ0y-zSSCdajE,4629 +unidecode/x09a.py,sha256=Z8pQsTc62CWgm0JPnj3kokKKf9_qfzRpo0u5iH61CaE,4623 +unidecode/x09b.py,sha256=piSZ2AAK5GavHJEa8qwI_lrldSSgNhxYvLua0Au_1aA,4655 +unidecode/x09c.py,sha256=NveMhN85_Cm4H1cnfHDTcnSj675MOVBq9Lkjpw3YxA0,4659 +unidecode/x09d.py,sha256=2Sj376QIs8rJ7VDrPW5RELhkJ8LI5JI4NRbFcl4DXlE,4632 +unidecode/x09e.py,sha256=z1bF6AML_d20dQm9HD7YBrnKqTQVjeTTI999hcLEe0M,4615 +unidecode/x09f.py,sha256=T-pS5hli39rA1GDDqZYfyHRupPALqklPXA-1i8pgc1I,4509 +unidecode/x0a0.py,sha256=EpopPuuocybgCcpX19Ii-udqsPXJjSces3360lqJ8vs,4428 +unidecode/x0a1.py,sha256=0hvF77d5E640SujjdHVqy5gMUH85gEdOv80eRvCEAGM,4469 +unidecode/x0a2.py,sha256=9Icpfk_ElebYd_xN09OMziFrpAGPXEUNVmawpnhbBaQ,4503 +unidecode/x0a3.py,sha256=G1lPrnCqYz0s4wsSa1qM0WgrZBWO_beRk3AgK0iVZLA,4521 +unidecode/x0a4.py,sha256=vS-wPpkfMmwRJjXTBYM4BGpzBfDoKWMadNNWaTPYcpI,4437 +unidecode/x0ac.py,sha256=wj7hl88VlCdc_eGpOL4m4CBJILyQqd9atObC5Xvd0aA,4709 +unidecode/x0ad.py,sha256=Rz5rn0fM-CqRjaN4TvSq_1StAQdyAF2WX3cUvcQHaWU,4766 +unidecode/x0ae.py,sha256=jNIBVB-Pw2ZNihAeyWbDIEq9Yt9zlhdfGylfvAaxUks,4875 +unidecode/x0af.py,sha256=Am5YC8Zfrun5NUKxU6LrU2-d5GgkGSBs7fZt2rqSi74,5012 +unidecode/x0b0.py,sha256=1bgHerCDAqIcJHYeGddJjJfRWiHCKtU2B0J-XGvcbbc,4853 +unidecode/x0b1.py,sha256=Six-lzGdvgJx4YsIa0lTusnBEV1zbCKQCquq17TDJoQ,4746 +unidecode/x0b2.py,sha256=HQDbmglNi4QfiRSGucUclgq_4FGpRjbJkWU1JTLAFGc,4680 +unidecode/x0b3.py,sha256=1lqxghVZiiStOAx1IG_vc1zZTXrAa7Z__QY6ZWvo2aA,4741 +unidecode/x0b4.py,sha256=V6BNSTxpyP8VuqF7x5z7bpF3MQAkwZfKtEu6NFr_vSg,4762 +unidecode/x0b5.py,sha256=9NVd2hNLyRlLceVlznba1dreqBGeKU_0gzmkgAw0gyg,4919 +unidecode/x0b6.py,sha256=V_vRsB0GICu9hqhO4pnbPWreDSevJ3bbmLRJkuQUxnE,4996 +unidecode/x0b7.py,sha256=CwBaCBICyVagnFjUpkwabuDvBJw7gAeqkSRpfBAVv8s,4833 +unidecode/x0b8.py,sha256=xYp-xy2LIwq95OWyS9vYMc_Z5od9dud0W1dxeg4P_Jk,4714 +unidecode/x0b9.py,sha256=z3hKNzBq_MeK9V3AyQzaY58cgi0-VGOsLk3-UFmszLQ,4704 +unidecode/x0ba.py,sha256=4gubifoBeJUUrwXEI4litJygekufEycmWDLrJ-Qvs14,4765 +unidecode/x0bb.py,sha256=bsCTABUdC6yTn8_0vhYe5jRP1z_BoAdificB8Y1c1hA,4730 +unidecode/x0bc.py,sha256=AhQvAz7yHlbQ_4c2KOIisq07eZJ5JQn6cV8I31oT9kg,4707 +unidecode/x0bd.py,sha256=IGtyVxIUr1mU3hokn6iUDJhXZezQozVvfWOyf4Pa5dI,4752 +unidecode/x0be.py,sha256=1D-hXu3p3wvOnGVMjEqVsrltYe7UuSwit2yqN5eFizc,4849 +unidecode/x0bf.py,sha256=NkEXqr2ER3BNFkTasDV9CHnkRBuX_Ao5OHGv_NgKAew,5010 +unidecode/x0c0.py,sha256=zDlHpyM0omza5TqGLb8Rhl7Wd-LlV1AjvH_xdnEnNFw,4856 +unidecode/x0c1.py,sha256=AC6xJyx9UblKAGNqGN7AH2Idb3_3vbc-I5U0Myig5fA,4765 +unidecode/x0c2.py,sha256=siRYLA8Cv9Z8XsRp3WQOBdRrPkjJOuEh8z1-3SMXOzQ,4710 +unidecode/x0c3.py,sha256=hlAFe6lsz0aLMixlpeFjV4I-WTIiA3B2BU58yGlTwRg,4975 +unidecode/x0c4.py,sha256=z3xZwSkf5ru1FCdBMHOr5fyglzVdyPhQVtWjq9xInsQ,5024 +unidecode/x0c5.py,sha256=F-DR0eVMRkemOnNXOtDjI5i6gW9136XLmWM_yMVvc84,4581 +unidecode/x0c6.py,sha256=7p_jMrHf3WUa_zANms-RGVN1bAeshgWLkC16_VcSawA,4490 +unidecode/x0c7.py,sha256=5eOAq4jFsPZ-zKO7lHzAGj_EvXdaMC4Kud7gvE-B7Tg,4564 +unidecode/x0c8.py,sha256=wltKvhBgn51jULzwUnEbmyDuK9JvQpQee0uTKK42-20,4733 +unidecode/x0c9.py,sha256=GoARON07wCoHN2wRHb5fvzqE9L3Yme2hKeciynUIAIk,4722 +unidecode/x0ca.py,sha256=BsBZTNj3npIkdo3L9pSEX7XvDT68KV7wFtOOwyEb2So,5007 +unidecode/x0cb.py,sha256=8T7vnJMRmYGyySYthMWz0bgN-MremktGImjejodFeMo,5012 +unidecode/x0cc.py,sha256=GKoHN-4vL4Y3EL42G0xbN74Tgspew1oMvxQtsIa3ess,4749 +unidecode/x0cd.py,sha256=7sZ05OjugbaombMRDYOVxgstZbXMcuX5kHFheKv4W2E,4738 +unidecode/x0ce.py,sha256=mOEHFrsAwIvcTnh7OKVK5qbuXUXHfJOR7D4FtXsQmao,4708 +unidecode/x0cf.py,sha256=H9PeYcbOG68F_yc7zsELUuN05ANfFNOUX-e3-gzx7Ow,4713 +unidecode/x0d0.py,sha256=eULqcGHPmaoEdl0EwRB5wWSu8M43bp4HoFo5gGljacg,4706 +unidecode/x0d1.py,sha256=BClLDAjPgsAX6MJCsuHfmfuhH9qfzUy_vb-d9zBs3Oc,4767 +unidecode/x0d2.py,sha256=e74nqGo4E4sF1sy8qBFu2ecWoRfJdoXI1xRFRPqYEz8,4724 +unidecode/x0d3.py,sha256=8-UmvJ3-ILXo9d3GA-ReOE4OfUenL3tVUJYldZ9gHu0,4705 +unidecode/x0d4.py,sha256=fwUmzksoddTKB8fH2rZMxRK3pJtLrxhcrYpHfBauAwE,4758 +unidecode/x0d5.py,sha256=rANSL5ndzLgSgYJQNEw57AfXpicRe7pvHRlKTPb4-QQ,4680 +unidecode/x0d6.py,sha256=fT8_cRzp7y60IIhn87kM9lLehKGAg5wYmfFOwgGp6e0,4765 +unidecode/x0d7.py,sha256=0zY-KFUnKk-CuYpb1zSYj3QdS6UsfZ_lsemOuRSeDwM,4559 +unidecode/x0f9.py,sha256=2PD0_fpDnaFO9ftICjYSOhnjAfBppjsj1TcLIuYjnCI,4567 +unidecode/x0fa.py,sha256=6X94S2GbR6XOwkzx2SYynZzBMHAbRHC9GvW_vXaTDRU,4406 +unidecode/x0fb.py,sha256=qaAP_vF3_-M--wKkyb0DfBjIdnGKuk4GQLxV7fp2-_4,3838 +unidecode/x0fc.py,sha256=KcyQnyv7gxNeVcAnRwQrm4NlabZE3CrnmtLqXj_7te8,3595 +unidecode/x0fd.py,sha256=fq1BGexi73J3QPUwnL4_LZT4uh8mxYqAgMNtofbfVKE,3764 +unidecode/x0fe.py,sha256=mpt-K-jqk36iouLz5HOcthOQJczqsca9aYkEGhJ6Wk4,3825 +unidecode/x0ff.py,sha256=KGE3aIdJCR-3kAVaXOyuY44M-KfCA9UQt4B9AlEJiq0,3983 +unidecode/x1d4.py,sha256=ZS_7TAX87oGtT7b8tIlWcmeHChVINZ4W9jl9wA6JfmU,3839 +unidecode/x1d5.py,sha256=Cuh3bUzoyp8c8lJ7Y_gLmAKQ03XHMCsgTZf3uE2-G2o,3839 +unidecode/x1d6.py,sha256=6fIRGTFODh3kysq10Xr_8EmG6HZuWztLjr4vitkk8OQ,3974 +unidecode/x1d7.py,sha256=jIs9oZBMbSh5OQvPiyUI4aAdji9EbzeOXigTq4Oq_kY,3645 +unidecode/x1f1.py,sha256=CcmetFXD5Xxt9ZY0xKAjQbe16Wlq-YccWvJ_eqdzeTc,3937 diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/WHEEL b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/WHEEL new file mode 100644 index 000000000..8b6dd1b5a --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/entry_points.txt b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/entry_points.txt new file mode 100644 index 000000000..3016afe65 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +unidecode = unidecode.util:main + diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/metadata.json b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/metadata.json new file mode 100644 index 000000000..64bbf1542 --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Text Processing", "Topic :: Text Processing :: Filters"], "extensions": {"python.commands": {"wrap_console": {"unidecode": "unidecode.util:main"}}, "python.details": {"contacts": [{"email": "tomaz.solc@tablix.org", "name": "Tomaz Solc", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}}, "python.exports": {"console_scripts": {"unidecode": "unidecode.util:main"}}}, "generator": "bdist_wheel (0.29.0)", "license": "GPL", "metadata_version": "2.0", "name": "Unidecode", "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*", "summary": "ASCII transliterations of Unicode text", "version": "1.1.1"} \ No newline at end of file diff --git a/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/top_level.txt b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/top_level.txt new file mode 100644 index 000000000..051b14ceb --- /dev/null +++ b/env/lib/python3.8/site-packages/Unidecode-1.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +unidecode diff --git a/env/lib/python3.8/site-packages/_virtualenv.pth b/env/lib/python3.8/site-packages/_virtualenv.pth new file mode 100644 index 000000000..1c3ff9986 --- /dev/null +++ b/env/lib/python3.8/site-packages/_virtualenv.pth @@ -0,0 +1 @@ +import _virtualenv \ No newline at end of file diff --git a/env/lib/python3.8/site-packages/_virtualenv.py b/env/lib/python3.8/site-packages/_virtualenv.py new file mode 100644 index 000000000..b399da4cc --- /dev/null +++ b/env/lib/python3.8/site-packages/_virtualenv.py @@ -0,0 +1,115 @@ +"""Patches that are applied at runtime to the virtual environment""" +# -*- coding: utf-8 -*- + +import os +import sys + +VIRTUALENV_PATCH_FILE = os.path.join(__file__) + + +def patch_dist(dist): + """ + Distutils allows user to configure some arguments via a configuration file: + https://docs.python.org/3/install/index.html#distutils-configuration-files + + Some of this arguments though don't make sense in context of the virtual environment files, let's fix them up. + """ + # we cannot allow some install config as that would get packages installed outside of the virtual environment + old_parse_config_files = dist.Distribution.parse_config_files + + def parse_config_files(self, *args, **kwargs): + result = old_parse_config_files(self, *args, **kwargs) + install = self.get_option_dict("install") + + if "prefix" in install: # the prefix governs where to install the libraries + install["prefix"] = VIRTUALENV_PATCH_FILE, os.path.abspath(sys.prefix) + for base in ("purelib", "platlib", "headers", "scripts", "data"): + key = "install_{}".format(base) + if key in install: # do not allow global configs to hijack venv paths + install.pop(key, None) + return result + + dist.Distribution.parse_config_files = parse_config_files + + +# Import hook that patches some modules to ignore configuration values that break package installation in case +# of virtual environments. +_DISTUTILS_PATCH = "distutils.dist", "setuptools.dist" +if sys.version_info > (3, 4): + # https://docs.python.org/3/library/importlib.html#setting-up-an-importer + from importlib.abc import MetaPathFinder + from importlib.util import find_spec + from threading import Lock + from functools import partial + + class _Finder(MetaPathFinder): + """A meta path finder that allows patching the imported distutils modules""" + + fullname = None + lock = Lock() + + def find_spec(self, fullname, path, target=None): + if fullname in _DISTUTILS_PATCH and self.fullname is None: + with self.lock: + self.fullname = fullname + try: + spec = find_spec(fullname, path) + if spec is not None: + # https://www.python.org/dev/peps/pep-0451/#how-loading-will-work + is_new_api = hasattr(spec.loader, "exec_module") + func_name = "exec_module" if is_new_api else "load_module" + old = getattr(spec.loader, func_name) + func = self.exec_module if is_new_api else self.load_module + if old is not func: + try: + setattr(spec.loader, func_name, partial(func, old)) + except AttributeError: + pass # C-Extension loaders are r/o such as zipimporter with + +Blinker includes code from Louie, by Patrick K. O'Brien, Mike +C. Fletcher, and Matthew R. Scott. diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/INSTALLER b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/LICENSE b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/LICENSE new file mode 100644 index 000000000..88f6e84a1 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) The Blinker authors and contributors + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/METADATA b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/METADATA new file mode 100644 index 000000000..25cb9f232 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/METADATA @@ -0,0 +1,103 @@ +Metadata-Version: 2.1 +Name: blinker +Version: 1.4 +Summary: Fast, simple object-to-object and broadcast signaling +Home-page: http://pythonhosted.org/blinker/ +Author: Jason Kirtland +Author-email: jek@discorporate.us +License: MIT License +Keywords: signal emit events broadcast +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.4 +Classifier: Programming Language :: Python :: 2.5 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.0 +Classifier: Programming Language :: Python :: 3.1 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities + +[![Build Status](https://travis-ci.org/jek/blinker.svg?branch=master)](https://travis-ci.org/jek/blinker) + + +# Blinker + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + + >>> from blinker import signal + >>> started = signal('round-started') + >>> def each(round): + ... print "Round %s!" % round + ... + >>> started.connect(each) + + >>> def round_two(round): + ... print "This is round two." + ... + >>> started.connect(round_two, sender=2) + + >>> for round in range(1, 4): + ... started.send(round) + ... + Round 1! + Round 2! + This is round two. + Round 3! + +See the [Blinker documentation](https://pythonhosted.org/blinker/) for more information. + +## Requirements + +Blinker requires Python 2.4 or higher, Python 3.0 or higher, or Jython 2.5 or higher. + +## Changelog Summary + +1.3 (July 3, 2013) + + - The global signal stash behind blinker.signal() is now backed by a + regular name-to-Signal dictionary. Previously, weak references were + held in the mapping and ephemeral usage in code like + ``signal('foo').connect(...)`` could have surprising program behavior + depending on import order of modules. + - blinker.Namespace is now built on a regular dict. Use + blinker.WeakNamespace for the older, weak-referencing behavior. + - Signal.connect('text-sender') uses an alternate hashing strategy to + avoid sharp edges in text identity. + +1.2 (October 26, 2011) + + - Added Signal.receiver_connected and Signal.receiver_disconnected + per-Signal signals. + - Deprecated the global 'receiver_connected' signal. + - Verified Python 3.2 support (no changes needed!) + +1.1 (July 21, 2010) + + - Added ``@signal.connect_via(sender)`` decorator + - Added ``signal.connected_to`` shorthand name for the + ``temporarily_connected_to`` context manager. + +1.0 (March 28, 2010) + + - Python 3.x compatibility + +0.9 (February 26, 2010) + + - Sphinx docs, project website + - Added ``with a_signal.temporarily_connected_to(receiver): ...`` support + + diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/RECORD b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/RECORD new file mode 100644 index 000000000..517b8e981 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/RECORD @@ -0,0 +1,15 @@ +blinker-1.4.dist-info/AUTHORS,sha256=f2tPqeT2VyCL9D9YelVKScG65gDrGzbMES0zp7b0p48,207 +blinker-1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.4.dist-info/LICENSE,sha256=7pmpCeGwT1Pz1JOD5kYromjPSTiLs6ZXRV2snjjN8Oo,1094 +blinker-1.4.dist-info/METADATA,sha256=xjofN2QBb0zejTtGF8S000R3eRXw5uGzdG15LjEy3ak,3308 +blinker-1.4.dist-info/RECORD,, +blinker-1.4.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92 +blinker-1.4.dist-info/top_level.txt,sha256=2NmsENM0J2t9Z8mkjxHDmGMQj7Bm8f5ZTTYe1x1fZtM,8 +blinker/__init__.py,sha256=vgkMDX61C3h5jhFvxiGJ_FCkajPLZi-KzZr_AAfV-_0,300 +blinker/__pycache__/__init__.cpython-38.pyc,, +blinker/__pycache__/_saferef.cpython-38.pyc,, +blinker/__pycache__/_utilities.cpython-38.pyc,, +blinker/__pycache__/base.cpython-38.pyc,, +blinker/_saferef.py,sha256=OprBfoWWJd791Qm9OY5c-v1bIo2qLalHah8hqAA18Sw,9223 +blinker/_utilities.py,sha256=ev0IgdfH4wMSmLO-J3gVZSc-umhhmJiQJWdQNy6lyTY,4457 +blinker/base.py,sha256=MJ_qn4ladUGMAU2M1k2OIPfgUi_INhbqfLrvjdsmHVM,16319 diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/WHEEL b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/WHEEL new file mode 100644 index 000000000..b552003ff --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/blinker-1.4.dist-info/top_level.txt b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/top_level.txt new file mode 100644 index 000000000..1ff4ca551 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker-1.4.dist-info/top_level.txt @@ -0,0 +1 @@ +blinker diff --git a/env/lib/python3.8/site-packages/blinker/__init__.py b/env/lib/python3.8/site-packages/blinker/__init__.py new file mode 100644 index 000000000..3ea239c66 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker/__init__.py @@ -0,0 +1,22 @@ +from blinker.base import ( + ANY, + NamedSignal, + Namespace, + Signal, + WeakNamespace, + receiver_connected, + signal, +) + +__all__ = [ + 'ANY', + 'NamedSignal', + 'Namespace', + 'Signal', + 'WeakNamespace', + 'receiver_connected', + 'signal', + ] + + +__version__ = '1.4' diff --git a/env/lib/python3.8/site-packages/blinker/_saferef.py b/env/lib/python3.8/site-packages/blinker/_saferef.py new file mode 100644 index 000000000..269e36246 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker/_saferef.py @@ -0,0 +1,234 @@ +# extracted from Louie, http://pylouie.org/ +# updated for Python 3 +# +# Copyright (c) 2006 Patrick K. O'Brien, Mike C. Fletcher, +# Matthew R. Scott +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the name of the 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 THE COPYRIGHT +# OWNER 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. +# +"""Refactored 'safe reference from dispatcher.py""" + +import operator +import sys +import traceback +import weakref + + +try: + callable +except NameError: + def callable(object): + return hasattr(object, '__call__') + + +if sys.version_info < (3,): + get_self = operator.attrgetter('im_self') + get_func = operator.attrgetter('im_func') +else: + get_self = operator.attrgetter('__self__') + get_func = operator.attrgetter('__func__') + + +def safe_ref(target, on_delete=None): + """Return a *safe* weak reference to a callable target. + + - ``target``: The object to be weakly referenced, if it's a bound + method reference, will create a BoundMethodWeakref, otherwise + creates a simple weakref. + + - ``on_delete``: If provided, will have a hard reference stored to + the callable to be called after the safe reference goes out of + scope with the reference object, (either a weakref or a + BoundMethodWeakref) as argument. + """ + try: + im_self = get_self(target) + except AttributeError: + if callable(on_delete): + return weakref.ref(target, on_delete) + else: + return weakref.ref(target) + else: + if im_self is not None: + # Turn a bound method into a BoundMethodWeakref instance. + # Keep track of these instances for lookup by disconnect(). + assert hasattr(target, 'im_func') or hasattr(target, '__func__'), ( + "safe_ref target %r has im_self, but no im_func, " + "don't know how to create reference" % target) + reference = BoundMethodWeakref(target=target, on_delete=on_delete) + return reference + + +class BoundMethodWeakref(object): + """'Safe' and reusable weak references to instance methods. + + BoundMethodWeakref objects provide a mechanism for referencing a + bound method without requiring that the method object itself + (which is normally a transient object) is kept alive. Instead, + the BoundMethodWeakref object keeps weak references to both the + object and the function which together define the instance method. + + Attributes: + + - ``key``: The identity key for the reference, calculated by the + class's calculate_key method applied to the target instance method. + + - ``deletion_methods``: Sequence of callable objects taking single + argument, a reference to this object which will be called when + *either* the target object or target function is garbage + collected (i.e. when this object becomes invalid). These are + specified as the on_delete parameters of safe_ref calls. + + - ``weak_self``: Weak reference to the target object. + + - ``weak_func``: Weak reference to the target function. + + Class Attributes: + + - ``_all_instances``: Class attribute pointing to all live + BoundMethodWeakref objects indexed by the class's + calculate_key(target) method applied to the target objects. + This weak value dictionary is used to short-circuit creation so + that multiple references to the same (object, function) pair + produce the same BoundMethodWeakref instance. + """ + + _all_instances = weakref.WeakValueDictionary() + + def __new__(cls, target, on_delete=None, *arguments, **named): + """Create new instance or return current instance. + + Basically this method of construction allows us to + short-circuit creation of references to already- referenced + instance methods. The key corresponding to the target is + calculated, and if there is already an existing reference, + that is returned, with its deletion_methods attribute updated. + Otherwise the new instance is created and registered in the + table of already-referenced methods. + """ + key = cls.calculate_key(target) + current = cls._all_instances.get(key) + if current is not None: + current.deletion_methods.append(on_delete) + return current + else: + base = super(BoundMethodWeakref, cls).__new__(cls) + cls._all_instances[key] = base + base.__init__(target, on_delete, *arguments, **named) + return base + + def __init__(self, target, on_delete=None): + """Return a weak-reference-like instance for a bound method. + + - ``target``: The instance-method target for the weak reference, + must have im_self and im_func attributes and be + reconstructable via the following, which is true of built-in + instance methods:: + + target.im_func.__get__( target.im_self ) + + - ``on_delete``: Optional callback which will be called when + this weak reference ceases to be valid (i.e. either the + object or the function is garbage collected). Should take a + single argument, which will be passed a pointer to this + object. + """ + def remove(weak, self=self): + """Set self.isDead to True when method or instance is destroyed.""" + methods = self.deletion_methods[:] + del self.deletion_methods[:] + try: + del self.__class__._all_instances[self.key] + except KeyError: + pass + for function in methods: + try: + if callable(function): + function(self) + except Exception: + try: + traceback.print_exc() + except AttributeError: + e = sys.exc_info()[1] + print ('Exception during saferef %s ' + 'cleanup function %s: %s' % (self, function, e)) + self.deletion_methods = [on_delete] + self.key = self.calculate_key(target) + im_self = get_self(target) + im_func = get_func(target) + self.weak_self = weakref.ref(im_self, remove) + self.weak_func = weakref.ref(im_func, remove) + self.self_name = str(im_self) + self.func_name = str(im_func.__name__) + + def calculate_key(cls, target): + """Calculate the reference key for this reference. + + Currently this is a two-tuple of the id()'s of the target + object and the target function respectively. + """ + return (id(get_self(target)), id(get_func(target))) + calculate_key = classmethod(calculate_key) + + def __str__(self): + """Give a friendly representation of the object.""" + return "%s(%s.%s)" % ( + self.__class__.__name__, + self.self_name, + self.func_name, + ) + + __repr__ = __str__ + + def __nonzero__(self): + """Whether we are still a valid reference.""" + return self() is not None + + def __cmp__(self, other): + """Compare with another reference.""" + if not isinstance(other, self.__class__): + return cmp(self.__class__, type(other)) + return cmp(self.key, other.key) + + def __call__(self): + """Return a strong reference to the bound method. + + If the target cannot be retrieved, then will return None, + otherwise returns a bound instance method for our object and + function. + + Note: You may call this method any number of times, as it does + not invalidate the reference. + """ + target = self.weak_self() + if target is not None: + function = self.weak_func() + if function is not None: + return function.__get__(target) + return None diff --git a/env/lib/python3.8/site-packages/blinker/_utilities.py b/env/lib/python3.8/site-packages/blinker/_utilities.py new file mode 100644 index 000000000..056270d7d --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker/_utilities.py @@ -0,0 +1,163 @@ +from weakref import ref + +from blinker._saferef import BoundMethodWeakref + + +try: + callable +except NameError: + def callable(object): + return hasattr(object, '__call__') + + +try: + from collections import defaultdict +except: + class defaultdict(dict): + + def __init__(self, default_factory=None, *a, **kw): + if (default_factory is not None and + not hasattr(default_factory, '__call__')): + raise TypeError('first argument must be callable') + dict.__init__(self, *a, **kw) + self.default_factory = default_factory + + def __getitem__(self, key): + try: + return dict.__getitem__(self, key) + except KeyError: + return self.__missing__(key) + + def __missing__(self, key): + if self.default_factory is None: + raise KeyError(key) + self[key] = value = self.default_factory() + return value + + def __reduce__(self): + if self.default_factory is None: + args = tuple() + else: + args = self.default_factory, + return type(self), args, None, None, self.items() + + def copy(self): + return self.__copy__() + + def __copy__(self): + return type(self)(self.default_factory, self) + + def __deepcopy__(self, memo): + import copy + return type(self)(self.default_factory, + copy.deepcopy(self.items())) + + def __repr__(self): + return 'defaultdict(%s, %s)' % (self.default_factory, + dict.__repr__(self)) + + +try: + from contextlib import contextmanager +except ImportError: + def contextmanager(fn): + def oops(*args, **kw): + raise RuntimeError("Python 2.5 or above is required to use " + "context managers.") + oops.__name__ = fn.__name__ + return oops + +class _symbol(object): + + def __init__(self, name): + """Construct a new named symbol.""" + self.__name__ = self.name = name + + def __reduce__(self): + return symbol, (self.name,) + + def __repr__(self): + return self.name +_symbol.__name__ = 'symbol' + + +class symbol(object): + """A constant symbol. + + >>> symbol('foo') is symbol('foo') + True + >>> symbol('foo') + foo + + A slight refinement of the MAGICCOOKIE=object() pattern. The primary + advantage of symbol() is its repr(). They are also singletons. + + Repeated calls of symbol('name') will all return the same instance. + + """ + symbols = {} + + def __new__(cls, name): + try: + return cls.symbols[name] + except KeyError: + return cls.symbols.setdefault(name, _symbol(name)) + + +try: + text = (str, unicode) +except NameError: + text = str + + +def hashable_identity(obj): + if hasattr(obj, '__func__'): + return (id(obj.__func__), id(obj.__self__)) + elif hasattr(obj, 'im_func'): + return (id(obj.im_func), id(obj.im_self)) + elif isinstance(obj, text): + return obj + else: + return id(obj) + + +WeakTypes = (ref, BoundMethodWeakref) + + +class annotatable_weakref(ref): + """A weakref.ref that supports custom instance attributes.""" + + +def reference(object, callback=None, **annotations): + """Return an annotated weak ref.""" + if callable(object): + weak = callable_reference(object, callback) + else: + weak = annotatable_weakref(object, callback) + for key, value in annotations.items(): + setattr(weak, key, value) + return weak + + +def callable_reference(object, callback=None): + """Return an annotated weak ref, supporting bound instance methods.""" + if hasattr(object, 'im_self') and object.im_self is not None: + return BoundMethodWeakref(target=object, on_delete=callback) + elif hasattr(object, '__self__') and object.__self__ is not None: + return BoundMethodWeakref(target=object, on_delete=callback) + return annotatable_weakref(object, callback) + + +class lazy_property(object): + """A @property that is only evaluated once.""" + + def __init__(self, deferred): + self._deferred = deferred + self.__doc__ = deferred.__doc__ + + def __get__(self, obj, cls): + if obj is None: + return self + value = self._deferred(obj) + setattr(obj, self._deferred.__name__, value) + return value diff --git a/env/lib/python3.8/site-packages/blinker/base.py b/env/lib/python3.8/site-packages/blinker/base.py new file mode 100644 index 000000000..cc5880e69 --- /dev/null +++ b/env/lib/python3.8/site-packages/blinker/base.py @@ -0,0 +1,455 @@ +# -*- coding: utf-8; fill-column: 76 -*- +"""Signals and events. + +A small implementation of signals, inspired by a snippet of Django signal +API client code seen in a blog post. Signals are first-class objects and +each manages its own receivers and message emission. + +The :func:`signal` function provides singleton behavior for named signals. + +""" +from warnings import warn +from weakref import WeakValueDictionary + +from blinker._utilities import ( + WeakTypes, + contextmanager, + defaultdict, + hashable_identity, + lazy_property, + reference, + symbol, + ) + + +ANY = symbol('ANY') +ANY.__doc__ = 'Token for "any sender".' +ANY_ID = 0 + + +class Signal(object): + """A notification emitter.""" + + #: An :obj:`ANY` convenience synonym, allows ``Signal.ANY`` + #: without an additional import. + ANY = ANY + + @lazy_property + def receiver_connected(self): + """Emitted after each :meth:`connect`. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: *receiver*, *sender*, and *weak*. + + .. versionadded:: 1.2 + + """ + return Signal(doc="Emitted after a receiver connects.") + + @lazy_property + def receiver_disconnected(self): + """Emitted after :meth:`disconnect`. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: *receiver* and *sender*. + + Note, this signal is emitted **only** when :meth:`disconnect` is + called explicitly. + + The disconnect signal can not be emitted by an automatic disconnect + (due to a weakly referenced receiver or sender going out of scope), + as the receiver and/or sender instances are no longer available for + use at the time this signal would be emitted. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc=None): + """ + :param doc: optional. If provided, will be assigned to the signal's + __doc__ attribute. + + """ + if doc: + self.__doc__ = doc + #: A mapping of connected receivers. + #: + #: The values of this mapping are not meaningful outside of the + #: internal :class:`Signal` implementation, however the boolean value + #: of the mapping is useful as an extremely efficient check to see if + #: any receivers are connected to the signal. + self.receivers = {} + self._by_receiver = defaultdict(set) + self._by_sender = defaultdict(set) + self._weak_senders = {} + + def connect(self, receiver, sender=ANY, weak=True): + """Connect *receiver* to signal events sent by *sender*. + + :param receiver: A callable. Will be invoked by :meth:`send` with + `sender=` as a single positional argument and any \*\*kwargs that + were provided to a call to :meth:`send`. + + :param sender: Any object or :obj:`ANY`, defaults to ``ANY``. + Restricts notifications delivered to *receiver* to only those + :meth:`send` emissions sent by *sender*. If ``ANY``, the receiver + will always be notified. A *receiver* may be connected to + multiple *sender* values on the same Signal through multiple calls + to :meth:`connect`. + + :param weak: If true, the Signal will hold a weakref to *receiver* + and automatically disconnect when *receiver* goes out of scope or + is garbage collected. Defaults to True. + + """ + receiver_id = hashable_identity(receiver) + if weak: + receiver_ref = reference(receiver, self._cleanup_receiver) + receiver_ref.receiver_id = receiver_id + else: + receiver_ref = receiver + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = hashable_identity(sender) + + self.receivers.setdefault(receiver_id, receiver_ref) + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + del receiver_ref + + if sender is not ANY and sender_id not in self._weak_senders: + # wire together a cleanup for weakref-able senders + try: + sender_ref = reference(sender, self._cleanup_sender) + sender_ref.sender_id = sender_id + except TypeError: + pass + else: + self._weak_senders.setdefault(sender_id, sender_ref) + del sender_ref + + # broadcast this connection. if receivers raise, disconnect. + if ('receiver_connected' in self.__dict__ and + self.receiver_connected.receivers): + try: + self.receiver_connected.send(self, + receiver=receiver, + sender=sender, + weak=weak) + except: + self.disconnect(receiver, sender) + raise + if receiver_connected.receivers and self is not receiver_connected: + try: + receiver_connected.send(self, + receiver_arg=receiver, + sender_arg=sender, + weak_arg=weak) + except: + self.disconnect(receiver, sender) + raise + return receiver + + def connect_via(self, sender, weak=False): + """Connect the decorated function as a receiver for *sender*. + + :param sender: Any object or :obj:`ANY`. The decorated function + will only receive :meth:`send` emissions sent by *sender*. If + ``ANY``, the receiver will always be notified. A function may be + decorated multiple times with differing *sender* values. + + :param weak: If true, the Signal will hold a weakref to the + decorated function and automatically disconnect when *receiver* + goes out of scope or is garbage collected. Unlike + :meth:`connect`, this defaults to False. + + The decorated function will be invoked by :meth:`send` with + `sender=` as a single positional argument and any \*\*kwargs that + were provided to the call to :meth:`send`. + + + .. versionadded:: 1.1 + + """ + def decorator(fn): + self.connect(fn, sender, weak) + return fn + return decorator + + @contextmanager + def connected_to(self, receiver, sender=ANY): + """Execute a block with the signal temporarily connected to *receiver*. + + :param receiver: a receiver callable + :param sender: optional, a sender to filter on + + This is a context manager for use in the ``with`` statement. It can + be useful in unit tests. *receiver* is connected to the signal for + the duration of the ``with`` block, and will be disconnected + automatically when exiting the block: + + .. testsetup:: + + from __future__ import with_statement + from blinker import Signal + on_ready = Signal() + receiver = lambda sender: None + + .. testcode:: + + with on_ready.connected_to(receiver): + # do stuff + on_ready.send(123) + + .. versionadded:: 1.1 + + """ + self.connect(receiver, sender=sender, weak=False) + try: + yield None + except: + self.disconnect(receiver) + raise + else: + self.disconnect(receiver) + + def temporarily_connected_to(self, receiver, sender=ANY): + """An alias for :meth:`connected_to`. + + :param receiver: a receiver callable + :param sender: optional, a sender to filter on + + .. versionadded:: 0.9 + + .. versionchanged:: 1.1 + Renamed to :meth:`connected_to`. ``temporarily_connected_to`` was + deprecated in 1.2 and will be removed in a subsequent version. + + """ + warn("temporarily_connected_to is deprecated; " + "use connected_to instead.", + DeprecationWarning) + return self.connected_to(receiver, sender) + + def send(self, *sender, **kwargs): + """Emit this signal on behalf of *sender*, passing on \*\*kwargs. + + Returns a list of 2-tuples, pairing receivers with their return + value. The ordering of receiver notification is undefined. + + :param \*sender: Any object or ``None``. If omitted, synonymous + with ``None``. Only accepts one positional argument. + + :param \*\*kwargs: Data to be sent to receivers. + + """ + # Using '*sender' rather than 'sender=None' allows 'sender' to be + # used as a keyword argument- i.e. it's an invisible name in the + # function signature. + if len(sender) == 0: + sender = None + elif len(sender) > 1: + raise TypeError('send() accepts only one positional argument, ' + '%s given' % len(sender)) + else: + sender = sender[0] + if not self.receivers: + return [] + else: + return [(receiver, receiver(sender, **kwargs)) + for receiver in self.receivers_for(sender)] + + def has_receivers_for(self, sender): + """True if there is probably a receiver for *sender*. + + Performs an optimistic check only. Does not guarantee that all + weakly referenced receivers are still alive. See + :meth:`receivers_for` for a stronger search. + + """ + if not self.receivers: + return False + if self._by_sender[ANY_ID]: + return True + if sender is ANY: + return False + return hashable_identity(sender) in self._by_sender + + def receivers_for(self, sender): + """Iterate all live receivers listening for *sender*.""" + # TODO: test receivers_for(ANY) + if self.receivers: + sender_id = hashable_identity(sender) + if sender_id in self._by_sender: + ids = (self._by_sender[ANY_ID] | + self._by_sender[sender_id]) + else: + ids = self._by_sender[ANY_ID].copy() + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + if receiver is None: + continue + if isinstance(receiver, WeakTypes): + strong = receiver() + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + receiver = strong + yield receiver + + def disconnect(self, receiver, sender=ANY): + """Disconnect *receiver* from this signal's events. + + :param receiver: a previously :meth:`connected` callable + + :param sender: a specific sender to disconnect from, or :obj:`ANY` + to disconnect from all senders. Defaults to ``ANY``. + + """ + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = hashable_identity(sender) + receiver_id = hashable_identity(receiver) + self._disconnect(receiver_id, sender_id) + + if ('receiver_disconnected' in self.__dict__ and + self.receiver_disconnected.receivers): + self.receiver_disconnected.send(self, + receiver=receiver, + sender=sender) + + def _disconnect(self, receiver_id, sender_id): + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, False): + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _cleanup_receiver(self, receiver_ref): + """Disconnect a receiver from all senders.""" + self._disconnect(receiver_ref.receiver_id, ANY_ID) + + def _cleanup_sender(self, sender_ref): + """Disconnect all receivers from a sender.""" + sender_id = sender_ref.sender_id + assert sender_id != ANY_ID + self._weak_senders.pop(sender_id, None) + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + def _cleanup_bookkeeping(self): + """Prune unused sender/receiver bookeeping. Not threadsafe. + + Connecting & disconnecting leave behind a small amount of bookeeping + for the receiver and sender values. Typical workloads using Blinker, + for example in most web apps, Flask, CLI scripts, etc., are not + adversely affected by this bookkeeping. + + With a long-running Python process performing dynamic signal routing + with high volume- e.g. connecting to function closures, "senders" are + all unique object instances, and doing all of this over and over- you + may see memory usage will grow due to extraneous bookeeping. (An empty + set() for each stale sender/receiver pair.) + + This method will prune that bookeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that + failure mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for _id, bucket in list(mapping.items()): + if not bucket: + mapping.pop(_id, None) + + def _clear_state(self): + """Throw away all signal state. Useful for unit tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +receiver_connected = Signal("""\ +Sent by a :class:`Signal` after a receiver connects. + +:argument: the Signal that was connected to +:keyword receiver_arg: the connected receiver +:keyword sender_arg: the sender to connect to +:keyword weak_arg: true if the connection to receiver_arg is a weak reference + +.. deprecated:: 1.2 + +As of 1.2, individual signals have their own private +:attr:`~Signal.receiver_connected` and +:attr:`~Signal.receiver_disconnected` signals with a slightly simplified +call signature. This global signal is planned to be removed in 1.6. + +""") + + +class NamedSignal(Signal): + """A named generic notification emitter.""" + + def __init__(self, name, doc=None): + Signal.__init__(self, doc) + + #: The name of this signal. + self.name = name + + def __repr__(self): + base = Signal.__repr__(self) + return "%s; %r>" % (base[:-1], self.name) + + +class Namespace(dict): + """A mapping of signal names to signals.""" + + def signal(self, name, doc=None): + """Return the :class:`NamedSignal` *name*, creating it if required. + + Repeated calls to this function will return the same signal object. + + """ + try: + return self[name] + except KeyError: + return self.setdefault(name, NamedSignal(name, doc)) + + +class WeakNamespace(WeakValueDictionary): + """A weak mapping of signal names to signals. + + Automatically cleans up unused Signals when the last reference goes out + of scope. This namespace implementation exists for a measure of legacy + compatibility with Blinker <= 1.2, and may be dropped in the future. + + .. versionadded:: 1.3 + + """ + + def signal(self, name, doc=None): + """Return the :class:`NamedSignal` *name*, creating it if required. + + Repeated calls to this function will return the same signal object. + + """ + try: + return self[name] + except KeyError: + return self.setdefault(name, NamedSignal(name, doc)) + + +signal = Namespace().signal diff --git a/env/lib/python3.8/site-packages/dateutil/__init__.py b/env/lib/python3.8/site-packages/dateutil/__init__.py new file mode 100644 index 000000000..0defb82e2 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +try: + from ._version import version as __version__ +except ImportError: + __version__ = 'unknown' + +__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz', + 'utils', 'zoneinfo'] diff --git a/env/lib/python3.8/site-packages/dateutil/_common.py b/env/lib/python3.8/site-packages/dateutil/_common.py new file mode 100644 index 000000000..4eb2659bd --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/_common.py @@ -0,0 +1,43 @@ +""" +Common code used in multiple modules. +""" + + +class weekday(object): + __slots__ = ["weekday", "n"] + + def __init__(self, weekday, n=None): + self.weekday = weekday + self.n = n + + def __call__(self, n): + if n == self.n: + return self + else: + return self.__class__(self.weekday, n) + + def __eq__(self, other): + try: + if self.weekday != other.weekday or self.n != other.n: + return False + except AttributeError: + return False + return True + + def __hash__(self): + return hash(( + self.weekday, + self.n, + )) + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] + if not self.n: + return s + else: + return "%s(%+d)" % (s, self.n) + +# vim:ts=4:sw=4:et diff --git a/env/lib/python3.8/site-packages/dateutil/_version.py b/env/lib/python3.8/site-packages/dateutil/_version.py new file mode 100644 index 000000000..eac120969 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/_version.py @@ -0,0 +1,4 @@ +# coding: utf-8 +# file generated by setuptools_scm +# don't change, don't track in version control +version = '2.8.1' diff --git a/env/lib/python3.8/site-packages/dateutil/easter.py b/env/lib/python3.8/site-packages/dateutil/easter.py new file mode 100644 index 000000000..53b7c7893 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/easter.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +""" +This module offers a generic easter computing method for any given year, using +Western, Orthodox or Julian algorithms. +""" + +import datetime + +__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] + +EASTER_JULIAN = 1 +EASTER_ORTHODOX = 2 +EASTER_WESTERN = 3 + + +def easter(year, method=EASTER_WESTERN): + """ + This method was ported from the work done by GM Arts, + on top of the algorithm by Claus Tondering, which was + based in part on the algorithm of Ouding (1940), as + quoted in "Explanatory Supplement to the Astronomical + Almanac", P. Kenneth Seidelmann, editor. + + This algorithm implements three different easter + calculation methods: + + 1 - Original calculation in Julian calendar, valid in + dates after 326 AD + 2 - Original method, with date converted to Gregorian + calendar, valid in years 1583 to 4099 + 3 - Revised method, in Gregorian calendar, valid in + years 1583 to 4099 as well + + These methods are represented by the constants: + + * ``EASTER_JULIAN = 1`` + * ``EASTER_ORTHODOX = 2`` + * ``EASTER_WESTERN = 3`` + + The default method is method 3. + + More about the algorithm may be found at: + + `GM Arts: Easter Algorithms `_ + + and + + `The Calendar FAQ: Easter `_ + + """ + + if not (1 <= method <= 3): + raise ValueError("invalid method") + + # g - Golden year - 1 + # c - Century + # h - (23 - Epact) mod 30 + # i - Number of days from March 21 to Paschal Full Moon + # j - Weekday for PFM (0=Sunday, etc) + # p - Number of days from March 21 to Sunday on or before PFM + # (-6 to 28 methods 1 & 3, to 56 for method 2) + # e - Extra days to add for method 2 (converting Julian + # date to Gregorian date) + + y = year + g = y % 19 + e = 0 + if method < 3: + # Old method + i = (19*g + 15) % 30 + j = (y + y//4 + i) % 7 + if method == 2: + # Extra dates to convert Julian to Gregorian date + e = 10 + if y > 1600: + e = e + y//100 - 16 - (y//100 - 16)//4 + else: + # New method + c = y//100 + h = (c - c//4 - (8*c + 13)//25 + 19*g + 15) % 30 + i = h - (h//28)*(1 - (h//28)*(29//(h + 1))*((21 - g)//11)) + j = (y + y//4 + i + 2 - c + c//4) % 7 + + # p can be from -6 to 56 corresponding to dates 22 March to 23 May + # (later dates apply to method 2, although 23 May never actually occurs) + p = i - j + e + d = 1 + (p + 27 + (p + 6)//40) % 31 + m = 3 + (p + 26)//30 + return datetime.date(int(y), int(m), int(d)) diff --git a/env/lib/python3.8/site-packages/dateutil/parser/__init__.py b/env/lib/python3.8/site-packages/dateutil/parser/__init__.py new file mode 100644 index 000000000..d174b0e4d --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/parser/__init__.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +from ._parser import parse, parser, parserinfo, ParserError +from ._parser import DEFAULTPARSER, DEFAULTTZPARSER +from ._parser import UnknownTimezoneWarning + +from ._parser import __doc__ + +from .isoparser import isoparser, isoparse + +__all__ = ['parse', 'parser', 'parserinfo', + 'isoparse', 'isoparser', + 'ParserError', + 'UnknownTimezoneWarning'] + + +### +# Deprecate portions of the private interface so that downstream code that +# is improperly relying on it is given *some* notice. + + +def __deprecated_private_func(f): + from functools import wraps + import warnings + + msg = ('{name} is a private function and may break without warning, ' + 'it will be moved and or renamed in future versions.') + msg = msg.format(name=f.__name__) + + @wraps(f) + def deprecated_func(*args, **kwargs): + warnings.warn(msg, DeprecationWarning) + return f(*args, **kwargs) + + return deprecated_func + +def __deprecate_private_class(c): + import warnings + + msg = ('{name} is a private class and may break without warning, ' + 'it will be moved and or renamed in future versions.') + msg = msg.format(name=c.__name__) + + class private_class(c): + __doc__ = c.__doc__ + + def __init__(self, *args, **kwargs): + warnings.warn(msg, DeprecationWarning) + super(private_class, self).__init__(*args, **kwargs) + + private_class.__name__ = c.__name__ + + return private_class + + +from ._parser import _timelex, _resultbase +from ._parser import _tzparser, _parsetz + +_timelex = __deprecate_private_class(_timelex) +_tzparser = __deprecate_private_class(_tzparser) +_resultbase = __deprecate_private_class(_resultbase) +_parsetz = __deprecated_private_func(_parsetz) diff --git a/env/lib/python3.8/site-packages/dateutil/parser/_parser.py b/env/lib/python3.8/site-packages/dateutil/parser/_parser.py new file mode 100644 index 000000000..458aa6a32 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/parser/_parser.py @@ -0,0 +1,1609 @@ +# -*- coding: utf-8 -*- +""" +This module offers a generic date/time string parser which is able to parse +most known formats to represent a date and/or time. + +This module attempts to be forgiving with regards to unlikely input formats, +returning a datetime object even for dates which are ambiguous. If an element +of a date/time stamp is omitted, the following rules are applied: + +- If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour + on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is + specified. +- If a time zone is omitted, a timezone-naive datetime is returned. + +If any other elements are missing, they are taken from the +:class:`datetime.datetime` object passed to the parameter ``default``. If this +results in a day number exceeding the valid number of days per month, the +value falls back to the end of the month. + +Additional resources about date/time string formats can be found below: + +- `A summary of the international standard date and time notation + `_ +- `W3C Date and Time Formats `_ +- `Time Formats (Planetary Rings Node) `_ +- `CPAN ParseDate module + `_ +- `Java SimpleDateFormat Class + `_ +""" +from __future__ import unicode_literals + +import datetime +import re +import string +import time +import warnings + +from calendar import monthrange +from io import StringIO + +import six +from six import integer_types, text_type + +from decimal import Decimal + +from warnings import warn + +from .. import relativedelta +from .. import tz + +__all__ = ["parse", "parserinfo", "ParserError"] + + +# TODO: pandas.core.tools.datetimes imports this explicitly. Might be worth +# making public and/or figuring out if there is something we can +# take off their plate. +class _timelex(object): + # Fractional seconds are sometimes split by a comma + _split_decimal = re.compile("([.,])") + + def __init__(self, instream): + if six.PY2: + # In Python 2, we can't duck type properly because unicode has + # a 'decode' function, and we'd be double-decoding + if isinstance(instream, (bytes, bytearray)): + instream = instream.decode() + else: + if getattr(instream, 'decode', None) is not None: + instream = instream.decode() + + if isinstance(instream, text_type): + instream = StringIO(instream) + elif getattr(instream, 'read', None) is None: + raise TypeError('Parser must be a string or character stream, not ' + '{itype}'.format(itype=instream.__class__.__name__)) + + self.instream = instream + self.charstack = [] + self.tokenstack = [] + self.eof = False + + def get_token(self): + """ + This function breaks the time string into lexical units (tokens), which + can be parsed by the parser. Lexical units are demarcated by changes in + the character set, so any continuous string of letters is considered + one unit, any continuous string of numbers is considered one unit. + + The main complication arises from the fact that dots ('.') can be used + both as separators (e.g. "Sep.20.2009") or decimal points (e.g. + "4:30:21.447"). As such, it is necessary to read the full context of + any dot-separated strings before breaking it into tokens; as such, this + function maintains a "token stack", for when the ambiguous context + demands that multiple tokens be parsed at once. + """ + if self.tokenstack: + return self.tokenstack.pop(0) + + seenletters = False + token = None + state = None + + while not self.eof: + # We only realize that we've reached the end of a token when we + # find a character that's not part of the current token - since + # that character may be part of the next token, it's stored in the + # charstack. + if self.charstack: + nextchar = self.charstack.pop(0) + else: + nextchar = self.instream.read(1) + while nextchar == '\x00': + nextchar = self.instream.read(1) + + if not nextchar: + self.eof = True + break + elif not state: + # First character of the token - determines if we're starting + # to parse a word, a number or something else. + token = nextchar + if self.isword(nextchar): + state = 'a' + elif self.isnum(nextchar): + state = '0' + elif self.isspace(nextchar): + token = ' ' + break # emit token + else: + break # emit token + elif state == 'a': + # If we've already started reading a word, we keep reading + # letters until we find something that's not part of a word. + seenletters = True + if self.isword(nextchar): + token += nextchar + elif nextchar == '.': + token += nextchar + state = 'a.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == '0': + # If we've already started reading a number, we keep reading + # numbers until we find something that doesn't fit. + if self.isnum(nextchar): + token += nextchar + elif nextchar == '.' or (nextchar == ',' and len(token) >= 2): + token += nextchar + state = '0.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == 'a.': + # If we've seen some letters and a dot separator, continue + # parsing, and the tokens will be broken up later. + seenletters = True + if nextchar == '.' or self.isword(nextchar): + token += nextchar + elif self.isnum(nextchar) and token[-1] == '.': + token += nextchar + state = '0.' + else: + self.charstack.append(nextchar) + break # emit token + elif state == '0.': + # If we've seen at least one dot separator, keep going, we'll + # break up the tokens later. + if nextchar == '.' or self.isnum(nextchar): + token += nextchar + elif self.isword(nextchar) and token[-1] == '.': + token += nextchar + state = 'a.' + else: + self.charstack.append(nextchar) + break # emit token + + if (state in ('a.', '0.') and (seenletters or token.count('.') > 1 or + token[-1] in '.,')): + l = self._split_decimal.split(token) + token = l[0] + for tok in l[1:]: + if tok: + self.tokenstack.append(tok) + + if state == '0.' and token.count('.') == 0: + token = token.replace(',', '.') + + return token + + def __iter__(self): + return self + + def __next__(self): + token = self.get_token() + if token is None: + raise StopIteration + + return token + + def next(self): + return self.__next__() # Python 2.x support + + @classmethod + def split(cls, s): + return list(cls(s)) + + @classmethod + def isword(cls, nextchar): + """ Whether or not the next character is part of a word """ + return nextchar.isalpha() + + @classmethod + def isnum(cls, nextchar): + """ Whether the next character is part of a number """ + return nextchar.isdigit() + + @classmethod + def isspace(cls, nextchar): + """ Whether the next character is whitespace """ + return nextchar.isspace() + + +class _resultbase(object): + + def __init__(self): + for attr in self.__slots__: + setattr(self, attr, None) + + def _repr(self, classname): + l = [] + for attr in self.__slots__: + value = getattr(self, attr) + if value is not None: + l.append("%s=%s" % (attr, repr(value))) + return "%s(%s)" % (classname, ", ".join(l)) + + def __len__(self): + return (sum(getattr(self, attr) is not None + for attr in self.__slots__)) + + def __repr__(self): + return self._repr(self.__class__.__name__) + + +class parserinfo(object): + """ + Class which handles what inputs are accepted. Subclass this to customize + the language and acceptable values for each parameter. + + :param dayfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the day (``True``) or month (``False``). If + ``yearfirst`` is set to ``True``, this distinguishes between YDM + and YMD. Default is ``False``. + + :param yearfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the year. If ``True``, the first number is taken + to be the year, otherwise the last number is taken to be the year. + Default is ``False``. + """ + + # m from a.m/p.m, t from ISO T separator + JUMP = [" ", ".", ",", ";", "-", "/", "'", + "at", "on", "and", "ad", "m", "t", "of", + "st", "nd", "rd", "th"] + + WEEKDAYS = [("Mon", "Monday"), + ("Tue", "Tuesday"), # TODO: "Tues" + ("Wed", "Wednesday"), + ("Thu", "Thursday"), # TODO: "Thurs" + ("Fri", "Friday"), + ("Sat", "Saturday"), + ("Sun", "Sunday")] + MONTHS = [("Jan", "January"), + ("Feb", "February"), # TODO: "Febr" + ("Mar", "March"), + ("Apr", "April"), + ("May", "May"), + ("Jun", "June"), + ("Jul", "July"), + ("Aug", "August"), + ("Sep", "Sept", "September"), + ("Oct", "October"), + ("Nov", "November"), + ("Dec", "December")] + HMS = [("h", "hour", "hours"), + ("m", "minute", "minutes"), + ("s", "second", "seconds")] + AMPM = [("am", "a"), + ("pm", "p")] + UTCZONE = ["UTC", "GMT", "Z", "z"] + PERTAIN = ["of"] + TZOFFSET = {} + # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate", + # "Anno Domini", "Year of Our Lord"] + + def __init__(self, dayfirst=False, yearfirst=False): + self._jump = self._convert(self.JUMP) + self._weekdays = self._convert(self.WEEKDAYS) + self._months = self._convert(self.MONTHS) + self._hms = self._convert(self.HMS) + self._ampm = self._convert(self.AMPM) + self._utczone = self._convert(self.UTCZONE) + self._pertain = self._convert(self.PERTAIN) + + self.dayfirst = dayfirst + self.yearfirst = yearfirst + + self._year = time.localtime().tm_year + self._century = self._year // 100 * 100 + + def _convert(self, lst): + dct = {} + for i, v in enumerate(lst): + if isinstance(v, tuple): + for v in v: + dct[v.lower()] = i + else: + dct[v.lower()] = i + return dct + + def jump(self, name): + return name.lower() in self._jump + + def weekday(self, name): + try: + return self._weekdays[name.lower()] + except KeyError: + pass + return None + + def month(self, name): + try: + return self._months[name.lower()] + 1 + except KeyError: + pass + return None + + def hms(self, name): + try: + return self._hms[name.lower()] + except KeyError: + return None + + def ampm(self, name): + try: + return self._ampm[name.lower()] + except KeyError: + return None + + def pertain(self, name): + return name.lower() in self._pertain + + def utczone(self, name): + return name.lower() in self._utczone + + def tzoffset(self, name): + if name in self._utczone: + return 0 + + return self.TZOFFSET.get(name) + + def convertyear(self, year, century_specified=False): + """ + Converts two-digit years to year within [-50, 49] + range of self._year (current local time) + """ + + # Function contract is that the year is always positive + assert year >= 0 + + if year < 100 and not century_specified: + # assume current century to start + year += self._century + + if year >= self._year + 50: # if too far in future + year -= 100 + elif year < self._year - 50: # if too far in past + year += 100 + + return year + + def validate(self, res): + # move to info + if res.year is not None: + res.year = self.convertyear(res.year, res.century_specified) + + if ((res.tzoffset == 0 and not res.tzname) or + (res.tzname == 'Z' or res.tzname == 'z')): + res.tzname = "UTC" + res.tzoffset = 0 + elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): + res.tzoffset = 0 + return True + + +class _ymd(list): + def __init__(self, *args, **kwargs): + super(self.__class__, self).__init__(*args, **kwargs) + self.century_specified = False + self.dstridx = None + self.mstridx = None + self.ystridx = None + + @property + def has_year(self): + return self.ystridx is not None + + @property + def has_month(self): + return self.mstridx is not None + + @property + def has_day(self): + return self.dstridx is not None + + def could_be_day(self, value): + if self.has_day: + return False + elif not self.has_month: + return 1 <= value <= 31 + elif not self.has_year: + # Be permissive, assume leap year + month = self[self.mstridx] + return 1 <= value <= monthrange(2000, month)[1] + else: + month = self[self.mstridx] + year = self[self.ystridx] + return 1 <= value <= monthrange(year, month)[1] + + def append(self, val, label=None): + if hasattr(val, '__len__'): + if val.isdigit() and len(val) > 2: + self.century_specified = True + if label not in [None, 'Y']: # pragma: no cover + raise ValueError(label) + label = 'Y' + elif val > 100: + self.century_specified = True + if label not in [None, 'Y']: # pragma: no cover + raise ValueError(label) + label = 'Y' + + super(self.__class__, self).append(int(val)) + + if label == 'M': + if self.has_month: + raise ValueError('Month is already set') + self.mstridx = len(self) - 1 + elif label == 'D': + if self.has_day: + raise ValueError('Day is already set') + self.dstridx = len(self) - 1 + elif label == 'Y': + if self.has_year: + raise ValueError('Year is already set') + self.ystridx = len(self) - 1 + + def _resolve_from_stridxs(self, strids): + """ + Try to resolve the identities of year/month/day elements using + ystridx, mstridx, and dstridx, if enough of these are specified. + """ + if len(self) == 3 and len(strids) == 2: + # we can back out the remaining stridx value + missing = [x for x in range(3) if x not in strids.values()] + key = [x for x in ['y', 'm', 'd'] if x not in strids] + assert len(missing) == len(key) == 1 + key = key[0] + val = missing[0] + strids[key] = val + + assert len(self) == len(strids) # otherwise this should not be called + out = {key: self[strids[key]] for key in strids} + return (out.get('y'), out.get('m'), out.get('d')) + + def resolve_ymd(self, yearfirst, dayfirst): + len_ymd = len(self) + year, month, day = (None, None, None) + + strids = (('y', self.ystridx), + ('m', self.mstridx), + ('d', self.dstridx)) + + strids = {key: val for key, val in strids if val is not None} + if (len(self) == len(strids) > 0 or + (len(self) == 3 and len(strids) == 2)): + return self._resolve_from_stridxs(strids) + + mstridx = self.mstridx + + if len_ymd > 3: + raise ValueError("More than three YMD values") + elif len_ymd == 1 or (mstridx is not None and len_ymd == 2): + # One member, or two members with a month string + if mstridx is not None: + month = self[mstridx] + # since mstridx is 0 or 1, self[mstridx-1] always + # looks up the other element + other = self[mstridx - 1] + else: + other = self[0] + + if len_ymd > 1 or mstridx is None: + if other > 31: + year = other + else: + day = other + + elif len_ymd == 2: + # Two members with numbers + if self[0] > 31: + # 99-01 + year, month = self + elif self[1] > 31: + # 01-99 + month, year = self + elif dayfirst and self[1] <= 12: + # 13-01 + day, month = self + else: + # 01-13 + month, day = self + + elif len_ymd == 3: + # Three members + if mstridx == 0: + if self[1] > 31: + # Apr-2003-25 + month, year, day = self + else: + month, day, year = self + elif mstridx == 1: + if self[0] > 31 or (yearfirst and self[2] <= 31): + # 99-Jan-01 + year, month, day = self + else: + # 01-Jan-01 + # Give precedence to day-first, since + # two-digit years is usually hand-written. + day, month, year = self + + elif mstridx == 2: + # WTF!? + if self[1] > 31: + # 01-99-Jan + day, year, month = self + else: + # 99-01-Jan + year, day, month = self + + else: + if (self[0] > 31 or + self.ystridx == 0 or + (yearfirst and self[1] <= 12 and self[2] <= 31)): + # 99-01-01 + if dayfirst and self[2] <= 12: + year, day, month = self + else: + year, month, day = self + elif self[0] > 12 or (dayfirst and self[1] <= 12): + # 13-01-01 + day, month, year = self + else: + # 01-13-01 + month, day, year = self + + return year, month, day + + +class parser(object): + def __init__(self, info=None): + self.info = info or parserinfo() + + def parse(self, timestr, default=None, + ignoretz=False, tzinfos=None, **kwargs): + """ + Parse the date/time string into a :class:`datetime.datetime` object. + + :param timestr: + Any date/time string using the supported formats. + + :param default: + The default datetime object, if this is a datetime object and not + ``None``, elements specified in ``timestr`` replace elements in the + default object. + + :param ignoretz: + If set ``True``, time zones in parsed strings are ignored and a + naive :class:`datetime.datetime` object is returned. + + :param tzinfos: + Additional time zone names / aliases which may be present in the + string. This argument maps time zone names (and optionally offsets + from those time zones) to time zones. This parameter can be a + dictionary with timezone aliases mapping time zone names to time + zones or a function taking two parameters (``tzname`` and + ``tzoffset``) and returning a time zone. + + The timezones to which the names are mapped can be an integer + offset from UTC in seconds or a :class:`tzinfo` object. + + .. doctest:: + :options: +NORMALIZE_WHITESPACE + + >>> from dateutil.parser import parse + >>> from dateutil.tz import gettz + >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")} + >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos) + datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200)) + >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos) + datetime.datetime(2012, 1, 19, 17, 21, + tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago')) + + This parameter is ignored if ``ignoretz`` is set. + + :param \\*\\*kwargs: + Keyword arguments as passed to ``_parse()``. + + :return: + Returns a :class:`datetime.datetime` object or, if the + ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the + first element being a :class:`datetime.datetime` object, the second + a tuple containing the fuzzy tokens. + + :raises ParserError: + Raised for invalid or unknown string format, if the provided + :class:`tzinfo` is not in a valid format, or if an invalid date + would be created. + + :raises TypeError: + Raised for non-string or character stream input. + + :raises OverflowError: + Raised if the parsed date exceeds the largest valid C integer on + your system. + """ + + if default is None: + default = datetime.datetime.now().replace(hour=0, minute=0, + second=0, microsecond=0) + + res, skipped_tokens = self._parse(timestr, **kwargs) + + if res is None: + raise ParserError("Unknown string format: %s", timestr) + + if len(res) == 0: + raise ParserError("String does not contain a date: %s", timestr) + + try: + ret = self._build_naive(res, default) + except ValueError as e: + six.raise_from(ParserError(e.args[0] + ": %s", timestr), e) + + if not ignoretz: + ret = self._build_tzaware(ret, res, tzinfos) + + if kwargs.get('fuzzy_with_tokens', False): + return ret, skipped_tokens + else: + return ret + + class _result(_resultbase): + __slots__ = ["year", "month", "day", "weekday", + "hour", "minute", "second", "microsecond", + "tzname", "tzoffset", "ampm","any_unused_tokens"] + + def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False, + fuzzy_with_tokens=False): + """ + Private method which performs the heavy lifting of parsing, called from + ``parse()``, which passes on its ``kwargs`` to this function. + + :param timestr: + The string to parse. + + :param dayfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the day (``True``) or month (``False``). If + ``yearfirst`` is set to ``True``, this distinguishes between YDM + and YMD. If set to ``None``, this value is retrieved from the + current :class:`parserinfo` object (which itself defaults to + ``False``). + + :param yearfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the year. If ``True``, the first number is taken + to be the year, otherwise the last number is taken to be the year. + If this is set to ``None``, the value is retrieved from the current + :class:`parserinfo` object (which itself defaults to ``False``). + + :param fuzzy: + Whether to allow fuzzy parsing, allowing for string like "Today is + January 1, 2047 at 8:21:00AM". + + :param fuzzy_with_tokens: + If ``True``, ``fuzzy`` is automatically set to True, and the parser + will return a tuple where the first element is the parsed + :class:`datetime.datetime` datetimestamp and the second element is + a tuple containing the portions of the string which were ignored: + + .. doctest:: + + >>> from dateutil.parser import parse + >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True) + (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at ')) + + """ + if fuzzy_with_tokens: + fuzzy = True + + info = self.info + + if dayfirst is None: + dayfirst = info.dayfirst + + if yearfirst is None: + yearfirst = info.yearfirst + + res = self._result() + l = _timelex.split(timestr) # Splits the timestr into tokens + + skipped_idxs = [] + + # year/month/day list + ymd = _ymd() + + len_l = len(l) + i = 0 + try: + while i < len_l: + + # Check if it's a number + value_repr = l[i] + try: + value = float(value_repr) + except ValueError: + value = None + + if value is not None: + # Numeric token + i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy) + + # Check weekday + elif info.weekday(l[i]) is not None: + value = info.weekday(l[i]) + res.weekday = value + + # Check month name + elif info.month(l[i]) is not None: + value = info.month(l[i]) + ymd.append(value, 'M') + + if i + 1 < len_l: + if l[i + 1] in ('-', '/'): + # Jan-01[-99] + sep = l[i + 1] + ymd.append(l[i + 2]) + + if i + 3 < len_l and l[i + 3] == sep: + # Jan-01-99 + ymd.append(l[i + 4]) + i += 2 + + i += 2 + + elif (i + 4 < len_l and l[i + 1] == l[i + 3] == ' ' and + info.pertain(l[i + 2])): + # Jan of 01 + # In this case, 01 is clearly year + if l[i + 4].isdigit(): + # Convert it here to become unambiguous + value = int(l[i + 4]) + year = str(info.convertyear(value)) + ymd.append(year, 'Y') + else: + # Wrong guess + pass + # TODO: not hit in tests + i += 4 + + # Check am/pm + elif info.ampm(l[i]) is not None: + value = info.ampm(l[i]) + val_is_ampm = self._ampm_valid(res.hour, res.ampm, fuzzy) + + if val_is_ampm: + res.hour = self._adjust_ampm(res.hour, value) + res.ampm = value + + elif fuzzy: + skipped_idxs.append(i) + + # Check for a timezone name + elif self._could_be_tzname(res.hour, res.tzname, res.tzoffset, l[i]): + res.tzname = l[i] + res.tzoffset = info.tzoffset(res.tzname) + + # Check for something like GMT+3, or BRST+3. Notice + # that it doesn't mean "I am 3 hours after GMT", but + # "my time +3 is GMT". If found, we reverse the + # logic so that timezone parsing code will get it + # right. + if i + 1 < len_l and l[i + 1] in ('+', '-'): + l[i + 1] = ('+', '-')[l[i + 1] == '+'] + res.tzoffset = None + if info.utczone(res.tzname): + # With something like GMT+3, the timezone + # is *not* GMT. + res.tzname = None + + # Check for a numbered timezone + elif res.hour is not None and l[i] in ('+', '-'): + signal = (-1, 1)[l[i] == '+'] + len_li = len(l[i + 1]) + + # TODO: check that l[i + 1] is integer? + if len_li == 4: + # -0300 + hour_offset = int(l[i + 1][:2]) + min_offset = int(l[i + 1][2:]) + elif i + 2 < len_l and l[i + 2] == ':': + # -03:00 + hour_offset = int(l[i + 1]) + min_offset = int(l[i + 3]) # TODO: Check that l[i+3] is minute-like? + i += 2 + elif len_li <= 2: + # -[0]3 + hour_offset = int(l[i + 1][:2]) + min_offset = 0 + else: + raise ValueError(timestr) + + res.tzoffset = signal * (hour_offset * 3600 + min_offset * 60) + + # Look for a timezone name between parenthesis + if (i + 5 < len_l and + info.jump(l[i + 2]) and l[i + 3] == '(' and + l[i + 5] == ')' and + 3 <= len(l[i + 4]) and + self._could_be_tzname(res.hour, res.tzname, + None, l[i + 4])): + # -0300 (BRST) + res.tzname = l[i + 4] + i += 4 + + i += 1 + + # Check jumps + elif not (info.jump(l[i]) or fuzzy): + raise ValueError(timestr) + + else: + skipped_idxs.append(i) + i += 1 + + # Process year/month/day + year, month, day = ymd.resolve_ymd(yearfirst, dayfirst) + + res.century_specified = ymd.century_specified + res.year = year + res.month = month + res.day = day + + except (IndexError, ValueError): + return None, None + + if not info.validate(res): + return None, None + + if fuzzy_with_tokens: + skipped_tokens = self._recombine_skipped(l, skipped_idxs) + return res, tuple(skipped_tokens) + else: + return res, None + + def _parse_numeric_token(self, tokens, idx, info, ymd, res, fuzzy): + # Token is a number + value_repr = tokens[idx] + try: + value = self._to_decimal(value_repr) + except Exception as e: + six.raise_from(ValueError('Unknown numeric token'), e) + + len_li = len(value_repr) + + len_l = len(tokens) + + if (len(ymd) == 3 and len_li in (2, 4) and + res.hour is None and + (idx + 1 >= len_l or + (tokens[idx + 1] != ':' and + info.hms(tokens[idx + 1]) is None))): + # 19990101T23[59] + s = tokens[idx] + res.hour = int(s[:2]) + + if len_li == 4: + res.minute = int(s[2:]) + + elif len_li == 6 or (len_li > 6 and tokens[idx].find('.') == 6): + # YYMMDD or HHMMSS[.ss] + s = tokens[idx] + + if not ymd and '.' not in tokens[idx]: + ymd.append(s[:2]) + ymd.append(s[2:4]) + ymd.append(s[4:]) + else: + # 19990101T235959[.59] + + # TODO: Check if res attributes already set. + res.hour = int(s[:2]) + res.minute = int(s[2:4]) + res.second, res.microsecond = self._parsems(s[4:]) + + elif len_li in (8, 12, 14): + # YYYYMMDD + s = tokens[idx] + ymd.append(s[:4], 'Y') + ymd.append(s[4:6]) + ymd.append(s[6:8]) + + if len_li > 8: + res.hour = int(s[8:10]) + res.minute = int(s[10:12]) + + if len_li > 12: + res.second = int(s[12:]) + + elif self._find_hms_idx(idx, tokens, info, allow_jump=True) is not None: + # HH[ ]h or MM[ ]m or SS[.ss][ ]s + hms_idx = self._find_hms_idx(idx, tokens, info, allow_jump=True) + (idx, hms) = self._parse_hms(idx, tokens, info, hms_idx) + if hms is not None: + # TODO: checking that hour/minute/second are not + # already set? + self._assign_hms(res, value_repr, hms) + + elif idx + 2 < len_l and tokens[idx + 1] == ':': + # HH:MM[:SS[.ss]] + res.hour = int(value) + value = self._to_decimal(tokens[idx + 2]) # TODO: try/except for this? + (res.minute, res.second) = self._parse_min_sec(value) + + if idx + 4 < len_l and tokens[idx + 3] == ':': + res.second, res.microsecond = self._parsems(tokens[idx + 4]) + + idx += 2 + + idx += 2 + + elif idx + 1 < len_l and tokens[idx + 1] in ('-', '/', '.'): + sep = tokens[idx + 1] + ymd.append(value_repr) + + if idx + 2 < len_l and not info.jump(tokens[idx + 2]): + if tokens[idx + 2].isdigit(): + # 01-01[-01] + ymd.append(tokens[idx + 2]) + else: + # 01-Jan[-01] + value = info.month(tokens[idx + 2]) + + if value is not None: + ymd.append(value, 'M') + else: + raise ValueError() + + if idx + 3 < len_l and tokens[idx + 3] == sep: + # We have three members + value = info.month(tokens[idx + 4]) + + if value is not None: + ymd.append(value, 'M') + else: + ymd.append(tokens[idx + 4]) + idx += 2 + + idx += 1 + idx += 1 + + elif idx + 1 >= len_l or info.jump(tokens[idx + 1]): + if idx + 2 < len_l and info.ampm(tokens[idx + 2]) is not None: + # 12 am + hour = int(value) + res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 2])) + idx += 1 + else: + # Year, month or day + ymd.append(value) + idx += 1 + + elif info.ampm(tokens[idx + 1]) is not None and (0 <= value < 24): + # 12am + hour = int(value) + res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 1])) + idx += 1 + + elif ymd.could_be_day(value): + ymd.append(value) + + elif not fuzzy: + raise ValueError() + + return idx + + def _find_hms_idx(self, idx, tokens, info, allow_jump): + len_l = len(tokens) + + if idx+1 < len_l and info.hms(tokens[idx+1]) is not None: + # There is an "h", "m", or "s" label following this token. We take + # assign the upcoming label to the current token. + # e.g. the "12" in 12h" + hms_idx = idx + 1 + + elif (allow_jump and idx+2 < len_l and tokens[idx+1] == ' ' and + info.hms(tokens[idx+2]) is not None): + # There is a space and then an "h", "m", or "s" label. + # e.g. the "12" in "12 h" + hms_idx = idx + 2 + + elif idx > 0 and info.hms(tokens[idx-1]) is not None: + # There is a "h", "m", or "s" preceding this token. Since neither + # of the previous cases was hit, there is no label following this + # token, so we use the previous label. + # e.g. the "04" in "12h04" + hms_idx = idx-1 + + elif (1 < idx == len_l-1 and tokens[idx-1] == ' ' and + info.hms(tokens[idx-2]) is not None): + # If we are looking at the final token, we allow for a + # backward-looking check to skip over a space. + # TODO: Are we sure this is the right condition here? + hms_idx = idx - 2 + + else: + hms_idx = None + + return hms_idx + + def _assign_hms(self, res, value_repr, hms): + # See GH issue #427, fixing float rounding + value = self._to_decimal(value_repr) + + if hms == 0: + # Hour + res.hour = int(value) + if value % 1: + res.minute = int(60*(value % 1)) + + elif hms == 1: + (res.minute, res.second) = self._parse_min_sec(value) + + elif hms == 2: + (res.second, res.microsecond) = self._parsems(value_repr) + + def _could_be_tzname(self, hour, tzname, tzoffset, token): + return (hour is not None and + tzname is None and + tzoffset is None and + len(token) <= 5 and + (all(x in string.ascii_uppercase for x in token) + or token in self.info.UTCZONE)) + + def _ampm_valid(self, hour, ampm, fuzzy): + """ + For fuzzy parsing, 'a' or 'am' (both valid English words) + may erroneously trigger the AM/PM flag. Deal with that + here. + """ + val_is_ampm = True + + # If there's already an AM/PM flag, this one isn't one. + if fuzzy and ampm is not None: + val_is_ampm = False + + # If AM/PM is found and hour is not, raise a ValueError + if hour is None: + if fuzzy: + val_is_ampm = False + else: + raise ValueError('No hour specified with AM or PM flag.') + elif not 0 <= hour <= 12: + # If AM/PM is found, it's a 12 hour clock, so raise + # an error for invalid range + if fuzzy: + val_is_ampm = False + else: + raise ValueError('Invalid hour specified for 12-hour clock.') + + return val_is_ampm + + def _adjust_ampm(self, hour, ampm): + if hour < 12 and ampm == 1: + hour += 12 + elif hour == 12 and ampm == 0: + hour = 0 + return hour + + def _parse_min_sec(self, value): + # TODO: Every usage of this function sets res.second to the return + # value. Are there any cases where second will be returned as None and + # we *don't* want to set res.second = None? + minute = int(value) + second = None + + sec_remainder = value % 1 + if sec_remainder: + second = int(60 * sec_remainder) + return (minute, second) + + def _parse_hms(self, idx, tokens, info, hms_idx): + # TODO: Is this going to admit a lot of false-positives for when we + # just happen to have digits and "h", "m" or "s" characters in non-date + # text? I guess hex hashes won't have that problem, but there's plenty + # of random junk out there. + if hms_idx is None: + hms = None + new_idx = idx + elif hms_idx > idx: + hms = info.hms(tokens[hms_idx]) + new_idx = hms_idx + else: + # Looking backwards, increment one. + hms = info.hms(tokens[hms_idx]) + 1 + new_idx = idx + + return (new_idx, hms) + + # ------------------------------------------------------------------ + # Handling for individual tokens. These are kept as methods instead + # of functions for the sake of customizability via subclassing. + + def _parsems(self, value): + """Parse a I[.F] seconds value into (seconds, microseconds).""" + if "." not in value: + return int(value), 0 + else: + i, f = value.split(".") + return int(i), int(f.ljust(6, "0")[:6]) + + def _to_decimal(self, val): + try: + decimal_value = Decimal(val) + # See GH 662, edge case, infinite value should not be converted + # via `_to_decimal` + if not decimal_value.is_finite(): + raise ValueError("Converted decimal value is infinite or NaN") + except Exception as e: + msg = "Could not convert %s to decimal" % val + six.raise_from(ValueError(msg), e) + else: + return decimal_value + + # ------------------------------------------------------------------ + # Post-Parsing construction of datetime output. These are kept as + # methods instead of functions for the sake of customizability via + # subclassing. + + def _build_tzinfo(self, tzinfos, tzname, tzoffset): + if callable(tzinfos): + tzdata = tzinfos(tzname, tzoffset) + else: + tzdata = tzinfos.get(tzname) + # handle case where tzinfo is paased an options that returns None + # eg tzinfos = {'BRST' : None} + if isinstance(tzdata, datetime.tzinfo) or tzdata is None: + tzinfo = tzdata + elif isinstance(tzdata, text_type): + tzinfo = tz.tzstr(tzdata) + elif isinstance(tzdata, integer_types): + tzinfo = tz.tzoffset(tzname, tzdata) + else: + raise TypeError("Offset must be tzinfo subclass, tz string, " + "or int offset.") + return tzinfo + + def _build_tzaware(self, naive, res, tzinfos): + if (callable(tzinfos) or (tzinfos and res.tzname in tzinfos)): + tzinfo = self._build_tzinfo(tzinfos, res.tzname, res.tzoffset) + aware = naive.replace(tzinfo=tzinfo) + aware = self._assign_tzname(aware, res.tzname) + + elif res.tzname and res.tzname in time.tzname: + aware = naive.replace(tzinfo=tz.tzlocal()) + + # Handle ambiguous local datetime + aware = self._assign_tzname(aware, res.tzname) + + # This is mostly relevant for winter GMT zones parsed in the UK + if (aware.tzname() != res.tzname and + res.tzname in self.info.UTCZONE): + aware = aware.replace(tzinfo=tz.UTC) + + elif res.tzoffset == 0: + aware = naive.replace(tzinfo=tz.UTC) + + elif res.tzoffset: + aware = naive.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) + + elif not res.tzname and not res.tzoffset: + # i.e. no timezone information was found. + aware = naive + + elif res.tzname: + # tz-like string was parsed but we don't know what to do + # with it + warnings.warn("tzname {tzname} identified but not understood. " + "Pass `tzinfos` argument in order to correctly " + "return a timezone-aware datetime. In a future " + "version, this will raise an " + "exception.".format(tzname=res.tzname), + category=UnknownTimezoneWarning) + aware = naive + + return aware + + def _build_naive(self, res, default): + repl = {} + for attr in ("year", "month", "day", "hour", + "minute", "second", "microsecond"): + value = getattr(res, attr) + if value is not None: + repl[attr] = value + + if 'day' not in repl: + # If the default day exceeds the last day of the month, fall back + # to the end of the month. + cyear = default.year if res.year is None else res.year + cmonth = default.month if res.month is None else res.month + cday = default.day if res.day is None else res.day + + if cday > monthrange(cyear, cmonth)[1]: + repl['day'] = monthrange(cyear, cmonth)[1] + + naive = default.replace(**repl) + + if res.weekday is not None and not res.day: + naive = naive + relativedelta.relativedelta(weekday=res.weekday) + + return naive + + def _assign_tzname(self, dt, tzname): + if dt.tzname() != tzname: + new_dt = tz.enfold(dt, fold=1) + if new_dt.tzname() == tzname: + return new_dt + + return dt + + def _recombine_skipped(self, tokens, skipped_idxs): + """ + >>> tokens = ["foo", " ", "bar", " ", "19June2000", "baz"] + >>> skipped_idxs = [0, 1, 2, 5] + >>> _recombine_skipped(tokens, skipped_idxs) + ["foo bar", "baz"] + """ + skipped_tokens = [] + for i, idx in enumerate(sorted(skipped_idxs)): + if i > 0 and idx - 1 == skipped_idxs[i - 1]: + skipped_tokens[-1] = skipped_tokens[-1] + tokens[idx] + else: + skipped_tokens.append(tokens[idx]) + + return skipped_tokens + + +DEFAULTPARSER = parser() + + +def parse(timestr, parserinfo=None, **kwargs): + """ + + Parse a string in one of the supported formats, using the + ``parserinfo`` parameters. + + :param timestr: + A string containing a date/time stamp. + + :param parserinfo: + A :class:`parserinfo` object containing parameters for the parser. + If ``None``, the default arguments to the :class:`parserinfo` + constructor are used. + + The ``**kwargs`` parameter takes the following keyword arguments: + + :param default: + The default datetime object, if this is a datetime object and not + ``None``, elements specified in ``timestr`` replace elements in the + default object. + + :param ignoretz: + If set ``True``, time zones in parsed strings are ignored and a naive + :class:`datetime` object is returned. + + :param tzinfos: + Additional time zone names / aliases which may be present in the + string. This argument maps time zone names (and optionally offsets + from those time zones) to time zones. This parameter can be a + dictionary with timezone aliases mapping time zone names to time + zones or a function taking two parameters (``tzname`` and + ``tzoffset``) and returning a time zone. + + The timezones to which the names are mapped can be an integer + offset from UTC in seconds or a :class:`tzinfo` object. + + .. doctest:: + :options: +NORMALIZE_WHITESPACE + + >>> from dateutil.parser import parse + >>> from dateutil.tz import gettz + >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")} + >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos) + datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200)) + >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos) + datetime.datetime(2012, 1, 19, 17, 21, + tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago')) + + This parameter is ignored if ``ignoretz`` is set. + + :param dayfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the day (``True``) or month (``False``). If + ``yearfirst`` is set to ``True``, this distinguishes between YDM and + YMD. If set to ``None``, this value is retrieved from the current + :class:`parserinfo` object (which itself defaults to ``False``). + + :param yearfirst: + Whether to interpret the first value in an ambiguous 3-integer date + (e.g. 01/05/09) as the year. If ``True``, the first number is taken to + be the year, otherwise the last number is taken to be the year. If + this is set to ``None``, the value is retrieved from the current + :class:`parserinfo` object (which itself defaults to ``False``). + + :param fuzzy: + Whether to allow fuzzy parsing, allowing for string like "Today is + January 1, 2047 at 8:21:00AM". + + :param fuzzy_with_tokens: + If ``True``, ``fuzzy`` is automatically set to True, and the parser + will return a tuple where the first element is the parsed + :class:`datetime.datetime` datetimestamp and the second element is + a tuple containing the portions of the string which were ignored: + + .. doctest:: + + >>> from dateutil.parser import parse + >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True) + (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at ')) + + :return: + Returns a :class:`datetime.datetime` object or, if the + ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the + first element being a :class:`datetime.datetime` object, the second + a tuple containing the fuzzy tokens. + + :raises ValueError: + Raised for invalid or unknown string format, if the provided + :class:`tzinfo` is not in a valid format, or if an invalid date + would be created. + + :raises OverflowError: + Raised if the parsed date exceeds the largest valid C integer on + your system. + """ + if parserinfo: + return parser(parserinfo).parse(timestr, **kwargs) + else: + return DEFAULTPARSER.parse(timestr, **kwargs) + + +class _tzparser(object): + + class _result(_resultbase): + + __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", + "start", "end"] + + class _attr(_resultbase): + __slots__ = ["month", "week", "weekday", + "yday", "jyday", "day", "time"] + + def __repr__(self): + return self._repr("") + + def __init__(self): + _resultbase.__init__(self) + self.start = self._attr() + self.end = self._attr() + + def parse(self, tzstr): + res = self._result() + l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x] + used_idxs = list() + try: + + len_l = len(l) + + i = 0 + while i < len_l: + # BRST+3[BRDT[+2]] + j = i + while j < len_l and not [x for x in l[j] + if x in "0123456789:,-+"]: + j += 1 + if j != i: + if not res.stdabbr: + offattr = "stdoffset" + res.stdabbr = "".join(l[i:j]) + else: + offattr = "dstoffset" + res.dstabbr = "".join(l[i:j]) + + for ii in range(j): + used_idxs.append(ii) + i = j + if (i < len_l and (l[i] in ('+', '-') or l[i][0] in + "0123456789")): + if l[i] in ('+', '-'): + # Yes, that's right. See the TZ variable + # documentation. + signal = (1, -1)[l[i] == '+'] + used_idxs.append(i) + i += 1 + else: + signal = -1 + len_li = len(l[i]) + if len_li == 4: + # -0300 + setattr(res, offattr, (int(l[i][:2]) * 3600 + + int(l[i][2:]) * 60) * signal) + elif i + 1 < len_l and l[i + 1] == ':': + # -03:00 + setattr(res, offattr, + (int(l[i]) * 3600 + + int(l[i + 2]) * 60) * signal) + used_idxs.append(i) + i += 2 + elif len_li <= 2: + # -[0]3 + setattr(res, offattr, + int(l[i][:2]) * 3600 * signal) + else: + return None + used_idxs.append(i) + i += 1 + if res.dstabbr: + break + else: + break + + + if i < len_l: + for j in range(i, len_l): + if l[j] == ';': + l[j] = ',' + + assert l[i] == ',' + + i += 1 + + if i >= len_l: + pass + elif (8 <= l.count(',') <= 9 and + not [y for x in l[i:] if x != ',' + for y in x if y not in "0123456789+-"]): + # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] + for x in (res.start, res.end): + x.month = int(l[i]) + used_idxs.append(i) + i += 2 + if l[i] == '-': + value = int(l[i + 1]) * -1 + used_idxs.append(i) + i += 1 + else: + value = int(l[i]) + used_idxs.append(i) + i += 2 + if value: + x.week = value + x.weekday = (int(l[i]) - 1) % 7 + else: + x.day = int(l[i]) + used_idxs.append(i) + i += 2 + x.time = int(l[i]) + used_idxs.append(i) + i += 2 + if i < len_l: + if l[i] in ('-', '+'): + signal = (-1, 1)[l[i] == "+"] + used_idxs.append(i) + i += 1 + else: + signal = 1 + used_idxs.append(i) + res.dstoffset = (res.stdoffset + int(l[i]) * signal) + + # This was a made-up format that is not in normal use + warn(('Parsed time zone "%s"' % tzstr) + + 'is in a non-standard dateutil-specific format, which ' + + 'is now deprecated; support for parsing this format ' + + 'will be removed in future versions. It is recommended ' + + 'that you switch to a standard format like the GNU ' + + 'TZ variable format.', tz.DeprecatedTzFormatWarning) + elif (l.count(',') == 2 and l[i:].count('/') <= 2 and + not [y for x in l[i:] if x not in (',', '/', 'J', 'M', + '.', '-', ':') + for y in x if y not in "0123456789"]): + for x in (res.start, res.end): + if l[i] == 'J': + # non-leap year day (1 based) + used_idxs.append(i) + i += 1 + x.jyday = int(l[i]) + elif l[i] == 'M': + # month[-.]week[-.]weekday + used_idxs.append(i) + i += 1 + x.month = int(l[i]) + used_idxs.append(i) + i += 1 + assert l[i] in ('-', '.') + used_idxs.append(i) + i += 1 + x.week = int(l[i]) + if x.week == 5: + x.week = -1 + used_idxs.append(i) + i += 1 + assert l[i] in ('-', '.') + used_idxs.append(i) + i += 1 + x.weekday = (int(l[i]) - 1) % 7 + else: + # year day (zero based) + x.yday = int(l[i]) + 1 + + used_idxs.append(i) + i += 1 + + if i < len_l and l[i] == '/': + used_idxs.append(i) + i += 1 + # start time + len_li = len(l[i]) + if len_li == 4: + # -0300 + x.time = (int(l[i][:2]) * 3600 + + int(l[i][2:]) * 60) + elif i + 1 < len_l and l[i + 1] == ':': + # -03:00 + x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60 + used_idxs.append(i) + i += 2 + if i + 1 < len_l and l[i + 1] == ':': + used_idxs.append(i) + i += 2 + x.time += int(l[i]) + elif len_li <= 2: + # -[0]3 + x.time = (int(l[i][:2]) * 3600) + else: + return None + used_idxs.append(i) + i += 1 + + assert i == len_l or l[i] == ',' + + i += 1 + + assert i >= len_l + + except (IndexError, ValueError, AssertionError): + return None + + unused_idxs = set(range(len_l)).difference(used_idxs) + res.any_unused_tokens = not {l[n] for n in unused_idxs}.issubset({",",":"}) + return res + + +DEFAULTTZPARSER = _tzparser() + + +def _parsetz(tzstr): + return DEFAULTTZPARSER.parse(tzstr) + + +class ParserError(ValueError): + """Error class for representing failure to parse a datetime string.""" + def __str__(self): + try: + return self.args[0] % self.args[1:] + except (TypeError, IndexError): + return super(ParserError, self).__str__() + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, str(self)) + + +class UnknownTimezoneWarning(RuntimeWarning): + """Raised when the parser finds a timezone it cannot parse into a tzinfo""" +# vim:ts=4:sw=4:et diff --git a/env/lib/python3.8/site-packages/dateutil/parser/isoparser.py b/env/lib/python3.8/site-packages/dateutil/parser/isoparser.py new file mode 100644 index 000000000..48f86a335 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/parser/isoparser.py @@ -0,0 +1,411 @@ +# -*- coding: utf-8 -*- +""" +This module offers a parser for ISO-8601 strings + +It is intended to support all valid date, time and datetime formats per the +ISO-8601 specification. + +..versionadded:: 2.7.0 +""" +from datetime import datetime, timedelta, time, date +import calendar +from dateutil import tz + +from functools import wraps + +import re +import six + +__all__ = ["isoparse", "isoparser"] + + +def _takes_ascii(f): + @wraps(f) + def func(self, str_in, *args, **kwargs): + # If it's a stream, read the whole thing + str_in = getattr(str_in, 'read', lambda: str_in)() + + # If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII + if isinstance(str_in, six.text_type): + # ASCII is the same in UTF-8 + try: + str_in = str_in.encode('ascii') + except UnicodeEncodeError as e: + msg = 'ISO-8601 strings should contain only ASCII characters' + six.raise_from(ValueError(msg), e) + + return f(self, str_in, *args, **kwargs) + + return func + + +class isoparser(object): + def __init__(self, sep=None): + """ + :param sep: + A single character that separates date and time portions. If + ``None``, the parser will accept any single character. + For strict ISO-8601 adherence, pass ``'T'``. + """ + if sep is not None: + if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'): + raise ValueError('Separator must be a single, non-numeric ' + + 'ASCII character') + + sep = sep.encode('ascii') + + self._sep = sep + + @_takes_ascii + def isoparse(self, dt_str): + """ + Parse an ISO-8601 datetime string into a :class:`datetime.datetime`. + + An ISO-8601 datetime string consists of a date portion, followed + optionally by a time portion - the date and time portions are separated + by a single character separator, which is ``T`` in the official + standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be + combined with a time portion. + + Supported date formats are: + + Common: + + - ``YYYY`` + - ``YYYY-MM`` or ``YYYYMM`` + - ``YYYY-MM-DD`` or ``YYYYMMDD`` + + Uncommon: + + - ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0) + - ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day + + The ISO week and day numbering follows the same logic as + :func:`datetime.date.isocalendar`. + + Supported time formats are: + + - ``hh`` + - ``hh:mm`` or ``hhmm`` + - ``hh:mm:ss`` or ``hhmmss`` + - ``hh:mm:ss.ssssss`` (Up to 6 sub-second digits) + + Midnight is a special case for `hh`, as the standard supports both + 00:00 and 24:00 as a representation. The decimal separator can be + either a dot or a comma. + + + .. caution:: + + Support for fractional components other than seconds is part of the + ISO-8601 standard, but is not currently implemented in this parser. + + Supported time zone offset formats are: + + - `Z` (UTC) + - `±HH:MM` + - `±HHMM` + - `±HH` + + Offsets will be represented as :class:`dateutil.tz.tzoffset` objects, + with the exception of UTC, which will be represented as + :class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such + as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`. + + :param dt_str: + A string or stream containing only an ISO-8601 datetime string + + :return: + Returns a :class:`datetime.datetime` representing the string. + Unspecified components default to their lowest value. + + .. warning:: + + As of version 2.7.0, the strictness of the parser should not be + considered a stable part of the contract. Any valid ISO-8601 string + that parses correctly with the default settings will continue to + parse correctly in future versions, but invalid strings that + currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not + guaranteed to continue failing in future versions if they encode + a valid date. + + .. versionadded:: 2.7.0 + """ + components, pos = self._parse_isodate(dt_str) + + if len(dt_str) > pos: + if self._sep is None or dt_str[pos:pos + 1] == self._sep: + components += self._parse_isotime(dt_str[pos + 1:]) + else: + raise ValueError('String contains unknown ISO components') + + if len(components) > 3 and components[3] == 24: + components[3] = 0 + return datetime(*components) + timedelta(days=1) + + return datetime(*components) + + @_takes_ascii + def parse_isodate(self, datestr): + """ + Parse the date portion of an ISO string. + + :param datestr: + The string portion of an ISO string, without a separator + + :return: + Returns a :class:`datetime.date` object + """ + components, pos = self._parse_isodate(datestr) + if pos < len(datestr): + raise ValueError('String contains unknown ISO ' + + 'components: {}'.format(datestr)) + return date(*components) + + @_takes_ascii + def parse_isotime(self, timestr): + """ + Parse the time portion of an ISO string. + + :param timestr: + The time portion of an ISO string, without a separator + + :return: + Returns a :class:`datetime.time` object + """ + components = self._parse_isotime(timestr) + if components[0] == 24: + components[0] = 0 + return time(*components) + + @_takes_ascii + def parse_tzstr(self, tzstr, zero_as_utc=True): + """ + Parse a valid ISO time zone string. + + See :func:`isoparser.isoparse` for details on supported formats. + + :param tzstr: + A string representing an ISO time zone offset + + :param zero_as_utc: + Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones + + :return: + Returns :class:`dateutil.tz.tzoffset` for offsets and + :class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is + specified) offsets equivalent to UTC. + """ + return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc) + + # Constants + _DATE_SEP = b'-' + _TIME_SEP = b':' + _FRACTION_REGEX = re.compile(b'[\\.,]([0-9]+)') + + def _parse_isodate(self, dt_str): + try: + return self._parse_isodate_common(dt_str) + except ValueError: + return self._parse_isodate_uncommon(dt_str) + + def _parse_isodate_common(self, dt_str): + len_str = len(dt_str) + components = [1, 1, 1] + + if len_str < 4: + raise ValueError('ISO string too short') + + # Year + components[0] = int(dt_str[0:4]) + pos = 4 + if pos >= len_str: + return components, pos + + has_sep = dt_str[pos:pos + 1] == self._DATE_SEP + if has_sep: + pos += 1 + + # Month + if len_str - pos < 2: + raise ValueError('Invalid common month') + + components[1] = int(dt_str[pos:pos + 2]) + pos += 2 + + if pos >= len_str: + if has_sep: + return components, pos + else: + raise ValueError('Invalid ISO format') + + if has_sep: + if dt_str[pos:pos + 1] != self._DATE_SEP: + raise ValueError('Invalid separator in ISO string') + pos += 1 + + # Day + if len_str - pos < 2: + raise ValueError('Invalid common day') + components[2] = int(dt_str[pos:pos + 2]) + return components, pos + 2 + + def _parse_isodate_uncommon(self, dt_str): + if len(dt_str) < 4: + raise ValueError('ISO string too short') + + # All ISO formats start with the year + year = int(dt_str[0:4]) + + has_sep = dt_str[4:5] == self._DATE_SEP + + pos = 4 + has_sep # Skip '-' if it's there + if dt_str[pos:pos + 1] == b'W': + # YYYY-?Www-?D? + pos += 1 + weekno = int(dt_str[pos:pos + 2]) + pos += 2 + + dayno = 1 + if len(dt_str) > pos: + if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep: + raise ValueError('Inconsistent use of dash separator') + + pos += has_sep + + dayno = int(dt_str[pos:pos + 1]) + pos += 1 + + base_date = self._calculate_weekdate(year, weekno, dayno) + else: + # YYYYDDD or YYYY-DDD + if len(dt_str) - pos < 3: + raise ValueError('Invalid ordinal day') + + ordinal_day = int(dt_str[pos:pos + 3]) + pos += 3 + + if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)): + raise ValueError('Invalid ordinal day' + + ' {} for year {}'.format(ordinal_day, year)) + + base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1) + + components = [base_date.year, base_date.month, base_date.day] + return components, pos + + def _calculate_weekdate(self, year, week, day): + """ + Calculate the day of corresponding to the ISO year-week-day calendar. + + This function is effectively the inverse of + :func:`datetime.date.isocalendar`. + + :param year: + The year in the ISO calendar + + :param week: + The week in the ISO calendar - range is [1, 53] + + :param day: + The day in the ISO calendar - range is [1 (MON), 7 (SUN)] + + :return: + Returns a :class:`datetime.date` + """ + if not 0 < week < 54: + raise ValueError('Invalid week: {}'.format(week)) + + if not 0 < day < 8: # Range is 1-7 + raise ValueError('Invalid weekday: {}'.format(day)) + + # Get week 1 for the specific year: + jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it + week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1) + + # Now add the specific number of weeks and days to get what we want + week_offset = (week - 1) * 7 + (day - 1) + return week_1 + timedelta(days=week_offset) + + def _parse_isotime(self, timestr): + len_str = len(timestr) + components = [0, 0, 0, 0, None] + pos = 0 + comp = -1 + + if len(timestr) < 2: + raise ValueError('ISO time too short') + + has_sep = len_str >= 3 and timestr[2:3] == self._TIME_SEP + + while pos < len_str and comp < 5: + comp += 1 + + if timestr[pos:pos + 1] in b'-+Zz': + # Detect time zone boundary + components[-1] = self._parse_tzstr(timestr[pos:]) + pos = len_str + break + + if comp < 3: + # Hour, minute, second + components[comp] = int(timestr[pos:pos + 2]) + pos += 2 + if (has_sep and pos < len_str and + timestr[pos:pos + 1] == self._TIME_SEP): + pos += 1 + + if comp == 3: + # Fraction of a second + frac = self._FRACTION_REGEX.match(timestr[pos:]) + if not frac: + continue + + us_str = frac.group(1)[:6] # Truncate to microseconds + components[comp] = int(us_str) * 10**(6 - len(us_str)) + pos += len(frac.group()) + + if pos < len_str: + raise ValueError('Unused components in ISO string') + + if components[0] == 24: + # Standard supports 00:00 and 24:00 as representations of midnight + if any(component != 0 for component in components[1:4]): + raise ValueError('Hour may only be 24 at 24:00:00.000') + + return components + + def _parse_tzstr(self, tzstr, zero_as_utc=True): + if tzstr == b'Z' or tzstr == b'z': + return tz.UTC + + if len(tzstr) not in {3, 5, 6}: + raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters') + + if tzstr[0:1] == b'-': + mult = -1 + elif tzstr[0:1] == b'+': + mult = 1 + else: + raise ValueError('Time zone offset requires sign') + + hours = int(tzstr[1:3]) + if len(tzstr) == 3: + minutes = 0 + else: + minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):]) + + if zero_as_utc and hours == 0 and minutes == 0: + return tz.UTC + else: + if minutes > 59: + raise ValueError('Invalid minutes in time zone offset') + + if hours > 23: + raise ValueError('Invalid hours in time zone offset') + + return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60) + + +DEFAULT_ISOPARSER = isoparser() +isoparse = DEFAULT_ISOPARSER.isoparse diff --git a/env/lib/python3.8/site-packages/dateutil/relativedelta.py b/env/lib/python3.8/site-packages/dateutil/relativedelta.py new file mode 100644 index 000000000..a9e85f7e6 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/relativedelta.py @@ -0,0 +1,599 @@ +# -*- coding: utf-8 -*- +import datetime +import calendar + +import operator +from math import copysign + +from six import integer_types +from warnings import warn + +from ._common import weekday + +MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7)) + +__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] + + +class relativedelta(object): + """ + The relativedelta type is designed to be applied to an existing datetime and + can replace specific components of that datetime, or represents an interval + of time. + + It is based on the specification of the excellent work done by M.-A. Lemburg + in his + `mx.DateTime `_ extension. + However, notice that this type does *NOT* implement the same algorithm as + his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. + + There are two different ways to build a relativedelta instance. The + first one is passing it two date/datetime classes:: + + relativedelta(datetime1, datetime2) + + The second one is passing it any number of the following keyword arguments:: + + relativedelta(arg1=x,arg2=y,arg3=z...) + + year, month, day, hour, minute, second, microsecond: + Absolute information (argument is singular); adding or subtracting a + relativedelta with absolute information does not perform an arithmetic + operation, but rather REPLACES the corresponding value in the + original datetime with the value(s) in relativedelta. + + years, months, weeks, days, hours, minutes, seconds, microseconds: + Relative information, may be negative (argument is plural); adding + or subtracting a relativedelta with relative information performs + the corresponding arithmetic operation on the original datetime value + with the information in the relativedelta. + + weekday: + One of the weekday instances (MO, TU, etc) available in the + relativedelta module. These instances may receive a parameter N, + specifying the Nth weekday, which could be positive or negative + (like MO(+1) or MO(-2)). Not specifying it is the same as specifying + +1. You can also use an integer, where 0=MO. This argument is always + relative e.g. if the calculated date is already Monday, using MO(1) + or MO(-1) won't change the day. To effectively make it absolute, use + it in combination with the day argument (e.g. day=1, MO(1) for first + Monday of the month). + + leapdays: + Will add given days to the date found, if year is a leap + year, and the date found is post 28 of february. + + yearday, nlyearday: + Set the yearday or the non-leap year day (jump leap days). + These are converted to day/month/leapdays information. + + There are relative and absolute forms of the keyword + arguments. The plural is relative, and the singular is + absolute. For each argument in the order below, the absolute form + is applied first (by setting each attribute to that value) and + then the relative form (by adding the value to the attribute). + + The order of attributes considered when this relativedelta is + added to a datetime is: + + 1. Year + 2. Month + 3. Day + 4. Hours + 5. Minutes + 6. Seconds + 7. Microseconds + + Finally, weekday is applied, using the rule described above. + + For example + + >>> from datetime import datetime + >>> from dateutil.relativedelta import relativedelta, MO + >>> dt = datetime(2018, 4, 9, 13, 37, 0) + >>> delta = relativedelta(hours=25, day=1, weekday=MO(1)) + >>> dt + delta + datetime.datetime(2018, 4, 2, 14, 37) + + First, the day is set to 1 (the first of the month), then 25 hours + are added, to get to the 2nd day and 14th hour, finally the + weekday is applied, but since the 2nd is already a Monday there is + no effect. + + """ + + def __init__(self, dt1=None, dt2=None, + years=0, months=0, days=0, leapdays=0, weeks=0, + hours=0, minutes=0, seconds=0, microseconds=0, + year=None, month=None, day=None, weekday=None, + yearday=None, nlyearday=None, + hour=None, minute=None, second=None, microsecond=None): + + if dt1 and dt2: + # datetime is a subclass of date. So both must be date + if not (isinstance(dt1, datetime.date) and + isinstance(dt2, datetime.date)): + raise TypeError("relativedelta only diffs datetime/date") + + # We allow two dates, or two datetimes, so we coerce them to be + # of the same type + if (isinstance(dt1, datetime.datetime) != + isinstance(dt2, datetime.datetime)): + if not isinstance(dt1, datetime.datetime): + dt1 = datetime.datetime.fromordinal(dt1.toordinal()) + elif not isinstance(dt2, datetime.datetime): + dt2 = datetime.datetime.fromordinal(dt2.toordinal()) + + self.years = 0 + self.months = 0 + self.days = 0 + self.leapdays = 0 + self.hours = 0 + self.minutes = 0 + self.seconds = 0 + self.microseconds = 0 + self.year = None + self.month = None + self.day = None + self.weekday = None + self.hour = None + self.minute = None + self.second = None + self.microsecond = None + self._has_time = 0 + + # Get year / month delta between the two + months = (dt1.year - dt2.year) * 12 + (dt1.month - dt2.month) + self._set_months(months) + + # Remove the year/month delta so the timedelta is just well-defined + # time units (seconds, days and microseconds) + dtm = self.__radd__(dt2) + + # If we've overshot our target, make an adjustment + if dt1 < dt2: + compare = operator.gt + increment = 1 + else: + compare = operator.lt + increment = -1 + + while compare(dt1, dtm): + months += increment + self._set_months(months) + dtm = self.__radd__(dt2) + + # Get the timedelta between the "months-adjusted" date and dt1 + delta = dt1 - dtm + self.seconds = delta.seconds + delta.days * 86400 + self.microseconds = delta.microseconds + else: + # Check for non-integer values in integer-only quantities + if any(x is not None and x != int(x) for x in (years, months)): + raise ValueError("Non-integer years and months are " + "ambiguous and not currently supported.") + + # Relative information + self.years = int(years) + self.months = int(months) + self.days = days + weeks * 7 + self.leapdays = leapdays + self.hours = hours + self.minutes = minutes + self.seconds = seconds + self.microseconds = microseconds + + # Absolute information + self.year = year + self.month = month + self.day = day + self.hour = hour + self.minute = minute + self.second = second + self.microsecond = microsecond + + if any(x is not None and int(x) != x + for x in (year, month, day, hour, + minute, second, microsecond)): + # For now we'll deprecate floats - later it'll be an error. + warn("Non-integer value passed as absolute information. " + + "This is not a well-defined condition and will raise " + + "errors in future versions.", DeprecationWarning) + + if isinstance(weekday, integer_types): + self.weekday = weekdays[weekday] + else: + self.weekday = weekday + + yday = 0 + if nlyearday: + yday = nlyearday + elif yearday: + yday = yearday + if yearday > 59: + self.leapdays = -1 + if yday: + ydayidx = [31, 59, 90, 120, 151, 181, 212, + 243, 273, 304, 334, 366] + for idx, ydays in enumerate(ydayidx): + if yday <= ydays: + self.month = idx+1 + if idx == 0: + self.day = yday + else: + self.day = yday-ydayidx[idx-1] + break + else: + raise ValueError("invalid year day (%d)" % yday) + + self._fix() + + def _fix(self): + if abs(self.microseconds) > 999999: + s = _sign(self.microseconds) + div, mod = divmod(self.microseconds * s, 1000000) + self.microseconds = mod * s + self.seconds += div * s + if abs(self.seconds) > 59: + s = _sign(self.seconds) + div, mod = divmod(self.seconds * s, 60) + self.seconds = mod * s + self.minutes += div * s + if abs(self.minutes) > 59: + s = _sign(self.minutes) + div, mod = divmod(self.minutes * s, 60) + self.minutes = mod * s + self.hours += div * s + if abs(self.hours) > 23: + s = _sign(self.hours) + div, mod = divmod(self.hours * s, 24) + self.hours = mod * s + self.days += div * s + if abs(self.months) > 11: + s = _sign(self.months) + div, mod = divmod(self.months * s, 12) + self.months = mod * s + self.years += div * s + if (self.hours or self.minutes or self.seconds or self.microseconds + or self.hour is not None or self.minute is not None or + self.second is not None or self.microsecond is not None): + self._has_time = 1 + else: + self._has_time = 0 + + @property + def weeks(self): + return int(self.days / 7.0) + + @weeks.setter + def weeks(self, value): + self.days = self.days - (self.weeks * 7) + value * 7 + + def _set_months(self, months): + self.months = months + if abs(self.months) > 11: + s = _sign(self.months) + div, mod = divmod(self.months * s, 12) + self.months = mod * s + self.years = div * s + else: + self.years = 0 + + def normalized(self): + """ + Return a version of this object represented entirely using integer + values for the relative attributes. + + >>> relativedelta(days=1.5, hours=2).normalized() + relativedelta(days=+1, hours=+14) + + :return: + Returns a :class:`dateutil.relativedelta.relativedelta` object. + """ + # Cascade remainders down (rounding each to roughly nearest microsecond) + days = int(self.days) + + hours_f = round(self.hours + 24 * (self.days - days), 11) + hours = int(hours_f) + + minutes_f = round(self.minutes + 60 * (hours_f - hours), 10) + minutes = int(minutes_f) + + seconds_f = round(self.seconds + 60 * (minutes_f - minutes), 8) + seconds = int(seconds_f) + + microseconds = round(self.microseconds + 1e6 * (seconds_f - seconds)) + + # Constructor carries overflow back up with call to _fix() + return self.__class__(years=self.years, months=self.months, + days=days, hours=hours, minutes=minutes, + seconds=seconds, microseconds=microseconds, + leapdays=self.leapdays, year=self.year, + month=self.month, day=self.day, + weekday=self.weekday, hour=self.hour, + minute=self.minute, second=self.second, + microsecond=self.microsecond) + + def __add__(self, other): + if isinstance(other, relativedelta): + return self.__class__(years=other.years + self.years, + months=other.months + self.months, + days=other.days + self.days, + hours=other.hours + self.hours, + minutes=other.minutes + self.minutes, + seconds=other.seconds + self.seconds, + microseconds=(other.microseconds + + self.microseconds), + leapdays=other.leapdays or self.leapdays, + year=(other.year if other.year is not None + else self.year), + month=(other.month if other.month is not None + else self.month), + day=(other.day if other.day is not None + else self.day), + weekday=(other.weekday if other.weekday is not None + else self.weekday), + hour=(other.hour if other.hour is not None + else self.hour), + minute=(other.minute if other.minute is not None + else self.minute), + second=(other.second if other.second is not None + else self.second), + microsecond=(other.microsecond if other.microsecond + is not None else + self.microsecond)) + if isinstance(other, datetime.timedelta): + return self.__class__(years=self.years, + months=self.months, + days=self.days + other.days, + hours=self.hours, + minutes=self.minutes, + seconds=self.seconds + other.seconds, + microseconds=self.microseconds + other.microseconds, + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + if not isinstance(other, datetime.date): + return NotImplemented + elif self._has_time and not isinstance(other, datetime.datetime): + other = datetime.datetime.fromordinal(other.toordinal()) + year = (self.year or other.year)+self.years + month = self.month or other.month + if self.months: + assert 1 <= abs(self.months) <= 12 + month += self.months + if month > 12: + year += 1 + month -= 12 + elif month < 1: + year -= 1 + month += 12 + day = min(calendar.monthrange(year, month)[1], + self.day or other.day) + repl = {"year": year, "month": month, "day": day} + for attr in ["hour", "minute", "second", "microsecond"]: + value = getattr(self, attr) + if value is not None: + repl[attr] = value + days = self.days + if self.leapdays and month > 2 and calendar.isleap(year): + days += self.leapdays + ret = (other.replace(**repl) + + datetime.timedelta(days=days, + hours=self.hours, + minutes=self.minutes, + seconds=self.seconds, + microseconds=self.microseconds)) + if self.weekday: + weekday, nth = self.weekday.weekday, self.weekday.n or 1 + jumpdays = (abs(nth) - 1) * 7 + if nth > 0: + jumpdays += (7 - ret.weekday() + weekday) % 7 + else: + jumpdays += (ret.weekday() - weekday) % 7 + jumpdays *= -1 + ret += datetime.timedelta(days=jumpdays) + return ret + + def __radd__(self, other): + return self.__add__(other) + + def __rsub__(self, other): + return self.__neg__().__radd__(other) + + def __sub__(self, other): + if not isinstance(other, relativedelta): + return NotImplemented # In case the other object defines __rsub__ + return self.__class__(years=self.years - other.years, + months=self.months - other.months, + days=self.days - other.days, + hours=self.hours - other.hours, + minutes=self.minutes - other.minutes, + seconds=self.seconds - other.seconds, + microseconds=self.microseconds - other.microseconds, + leapdays=self.leapdays or other.leapdays, + year=(self.year if self.year is not None + else other.year), + month=(self.month if self.month is not None else + other.month), + day=(self.day if self.day is not None else + other.day), + weekday=(self.weekday if self.weekday is not None else + other.weekday), + hour=(self.hour if self.hour is not None else + other.hour), + minute=(self.minute if self.minute is not None else + other.minute), + second=(self.second if self.second is not None else + other.second), + microsecond=(self.microsecond if self.microsecond + is not None else + other.microsecond)) + + def __abs__(self): + return self.__class__(years=abs(self.years), + months=abs(self.months), + days=abs(self.days), + hours=abs(self.hours), + minutes=abs(self.minutes), + seconds=abs(self.seconds), + microseconds=abs(self.microseconds), + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + + def __neg__(self): + return self.__class__(years=-self.years, + months=-self.months, + days=-self.days, + hours=-self.hours, + minutes=-self.minutes, + seconds=-self.seconds, + microseconds=-self.microseconds, + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + + def __bool__(self): + return not (not self.years and + not self.months and + not self.days and + not self.hours and + not self.minutes and + not self.seconds and + not self.microseconds and + not self.leapdays and + self.year is None and + self.month is None and + self.day is None and + self.weekday is None and + self.hour is None and + self.minute is None and + self.second is None and + self.microsecond is None) + # Compatibility with Python 2.x + __nonzero__ = __bool__ + + def __mul__(self, other): + try: + f = float(other) + except TypeError: + return NotImplemented + + return self.__class__(years=int(self.years * f), + months=int(self.months * f), + days=int(self.days * f), + hours=int(self.hours * f), + minutes=int(self.minutes * f), + seconds=int(self.seconds * f), + microseconds=int(self.microseconds * f), + leapdays=self.leapdays, + year=self.year, + month=self.month, + day=self.day, + weekday=self.weekday, + hour=self.hour, + minute=self.minute, + second=self.second, + microsecond=self.microsecond) + + __rmul__ = __mul__ + + def __eq__(self, other): + if not isinstance(other, relativedelta): + return NotImplemented + if self.weekday or other.weekday: + if not self.weekday or not other.weekday: + return False + if self.weekday.weekday != other.weekday.weekday: + return False + n1, n2 = self.weekday.n, other.weekday.n + if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): + return False + return (self.years == other.years and + self.months == other.months and + self.days == other.days and + self.hours == other.hours and + self.minutes == other.minutes and + self.seconds == other.seconds and + self.microseconds == other.microseconds and + self.leapdays == other.leapdays and + self.year == other.year and + self.month == other.month and + self.day == other.day and + self.hour == other.hour and + self.minute == other.minute and + self.second == other.second and + self.microsecond == other.microsecond) + + def __hash__(self): + return hash(( + self.weekday, + self.years, + self.months, + self.days, + self.hours, + self.minutes, + self.seconds, + self.microseconds, + self.leapdays, + self.year, + self.month, + self.day, + self.hour, + self.minute, + self.second, + self.microsecond, + )) + + def __ne__(self, other): + return not self.__eq__(other) + + def __div__(self, other): + try: + reciprocal = 1 / float(other) + except TypeError: + return NotImplemented + + return self.__mul__(reciprocal) + + __truediv__ = __div__ + + def __repr__(self): + l = [] + for attr in ["years", "months", "days", "leapdays", + "hours", "minutes", "seconds", "microseconds"]: + value = getattr(self, attr) + if value: + l.append("{attr}={value:+g}".format(attr=attr, value=value)) + for attr in ["year", "month", "day", "weekday", + "hour", "minute", "second", "microsecond"]: + value = getattr(self, attr) + if value is not None: + l.append("{attr}={value}".format(attr=attr, value=repr(value))) + return "{classname}({attrs})".format(classname=self.__class__.__name__, + attrs=", ".join(l)) + + +def _sign(x): + return int(copysign(1, x)) + +# vim:ts=4:sw=4:et diff --git a/env/lib/python3.8/site-packages/dateutil/rrule.py b/env/lib/python3.8/site-packages/dateutil/rrule.py new file mode 100644 index 000000000..6bf0ea9c6 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/rrule.py @@ -0,0 +1,1735 @@ +# -*- coding: utf-8 -*- +""" +The rrule module offers a small, complete, and very fast, implementation of +the recurrence rules documented in the +`iCalendar RFC `_, +including support for caching of results. +""" +import itertools +import datetime +import calendar +import re +import sys + +try: + from math import gcd +except ImportError: + from fractions import gcd + +from six import advance_iterator, integer_types +from six.moves import _thread, range +import heapq + +from ._common import weekday as weekdaybase + +# For warning about deprecation of until and count +from warnings import warn + +__all__ = ["rrule", "rruleset", "rrulestr", + "YEARLY", "MONTHLY", "WEEKLY", "DAILY", + "HOURLY", "MINUTELY", "SECONDLY", + "MO", "TU", "WE", "TH", "FR", "SA", "SU"] + +# Every mask is 7 days longer to handle cross-year weekly periods. +M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30 + + [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) +M365MASK = list(M366MASK) +M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32)) +MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) +MDAY365MASK = list(MDAY366MASK) +M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0)) +NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) +NMDAY365MASK = list(NMDAY366MASK) +M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366) +M365RANGE = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365) +WDAYMASK = [0, 1, 2, 3, 4, 5, 6]*55 +del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] +MDAY365MASK = tuple(MDAY365MASK) +M365MASK = tuple(M365MASK) + +FREQNAMES = ['YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY', 'HOURLY', 'MINUTELY', 'SECONDLY'] + +(YEARLY, + MONTHLY, + WEEKLY, + DAILY, + HOURLY, + MINUTELY, + SECONDLY) = list(range(7)) + +# Imported on demand. +easter = None +parser = None + + +class weekday(weekdaybase): + """ + This version of weekday does not allow n = 0. + """ + def __init__(self, wkday, n=None): + if n == 0: + raise ValueError("Can't create weekday with n==0") + + super(weekday, self).__init__(wkday, n) + + +MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7)) + + +def _invalidates_cache(f): + """ + Decorator for rruleset methods which may invalidate the + cached length. + """ + def inner_func(self, *args, **kwargs): + rv = f(self, *args, **kwargs) + self._invalidate_cache() + return rv + + return inner_func + + +class rrulebase(object): + def __init__(self, cache=False): + if cache: + self._cache = [] + self._cache_lock = _thread.allocate_lock() + self._invalidate_cache() + else: + self._cache = None + self._cache_complete = False + self._len = None + + def __iter__(self): + if self._cache_complete: + return iter(self._cache) + elif self._cache is None: + return self._iter() + else: + return self._iter_cached() + + def _invalidate_cache(self): + if self._cache is not None: + self._cache = [] + self._cache_complete = False + self._cache_gen = self._iter() + + if self._cache_lock.locked(): + self._cache_lock.release() + + self._len = None + + def _iter_cached(self): + i = 0 + gen = self._cache_gen + cache = self._cache + acquire = self._cache_lock.acquire + release = self._cache_lock.release + while gen: + if i == len(cache): + acquire() + if self._cache_complete: + break + try: + for j in range(10): + cache.append(advance_iterator(gen)) + except StopIteration: + self._cache_gen = gen = None + self._cache_complete = True + break + release() + yield cache[i] + i += 1 + while i < self._len: + yield cache[i] + i += 1 + + def __getitem__(self, item): + if self._cache_complete: + return self._cache[item] + elif isinstance(item, slice): + if item.step and item.step < 0: + return list(iter(self))[item] + else: + return list(itertools.islice(self, + item.start or 0, + item.stop or sys.maxsize, + item.step or 1)) + elif item >= 0: + gen = iter(self) + try: + for i in range(item+1): + res = advance_iterator(gen) + except StopIteration: + raise IndexError + return res + else: + return list(iter(self))[item] + + def __contains__(self, item): + if self._cache_complete: + return item in self._cache + else: + for i in self: + if i == item: + return True + elif i > item: + return False + return False + + # __len__() introduces a large performance penalty. + def count(self): + """ Returns the number of recurrences in this set. It will have go + trough the whole recurrence, if this hasn't been done before. """ + if self._len is None: + for x in self: + pass + return self._len + + def before(self, dt, inc=False): + """ Returns the last recurrence before the given datetime instance. The + inc keyword defines what happens if dt is an occurrence. With + inc=True, if dt itself is an occurrence, it will be returned. """ + if self._cache_complete: + gen = self._cache + else: + gen = self + last = None + if inc: + for i in gen: + if i > dt: + break + last = i + else: + for i in gen: + if i >= dt: + break + last = i + return last + + def after(self, dt, inc=False): + """ Returns the first recurrence after the given datetime instance. The + inc keyword defines what happens if dt is an occurrence. With + inc=True, if dt itself is an occurrence, it will be returned. """ + if self._cache_complete: + gen = self._cache + else: + gen = self + if inc: + for i in gen: + if i >= dt: + return i + else: + for i in gen: + if i > dt: + return i + return None + + def xafter(self, dt, count=None, inc=False): + """ + Generator which yields up to `count` recurrences after the given + datetime instance, equivalent to `after`. + + :param dt: + The datetime at which to start generating recurrences. + + :param count: + The maximum number of recurrences to generate. If `None` (default), + dates are generated until the recurrence rule is exhausted. + + :param inc: + If `dt` is an instance of the rule and `inc` is `True`, it is + included in the output. + + :yields: Yields a sequence of `datetime` objects. + """ + + if self._cache_complete: + gen = self._cache + else: + gen = self + + # Select the comparison function + if inc: + comp = lambda dc, dtc: dc >= dtc + else: + comp = lambda dc, dtc: dc > dtc + + # Generate dates + n = 0 + for d in gen: + if comp(d, dt): + if count is not None: + n += 1 + if n > count: + break + + yield d + + def between(self, after, before, inc=False, count=1): + """ Returns all the occurrences of the rrule between after and before. + The inc keyword defines what happens if after and/or before are + themselves occurrences. With inc=True, they will be included in the + list, if they are found in the recurrence set. """ + if self._cache_complete: + gen = self._cache + else: + gen = self + started = False + l = [] + if inc: + for i in gen: + if i > before: + break + elif not started: + if i >= after: + started = True + l.append(i) + else: + l.append(i) + else: + for i in gen: + if i >= before: + break + elif not started: + if i > after: + started = True + l.append(i) + else: + l.append(i) + return l + + +class rrule(rrulebase): + """ + That's the base of the rrule operation. It accepts all the keywords + defined in the RFC as its constructor parameters (except byday, + which was renamed to byweekday) and more. The constructor prototype is:: + + rrule(freq) + + Where freq must be one of YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, + or SECONDLY. + + .. note:: + Per RFC section 3.3.10, recurrence instances falling on invalid dates + and times are ignored rather than coerced: + + Recurrence rules may generate recurrence instances with an invalid + date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM + on a day where the local time is moved forward by an hour at 1:00 + AM). Such recurrence instances MUST be ignored and MUST NOT be + counted as part of the recurrence set. + + This can lead to possibly surprising behavior when, for example, the + start date occurs at the end of the month: + + >>> from dateutil.rrule import rrule, MONTHLY + >>> from datetime import datetime + >>> start_date = datetime(2014, 12, 31) + >>> list(rrule(freq=MONTHLY, count=4, dtstart=start_date)) + ... # doctest: +NORMALIZE_WHITESPACE + [datetime.datetime(2014, 12, 31, 0, 0), + datetime.datetime(2015, 1, 31, 0, 0), + datetime.datetime(2015, 3, 31, 0, 0), + datetime.datetime(2015, 5, 31, 0, 0)] + + Additionally, it supports the following keyword arguments: + + :param dtstart: + The recurrence start. Besides being the base for the recurrence, + missing parameters in the final recurrence instances will also be + extracted from this date. If not given, datetime.now() will be used + instead. + :param interval: + The interval between each freq iteration. For example, when using + YEARLY, an interval of 2 means once every two years, but with HOURLY, + it means once every two hours. The default interval is 1. + :param wkst: + The week start day. Must be one of the MO, TU, WE constants, or an + integer, specifying the first day of the week. This will affect + recurrences based on weekly periods. The default week start is got + from calendar.firstweekday(), and may be modified by + calendar.setfirstweekday(). + :param count: + If given, this determines how many occurrences will be generated. + + .. note:: + As of version 2.5.0, the use of the keyword ``until`` in conjunction + with ``count`` is deprecated, to make sure ``dateutil`` is fully + compliant with `RFC-5545 Sec. 3.3.10 `_. Therefore, ``until`` and ``count`` + **must not** occur in the same call to ``rrule``. + :param until: + If given, this must be a datetime instance specifying the upper-bound + limit of the recurrence. The last recurrence in the rule is the greatest + datetime that is less than or equal to the value specified in the + ``until`` parameter. + + .. note:: + As of version 2.5.0, the use of the keyword ``until`` in conjunction + with ``count`` is deprecated, to make sure ``dateutil`` is fully + compliant with `RFC-5545 Sec. 3.3.10 `_. Therefore, ``until`` and ``count`` + **must not** occur in the same call to ``rrule``. + :param bysetpos: + If given, it must be either an integer, or a sequence of integers, + positive or negative. Each given integer will specify an occurrence + number, corresponding to the nth occurrence of the rule inside the + frequency period. For example, a bysetpos of -1 if combined with a + MONTHLY frequency, and a byweekday of (MO, TU, WE, TH, FR), will + result in the last work day of every month. + :param bymonth: + If given, it must be either an integer, or a sequence of integers, + meaning the months to apply the recurrence to. + :param bymonthday: + If given, it must be either an integer, or a sequence of integers, + meaning the month days to apply the recurrence to. + :param byyearday: + If given, it must be either an integer, or a sequence of integers, + meaning the year days to apply the recurrence to. + :param byeaster: + If given, it must be either an integer, or a sequence of integers, + positive or negative. Each integer will define an offset from the + Easter Sunday. Passing the offset 0 to byeaster will yield the Easter + Sunday itself. This is an extension to the RFC specification. + :param byweekno: + If given, it must be either an integer, or a sequence of integers, + meaning the week numbers to apply the recurrence to. Week numbers + have the meaning described in ISO8601, that is, the first week of + the year is that containing at least four days of the new year. + :param byweekday: + If given, it must be either an integer (0 == MO), a sequence of + integers, one of the weekday constants (MO, TU, etc), or a sequence + of these constants. When given, these variables will define the + weekdays where the recurrence will be applied. It's also possible to + use an argument n for the weekday instances, which will mean the nth + occurrence of this weekday in the period. For example, with MONTHLY, + or with YEARLY and BYMONTH, using FR(+1) in byweekday will specify the + first friday of the month where the recurrence happens. Notice that in + the RFC documentation, this is specified as BYDAY, but was renamed to + avoid the ambiguity of that keyword. + :param byhour: + If given, it must be either an integer, or a sequence of integers, + meaning the hours to apply the recurrence to. + :param byminute: + If given, it must be either an integer, or a sequence of integers, + meaning the minutes to apply the recurrence to. + :param bysecond: + If given, it must be either an integer, or a sequence of integers, + meaning the seconds to apply the recurrence to. + :param cache: + If given, it must be a boolean value specifying to enable or disable + caching of results. If you will use the same rrule instance multiple + times, enabling caching will improve the performance considerably. + """ + def __init__(self, freq, dtstart=None, + interval=1, wkst=None, count=None, until=None, bysetpos=None, + bymonth=None, bymonthday=None, byyearday=None, byeaster=None, + byweekno=None, byweekday=None, + byhour=None, byminute=None, bysecond=None, + cache=False): + super(rrule, self).__init__(cache) + global easter + if not dtstart: + if until and until.tzinfo: + dtstart = datetime.datetime.now(tz=until.tzinfo).replace(microsecond=0) + else: + dtstart = datetime.datetime.now().replace(microsecond=0) + elif not isinstance(dtstart, datetime.datetime): + dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) + else: + dtstart = dtstart.replace(microsecond=0) + self._dtstart = dtstart + self._tzinfo = dtstart.tzinfo + self._freq = freq + self._interval = interval + self._count = count + + # Cache the original byxxx rules, if they are provided, as the _byxxx + # attributes do not necessarily map to the inputs, and this can be + # a problem in generating the strings. Only store things if they've + # been supplied (the string retrieval will just use .get()) + self._original_rule = {} + + if until and not isinstance(until, datetime.datetime): + until = datetime.datetime.fromordinal(until.toordinal()) + self._until = until + + if self._dtstart and self._until: + if (self._dtstart.tzinfo is not None) != (self._until.tzinfo is not None): + # According to RFC5545 Section 3.3.10: + # https://tools.ietf.org/html/rfc5545#section-3.3.10 + # + # > If the "DTSTART" property is specified as a date with UTC + # > time or a date with local time and time zone reference, + # > then the UNTIL rule part MUST be specified as a date with + # > UTC time. + raise ValueError( + 'RRULE UNTIL values must be specified in UTC when DTSTART ' + 'is timezone-aware' + ) + + if count is not None and until: + warn("Using both 'count' and 'until' is inconsistent with RFC 5545" + " and has been deprecated in dateutil. Future versions will " + "raise an error.", DeprecationWarning) + + if wkst is None: + self._wkst = calendar.firstweekday() + elif isinstance(wkst, integer_types): + self._wkst = wkst + else: + self._wkst = wkst.weekday + + if bysetpos is None: + self._bysetpos = None + elif isinstance(bysetpos, integer_types): + if bysetpos == 0 or not (-366 <= bysetpos <= 366): + raise ValueError("bysetpos must be between 1 and 366, " + "or between -366 and -1") + self._bysetpos = (bysetpos,) + else: + self._bysetpos = tuple(bysetpos) + for pos in self._bysetpos: + if pos == 0 or not (-366 <= pos <= 366): + raise ValueError("bysetpos must be between 1 and 366, " + "or between -366 and -1") + + if self._bysetpos: + self._original_rule['bysetpos'] = self._bysetpos + + if (byweekno is None and byyearday is None and bymonthday is None and + byweekday is None and byeaster is None): + if freq == YEARLY: + if bymonth is None: + bymonth = dtstart.month + self._original_rule['bymonth'] = None + bymonthday = dtstart.day + self._original_rule['bymonthday'] = None + elif freq == MONTHLY: + bymonthday = dtstart.day + self._original_rule['bymonthday'] = None + elif freq == WEEKLY: + byweekday = dtstart.weekday() + self._original_rule['byweekday'] = None + + # bymonth + if bymonth is None: + self._bymonth = None + else: + if isinstance(bymonth, integer_types): + bymonth = (bymonth,) + + self._bymonth = tuple(sorted(set(bymonth))) + + if 'bymonth' not in self._original_rule: + self._original_rule['bymonth'] = self._bymonth + + # byyearday + if byyearday is None: + self._byyearday = None + else: + if isinstance(byyearday, integer_types): + byyearday = (byyearday,) + + self._byyearday = tuple(sorted(set(byyearday))) + self._original_rule['byyearday'] = self._byyearday + + # byeaster + if byeaster is not None: + if not easter: + from dateutil import easter + if isinstance(byeaster, integer_types): + self._byeaster = (byeaster,) + else: + self._byeaster = tuple(sorted(byeaster)) + + self._original_rule['byeaster'] = self._byeaster + else: + self._byeaster = None + + # bymonthday + if bymonthday is None: + self._bymonthday = () + self._bynmonthday = () + else: + if isinstance(bymonthday, integer_types): + bymonthday = (bymonthday,) + + bymonthday = set(bymonthday) # Ensure it's unique + + self._bymonthday = tuple(sorted(x for x in bymonthday if x > 0)) + self._bynmonthday = tuple(sorted(x for x in bymonthday if x < 0)) + + # Storing positive numbers first, then negative numbers + if 'bymonthday' not in self._original_rule: + self._original_rule['bymonthday'] = tuple( + itertools.chain(self._bymonthday, self._bynmonthday)) + + # byweekno + if byweekno is None: + self._byweekno = None + else: + if isinstance(byweekno, integer_types): + byweekno = (byweekno,) + + self._byweekno = tuple(sorted(set(byweekno))) + + self._original_rule['byweekno'] = self._byweekno + + # byweekday / bynweekday + if byweekday is None: + self._byweekday = None + self._bynweekday = None + else: + # If it's one of the valid non-sequence types, convert to a + # single-element sequence before the iterator that builds the + # byweekday set. + if isinstance(byweekday, integer_types) or hasattr(byweekday, "n"): + byweekday = (byweekday,) + + self._byweekday = set() + self._bynweekday = set() + for wday in byweekday: + if isinstance(wday, integer_types): + self._byweekday.add(wday) + elif not wday.n or freq > MONTHLY: + self._byweekday.add(wday.weekday) + else: + self._bynweekday.add((wday.weekday, wday.n)) + + if not self._byweekday: + self._byweekday = None + elif not self._bynweekday: + self._bynweekday = None + + if self._byweekday is not None: + self._byweekday = tuple(sorted(self._byweekday)) + orig_byweekday = [weekday(x) for x in self._byweekday] + else: + orig_byweekday = () + + if self._bynweekday is not None: + self._bynweekday = tuple(sorted(self._bynweekday)) + orig_bynweekday = [weekday(*x) for x in self._bynweekday] + else: + orig_bynweekday = () + + if 'byweekday' not in self._original_rule: + self._original_rule['byweekday'] = tuple(itertools.chain( + orig_byweekday, orig_bynweekday)) + + # byhour + if byhour is None: + if freq < HOURLY: + self._byhour = {dtstart.hour} + else: + self._byhour = None + else: + if isinstance(byhour, integer_types): + byhour = (byhour,) + + if freq == HOURLY: + self._byhour = self.__construct_byset(start=dtstart.hour, + byxxx=byhour, + base=24) + else: + self._byhour = set(byhour) + + self._byhour = tuple(sorted(self._byhour)) + self._original_rule['byhour'] = self._byhour + + # byminute + if byminute is None: + if freq < MINUTELY: + self._byminute = {dtstart.minute} + else: + self._byminute = None + else: + if isinstance(byminute, integer_types): + byminute = (byminute,) + + if freq == MINUTELY: + self._byminute = self.__construct_byset(start=dtstart.minute, + byxxx=byminute, + base=60) + else: + self._byminute = set(byminute) + + self._byminute = tuple(sorted(self._byminute)) + self._original_rule['byminute'] = self._byminute + + # bysecond + if bysecond is None: + if freq < SECONDLY: + self._bysecond = ((dtstart.second,)) + else: + self._bysecond = None + else: + if isinstance(bysecond, integer_types): + bysecond = (bysecond,) + + self._bysecond = set(bysecond) + + if freq == SECONDLY: + self._bysecond = self.__construct_byset(start=dtstart.second, + byxxx=bysecond, + base=60) + else: + self._bysecond = set(bysecond) + + self._bysecond = tuple(sorted(self._bysecond)) + self._original_rule['bysecond'] = self._bysecond + + if self._freq >= HOURLY: + self._timeset = None + else: + self._timeset = [] + for hour in self._byhour: + for minute in self._byminute: + for second in self._bysecond: + self._timeset.append( + datetime.time(hour, minute, second, + tzinfo=self._tzinfo)) + self._timeset.sort() + self._timeset = tuple(self._timeset) + + def __str__(self): + """ + Output a string that would generate this RRULE if passed to rrulestr. + This is mostly compatible with RFC5545, except for the + dateutil-specific extension BYEASTER. + """ + + output = [] + h, m, s = [None] * 3 + if self._dtstart: + output.append(self._dtstart.strftime('DTSTART:%Y%m%dT%H%M%S')) + h, m, s = self._dtstart.timetuple()[3:6] + + parts = ['FREQ=' + FREQNAMES[self._freq]] + if self._interval != 1: + parts.append('INTERVAL=' + str(self._interval)) + + if self._wkst: + parts.append('WKST=' + repr(weekday(self._wkst))[0:2]) + + if self._count is not None: + parts.append('COUNT=' + str(self._count)) + + if self._until: + parts.append(self._until.strftime('UNTIL=%Y%m%dT%H%M%S')) + + if self._original_rule.get('byweekday') is not None: + # The str() method on weekday objects doesn't generate + # RFC5545-compliant strings, so we should modify that. + original_rule = dict(self._original_rule) + wday_strings = [] + for wday in original_rule['byweekday']: + if wday.n: + wday_strings.append('{n:+d}{wday}'.format( + n=wday.n, + wday=repr(wday)[0:2])) + else: + wday_strings.append(repr(wday)) + + original_rule['byweekday'] = wday_strings + else: + original_rule = self._original_rule + + partfmt = '{name}={vals}' + for name, key in [('BYSETPOS', 'bysetpos'), + ('BYMONTH', 'bymonth'), + ('BYMONTHDAY', 'bymonthday'), + ('BYYEARDAY', 'byyearday'), + ('BYWEEKNO', 'byweekno'), + ('BYDAY', 'byweekday'), + ('BYHOUR', 'byhour'), + ('BYMINUTE', 'byminute'), + ('BYSECOND', 'bysecond'), + ('BYEASTER', 'byeaster')]: + value = original_rule.get(key) + if value: + parts.append(partfmt.format(name=name, vals=(','.join(str(v) + for v in value)))) + + output.append('RRULE:' + ';'.join(parts)) + return '\n'.join(output) + + def replace(self, **kwargs): + """Return new rrule with same attributes except for those attributes given new + values by whichever keyword arguments are specified.""" + new_kwargs = {"interval": self._interval, + "count": self._count, + "dtstart": self._dtstart, + "freq": self._freq, + "until": self._until, + "wkst": self._wkst, + "cache": False if self._cache is None else True } + new_kwargs.update(self._original_rule) + new_kwargs.update(kwargs) + return rrule(**new_kwargs) + + def _iter(self): + year, month, day, hour, minute, second, weekday, yearday, _ = \ + self._dtstart.timetuple() + + # Some local variables to speed things up a bit + freq = self._freq + interval = self._interval + wkst = self._wkst + until = self._until + bymonth = self._bymonth + byweekno = self._byweekno + byyearday = self._byyearday + byweekday = self._byweekday + byeaster = self._byeaster + bymonthday = self._bymonthday + bynmonthday = self._bynmonthday + bysetpos = self._bysetpos + byhour = self._byhour + byminute = self._byminute + bysecond = self._bysecond + + ii = _iterinfo(self) + ii.rebuild(year, month) + + getdayset = {YEARLY: ii.ydayset, + MONTHLY: ii.mdayset, + WEEKLY: ii.wdayset, + DAILY: ii.ddayset, + HOURLY: ii.ddayset, + MINUTELY: ii.ddayset, + SECONDLY: ii.ddayset}[freq] + + if freq < HOURLY: + timeset = self._timeset + else: + gettimeset = {HOURLY: ii.htimeset, + MINUTELY: ii.mtimeset, + SECONDLY: ii.stimeset}[freq] + if ((freq >= HOURLY and + self._byhour and hour not in self._byhour) or + (freq >= MINUTELY and + self._byminute and minute not in self._byminute) or + (freq >= SECONDLY and + self._bysecond and second not in self._bysecond)): + timeset = () + else: + timeset = gettimeset(hour, minute, second) + + total = 0 + count = self._count + while True: + # Get dayset with the right frequency + dayset, start, end = getdayset(year, month, day) + + # Do the "hard" work ;-) + filtered = False + for i in dayset[start:end]: + if ((bymonth and ii.mmask[i] not in bymonth) or + (byweekno and not ii.wnomask[i]) or + (byweekday and ii.wdaymask[i] not in byweekday) or + (ii.nwdaymask and not ii.nwdaymask[i]) or + (byeaster and not ii.eastermask[i]) or + ((bymonthday or bynmonthday) and + ii.mdaymask[i] not in bymonthday and + ii.nmdaymask[i] not in bynmonthday) or + (byyearday and + ((i < ii.yearlen and i+1 not in byyearday and + -ii.yearlen+i not in byyearday) or + (i >= ii.yearlen and i+1-ii.yearlen not in byyearday and + -ii.nextyearlen+i-ii.yearlen not in byyearday)))): + dayset[i] = None + filtered = True + + # Output results + if bysetpos and timeset: + poslist = [] + for pos in bysetpos: + if pos < 0: + daypos, timepos = divmod(pos, len(timeset)) + else: + daypos, timepos = divmod(pos-1, len(timeset)) + try: + i = [x for x in dayset[start:end] + if x is not None][daypos] + time = timeset[timepos] + except IndexError: + pass + else: + date = datetime.date.fromordinal(ii.yearordinal+i) + res = datetime.datetime.combine(date, time) + if res not in poslist: + poslist.append(res) + poslist.sort() + for res in poslist: + if until and res > until: + self._len = total + return + elif res >= self._dtstart: + if count is not None: + count -= 1 + if count < 0: + self._len = total + return + total += 1 + yield res + else: + for i in dayset[start:end]: + if i is not None: + date = datetime.date.fromordinal(ii.yearordinal + i) + for time in timeset: + res = datetime.datetime.combine(date, time) + if until and res > until: + self._len = total + return + elif res >= self._dtstart: + if count is not None: + count -= 1 + if count < 0: + self._len = total + return + + total += 1 + yield res + + # Handle frequency and interval + fixday = False + if freq == YEARLY: + year += interval + if year > datetime.MAXYEAR: + self._len = total + return + ii.rebuild(year, month) + elif freq == MONTHLY: + month += interval + if month > 12: + div, mod = divmod(month, 12) + month = mod + year += div + if month == 0: + month = 12 + year -= 1 + if year > datetime.MAXYEAR: + self._len = total + return + ii.rebuild(year, month) + elif freq == WEEKLY: + if wkst > weekday: + day += -(weekday+1+(6-wkst))+self._interval*7 + else: + day += -(weekday-wkst)+self._interval*7 + weekday = wkst + fixday = True + elif freq == DAILY: + day += interval + fixday = True + elif freq == HOURLY: + if filtered: + # Jump to one iteration before next day + hour += ((23-hour)//interval)*interval + + if byhour: + ndays, hour = self.__mod_distance(value=hour, + byxxx=self._byhour, + base=24) + else: + ndays, hour = divmod(hour+interval, 24) + + if ndays: + day += ndays + fixday = True + + timeset = gettimeset(hour, minute, second) + elif freq == MINUTELY: + if filtered: + # Jump to one iteration before next day + minute += ((1439-(hour*60+minute))//interval)*interval + + valid = False + rep_rate = (24*60) + for j in range(rep_rate // gcd(interval, rep_rate)): + if byminute: + nhours, minute = \ + self.__mod_distance(value=minute, + byxxx=self._byminute, + base=60) + else: + nhours, minute = divmod(minute+interval, 60) + + div, hour = divmod(hour+nhours, 24) + if div: + day += div + fixday = True + filtered = False + + if not byhour or hour in byhour: + valid = True + break + + if not valid: + raise ValueError('Invalid combination of interval and ' + + 'byhour resulting in empty rule.') + + timeset = gettimeset(hour, minute, second) + elif freq == SECONDLY: + if filtered: + # Jump to one iteration before next day + second += (((86399 - (hour * 3600 + minute * 60 + second)) + // interval) * interval) + + rep_rate = (24 * 3600) + valid = False + for j in range(0, rep_rate // gcd(interval, rep_rate)): + if bysecond: + nminutes, second = \ + self.__mod_distance(value=second, + byxxx=self._bysecond, + base=60) + else: + nminutes, second = divmod(second+interval, 60) + + div, minute = divmod(minute+nminutes, 60) + if div: + hour += div + div, hour = divmod(hour, 24) + if div: + day += div + fixday = True + + if ((not byhour or hour in byhour) and + (not byminute or minute in byminute) and + (not bysecond or second in bysecond)): + valid = True + break + + if not valid: + raise ValueError('Invalid combination of interval, ' + + 'byhour and byminute resulting in empty' + + ' rule.') + + timeset = gettimeset(hour, minute, second) + + if fixday and day > 28: + daysinmonth = calendar.monthrange(year, month)[1] + if day > daysinmonth: + while day > daysinmonth: + day -= daysinmonth + month += 1 + if month == 13: + month = 1 + year += 1 + if year > datetime.MAXYEAR: + self._len = total + return + daysinmonth = calendar.monthrange(year, month)[1] + ii.rebuild(year, month) + + def __construct_byset(self, start, byxxx, base): + """ + If a `BYXXX` sequence is passed to the constructor at the same level as + `FREQ` (e.g. `FREQ=HOURLY,BYHOUR={2,4,7},INTERVAL=3`), there are some + specifications which cannot be reached given some starting conditions. + + This occurs whenever the interval is not coprime with the base of a + given unit and the difference between the starting position and the + ending position is not coprime with the greatest common denominator + between the interval and the base. For example, with a FREQ of hourly + starting at 17:00 and an interval of 4, the only valid values for + BYHOUR would be {21, 1, 5, 9, 13, 17}, because 4 and 24 are not + coprime. + + :param start: + Specifies the starting position. + :param byxxx: + An iterable containing the list of allowed values. + :param base: + The largest allowable value for the specified frequency (e.g. + 24 hours, 60 minutes). + + This does not preserve the type of the iterable, returning a set, since + the values should be unique and the order is irrelevant, this will + speed up later lookups. + + In the event of an empty set, raises a :exception:`ValueError`, as this + results in an empty rrule. + """ + + cset = set() + + # Support a single byxxx value. + if isinstance(byxxx, integer_types): + byxxx = (byxxx, ) + + for num in byxxx: + i_gcd = gcd(self._interval, base) + # Use divmod rather than % because we need to wrap negative nums. + if i_gcd == 1 or divmod(num - start, i_gcd)[1] == 0: + cset.add(num) + + if len(cset) == 0: + raise ValueError("Invalid rrule byxxx generates an empty set.") + + return cset + + def __mod_distance(self, value, byxxx, base): + """ + Calculates the next value in a sequence where the `FREQ` parameter is + specified along with a `BYXXX` parameter at the same "level" + (e.g. `HOURLY` specified with `BYHOUR`). + + :param value: + The old value of the component. + :param byxxx: + The `BYXXX` set, which should have been generated by + `rrule._construct_byset`, or something else which checks that a + valid rule is present. + :param base: + The largest allowable value for the specified frequency (e.g. + 24 hours, 60 minutes). + + If a valid value is not found after `base` iterations (the maximum + number before the sequence would start to repeat), this raises a + :exception:`ValueError`, as no valid values were found. + + This returns a tuple of `divmod(n*interval, base)`, where `n` is the + smallest number of `interval` repetitions until the next specified + value in `byxxx` is found. + """ + accumulator = 0 + for ii in range(1, base + 1): + # Using divmod() over % to account for negative intervals + div, value = divmod(value + self._interval, base) + accumulator += div + if value in byxxx: + return (accumulator, value) + + +class _iterinfo(object): + __slots__ = ["rrule", "lastyear", "lastmonth", + "yearlen", "nextyearlen", "yearordinal", "yearweekday", + "mmask", "mrange", "mdaymask", "nmdaymask", + "wdaymask", "wnomask", "nwdaymask", "eastermask"] + + def __init__(self, rrule): + for attr in self.__slots__: + setattr(self, attr, None) + self.rrule = rrule + + def rebuild(self, year, month): + # Every mask is 7 days longer to handle cross-year weekly periods. + rr = self.rrule + if year != self.lastyear: + self.yearlen = 365 + calendar.isleap(year) + self.nextyearlen = 365 + calendar.isleap(year + 1) + firstyday = datetime.date(year, 1, 1) + self.yearordinal = firstyday.toordinal() + self.yearweekday = firstyday.weekday() + + wday = datetime.date(year, 1, 1).weekday() + if self.yearlen == 365: + self.mmask = M365MASK + self.mdaymask = MDAY365MASK + self.nmdaymask = NMDAY365MASK + self.wdaymask = WDAYMASK[wday:] + self.mrange = M365RANGE + else: + self.mmask = M366MASK + self.mdaymask = MDAY366MASK + self.nmdaymask = NMDAY366MASK + self.wdaymask = WDAYMASK[wday:] + self.mrange = M366RANGE + + if not rr._byweekno: + self.wnomask = None + else: + self.wnomask = [0]*(self.yearlen+7) + # no1wkst = firstwkst = self.wdaymask.index(rr._wkst) + no1wkst = firstwkst = (7-self.yearweekday+rr._wkst) % 7 + if no1wkst >= 4: + no1wkst = 0 + # Number of days in the year, plus the days we got + # from last year. + wyearlen = self.yearlen+(self.yearweekday-rr._wkst) % 7 + else: + # Number of days in the year, minus the days we + # left in last year. + wyearlen = self.yearlen-no1wkst + div, mod = divmod(wyearlen, 7) + numweeks = div+mod//4 + for n in rr._byweekno: + if n < 0: + n += numweeks+1 + if not (0 < n <= numweeks): + continue + if n > 1: + i = no1wkst+(n-1)*7 + if no1wkst != firstwkst: + i -= 7-firstwkst + else: + i = no1wkst + for j in range(7): + self.wnomask[i] = 1 + i += 1 + if self.wdaymask[i] == rr._wkst: + break + if 1 in rr._byweekno: + # Check week number 1 of next year as well + # TODO: Check -numweeks for next year. + i = no1wkst+numweeks*7 + if no1wkst != firstwkst: + i -= 7-firstwkst + if i < self.yearlen: + # If week starts in next year, we + # don't care about it. + for j in range(7): + self.wnomask[i] = 1 + i += 1 + if self.wdaymask[i] == rr._wkst: + break + if no1wkst: + # Check last week number of last year as + # well. If no1wkst is 0, either the year + # started on week start, or week number 1 + # got days from last year, so there are no + # days from last year's last week number in + # this year. + if -1 not in rr._byweekno: + lyearweekday = datetime.date(year-1, 1, 1).weekday() + lno1wkst = (7-lyearweekday+rr._wkst) % 7 + lyearlen = 365+calendar.isleap(year-1) + if lno1wkst >= 4: + lno1wkst = 0 + lnumweeks = 52+(lyearlen + + (lyearweekday-rr._wkst) % 7) % 7//4 + else: + lnumweeks = 52+(self.yearlen-no1wkst) % 7//4 + else: + lnumweeks = -1 + if lnumweeks in rr._byweekno: + for i in range(no1wkst): + self.wnomask[i] = 1 + + if (rr._bynweekday and (month != self.lastmonth or + year != self.lastyear)): + ranges = [] + if rr._freq == YEARLY: + if rr._bymonth: + for month in rr._bymonth: + ranges.append(self.mrange[month-1:month+1]) + else: + ranges = [(0, self.yearlen)] + elif rr._freq == MONTHLY: + ranges = [self.mrange[month-1:month+1]] + if ranges: + # Weekly frequency won't get here, so we may not + # care about cross-year weekly periods. + self.nwdaymask = [0]*self.yearlen + for first, last in ranges: + last -= 1 + for wday, n in rr._bynweekday: + if n < 0: + i = last+(n+1)*7 + i -= (self.wdaymask[i]-wday) % 7 + else: + i = first+(n-1)*7 + i += (7-self.wdaymask[i]+wday) % 7 + if first <= i <= last: + self.nwdaymask[i] = 1 + + if rr._byeaster: + self.eastermask = [0]*(self.yearlen+7) + eyday = easter.easter(year).toordinal()-self.yearordinal + for offset in rr._byeaster: + self.eastermask[eyday+offset] = 1 + + self.lastyear = year + self.lastmonth = month + + def ydayset(self, year, month, day): + return list(range(self.yearlen)), 0, self.yearlen + + def mdayset(self, year, month, day): + dset = [None]*self.yearlen + start, end = self.mrange[month-1:month+1] + for i in range(start, end): + dset[i] = i + return dset, start, end + + def wdayset(self, year, month, day): + # We need to handle cross-year weeks here. + dset = [None]*(self.yearlen+7) + i = datetime.date(year, month, day).toordinal()-self.yearordinal + start = i + for j in range(7): + dset[i] = i + i += 1 + # if (not (0 <= i < self.yearlen) or + # self.wdaymask[i] == self.rrule._wkst): + # This will cross the year boundary, if necessary. + if self.wdaymask[i] == self.rrule._wkst: + break + return dset, start, i + + def ddayset(self, year, month, day): + dset = [None] * self.yearlen + i = datetime.date(year, month, day).toordinal() - self.yearordinal + dset[i] = i + return dset, i, i + 1 + + def htimeset(self, hour, minute, second): + tset = [] + rr = self.rrule + for minute in rr._byminute: + for second in rr._bysecond: + tset.append(datetime.time(hour, minute, second, + tzinfo=rr._tzinfo)) + tset.sort() + return tset + + def mtimeset(self, hour, minute, second): + tset = [] + rr = self.rrule + for second in rr._bysecond: + tset.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) + tset.sort() + return tset + + def stimeset(self, hour, minute, second): + return (datetime.time(hour, minute, second, + tzinfo=self.rrule._tzinfo),) + + +class rruleset(rrulebase): + """ The rruleset type allows more complex recurrence setups, mixing + multiple rules, dates, exclusion rules, and exclusion dates. The type + constructor takes the following keyword arguments: + + :param cache: If True, caching of results will be enabled, improving + performance of multiple queries considerably. """ + + class _genitem(object): + def __init__(self, genlist, gen): + try: + self.dt = advance_iterator(gen) + genlist.append(self) + except StopIteration: + pass + self.genlist = genlist + self.gen = gen + + def __next__(self): + try: + self.dt = advance_iterator(self.gen) + except StopIteration: + if self.genlist[0] is self: + heapq.heappop(self.genlist) + else: + self.genlist.remove(self) + heapq.heapify(self.genlist) + + next = __next__ + + def __lt__(self, other): + return self.dt < other.dt + + def __gt__(self, other): + return self.dt > other.dt + + def __eq__(self, other): + return self.dt == other.dt + + def __ne__(self, other): + return self.dt != other.dt + + def __init__(self, cache=False): + super(rruleset, self).__init__(cache) + self._rrule = [] + self._rdate = [] + self._exrule = [] + self._exdate = [] + + @_invalidates_cache + def rrule(self, rrule): + """ Include the given :py:class:`rrule` instance in the recurrence set + generation. """ + self._rrule.append(rrule) + + @_invalidates_cache + def rdate(self, rdate): + """ Include the given :py:class:`datetime` instance in the recurrence + set generation. """ + self._rdate.append(rdate) + + @_invalidates_cache + def exrule(self, exrule): + """ Include the given rrule instance in the recurrence set exclusion + list. Dates which are part of the given recurrence rules will not + be generated, even if some inclusive rrule or rdate matches them. + """ + self._exrule.append(exrule) + + @_invalidates_cache + def exdate(self, exdate): + """ Include the given datetime instance in the recurrence set + exclusion list. Dates included that way will not be generated, + even if some inclusive rrule or rdate matches them. """ + self._exdate.append(exdate) + + def _iter(self): + rlist = [] + self._rdate.sort() + self._genitem(rlist, iter(self._rdate)) + for gen in [iter(x) for x in self._rrule]: + self._genitem(rlist, gen) + exlist = [] + self._exdate.sort() + self._genitem(exlist, iter(self._exdate)) + for gen in [iter(x) for x in self._exrule]: + self._genitem(exlist, gen) + lastdt = None + total = 0 + heapq.heapify(rlist) + heapq.heapify(exlist) + while rlist: + ritem = rlist[0] + if not lastdt or lastdt != ritem.dt: + while exlist and exlist[0] < ritem: + exitem = exlist[0] + advance_iterator(exitem) + if exlist and exlist[0] is exitem: + heapq.heapreplace(exlist, exitem) + if not exlist or ritem != exlist[0]: + total += 1 + yield ritem.dt + lastdt = ritem.dt + advance_iterator(ritem) + if rlist and rlist[0] is ritem: + heapq.heapreplace(rlist, ritem) + self._len = total + + + + +class _rrulestr(object): + """ Parses a string representation of a recurrence rule or set of + recurrence rules. + + :param s: + Required, a string defining one or more recurrence rules. + + :param dtstart: + If given, used as the default recurrence start if not specified in the + rule string. + + :param cache: + If set ``True`` caching of results will be enabled, improving + performance of multiple queries considerably. + + :param unfold: + If set ``True`` indicates that a rule string is split over more + than one line and should be joined before processing. + + :param forceset: + If set ``True`` forces a :class:`dateutil.rrule.rruleset` to + be returned. + + :param compatible: + If set ``True`` forces ``unfold`` and ``forceset`` to be ``True``. + + :param ignoretz: + If set ``True``, time zones in parsed strings are ignored and a naive + :class:`datetime.datetime` object is returned. + + :param tzids: + If given, a callable or mapping used to retrieve a + :class:`datetime.tzinfo` from a string representation. + Defaults to :func:`dateutil.tz.gettz`. + + :param tzinfos: + Additional time zone names / aliases which may be present in a string + representation. See :func:`dateutil.parser.parse` for more + information. + + :return: + Returns a :class:`dateutil.rrule.rruleset` or + :class:`dateutil.rrule.rrule` + """ + + _freq_map = {"YEARLY": YEARLY, + "MONTHLY": MONTHLY, + "WEEKLY": WEEKLY, + "DAILY": DAILY, + "HOURLY": HOURLY, + "MINUTELY": MINUTELY, + "SECONDLY": SECONDLY} + + _weekday_map = {"MO": 0, "TU": 1, "WE": 2, "TH": 3, + "FR": 4, "SA": 5, "SU": 6} + + def _handle_int(self, rrkwargs, name, value, **kwargs): + rrkwargs[name.lower()] = int(value) + + def _handle_int_list(self, rrkwargs, name, value, **kwargs): + rrkwargs[name.lower()] = [int(x) for x in value.split(',')] + + _handle_INTERVAL = _handle_int + _handle_COUNT = _handle_int + _handle_BYSETPOS = _handle_int_list + _handle_BYMONTH = _handle_int_list + _handle_BYMONTHDAY = _handle_int_list + _handle_BYYEARDAY = _handle_int_list + _handle_BYEASTER = _handle_int_list + _handle_BYWEEKNO = _handle_int_list + _handle_BYHOUR = _handle_int_list + _handle_BYMINUTE = _handle_int_list + _handle_BYSECOND = _handle_int_list + + def _handle_FREQ(self, rrkwargs, name, value, **kwargs): + rrkwargs["freq"] = self._freq_map[value] + + def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): + global parser + if not parser: + from dateutil import parser + try: + rrkwargs["until"] = parser.parse(value, + ignoretz=kwargs.get("ignoretz"), + tzinfos=kwargs.get("tzinfos")) + except ValueError: + raise ValueError("invalid until date") + + def _handle_WKST(self, rrkwargs, name, value, **kwargs): + rrkwargs["wkst"] = self._weekday_map[value] + + def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwargs): + """ + Two ways to specify this: +1MO or MO(+1) + """ + l = [] + for wday in value.split(','): + if '(' in wday: + # If it's of the form TH(+1), etc. + splt = wday.split('(') + w = splt[0] + n = int(splt[1][:-1]) + elif len(wday): + # If it's of the form +1MO + for i in range(len(wday)): + if wday[i] not in '+-0123456789': + break + n = wday[:i] or None + w = wday[i:] + if n: + n = int(n) + else: + raise ValueError("Invalid (empty) BYDAY specification.") + + l.append(weekdays[self._weekday_map[w]](n)) + rrkwargs["byweekday"] = l + + _handle_BYDAY = _handle_BYWEEKDAY + + def _parse_rfc_rrule(self, line, + dtstart=None, + cache=False, + ignoretz=False, + tzinfos=None): + if line.find(':') != -1: + name, value = line.split(':') + if name != "RRULE": + raise ValueError("unknown parameter name") + else: + value = line + rrkwargs = {} + for pair in value.split(';'): + name, value = pair.split('=') + name = name.upper() + value = value.upper() + try: + getattr(self, "_handle_"+name)(rrkwargs, name, value, + ignoretz=ignoretz, + tzinfos=tzinfos) + except AttributeError: + raise ValueError("unknown parameter '%s'" % name) + except (KeyError, ValueError): + raise ValueError("invalid '%s': %s" % (name, value)) + return rrule(dtstart=dtstart, cache=cache, **rrkwargs) + + def _parse_date_value(self, date_value, parms, rule_tzids, + ignoretz, tzids, tzinfos): + global parser + if not parser: + from dateutil import parser + + datevals = [] + value_found = False + TZID = None + + for parm in parms: + if parm.startswith("TZID="): + try: + tzkey = rule_tzids[parm.split('TZID=')[-1]] + except KeyError: + continue + if tzids is None: + from . import tz + tzlookup = tz.gettz + elif callable(tzids): + tzlookup = tzids + else: + tzlookup = getattr(tzids, 'get', None) + if tzlookup is None: + msg = ('tzids must be a callable, mapping, or None, ' + 'not %s' % tzids) + raise ValueError(msg) + + TZID = tzlookup(tzkey) + continue + + # RFC 5445 3.8.2.4: The VALUE parameter is optional, but may be found + # only once. + if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}: + raise ValueError("unsupported parm: " + parm) + else: + if value_found: + msg = ("Duplicate value parameter found in: " + parm) + raise ValueError(msg) + value_found = True + + for datestr in date_value.split(','): + date = parser.parse(datestr, ignoretz=ignoretz, tzinfos=tzinfos) + if TZID is not None: + if date.tzinfo is None: + date = date.replace(tzinfo=TZID) + else: + raise ValueError('DTSTART/EXDATE specifies multiple timezone') + datevals.append(date) + + return datevals + + def _parse_rfc(self, s, + dtstart=None, + cache=False, + unfold=False, + forceset=False, + compatible=False, + ignoretz=False, + tzids=None, + tzinfos=None): + global parser + if compatible: + forceset = True + unfold = True + + TZID_NAMES = dict(map( + lambda x: (x.upper(), x), + re.findall('TZID=(?P[^:]+):', s) + )) + s = s.upper() + if not s.strip(): + raise ValueError("empty string") + if unfold: + lines = s.splitlines() + i = 0 + while i < len(lines): + line = lines[i].rstrip() + if not line: + del lines[i] + elif i > 0 and line[0] == " ": + lines[i-1] += line[1:] + del lines[i] + else: + i += 1 + else: + lines = s.split() + if (not forceset and len(lines) == 1 and (s.find(':') == -1 or + s.startswith('RRULE:'))): + return self._parse_rfc_rrule(lines[0], cache=cache, + dtstart=dtstart, ignoretz=ignoretz, + tzinfos=tzinfos) + else: + rrulevals = [] + rdatevals = [] + exrulevals = [] + exdatevals = [] + for line in lines: + if not line: + continue + if line.find(':') == -1: + name = "RRULE" + value = line + else: + name, value = line.split(':', 1) + parms = name.split(';') + if not parms: + raise ValueError("empty property name") + name = parms[0] + parms = parms[1:] + if name == "RRULE": + for parm in parms: + raise ValueError("unsupported RRULE parm: "+parm) + rrulevals.append(value) + elif name == "RDATE": + for parm in parms: + if parm != "VALUE=DATE-TIME": + raise ValueError("unsupported RDATE parm: "+parm) + rdatevals.append(value) + elif name == "EXRULE": + for parm in parms: + raise ValueError("unsupported EXRULE parm: "+parm) + exrulevals.append(value) + elif name == "EXDATE": + exdatevals.extend( + self._parse_date_value(value, parms, + TZID_NAMES, ignoretz, + tzids, tzinfos) + ) + elif name == "DTSTART": + dtvals = self._parse_date_value(value, parms, TZID_NAMES, + ignoretz, tzids, tzinfos) + if len(dtvals) != 1: + raise ValueError("Multiple DTSTART values specified:" + + value) + dtstart = dtvals[0] + else: + raise ValueError("unsupported property: "+name) + if (forceset or len(rrulevals) > 1 or rdatevals + or exrulevals or exdatevals): + if not parser and (rdatevals or exdatevals): + from dateutil import parser + rset = rruleset(cache=cache) + for value in rrulevals: + rset.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in rdatevals: + for datestr in value.split(','): + rset.rdate(parser.parse(datestr, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in exrulevals: + rset.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, + ignoretz=ignoretz, + tzinfos=tzinfos)) + for value in exdatevals: + rset.exdate(value) + if compatible and dtstart: + rset.rdate(dtstart) + return rset + else: + return self._parse_rfc_rrule(rrulevals[0], + dtstart=dtstart, + cache=cache, + ignoretz=ignoretz, + tzinfos=tzinfos) + + def __call__(self, s, **kwargs): + return self._parse_rfc(s, **kwargs) + + +rrulestr = _rrulestr() + +# vim:ts=4:sw=4:et diff --git a/env/lib/python3.8/site-packages/dateutil/tz/__init__.py b/env/lib/python3.8/site-packages/dateutil/tz/__init__.py new file mode 100644 index 000000000..af1352c47 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tz/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +from .tz import * +from .tz import __doc__ + +__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", + "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz", + "enfold", "datetime_ambiguous", "datetime_exists", + "resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"] + + +class DeprecatedTzFormatWarning(Warning): + """Warning raised when time zones are parsed from deprecated formats.""" diff --git a/env/lib/python3.8/site-packages/dateutil/tz/_common.py b/env/lib/python3.8/site-packages/dateutil/tz/_common.py new file mode 100644 index 000000000..e6ac11831 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tz/_common.py @@ -0,0 +1,419 @@ +from six import PY2 + +from functools import wraps + +from datetime import datetime, timedelta, tzinfo + + +ZERO = timedelta(0) + +__all__ = ['tzname_in_python2', 'enfold'] + + +def tzname_in_python2(namefunc): + """Change unicode output into bytestrings in Python 2 + + tzname() API changed in Python 3. It used to return bytes, but was changed + to unicode strings + """ + if PY2: + @wraps(namefunc) + def adjust_encoding(*args, **kwargs): + name = namefunc(*args, **kwargs) + if name is not None: + name = name.encode() + + return name + + return adjust_encoding + else: + return namefunc + + +# The following is adapted from Alexander Belopolsky's tz library +# https://github.com/abalkin/tz +if hasattr(datetime, 'fold'): + # This is the pre-python 3.6 fold situation + def enfold(dt, fold=1): + """ + Provides a unified interface for assigning the ``fold`` attribute to + datetimes both before and after the implementation of PEP-495. + + :param fold: + The value for the ``fold`` attribute in the returned datetime. This + should be either 0 or 1. + + :return: + Returns an object for which ``getattr(dt, 'fold', 0)`` returns + ``fold`` for all versions of Python. In versions prior to + Python 3.6, this is a ``_DatetimeWithFold`` object, which is a + subclass of :py:class:`datetime.datetime` with the ``fold`` + attribute added, if ``fold`` is 1. + + .. versionadded:: 2.6.0 + """ + return dt.replace(fold=fold) + +else: + class _DatetimeWithFold(datetime): + """ + This is a class designed to provide a PEP 495-compliant interface for + Python versions before 3.6. It is used only for dates in a fold, so + the ``fold`` attribute is fixed at ``1``. + + .. versionadded:: 2.6.0 + """ + __slots__ = () + + def replace(self, *args, **kwargs): + """ + Return a datetime with the same attributes, except for those + attributes given new values by whichever keyword arguments are + specified. Note that tzinfo=None can be specified to create a naive + datetime from an aware datetime with no conversion of date and time + data. + + This is reimplemented in ``_DatetimeWithFold`` because pypy3 will + return a ``datetime.datetime`` even if ``fold`` is unchanged. + """ + argnames = ( + 'year', 'month', 'day', 'hour', 'minute', 'second', + 'microsecond', 'tzinfo' + ) + + for arg, argname in zip(args, argnames): + if argname in kwargs: + raise TypeError('Duplicate argument: {}'.format(argname)) + + kwargs[argname] = arg + + for argname in argnames: + if argname not in kwargs: + kwargs[argname] = getattr(self, argname) + + dt_class = self.__class__ if kwargs.get('fold', 1) else datetime + + return dt_class(**kwargs) + + @property + def fold(self): + return 1 + + def enfold(dt, fold=1): + """ + Provides a unified interface for assigning the ``fold`` attribute to + datetimes both before and after the implementation of PEP-495. + + :param fold: + The value for the ``fold`` attribute in the returned datetime. This + should be either 0 or 1. + + :return: + Returns an object for which ``getattr(dt, 'fold', 0)`` returns + ``fold`` for all versions of Python. In versions prior to + Python 3.6, this is a ``_DatetimeWithFold`` object, which is a + subclass of :py:class:`datetime.datetime` with the ``fold`` + attribute added, if ``fold`` is 1. + + .. versionadded:: 2.6.0 + """ + if getattr(dt, 'fold', 0) == fold: + return dt + + args = dt.timetuple()[:6] + args += (dt.microsecond, dt.tzinfo) + + if fold: + return _DatetimeWithFold(*args) + else: + return datetime(*args) + + +def _validate_fromutc_inputs(f): + """ + The CPython version of ``fromutc`` checks that the input is a ``datetime`` + object and that ``self`` is attached as its ``tzinfo``. + """ + @wraps(f) + def fromutc(self, dt): + if not isinstance(dt, datetime): + raise TypeError("fromutc() requires a datetime argument") + if dt.tzinfo is not self: + raise ValueError("dt.tzinfo is not self") + + return f(self, dt) + + return fromutc + + +class _tzinfo(tzinfo): + """ + Base class for all ``dateutil`` ``tzinfo`` objects. + """ + + def is_ambiguous(self, dt): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + + + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + + dt = dt.replace(tzinfo=self) + + wall_0 = enfold(dt, fold=0) + wall_1 = enfold(dt, fold=1) + + same_offset = wall_0.utcoffset() == wall_1.utcoffset() + same_dt = wall_0.replace(tzinfo=None) == wall_1.replace(tzinfo=None) + + return same_dt and not same_offset + + def _fold_status(self, dt_utc, dt_wall): + """ + Determine the fold status of a "wall" datetime, given a representation + of the same datetime as a (naive) UTC datetime. This is calculated based + on the assumption that ``dt.utcoffset() - dt.dst()`` is constant for all + datetimes, and that this offset is the actual number of hours separating + ``dt_utc`` and ``dt_wall``. + + :param dt_utc: + Representation of the datetime as UTC + + :param dt_wall: + Representation of the datetime as "wall time". This parameter must + either have a `fold` attribute or have a fold-naive + :class:`datetime.tzinfo` attached, otherwise the calculation may + fail. + """ + if self.is_ambiguous(dt_wall): + delta_wall = dt_wall - dt_utc + _fold = int(delta_wall == (dt_utc.utcoffset() - dt_utc.dst())) + else: + _fold = 0 + + return _fold + + def _fold(self, dt): + return getattr(dt, 'fold', 0) + + def _fromutc(self, dt): + """ + Given a timezone-aware datetime in a given timezone, calculates a + timezone-aware datetime in a new timezone. + + Since this is the one time that we *know* we have an unambiguous + datetime object, we take this opportunity to determine whether the + datetime is ambiguous and in a "fold" state (e.g. if it's the first + occurrence, chronologically, of the ambiguous datetime). + + :param dt: + A timezone-aware :class:`datetime.datetime` object. + """ + + # Re-implement the algorithm from Python's datetime.py + dtoff = dt.utcoffset() + if dtoff is None: + raise ValueError("fromutc() requires a non-None utcoffset() " + "result") + + # The original datetime.py code assumes that `dst()` defaults to + # zero during ambiguous times. PEP 495 inverts this presumption, so + # for pre-PEP 495 versions of python, we need to tweak the algorithm. + dtdst = dt.dst() + if dtdst is None: + raise ValueError("fromutc() requires a non-None dst() result") + delta = dtoff - dtdst + + dt += delta + # Set fold=1 so we can default to being in the fold for + # ambiguous dates. + dtdst = enfold(dt, fold=1).dst() + if dtdst is None: + raise ValueError("fromutc(): dt.dst gave inconsistent " + "results; cannot convert") + return dt + dtdst + + @_validate_fromutc_inputs + def fromutc(self, dt): + """ + Given a timezone-aware datetime in a given timezone, calculates a + timezone-aware datetime in a new timezone. + + Since this is the one time that we *know* we have an unambiguous + datetime object, we take this opportunity to determine whether the + datetime is ambiguous and in a "fold" state (e.g. if it's the first + occurrence, chronologically, of the ambiguous datetime). + + :param dt: + A timezone-aware :class:`datetime.datetime` object. + """ + dt_wall = self._fromutc(dt) + + # Calculate the fold status given the two datetimes. + _fold = self._fold_status(dt, dt_wall) + + # Set the default fold value for ambiguous dates + return enfold(dt_wall, fold=_fold) + + +class tzrangebase(_tzinfo): + """ + This is an abstract base class for time zones represented by an annual + transition into and out of DST. Child classes should implement the following + methods: + + * ``__init__(self, *args, **kwargs)`` + * ``transitions(self, year)`` - this is expected to return a tuple of + datetimes representing the DST on and off transitions in standard + time. + + A fully initialized ``tzrangebase`` subclass should also provide the + following attributes: + * ``hasdst``: Boolean whether or not the zone uses DST. + * ``_dst_offset`` / ``_std_offset``: :class:`datetime.timedelta` objects + representing the respective UTC offsets. + * ``_dst_abbr`` / ``_std_abbr``: Strings representing the timezone short + abbreviations in DST and STD, respectively. + * ``_hasdst``: Whether or not the zone has DST. + + .. versionadded:: 2.6.0 + """ + def __init__(self): + raise NotImplementedError('tzrangebase is an abstract base class') + + def utcoffset(self, dt): + isdst = self._isdst(dt) + + if isdst is None: + return None + elif isdst: + return self._dst_offset + else: + return self._std_offset + + def dst(self, dt): + isdst = self._isdst(dt) + + if isdst is None: + return None + elif isdst: + return self._dst_base_offset + else: + return ZERO + + @tzname_in_python2 + def tzname(self, dt): + if self._isdst(dt): + return self._dst_abbr + else: + return self._std_abbr + + def fromutc(self, dt): + """ Given a datetime in UTC, return local time """ + if not isinstance(dt, datetime): + raise TypeError("fromutc() requires a datetime argument") + + if dt.tzinfo is not self: + raise ValueError("dt.tzinfo is not self") + + # Get transitions - if there are none, fixed offset + transitions = self.transitions(dt.year) + if transitions is None: + return dt + self.utcoffset(dt) + + # Get the transition times in UTC + dston, dstoff = transitions + + dston -= self._std_offset + dstoff -= self._std_offset + + utc_transitions = (dston, dstoff) + dt_utc = dt.replace(tzinfo=None) + + isdst = self._naive_isdst(dt_utc, utc_transitions) + + if isdst: + dt_wall = dt + self._dst_offset + else: + dt_wall = dt + self._std_offset + + _fold = int(not isdst and self.is_ambiguous(dt_wall)) + + return enfold(dt_wall, fold=_fold) + + def is_ambiguous(self, dt): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + + + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + if not self.hasdst: + return False + + start, end = self.transitions(dt.year) + + dt = dt.replace(tzinfo=None) + return (end <= dt < end + self._dst_base_offset) + + def _isdst(self, dt): + if not self.hasdst: + return False + elif dt is None: + return None + + transitions = self.transitions(dt.year) + + if transitions is None: + return False + + dt = dt.replace(tzinfo=None) + + isdst = self._naive_isdst(dt, transitions) + + # Handle ambiguous dates + if not isdst and self.is_ambiguous(dt): + return not self._fold(dt) + else: + return isdst + + def _naive_isdst(self, dt, transitions): + dston, dstoff = transitions + + dt = dt.replace(tzinfo=None) + + if dston < dstoff: + isdst = dston <= dt < dstoff + else: + isdst = not dstoff <= dt < dston + + return isdst + + @property + def _dst_base_offset(self): + return self._dst_offset - self._std_offset + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return "%s(...)" % self.__class__.__name__ + + __reduce__ = object.__reduce__ diff --git a/env/lib/python3.8/site-packages/dateutil/tz/_factories.py b/env/lib/python3.8/site-packages/dateutil/tz/_factories.py new file mode 100644 index 000000000..f8a65891a --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tz/_factories.py @@ -0,0 +1,80 @@ +from datetime import timedelta +import weakref +from collections import OrderedDict + +from six.moves import _thread + + +class _TzSingleton(type): + def __init__(cls, *args, **kwargs): + cls.__instance = None + super(_TzSingleton, cls).__init__(*args, **kwargs) + + def __call__(cls): + if cls.__instance is None: + cls.__instance = super(_TzSingleton, cls).__call__() + return cls.__instance + + +class _TzFactory(type): + def instance(cls, *args, **kwargs): + """Alternate constructor that returns a fresh instance""" + return type.__call__(cls, *args, **kwargs) + + +class _TzOffsetFactory(_TzFactory): + def __init__(cls, *args, **kwargs): + cls.__instances = weakref.WeakValueDictionary() + cls.__strong_cache = OrderedDict() + cls.__strong_cache_size = 8 + + cls._cache_lock = _thread.allocate_lock() + + def __call__(cls, name, offset): + if isinstance(offset, timedelta): + key = (name, offset.total_seconds()) + else: + key = (name, offset) + + instance = cls.__instances.get(key, None) + if instance is None: + instance = cls.__instances.setdefault(key, + cls.instance(name, offset)) + + # This lock may not be necessary in Python 3. See GH issue #901 + with cls._cache_lock: + cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance) + + # Remove an item if the strong cache is overpopulated + if len(cls.__strong_cache) > cls.__strong_cache_size: + cls.__strong_cache.popitem(last=False) + + return instance + + +class _TzStrFactory(_TzFactory): + def __init__(cls, *args, **kwargs): + cls.__instances = weakref.WeakValueDictionary() + cls.__strong_cache = OrderedDict() + cls.__strong_cache_size = 8 + + cls.__cache_lock = _thread.allocate_lock() + + def __call__(cls, s, posix_offset=False): + key = (s, posix_offset) + instance = cls.__instances.get(key, None) + + if instance is None: + instance = cls.__instances.setdefault(key, + cls.instance(s, posix_offset)) + + # This lock may not be necessary in Python 3. See GH issue #901 + with cls.__cache_lock: + cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance) + + # Remove an item if the strong cache is overpopulated + if len(cls.__strong_cache) > cls.__strong_cache_size: + cls.__strong_cache.popitem(last=False) + + return instance + diff --git a/env/lib/python3.8/site-packages/dateutil/tz/tz.py b/env/lib/python3.8/site-packages/dateutil/tz/tz.py new file mode 100644 index 000000000..af81e88e1 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tz/tz.py @@ -0,0 +1,1849 @@ +# -*- coding: utf-8 -*- +""" +This module offers timezone implementations subclassing the abstract +:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format +files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`, +etc), TZ environment string (in all known formats), given ranges (with help +from relative deltas), local machine timezone, fixed offset timezone, and UTC +timezone. +""" +import datetime +import struct +import time +import sys +import os +import bisect +import weakref +from collections import OrderedDict + +import six +from six import string_types +from six.moves import _thread +from ._common import tzname_in_python2, _tzinfo +from ._common import tzrangebase, enfold +from ._common import _validate_fromutc_inputs + +from ._factories import _TzSingleton, _TzOffsetFactory +from ._factories import _TzStrFactory +try: + from .win import tzwin, tzwinlocal +except ImportError: + tzwin = tzwinlocal = None + +# For warning about rounding tzinfo +from warnings import warn + +ZERO = datetime.timedelta(0) +EPOCH = datetime.datetime.utcfromtimestamp(0) +EPOCHORDINAL = EPOCH.toordinal() + + +@six.add_metaclass(_TzSingleton) +class tzutc(datetime.tzinfo): + """ + This is a tzinfo object that represents the UTC time zone. + + **Examples:** + + .. doctest:: + + >>> from datetime import * + >>> from dateutil.tz import * + + >>> datetime.now() + datetime.datetime(2003, 9, 27, 9, 40, 1, 521290) + + >>> datetime.now(tzutc()) + datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc()) + + >>> datetime.now(tzutc()).tzname() + 'UTC' + + .. versionchanged:: 2.7.0 + ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will + always return the same object. + + .. doctest:: + + >>> from dateutil.tz import tzutc, UTC + >>> tzutc() is tzutc() + True + >>> tzutc() is UTC + True + """ + def utcoffset(self, dt): + return ZERO + + def dst(self, dt): + return ZERO + + @tzname_in_python2 + def tzname(self, dt): + return "UTC" + + def is_ambiguous(self, dt): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + + + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + return False + + @_validate_fromutc_inputs + def fromutc(self, dt): + """ + Fast track version of fromutc() returns the original ``dt`` object for + any valid :py:class:`datetime.datetime` object. + """ + return dt + + def __eq__(self, other): + if not isinstance(other, (tzutc, tzoffset)): + return NotImplemented + + return (isinstance(other, tzutc) or + (isinstance(other, tzoffset) and other._offset == ZERO)) + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return "%s()" % self.__class__.__name__ + + __reduce__ = object.__reduce__ + + +#: Convenience constant providing a :class:`tzutc()` instance +#: +#: .. versionadded:: 2.7.0 +UTC = tzutc() + + +@six.add_metaclass(_TzOffsetFactory) +class tzoffset(datetime.tzinfo): + """ + A simple class for representing a fixed offset from UTC. + + :param name: + The timezone name, to be returned when ``tzname()`` is called. + :param offset: + The time zone offset in seconds, or (since version 2.6.0, represented + as a :py:class:`datetime.timedelta` object). + """ + def __init__(self, name, offset): + self._name = name + + try: + # Allow a timedelta + offset = offset.total_seconds() + except (TypeError, AttributeError): + pass + + self._offset = datetime.timedelta(seconds=_get_supported_offset(offset)) + + def utcoffset(self, dt): + return self._offset + + def dst(self, dt): + return ZERO + + @tzname_in_python2 + def tzname(self, dt): + return self._name + + @_validate_fromutc_inputs + def fromutc(self, dt): + return dt + self._offset + + def is_ambiguous(self, dt): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + return False + + def __eq__(self, other): + if not isinstance(other, tzoffset): + return NotImplemented + + return self._offset == other._offset + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return "%s(%s, %s)" % (self.__class__.__name__, + repr(self._name), + int(self._offset.total_seconds())) + + __reduce__ = object.__reduce__ + + +class tzlocal(_tzinfo): + """ + A :class:`tzinfo` subclass built around the ``time`` timezone functions. + """ + def __init__(self): + super(tzlocal, self).__init__() + + self._std_offset = datetime.timedelta(seconds=-time.timezone) + if time.daylight: + self._dst_offset = datetime.timedelta(seconds=-time.altzone) + else: + self._dst_offset = self._std_offset + + self._dst_saved = self._dst_offset - self._std_offset + self._hasdst = bool(self._dst_saved) + self._tznames = tuple(time.tzname) + + def utcoffset(self, dt): + if dt is None and self._hasdst: + return None + + if self._isdst(dt): + return self._dst_offset + else: + return self._std_offset + + def dst(self, dt): + if dt is None and self._hasdst: + return None + + if self._isdst(dt): + return self._dst_offset - self._std_offset + else: + return ZERO + + @tzname_in_python2 + def tzname(self, dt): + return self._tznames[self._isdst(dt)] + + def is_ambiguous(self, dt): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + + + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + naive_dst = self._naive_is_dst(dt) + return (not naive_dst and + (naive_dst != self._naive_is_dst(dt - self._dst_saved))) + + def _naive_is_dst(self, dt): + timestamp = _datetime_to_timestamp(dt) + return time.localtime(timestamp + time.timezone).tm_isdst + + def _isdst(self, dt, fold_naive=True): + # We can't use mktime here. It is unstable when deciding if + # the hour near to a change is DST or not. + # + # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, + # dt.minute, dt.second, dt.weekday(), 0, -1)) + # return time.localtime(timestamp).tm_isdst + # + # The code above yields the following result: + # + # >>> import tz, datetime + # >>> t = tz.tzlocal() + # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + # 'BRDT' + # >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() + # 'BRST' + # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + # 'BRST' + # >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() + # 'BRDT' + # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() + # 'BRDT' + # + # Here is a more stable implementation: + # + if not self._hasdst: + return False + + # Check for ambiguous times: + dstval = self._naive_is_dst(dt) + fold = getattr(dt, 'fold', None) + + if self.is_ambiguous(dt): + if fold is not None: + return not self._fold(dt) + else: + return True + + return dstval + + def __eq__(self, other): + if isinstance(other, tzlocal): + return (self._std_offset == other._std_offset and + self._dst_offset == other._dst_offset) + elif isinstance(other, tzutc): + return (not self._hasdst and + self._tznames[0] in {'UTC', 'GMT'} and + self._std_offset == ZERO) + elif isinstance(other, tzoffset): + return (not self._hasdst and + self._tznames[0] == other._name and + self._std_offset == other._offset) + else: + return NotImplemented + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return "%s()" % self.__class__.__name__ + + __reduce__ = object.__reduce__ + + +class _ttinfo(object): + __slots__ = ["offset", "delta", "isdst", "abbr", + "isstd", "isgmt", "dstoffset"] + + def __init__(self): + for attr in self.__slots__: + setattr(self, attr, None) + + def __repr__(self): + l = [] + for attr in self.__slots__: + value = getattr(self, attr) + if value is not None: + l.append("%s=%s" % (attr, repr(value))) + return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) + + def __eq__(self, other): + if not isinstance(other, _ttinfo): + return NotImplemented + + return (self.offset == other.offset and + self.delta == other.delta and + self.isdst == other.isdst and + self.abbr == other.abbr and + self.isstd == other.isstd and + self.isgmt == other.isgmt and + self.dstoffset == other.dstoffset) + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __getstate__(self): + state = {} + for name in self.__slots__: + state[name] = getattr(self, name, None) + return state + + def __setstate__(self, state): + for name in self.__slots__: + if name in state: + setattr(self, name, state[name]) + + +class _tzfile(object): + """ + Lightweight class for holding the relevant transition and time zone + information read from binary tzfiles. + """ + attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list', + 'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first'] + + def __init__(self, **kwargs): + for attr in self.attrs: + setattr(self, attr, kwargs.get(attr, None)) + + +class tzfile(_tzinfo): + """ + This is a ``tzinfo`` subclass that allows one to use the ``tzfile(5)`` + format timezone files to extract current and historical zone information. + + :param fileobj: + This can be an opened file stream or a file name that the time zone + information can be read from. + + :param filename: + This is an optional parameter specifying the source of the time zone + information in the event that ``fileobj`` is a file object. If omitted + and ``fileobj`` is a file stream, this parameter will be set either to + ``fileobj``'s ``name`` attribute or to ``repr(fileobj)``. + + See `Sources for Time Zone and Daylight Saving Time Data + `_ for more information. + Time zone files can be compiled from the `IANA Time Zone database files + `_ with the `zic time zone compiler + `_ + + .. note:: + + Only construct a ``tzfile`` directly if you have a specific timezone + file on disk that you want to read into a Python ``tzinfo`` object. + If you want to get a ``tzfile`` representing a specific IANA zone, + (e.g. ``'America/New_York'``), you should call + :func:`dateutil.tz.gettz` with the zone identifier. + + + **Examples:** + + Using the US Eastern time zone as an example, we can see that a ``tzfile`` + provides time zone information for the standard Daylight Saving offsets: + + .. testsetup:: tzfile + + from dateutil.tz import gettz + from datetime import datetime + + .. doctest:: tzfile + + >>> NYC = gettz('America/New_York') + >>> NYC + tzfile('/usr/share/zoneinfo/America/New_York') + + >>> print(datetime(2016, 1, 3, tzinfo=NYC)) # EST + 2016-01-03 00:00:00-05:00 + + >>> print(datetime(2016, 7, 7, tzinfo=NYC)) # EDT + 2016-07-07 00:00:00-04:00 + + + The ``tzfile`` structure contains a fully history of the time zone, + so historical dates will also have the right offsets. For example, before + the adoption of the UTC standards, New York used local solar mean time: + + .. doctest:: tzfile + + >>> print(datetime(1901, 4, 12, tzinfo=NYC)) # LMT + 1901-04-12 00:00:00-04:56 + + And during World War II, New York was on "Eastern War Time", which was a + state of permanent daylight saving time: + + .. doctest:: tzfile + + >>> print(datetime(1944, 2, 7, tzinfo=NYC)) # EWT + 1944-02-07 00:00:00-04:00 + + """ + + def __init__(self, fileobj, filename=None): + super(tzfile, self).__init__() + + file_opened_here = False + if isinstance(fileobj, string_types): + self._filename = fileobj + fileobj = open(fileobj, 'rb') + file_opened_here = True + elif filename is not None: + self._filename = filename + elif hasattr(fileobj, "name"): + self._filename = fileobj.name + else: + self._filename = repr(fileobj) + + if fileobj is not None: + if not file_opened_here: + fileobj = _nullcontext(fileobj) + + with fileobj as file_stream: + tzobj = self._read_tzfile(file_stream) + + self._set_tzdata(tzobj) + + def _set_tzdata(self, tzobj): + """ Set the time zone data of this object from a _tzfile object """ + # Copy the relevant attributes over as private attributes + for attr in _tzfile.attrs: + setattr(self, '_' + attr, getattr(tzobj, attr)) + + def _read_tzfile(self, fileobj): + out = _tzfile() + + # From tzfile(5): + # + # The time zone information files used by tzset(3) + # begin with the magic characters "TZif" to identify + # them as time zone information files, followed by + # sixteen bytes reserved for future use, followed by + # six four-byte values of type long, written in a + # ``standard'' byte order (the high-order byte + # of the value is written first). + if fileobj.read(4).decode() != "TZif": + raise ValueError("magic not found") + + fileobj.read(16) + + ( + # The number of UTC/local indicators stored in the file. + ttisgmtcnt, + + # The number of standard/wall indicators stored in the file. + ttisstdcnt, + + # The number of leap seconds for which data is + # stored in the file. + leapcnt, + + # The number of "transition times" for which data + # is stored in the file. + timecnt, + + # The number of "local time types" for which data + # is stored in the file (must not be zero). + typecnt, + + # The number of characters of "time zone + # abbreviation strings" stored in the file. + charcnt, + + ) = struct.unpack(">6l", fileobj.read(24)) + + # The above header is followed by tzh_timecnt four-byte + # values of type long, sorted in ascending order. + # These values are written in ``standard'' byte order. + # Each is used as a transition time (as returned by + # time(2)) at which the rules for computing local time + # change. + + if timecnt: + out.trans_list_utc = list(struct.unpack(">%dl" % timecnt, + fileobj.read(timecnt*4))) + else: + out.trans_list_utc = [] + + # Next come tzh_timecnt one-byte values of type unsigned + # char; each one tells which of the different types of + # ``local time'' types described in the file is associated + # with the same-indexed transition time. These values + # serve as indices into an array of ttinfo structures that + # appears next in the file. + + if timecnt: + out.trans_idx = struct.unpack(">%dB" % timecnt, + fileobj.read(timecnt)) + else: + out.trans_idx = [] + + # Each ttinfo structure is written as a four-byte value + # for tt_gmtoff of type long, in a standard byte + # order, followed by a one-byte value for tt_isdst + # and a one-byte value for tt_abbrind. In each + # structure, tt_gmtoff gives the number of + # seconds to be added to UTC, tt_isdst tells whether + # tm_isdst should be set by localtime(3), and + # tt_abbrind serves as an index into the array of + # time zone abbreviation characters that follow the + # ttinfo structure(s) in the file. + + ttinfo = [] + + for i in range(typecnt): + ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) + + abbr = fileobj.read(charcnt).decode() + + # Then there are tzh_leapcnt pairs of four-byte + # values, written in standard byte order; the + # first value of each pair gives the time (as + # returned by time(2)) at which a leap second + # occurs; the second gives the total number of + # leap seconds to be applied after the given time. + # The pairs of values are sorted in ascending order + # by time. + + # Not used, for now (but seek for correct file position) + if leapcnt: + fileobj.seek(leapcnt * 8, os.SEEK_CUR) + + # Then there are tzh_ttisstdcnt standard/wall + # indicators, each stored as a one-byte value; + # they tell whether the transition times associated + # with local time types were specified as standard + # time or wall clock time, and are used when + # a time zone file is used in handling POSIX-style + # time zone environment variables. + + if ttisstdcnt: + isstd = struct.unpack(">%db" % ttisstdcnt, + fileobj.read(ttisstdcnt)) + + # Finally, there are tzh_ttisgmtcnt UTC/local + # indicators, each stored as a one-byte value; + # they tell whether the transition times associated + # with local time types were specified as UTC or + # local time, and are used when a time zone file + # is used in handling POSIX-style time zone envi- + # ronment variables. + + if ttisgmtcnt: + isgmt = struct.unpack(">%db" % ttisgmtcnt, + fileobj.read(ttisgmtcnt)) + + # Build ttinfo list + out.ttinfo_list = [] + for i in range(typecnt): + gmtoff, isdst, abbrind = ttinfo[i] + gmtoff = _get_supported_offset(gmtoff) + tti = _ttinfo() + tti.offset = gmtoff + tti.dstoffset = datetime.timedelta(0) + tti.delta = datetime.timedelta(seconds=gmtoff) + tti.isdst = isdst + tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] + tti.isstd = (ttisstdcnt > i and isstd[i] != 0) + tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) + out.ttinfo_list.append(tti) + + # Replace ttinfo indexes for ttinfo objects. + out.trans_idx = [out.ttinfo_list[idx] for idx in out.trans_idx] + + # Set standard, dst, and before ttinfos. before will be + # used when a given time is before any transitions, + # and will be set to the first non-dst ttinfo, or to + # the first dst, if all of them are dst. + out.ttinfo_std = None + out.ttinfo_dst = None + out.ttinfo_before = None + if out.ttinfo_list: + if not out.trans_list_utc: + out.ttinfo_std = out.ttinfo_first = out.ttinfo_list[0] + else: + for i in range(timecnt-1, -1, -1): + tti = out.trans_idx[i] + if not out.ttinfo_std and not tti.isdst: + out.ttinfo_std = tti + elif not out.ttinfo_dst and tti.isdst: + out.ttinfo_dst = tti + + if out.ttinfo_std and out.ttinfo_dst: + break + else: + if out.ttinfo_dst and not out.ttinfo_std: + out.ttinfo_std = out.ttinfo_dst + + for tti in out.ttinfo_list: + if not tti.isdst: + out.ttinfo_before = tti + break + else: + out.ttinfo_before = out.ttinfo_list[0] + + # Now fix transition times to become relative to wall time. + # + # I'm not sure about this. In my tests, the tz source file + # is setup to wall time, and in the binary file isstd and + # isgmt are off, so it should be in wall time. OTOH, it's + # always in gmt time. Let me know if you have comments + # about this. + lastdst = None + lastoffset = None + lastdstoffset = None + lastbaseoffset = None + out.trans_list = [] + + for i, tti in enumerate(out.trans_idx): + offset = tti.offset + dstoffset = 0 + + if lastdst is not None: + if tti.isdst: + if not lastdst: + dstoffset = offset - lastoffset + + if not dstoffset and lastdstoffset: + dstoffset = lastdstoffset + + tti.dstoffset = datetime.timedelta(seconds=dstoffset) + lastdstoffset = dstoffset + + # If a time zone changes its base offset during a DST transition, + # then you need to adjust by the previous base offset to get the + # transition time in local time. Otherwise you use the current + # base offset. Ideally, I would have some mathematical proof of + # why this is true, but I haven't really thought about it enough. + baseoffset = offset - dstoffset + adjustment = baseoffset + if (lastbaseoffset is not None and baseoffset != lastbaseoffset + and tti.isdst != lastdst): + # The base DST has changed + adjustment = lastbaseoffset + + lastdst = tti.isdst + lastoffset = offset + lastbaseoffset = baseoffset + + out.trans_list.append(out.trans_list_utc[i] + adjustment) + + out.trans_idx = tuple(out.trans_idx) + out.trans_list = tuple(out.trans_list) + out.trans_list_utc = tuple(out.trans_list_utc) + + return out + + def _find_last_transition(self, dt, in_utc=False): + # If there's no list, there are no transitions to find + if not self._trans_list: + return None + + timestamp = _datetime_to_timestamp(dt) + + # Find where the timestamp fits in the transition list - if the + # timestamp is a transition time, it's part of the "after" period. + trans_list = self._trans_list_utc if in_utc else self._trans_list + idx = bisect.bisect_right(trans_list, timestamp) + + # We want to know when the previous transition was, so subtract off 1 + return idx - 1 + + def _get_ttinfo(self, idx): + # For no list or after the last transition, default to _ttinfo_std + if idx is None or (idx + 1) >= len(self._trans_list): + return self._ttinfo_std + + # If there is a list and the time is before it, return _ttinfo_before + if idx < 0: + return self._ttinfo_before + + return self._trans_idx[idx] + + def _find_ttinfo(self, dt): + idx = self._resolve_ambiguous_time(dt) + + return self._get_ttinfo(idx) + + def fromutc(self, dt): + """ + The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`. + + :param dt: + A :py:class:`datetime.datetime` object. + + :raises TypeError: + Raised if ``dt`` is not a :py:class:`datetime.datetime` object. + + :raises ValueError: + Raised if this is called with a ``dt`` which does not have this + ``tzinfo`` attached. + + :return: + Returns a :py:class:`datetime.datetime` object representing the + wall time in ``self``'s time zone. + """ + # These isinstance checks are in datetime.tzinfo, so we'll preserve + # them, even if we don't care about duck typing. + if not isinstance(dt, datetime.datetime): + raise TypeError("fromutc() requires a datetime argument") + + if dt.tzinfo is not self: + raise ValueError("dt.tzinfo is not self") + + # First treat UTC as wall time and get the transition we're in. + idx = self._find_last_transition(dt, in_utc=True) + tti = self._get_ttinfo(idx) + + dt_out = dt + datetime.timedelta(seconds=tti.offset) + + fold = self.is_ambiguous(dt_out, idx=idx) + + return enfold(dt_out, fold=int(fold)) + + def is_ambiguous(self, dt, idx=None): + """ + Whether or not the "wall time" of a given datetime is ambiguous in this + zone. + + :param dt: + A :py:class:`datetime.datetime`, naive or time zone aware. + + + :return: + Returns ``True`` if ambiguous, ``False`` otherwise. + + .. versionadded:: 2.6.0 + """ + if idx is None: + idx = self._find_last_transition(dt) + + # Calculate the difference in offsets from current to previous + timestamp = _datetime_to_timestamp(dt) + tti = self._get_ttinfo(idx) + + if idx is None or idx <= 0: + return False + + od = self._get_ttinfo(idx - 1).offset - tti.offset + tt = self._trans_list[idx] # Transition time + + return timestamp < tt + od + + def _resolve_ambiguous_time(self, dt): + idx = self._find_last_transition(dt) + + # If we have no transitions, return the index + _fold = self._fold(dt) + if idx is None or idx == 0: + return idx + + # If it's ambiguous and we're in a fold, shift to a different index. + idx_offset = int(not _fold and self.is_ambiguous(dt, idx)) + + return idx - idx_offset + + def utcoffset(self, dt): + if dt is None: + return None + + if not self._ttinfo_std: + return ZERO + + return self._find_ttinfo(dt).delta + + def dst(self, dt): + if dt is None: + return None + + if not self._ttinfo_dst: + return ZERO + + tti = self._find_ttinfo(dt) + + if not tti.isdst: + return ZERO + + # The documentation says that utcoffset()-dst() must + # be constant for every dt. + return tti.dstoffset + + @tzname_in_python2 + def tzname(self, dt): + if not self._ttinfo_std or dt is None: + return None + return self._find_ttinfo(dt).abbr + + def __eq__(self, other): + if not isinstance(other, tzfile): + return NotImplemented + return (self._trans_list == other._trans_list and + self._trans_idx == other._trans_idx and + self._ttinfo_list == other._ttinfo_list) + + __hash__ = None + + def __ne__(self, other): + return not (self == other) + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self._filename)) + + def __reduce__(self): + return self.__reduce_ex__(None) + + def __reduce_ex__(self, protocol): + return (self.__class__, (None, self._filename), self.__dict__) + + +class tzrange(tzrangebase): + """ + The ``tzrange`` object is a time zone specified by a set of offsets and + abbreviations, equivalent to the way the ``TZ`` variable can be specified + in POSIX-like systems, but using Python delta objects to specify DST + start, end and offsets. + + :param stdabbr: + The abbreviation for standard time (e.g. ``'EST'``). + + :param stdoffset: + An integer or :class:`datetime.timedelta` object or equivalent + specifying the base offset from UTC. + + If unspecified, +00:00 is used. + + :param dstabbr: + The abbreviation for DST / "Summer" time (e.g. ``'EDT'``). + + If specified, with no other DST information, DST is assumed to occur + and the default behavior or ``dstoffset``, ``start`` and ``end`` is + used. If unspecified and no other DST information is specified, it + is assumed that this zone has no DST. + + If this is unspecified and other DST information is *is* specified, + DST occurs in the zone but the time zone abbreviation is left + unchanged. + + :param dstoffset: + A an integer or :class:`datetime.timedelta` object or equivalent + specifying the UTC offset during DST. If unspecified and any other DST + information is specified, it is assumed to be the STD offset +1 hour. + + :param start: + A :class:`relativedelta.relativedelta` object or equivalent specifying + the time and time of year that daylight savings time starts. To + specify, for example, that DST starts at 2AM on the 2nd Sunday in + March, pass: + + ``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))`` + + If unspecified and any other DST information is specified, the default + value is 2 AM on the first Sunday in April. + + :param end: + A :class:`relativedelta.relativedelta` object or equivalent + representing the time and time of year that daylight savings time + ends, with the same specification method as in ``start``. One note is + that this should point to the first time in the *standard* zone, so if + a transition occurs at 2AM in the DST zone and the clocks are set back + 1 hour to 1AM, set the ``hours`` parameter to +1. + + + **Examples:** + + .. testsetup:: tzrange + + from dateutil.tz import tzrange, tzstr + + .. doctest:: tzrange + + >>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT") + True + + >>> from dateutil.relativedelta import * + >>> range1 = tzrange("EST", -18000, "EDT") + >>> range2 = tzrange("EST", -18000, "EDT", -14400, + ... relativedelta(hours=+2, month=4, day=1, + ... weekday=SU(+1)), + ... relativedelta(hours=+1, month=10, day=31, + ... weekday=SU(-1))) + >>> tzstr('EST5EDT') == range1 == range2 + True + + """ + def __init__(self, stdabbr, stdoffset=None, + dstabbr=None, dstoffset=None, + start=None, end=None): + + global relativedelta + from dateutil import relativedelta + + self._std_abbr = stdabbr + self._dst_abbr = dstabbr + + try: + stdoffset = stdoffset.total_seconds() + except (TypeError, AttributeError): + pass + + try: + dstoffset = dstoffset.total_seconds() + except (TypeError, AttributeError): + pass + + if stdoffset is not None: + self._std_offset = datetime.timedelta(seconds=stdoffset) + else: + self._std_offset = ZERO + + if dstoffset is not None: + self._dst_offset = datetime.timedelta(seconds=dstoffset) + elif dstabbr and stdoffset is not None: + self._dst_offset = self._std_offset + datetime.timedelta(hours=+1) + else: + self._dst_offset = ZERO + + if dstabbr and start is None: + self._start_delta = relativedelta.relativedelta( + hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) + else: + self._start_delta = start + + if dstabbr and end is None: + self._end_delta = relativedelta.relativedelta( + hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) + else: + self._end_delta = end + + self._dst_base_offset_ = self._dst_offset - self._std_offset + self.hasdst = bool(self._start_delta) + + def transitions(self, year): + """ + For a given year, get the DST on and off transition times, expressed + always on the standard time side. For zones with no transitions, this + function returns ``None``. + + :param year: + The year whose transitions you would like to query. + + :return: + Returns a :class:`tuple` of :class:`datetime.datetime` objects, + ``(dston, dstoff)`` for zones with an annual DST transition, or + ``None`` for fixed offset zones. + """ + if not self.hasdst: + return None + + base_year = datetime.datetime(year, 1, 1) + + start = base_year + self._start_delta + end = base_year + self._end_delta + + return (start, end) + + def __eq__(self, other): + if not isinstance(other, tzrange): + return NotImplemented + + return (self._std_abbr == other._std_abbr and + self._dst_abbr == other._dst_abbr and + self._std_offset == other._std_offset and + self._dst_offset == other._dst_offset and + self._start_delta == other._start_delta and + self._end_delta == other._end_delta) + + @property + def _dst_base_offset(self): + return self._dst_base_offset_ + + +@six.add_metaclass(_TzStrFactory) +class tzstr(tzrange): + """ + ``tzstr`` objects are time zone objects specified by a time-zone string as + it would be passed to a ``TZ`` variable on POSIX-style systems (see + the `GNU C Library: TZ Variable`_ for more details). + + There is one notable exception, which is that POSIX-style time zones use an + inverted offset format, so normally ``GMT+3`` would be parsed as an offset + 3 hours *behind* GMT. The ``tzstr`` time zone object will parse this as an + offset 3 hours *ahead* of GMT. If you would like to maintain the POSIX + behavior, pass a ``True`` value to ``posix_offset``. + + The :class:`tzrange` object provides the same functionality, but is + specified using :class:`relativedelta.relativedelta` objects. rather than + strings. + + :param s: + A time zone string in ``TZ`` variable format. This can be a + :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x: + :class:`unicode`) or a stream emitting unicode characters + (e.g. :class:`StringIO`). + + :param posix_offset: + Optional. If set to ``True``, interpret strings such as ``GMT+3`` or + ``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the + POSIX standard. + + .. caution:: + + Prior to version 2.7.0, this function also supported time zones + in the format: + + * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600`` + * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600`` + + This format is non-standard and has been deprecated; this function + will raise a :class:`DeprecatedTZFormatWarning` until + support is removed in a future version. + + .. _`GNU C Library: TZ Variable`: + https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + """ + def __init__(self, s, posix_offset=False): + global parser + from dateutil.parser import _parser as parser + + self._s = s + + res = parser._parsetz(s) + if res is None or res.any_unused_tokens: + raise ValueError("unknown string format") + + # Here we break the compatibility with the TZ variable handling. + # GMT-3 actually *means* the timezone -3. + if res.stdabbr in ("GMT", "UTC") and not posix_offset: + res.stdoffset *= -1 + + # We must initialize it first, since _delta() needs + # _std_offset and _dst_offset set. Use False in start/end + # to avoid building it two times. + tzrange.__init__(self, res.stdabbr, res.stdoffset, + res.dstabbr, res.dstoffset, + start=False, end=False) + + if not res.dstabbr: + self._start_delta = None + self._end_delta = None + else: + self._start_delta = self._delta(res.start) + if self._start_delta: + self._end_delta = self._delta(res.end, isend=1) + + self.hasdst = bool(self._start_delta) + + def _delta(self, x, isend=0): + from dateutil import relativedelta + kwargs = {} + if x.month is not None: + kwargs["month"] = x.month + if x.weekday is not None: + kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) + if x.week > 0: + kwargs["day"] = 1 + else: + kwargs["day"] = 31 + elif x.day: + kwargs["day"] = x.day + elif x.yday is not None: + kwargs["yearday"] = x.yday + elif x.jyday is not None: + kwargs["nlyearday"] = x.jyday + if not kwargs: + # Default is to start on first sunday of april, and end + # on last sunday of october. + if not isend: + kwargs["month"] = 4 + kwargs["day"] = 1 + kwargs["weekday"] = relativedelta.SU(+1) + else: + kwargs["month"] = 10 + kwargs["day"] = 31 + kwargs["weekday"] = relativedelta.SU(-1) + if x.time is not None: + kwargs["seconds"] = x.time + else: + # Default is 2AM. + kwargs["seconds"] = 7200 + if isend: + # Convert to standard time, to follow the documented way + # of working with the extra hour. See the documentation + # of the tzinfo class. + delta = self._dst_offset - self._std_offset + kwargs["seconds"] -= delta.seconds + delta.days * 86400 + return relativedelta.relativedelta(**kwargs) + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self._s)) + + +class _tzicalvtzcomp(object): + def __init__(self, tzoffsetfrom, tzoffsetto, isdst, + tzname=None, rrule=None): + self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) + self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) + self.tzoffsetdiff = self.tzoffsetto - self.tzoffsetfrom + self.isdst = isdst + self.tzname = tzname + self.rrule = rrule + + +class _tzicalvtz(_tzinfo): + def __init__(self, tzid, comps=[]): + super(_tzicalvtz, self).__init__() + + self._tzid = tzid + self._comps = comps + self._cachedate = [] + self._cachecomp = [] + self._cache_lock = _thread.allocate_lock() + + def _find_comp(self, dt): + if len(self._comps) == 1: + return self._comps[0] + + dt = dt.replace(tzinfo=None) + + try: + with self._cache_lock: + return self._cachecomp[self._cachedate.index( + (dt, self._fold(dt)))] + except ValueError: + pass + + lastcompdt = None + lastcomp = None + + for comp in self._comps: + compdt = self._find_compdt(comp, dt) + + if compdt and (not lastcompdt or lastcompdt < compdt): + lastcompdt = compdt + lastcomp = comp + + if not lastcomp: + # RFC says nothing about what to do when a given + # time is before the first onset date. We'll look for the + # first standard component, or the first component, if + # none is found. + for comp in self._comps: + if not comp.isdst: + lastcomp = comp + break + else: + lastcomp = comp[0] + + with self._cache_lock: + self._cachedate.insert(0, (dt, self._fold(dt))) + self._cachecomp.insert(0, lastcomp) + + if len(self._cachedate) > 10: + self._cachedate.pop() + self._cachecomp.pop() + + return lastcomp + + def _find_compdt(self, comp, dt): + if comp.tzoffsetdiff < ZERO and self._fold(dt): + dt -= comp.tzoffsetdiff + + compdt = comp.rrule.before(dt, inc=True) + + return compdt + + def utcoffset(self, dt): + if dt is None: + return None + + return self._find_comp(dt).tzoffsetto + + def dst(self, dt): + comp = self._find_comp(dt) + if comp.isdst: + return comp.tzoffsetdiff + else: + return ZERO + + @tzname_in_python2 + def tzname(self, dt): + return self._find_comp(dt).tzname + + def __repr__(self): + return "" % repr(self._tzid) + + __reduce__ = object.__reduce__ + + +class tzical(object): + """ + This object is designed to parse an iCalendar-style ``VTIMEZONE`` structure + as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects. + + :param `fileobj`: + A file or stream in iCalendar format, which should be UTF-8 encoded + with CRLF endings. + + .. _`RFC 5545`: https://tools.ietf.org/html/rfc5545 + """ + def __init__(self, fileobj): + global rrule + from dateutil import rrule + + if isinstance(fileobj, string_types): + self._s = fileobj + # ical should be encoded in UTF-8 with CRLF + fileobj = open(fileobj, 'r') + else: + self._s = getattr(fileobj, 'name', repr(fileobj)) + fileobj = _nullcontext(fileobj) + + self._vtz = {} + + with fileobj as fobj: + self._parse_rfc(fobj.read()) + + def keys(self): + """ + Retrieves the available time zones as a list. + """ + return list(self._vtz.keys()) + + def get(self, tzid=None): + """ + Retrieve a :py:class:`datetime.tzinfo` object by its ``tzid``. + + :param tzid: + If there is exactly one time zone available, omitting ``tzid`` + or passing :py:const:`None` value returns it. Otherwise a valid + key (which can be retrieved from :func:`keys`) is required. + + :raises ValueError: + Raised if ``tzid`` is not specified but there are either more + or fewer than 1 zone defined. + + :returns: + Returns either a :py:class:`datetime.tzinfo` object representing + the relevant time zone or :py:const:`None` if the ``tzid`` was + not found. + """ + if tzid is None: + if len(self._vtz) == 0: + raise ValueError("no timezones defined") + elif len(self._vtz) > 1: + raise ValueError("more than one timezone available") + tzid = next(iter(self._vtz)) + + return self._vtz.get(tzid) + + def _parse_offset(self, s): + s = s.strip() + if not s: + raise ValueError("empty offset") + if s[0] in ('+', '-'): + signal = (-1, +1)[s[0] == '+'] + s = s[1:] + else: + signal = +1 + if len(s) == 4: + return (int(s[:2]) * 3600 + int(s[2:]) * 60) * signal + elif len(s) == 6: + return (int(s[:2]) * 3600 + int(s[2:4]) * 60 + int(s[4:])) * signal + else: + raise ValueError("invalid offset: " + s) + + def _parse_rfc(self, s): + lines = s.splitlines() + if not lines: + raise ValueError("empty string") + + # Unfold + i = 0 + while i < len(lines): + line = lines[i].rstrip() + if not line: + del lines[i] + elif i > 0 and line[0] == " ": + lines[i-1] += line[1:] + del lines[i] + else: + i += 1 + + tzid = None + comps = [] + invtz = False + comptype = None + for line in lines: + if not line: + continue + name, value = line.split(':', 1) + parms = name.split(';') + if not parms: + raise ValueError("empty property name") + name = parms[0].upper() + parms = parms[1:] + if invtz: + if name == "BEGIN": + if value in ("STANDARD", "DAYLIGHT"): + # Process component + pass + else: + raise ValueError("unknown component: "+value) + comptype = value + founddtstart = False + tzoffsetfrom = None + tzoffsetto = None + rrulelines = [] + tzname = None + elif name == "END": + if value == "VTIMEZONE": + if comptype: + raise ValueError("component not closed: "+comptype) + if not tzid: + raise ValueError("mandatory TZID not found") + if not comps: + raise ValueError( + "at least one component is needed") + # Process vtimezone + self._vtz[tzid] = _tzicalvtz(tzid, comps) + invtz = False + elif value == comptype: + if not founddtstart: + raise ValueError("mandatory DTSTART not found") + if tzoffsetfrom is None: + raise ValueError( + "mandatory TZOFFSETFROM not found") + if tzoffsetto is None: + raise ValueError( + "mandatory TZOFFSETFROM not found") + # Process component + rr = None + if rrulelines: + rr = rrule.rrulestr("\n".join(rrulelines), + compatible=True, + ignoretz=True, + cache=True) + comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, + (comptype == "DAYLIGHT"), + tzname, rr) + comps.append(comp) + comptype = None + else: + raise ValueError("invalid component end: "+value) + elif comptype: + if name == "DTSTART": + # DTSTART in VTIMEZONE takes a subset of valid RRULE + # values under RFC 5545. + for parm in parms: + if parm != 'VALUE=DATE-TIME': + msg = ('Unsupported DTSTART param in ' + + 'VTIMEZONE: ' + parm) + raise ValueError(msg) + rrulelines.append(line) + founddtstart = True + elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): + rrulelines.append(line) + elif name == "TZOFFSETFROM": + if parms: + raise ValueError( + "unsupported %s parm: %s " % (name, parms[0])) + tzoffsetfrom = self._parse_offset(value) + elif name == "TZOFFSETTO": + if parms: + raise ValueError( + "unsupported TZOFFSETTO parm: "+parms[0]) + tzoffsetto = self._parse_offset(value) + elif name == "TZNAME": + if parms: + raise ValueError( + "unsupported TZNAME parm: "+parms[0]) + tzname = value + elif name == "COMMENT": + pass + else: + raise ValueError("unsupported property: "+name) + else: + if name == "TZID": + if parms: + raise ValueError( + "unsupported TZID parm: "+parms[0]) + tzid = value + elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): + pass + else: + raise ValueError("unsupported property: "+name) + elif name == "BEGIN" and value == "VTIMEZONE": + tzid = None + comps = [] + invtz = True + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self._s)) + + +if sys.platform != "win32": + TZFILES = ["/etc/localtime", "localtime"] + TZPATHS = ["/usr/share/zoneinfo", + "/usr/lib/zoneinfo", + "/usr/share/lib/zoneinfo", + "/etc/zoneinfo"] +else: + TZFILES = [] + TZPATHS = [] + + +def __get_gettz(): + tzlocal_classes = (tzlocal,) + if tzwinlocal is not None: + tzlocal_classes += (tzwinlocal,) + + class GettzFunc(object): + """ + Retrieve a time zone object from a string representation + + This function is intended to retrieve the :py:class:`tzinfo` subclass + that best represents the time zone that would be used if a POSIX + `TZ variable`_ were set to the same value. + + If no argument or an empty string is passed to ``gettz``, local time + is returned: + + .. code-block:: python3 + + >>> gettz() + tzfile('/etc/localtime') + + This function is also the preferred way to map IANA tz database keys + to :class:`tzfile` objects: + + .. code-block:: python3 + + >>> gettz('Pacific/Kiritimati') + tzfile('/usr/share/zoneinfo/Pacific/Kiritimati') + + On Windows, the standard is extended to include the Windows-specific + zone names provided by the operating system: + + .. code-block:: python3 + + >>> gettz('Egypt Standard Time') + tzwin('Egypt Standard Time') + + Passing a GNU ``TZ`` style string time zone specification returns a + :class:`tzstr` object: + + .. code-block:: python3 + + >>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3') + tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3') + + :param name: + A time zone name (IANA, or, on Windows, Windows keys), location of + a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone + specifier. An empty string, no argument or ``None`` is interpreted + as local time. + + :return: + Returns an instance of one of ``dateutil``'s :py:class:`tzinfo` + subclasses. + + .. versionchanged:: 2.7.0 + + After version 2.7.0, any two calls to ``gettz`` using the same + input strings will return the same object: + + .. code-block:: python3 + + >>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago') + True + + In addition to improving performance, this ensures that + `"same zone" semantics`_ are used for datetimes in the same zone. + + + .. _`TZ variable`: + https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + + .. _`"same zone" semantics`: + https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html + """ + def __init__(self): + + self.__instances = weakref.WeakValueDictionary() + self.__strong_cache_size = 8 + self.__strong_cache = OrderedDict() + self._cache_lock = _thread.allocate_lock() + + def __call__(self, name=None): + with self._cache_lock: + rv = self.__instances.get(name, None) + + if rv is None: + rv = self.nocache(name=name) + if not (name is None + or isinstance(rv, tzlocal_classes) + or rv is None): + # tzlocal is slightly more complicated than the other + # time zone providers because it depends on environment + # at construction time, so don't cache that. + # + # We also cannot store weak references to None, so we + # will also not store that. + self.__instances[name] = rv + else: + # No need for strong caching, return immediately + return rv + + self.__strong_cache[name] = self.__strong_cache.pop(name, rv) + + if len(self.__strong_cache) > self.__strong_cache_size: + self.__strong_cache.popitem(last=False) + + return rv + + def set_cache_size(self, size): + with self._cache_lock: + self.__strong_cache_size = size + while len(self.__strong_cache) > size: + self.__strong_cache.popitem(last=False) + + def cache_clear(self): + with self._cache_lock: + self.__instances = weakref.WeakValueDictionary() + self.__strong_cache.clear() + + @staticmethod + def nocache(name=None): + """A non-cached version of gettz""" + tz = None + if not name: + try: + name = os.environ["TZ"] + except KeyError: + pass + if name is None or name == ":": + for filepath in TZFILES: + if not os.path.isabs(filepath): + filename = filepath + for path in TZPATHS: + filepath = os.path.join(path, filename) + if os.path.isfile(filepath): + break + else: + continue + if os.path.isfile(filepath): + try: + tz = tzfile(filepath) + break + except (IOError, OSError, ValueError): + pass + else: + tz = tzlocal() + else: + try: + if name.startswith(":"): + name = name[1:] + except TypeError as e: + if isinstance(name, bytes): + new_msg = "gettz argument should be str, not bytes" + six.raise_from(TypeError(new_msg), e) + else: + raise + if os.path.isabs(name): + if os.path.isfile(name): + tz = tzfile(name) + else: + tz = None + else: + for path in TZPATHS: + filepath = os.path.join(path, name) + if not os.path.isfile(filepath): + filepath = filepath.replace(' ', '_') + if not os.path.isfile(filepath): + continue + try: + tz = tzfile(filepath) + break + except (IOError, OSError, ValueError): + pass + else: + tz = None + if tzwin is not None: + try: + tz = tzwin(name) + except (WindowsError, UnicodeEncodeError): + # UnicodeEncodeError is for Python 2.7 compat + tz = None + + if not tz: + from dateutil.zoneinfo import get_zonefile_instance + tz = get_zonefile_instance().get(name) + + if not tz: + for c in name: + # name is not a tzstr unless it has at least + # one offset. For short values of "name", an + # explicit for loop seems to be the fastest way + # To determine if a string contains a digit + if c in "0123456789": + try: + tz = tzstr(name) + except ValueError: + pass + break + else: + if name in ("GMT", "UTC"): + tz = UTC + elif name in time.tzname: + tz = tzlocal() + return tz + + return GettzFunc() + + +gettz = __get_gettz() +del __get_gettz + + +def datetime_exists(dt, tz=None): + """ + Given a datetime and a time zone, determine whether or not a given datetime + would fall in a gap. + + :param dt: + A :class:`datetime.datetime` (whose time zone will be ignored if ``tz`` + is provided.) + + :param tz: + A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If + ``None`` or not provided, the datetime's own time zone will be used. + + :return: + Returns a boolean value whether or not the "wall time" exists in + ``tz``. + + .. versionadded:: 2.7.0 + """ + if tz is None: + if dt.tzinfo is None: + raise ValueError('Datetime is naive and no time zone provided.') + tz = dt.tzinfo + + dt = dt.replace(tzinfo=None) + + # This is essentially a test of whether or not the datetime can survive + # a round trip to UTC. + dt_rt = dt.replace(tzinfo=tz).astimezone(UTC).astimezone(tz) + dt_rt = dt_rt.replace(tzinfo=None) + + return dt == dt_rt + + +def datetime_ambiguous(dt, tz=None): + """ + Given a datetime and a time zone, determine whether or not a given datetime + is ambiguous (i.e if there are two times differentiated only by their DST + status). + + :param dt: + A :class:`datetime.datetime` (whose time zone will be ignored if ``tz`` + is provided.) + + :param tz: + A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If + ``None`` or not provided, the datetime's own time zone will be used. + + :return: + Returns a boolean value whether or not the "wall time" is ambiguous in + ``tz``. + + .. versionadded:: 2.6.0 + """ + if tz is None: + if dt.tzinfo is None: + raise ValueError('Datetime is naive and no time zone provided.') + + tz = dt.tzinfo + + # If a time zone defines its own "is_ambiguous" function, we'll use that. + is_ambiguous_fn = getattr(tz, 'is_ambiguous', None) + if is_ambiguous_fn is not None: + try: + return tz.is_ambiguous(dt) + except Exception: + pass + + # If it doesn't come out and tell us it's ambiguous, we'll just check if + # the fold attribute has any effect on this particular date and time. + dt = dt.replace(tzinfo=tz) + wall_0 = enfold(dt, fold=0) + wall_1 = enfold(dt, fold=1) + + same_offset = wall_0.utcoffset() == wall_1.utcoffset() + same_dst = wall_0.dst() == wall_1.dst() + + return not (same_offset and same_dst) + + +def resolve_imaginary(dt): + """ + Given a datetime that may be imaginary, return an existing datetime. + + This function assumes that an imaginary datetime represents what the + wall time would be in a zone had the offset transition not occurred, so + it will always fall forward by the transition's change in offset. + + .. doctest:: + + >>> from dateutil import tz + >>> from datetime import datetime + >>> NYC = tz.gettz('America/New_York') + >>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC))) + 2017-03-12 03:30:00-04:00 + + >>> KIR = tz.gettz('Pacific/Kiritimati') + >>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR))) + 1995-01-02 12:30:00+14:00 + + As a note, :func:`datetime.astimezone` is guaranteed to produce a valid, + existing datetime, so a round-trip to and from UTC is sufficient to get + an extant datetime, however, this generally "falls back" to an earlier time + rather than falling forward to the STD side (though no guarantees are made + about this behavior). + + :param dt: + A :class:`datetime.datetime` which may or may not exist. + + :return: + Returns an existing :class:`datetime.datetime`. If ``dt`` was not + imaginary, the datetime returned is guaranteed to be the same object + passed to the function. + + .. versionadded:: 2.7.0 + """ + if dt.tzinfo is not None and not datetime_exists(dt): + + curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset() + old_offset = (dt - datetime.timedelta(hours=24)).utcoffset() + + dt += curr_offset - old_offset + + return dt + + +def _datetime_to_timestamp(dt): + """ + Convert a :class:`datetime.datetime` object to an epoch timestamp in + seconds since January 1, 1970, ignoring the time zone. + """ + return (dt.replace(tzinfo=None) - EPOCH).total_seconds() + + +if sys.version_info >= (3, 6): + def _get_supported_offset(second_offset): + return second_offset +else: + def _get_supported_offset(second_offset): + # For python pre-3.6, round to full-minutes if that's not the case. + # Python's datetime doesn't accept sub-minute timezones. Check + # http://python.org/sf/1447945 or https://bugs.python.org/issue5288 + # for some information. + old_offset = second_offset + calculated_offset = 60 * ((second_offset + 30) // 60) + return calculated_offset + + +try: + # Python 3.7 feature + from contextlib import nullcontext as _nullcontext +except ImportError: + class _nullcontext(object): + """ + Class for wrapping contexts so that they are passed through in a + with statement. + """ + def __init__(self, context): + self.context = context + + def __enter__(self): + return self.context + + def __exit__(*args, **kwargs): + pass + +# vim:ts=4:sw=4:et diff --git a/env/lib/python3.8/site-packages/dateutil/tz/win.py b/env/lib/python3.8/site-packages/dateutil/tz/win.py new file mode 100644 index 000000000..cde07ba79 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tz/win.py @@ -0,0 +1,370 @@ +# -*- coding: utf-8 -*- +""" +This module provides an interface to the native time zone data on Windows, +including :py:class:`datetime.tzinfo` implementations. + +Attempting to import this module on a non-Windows platform will raise an +:py:obj:`ImportError`. +""" +# This code was originally contributed by Jeffrey Harris. +import datetime +import struct + +from six.moves import winreg +from six import text_type + +try: + import ctypes + from ctypes import wintypes +except ValueError: + # ValueError is raised on non-Windows systems for some horrible reason. + raise ImportError("Running tzwin on non-Windows system") + +from ._common import tzrangebase + +__all__ = ["tzwin", "tzwinlocal", "tzres"] + +ONEWEEK = datetime.timedelta(7) + +TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" +TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" +TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" + + +def _settzkeyname(): + handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + try: + winreg.OpenKey(handle, TZKEYNAMENT).Close() + TZKEYNAME = TZKEYNAMENT + except WindowsError: + TZKEYNAME = TZKEYNAME9X + handle.Close() + return TZKEYNAME + + +TZKEYNAME = _settzkeyname() + + +class tzres(object): + """ + Class for accessing ``tzres.dll``, which contains timezone name related + resources. + + .. versionadded:: 2.5.0 + """ + p_wchar = ctypes.POINTER(wintypes.WCHAR) # Pointer to a wide char + + def __init__(self, tzres_loc='tzres.dll'): + # Load the user32 DLL so we can load strings from tzres + user32 = ctypes.WinDLL('user32') + + # Specify the LoadStringW function + user32.LoadStringW.argtypes = (wintypes.HINSTANCE, + wintypes.UINT, + wintypes.LPWSTR, + ctypes.c_int) + + self.LoadStringW = user32.LoadStringW + self._tzres = ctypes.WinDLL(tzres_loc) + self.tzres_loc = tzres_loc + + def load_name(self, offset): + """ + Load a timezone name from a DLL offset (integer). + + >>> from dateutil.tzwin import tzres + >>> tzr = tzres() + >>> print(tzr.load_name(112)) + 'Eastern Standard Time' + + :param offset: + A positive integer value referring to a string from the tzres dll. + + .. note:: + + Offsets found in the registry are generally of the form + ``@tzres.dll,-114``. The offset in this case is 114, not -114. + + """ + resource = self.p_wchar() + lpBuffer = ctypes.cast(ctypes.byref(resource), wintypes.LPWSTR) + nchar = self.LoadStringW(self._tzres._handle, offset, lpBuffer, 0) + return resource[:nchar] + + def name_from_string(self, tzname_str): + """ + Parse strings as returned from the Windows registry into the time zone + name as defined in the registry. + + >>> from dateutil.tzwin import tzres + >>> tzr = tzres() + >>> print(tzr.name_from_string('@tzres.dll,-251')) + 'Dateline Daylight Time' + >>> print(tzr.name_from_string('Eastern Standard Time')) + 'Eastern Standard Time' + + :param tzname_str: + A timezone name string as returned from a Windows registry key. + + :return: + Returns the localized timezone string from tzres.dll if the string + is of the form `@tzres.dll,-offset`, else returns the input string. + """ + if not tzname_str.startswith('@'): + return tzname_str + + name_splt = tzname_str.split(',-') + try: + offset = int(name_splt[1]) + except: + raise ValueError("Malformed timezone string.") + + return self.load_name(offset) + + +class tzwinbase(tzrangebase): + """tzinfo class based on win32's timezones available in the registry.""" + def __init__(self): + raise NotImplementedError('tzwinbase is an abstract base class') + + def __eq__(self, other): + # Compare on all relevant dimensions, including name. + if not isinstance(other, tzwinbase): + return NotImplemented + + return (self._std_offset == other._std_offset and + self._dst_offset == other._dst_offset and + self._stddayofweek == other._stddayofweek and + self._dstdayofweek == other._dstdayofweek and + self._stdweeknumber == other._stdweeknumber and + self._dstweeknumber == other._dstweeknumber and + self._stdhour == other._stdhour and + self._dsthour == other._dsthour and + self._stdminute == other._stdminute and + self._dstminute == other._dstminute and + self._std_abbr == other._std_abbr and + self._dst_abbr == other._dst_abbr) + + @staticmethod + def list(): + """Return a list of all time zones known to the system.""" + with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle: + with winreg.OpenKey(handle, TZKEYNAME) as tzkey: + result = [winreg.EnumKey(tzkey, i) + for i in range(winreg.QueryInfoKey(tzkey)[0])] + return result + + def display(self): + """ + Return the display name of the time zone. + """ + return self._display + + def transitions(self, year): + """ + For a given year, get the DST on and off transition times, expressed + always on the standard time side. For zones with no transitions, this + function returns ``None``. + + :param year: + The year whose transitions you would like to query. + + :return: + Returns a :class:`tuple` of :class:`datetime.datetime` objects, + ``(dston, dstoff)`` for zones with an annual DST transition, or + ``None`` for fixed offset zones. + """ + + if not self.hasdst: + return None + + dston = picknthweekday(year, self._dstmonth, self._dstdayofweek, + self._dsthour, self._dstminute, + self._dstweeknumber) + + dstoff = picknthweekday(year, self._stdmonth, self._stddayofweek, + self._stdhour, self._stdminute, + self._stdweeknumber) + + # Ambiguous dates default to the STD side + dstoff -= self._dst_base_offset + + return dston, dstoff + + def _get_hasdst(self): + return self._dstmonth != 0 + + @property + def _dst_base_offset(self): + return self._dst_base_offset_ + + +class tzwin(tzwinbase): + """ + Time zone object created from the zone info in the Windows registry + + These are similar to :py:class:`dateutil.tz.tzrange` objects in that + the time zone data is provided in the format of a single offset rule + for either 0 or 2 time zone transitions per year. + + :param: name + The name of a Windows time zone key, e.g. "Eastern Standard Time". + The full list of keys can be retrieved with :func:`tzwin.list`. + """ + + def __init__(self, name): + self._name = name + + with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle: + tzkeyname = text_type("{kn}\\{name}").format(kn=TZKEYNAME, name=name) + with winreg.OpenKey(handle, tzkeyname) as tzkey: + keydict = valuestodict(tzkey) + + self._std_abbr = keydict["Std"] + self._dst_abbr = keydict["Dlt"] + + self._display = keydict["Display"] + + # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm + tup = struct.unpack("=3l16h", keydict["TZI"]) + stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 + dstoffset = stdoffset-tup[2] # + DaylightBias * -1 + self._std_offset = datetime.timedelta(minutes=stdoffset) + self._dst_offset = datetime.timedelta(minutes=dstoffset) + + # for the meaning see the win32 TIME_ZONE_INFORMATION structure docs + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx + (self._stdmonth, + self._stddayofweek, # Sunday = 0 + self._stdweeknumber, # Last = 5 + self._stdhour, + self._stdminute) = tup[4:9] + + (self._dstmonth, + self._dstdayofweek, # Sunday = 0 + self._dstweeknumber, # Last = 5 + self._dsthour, + self._dstminute) = tup[12:17] + + self._dst_base_offset_ = self._dst_offset - self._std_offset + self.hasdst = self._get_hasdst() + + def __repr__(self): + return "tzwin(%s)" % repr(self._name) + + def __reduce__(self): + return (self.__class__, (self._name,)) + + +class tzwinlocal(tzwinbase): + """ + Class representing the local time zone information in the Windows registry + + While :class:`dateutil.tz.tzlocal` makes system calls (via the :mod:`time` + module) to retrieve time zone information, ``tzwinlocal`` retrieves the + rules directly from the Windows registry and creates an object like + :class:`dateutil.tz.tzwin`. + + Because Windows does not have an equivalent of :func:`time.tzset`, on + Windows, :class:`dateutil.tz.tzlocal` instances will always reflect the + time zone settings *at the time that the process was started*, meaning + changes to the machine's time zone settings during the run of a program + on Windows will **not** be reflected by :class:`dateutil.tz.tzlocal`. + Because ``tzwinlocal`` reads the registry directly, it is unaffected by + this issue. + """ + def __init__(self): + with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle: + with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey: + keydict = valuestodict(tzlocalkey) + + self._std_abbr = keydict["StandardName"] + self._dst_abbr = keydict["DaylightName"] + + try: + tzkeyname = text_type('{kn}\\{sn}').format(kn=TZKEYNAME, + sn=self._std_abbr) + with winreg.OpenKey(handle, tzkeyname) as tzkey: + _keydict = valuestodict(tzkey) + self._display = _keydict["Display"] + except OSError: + self._display = None + + stdoffset = -keydict["Bias"]-keydict["StandardBias"] + dstoffset = stdoffset-keydict["DaylightBias"] + + self._std_offset = datetime.timedelta(minutes=stdoffset) + self._dst_offset = datetime.timedelta(minutes=dstoffset) + + # For reasons unclear, in this particular key, the day of week has been + # moved to the END of the SYSTEMTIME structure. + tup = struct.unpack("=8h", keydict["StandardStart"]) + + (self._stdmonth, + self._stdweeknumber, # Last = 5 + self._stdhour, + self._stdminute) = tup[1:5] + + self._stddayofweek = tup[7] + + tup = struct.unpack("=8h", keydict["DaylightStart"]) + + (self._dstmonth, + self._dstweeknumber, # Last = 5 + self._dsthour, + self._dstminute) = tup[1:5] + + self._dstdayofweek = tup[7] + + self._dst_base_offset_ = self._dst_offset - self._std_offset + self.hasdst = self._get_hasdst() + + def __repr__(self): + return "tzwinlocal()" + + def __str__(self): + # str will return the standard name, not the daylight name. + return "tzwinlocal(%s)" % repr(self._std_abbr) + + def __reduce__(self): + return (self.__class__, ()) + + +def picknthweekday(year, month, dayofweek, hour, minute, whichweek): + """ dayofweek == 0 means Sunday, whichweek 5 means last instance """ + first = datetime.datetime(year, month, 1, hour, minute) + + # This will work if dayofweek is ISO weekday (1-7) or Microsoft-style (0-6), + # Because 7 % 7 = 0 + weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7) + 1) + wd = weekdayone + ((whichweek - 1) * ONEWEEK) + if (wd.month != month): + wd -= ONEWEEK + + return wd + + +def valuestodict(key): + """Convert a registry key's values to a dictionary.""" + dout = {} + size = winreg.QueryInfoKey(key)[1] + tz_res = None + + for i in range(size): + key_name, value, dtype = winreg.EnumValue(key, i) + if dtype == winreg.REG_DWORD or dtype == winreg.REG_DWORD_LITTLE_ENDIAN: + # If it's a DWORD (32-bit integer), it's stored as unsigned - convert + # that to a proper signed integer + if value & (1 << 31): + value = value - (1 << 32) + elif dtype == winreg.REG_SZ: + # If it's a reference to the tzres DLL, load the actual string + if value.startswith('@tzres'): + tz_res = tz_res or tzres() + value = tz_res.name_from_string(value) + + value = value.rstrip('\x00') # Remove trailing nulls + + dout[key_name] = value + + return dout diff --git a/env/lib/python3.8/site-packages/dateutil/tzwin.py b/env/lib/python3.8/site-packages/dateutil/tzwin.py new file mode 100644 index 000000000..cebc673e4 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/tzwin.py @@ -0,0 +1,2 @@ +# tzwin has moved to dateutil.tz.win +from .tz.win import * diff --git a/env/lib/python3.8/site-packages/dateutil/utils.py b/env/lib/python3.8/site-packages/dateutil/utils.py new file mode 100644 index 000000000..44d9c9945 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/utils.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +""" +This module offers general convenience and utility functions for dealing with +datetimes. + +.. versionadded:: 2.7.0 +""" +from __future__ import unicode_literals + +from datetime import datetime, time + + +def today(tzinfo=None): + """ + Returns a :py:class:`datetime` representing the current day at midnight + + :param tzinfo: + The time zone to attach (also used to determine the current day). + + :return: + A :py:class:`datetime.datetime` object representing the current day + at midnight. + """ + + dt = datetime.now(tzinfo) + return datetime.combine(dt.date(), time(0, tzinfo=tzinfo)) + + +def default_tzinfo(dt, tzinfo): + """ + Sets the ``tzinfo`` parameter on naive datetimes only + + This is useful for example when you are provided a datetime that may have + either an implicit or explicit time zone, such as when parsing a time zone + string. + + .. doctest:: + + >>> from dateutil.tz import tzoffset + >>> from dateutil.parser import parse + >>> from dateutil.utils import default_tzinfo + >>> dflt_tz = tzoffset("EST", -18000) + >>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz)) + 2014-01-01 12:30:00+00:00 + >>> print(default_tzinfo(parse('2014-01-01 12:30'), dflt_tz)) + 2014-01-01 12:30:00-05:00 + + :param dt: + The datetime on which to replace the time zone + + :param tzinfo: + The :py:class:`datetime.tzinfo` subclass instance to assign to + ``dt`` if (and only if) it is naive. + + :return: + Returns an aware :py:class:`datetime.datetime`. + """ + if dt.tzinfo is not None: + return dt + else: + return dt.replace(tzinfo=tzinfo) + + +def within_delta(dt1, dt2, delta): + """ + Useful for comparing two datetimes that may a negilible difference + to be considered equal. + """ + delta = abs(delta) + difference = dt1 - dt2 + return -delta <= difference <= delta diff --git a/env/lib/python3.8/site-packages/dateutil/zoneinfo/__init__.py b/env/lib/python3.8/site-packages/dateutil/zoneinfo/__init__.py new file mode 100644 index 000000000..34f11ad66 --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/zoneinfo/__init__.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +import warnings +import json + +from tarfile import TarFile +from pkgutil import get_data +from io import BytesIO + +from dateutil.tz import tzfile as _tzfile + +__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"] + +ZONEFILENAME = "dateutil-zoneinfo.tar.gz" +METADATA_FN = 'METADATA' + + +class tzfile(_tzfile): + def __reduce__(self): + return (gettz, (self._filename,)) + + +def getzoneinfofile_stream(): + try: + return BytesIO(get_data(__name__, ZONEFILENAME)) + except IOError as e: # TODO switch to FileNotFoundError? + warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror)) + return None + + +class ZoneInfoFile(object): + def __init__(self, zonefile_stream=None): + if zonefile_stream is not None: + with TarFile.open(fileobj=zonefile_stream) as tf: + self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name) + for zf in tf.getmembers() + if zf.isfile() and zf.name != METADATA_FN} + # deal with links: They'll point to their parent object. Less + # waste of memory + links = {zl.name: self.zones[zl.linkname] + for zl in tf.getmembers() if + zl.islnk() or zl.issym()} + self.zones.update(links) + try: + metadata_json = tf.extractfile(tf.getmember(METADATA_FN)) + metadata_str = metadata_json.read().decode('UTF-8') + self.metadata = json.loads(metadata_str) + except KeyError: + # no metadata in tar file + self.metadata = None + else: + self.zones = {} + self.metadata = None + + def get(self, name, default=None): + """ + Wrapper for :func:`ZoneInfoFile.zones.get`. This is a convenience method + for retrieving zones from the zone dictionary. + + :param name: + The name of the zone to retrieve. (Generally IANA zone names) + + :param default: + The value to return in the event of a missing key. + + .. versionadded:: 2.6.0 + + """ + return self.zones.get(name, default) + + +# The current API has gettz as a module function, although in fact it taps into +# a stateful class. So as a workaround for now, without changing the API, we +# will create a new "global" class instance the first time a user requests a +# timezone. Ugly, but adheres to the api. +# +# TODO: Remove after deprecation period. +_CLASS_ZONE_INSTANCE = [] + + +def get_zonefile_instance(new_instance=False): + """ + This is a convenience function which provides a :class:`ZoneInfoFile` + instance using the data provided by the ``dateutil`` package. By default, it + caches a single instance of the ZoneInfoFile object and returns that. + + :param new_instance: + If ``True``, a new instance of :class:`ZoneInfoFile` is instantiated and + used as the cached instance for the next call. Otherwise, new instances + are created only as necessary. + + :return: + Returns a :class:`ZoneInfoFile` object. + + .. versionadded:: 2.6 + """ + if new_instance: + zif = None + else: + zif = getattr(get_zonefile_instance, '_cached_instance', None) + + if zif is None: + zif = ZoneInfoFile(getzoneinfofile_stream()) + + get_zonefile_instance._cached_instance = zif + + return zif + + +def gettz(name): + """ + This retrieves a time zone from the local zoneinfo tarball that is packaged + with dateutil. + + :param name: + An IANA-style time zone name, as found in the zoneinfo file. + + :return: + Returns a :class:`dateutil.tz.tzfile` time zone object. + + .. warning:: + It is generally inadvisable to use this function, and it is only + provided for API compatibility with earlier versions. This is *not* + equivalent to ``dateutil.tz.gettz()``, which selects an appropriate + time zone based on the inputs, favoring system zoneinfo. This is ONLY + for accessing the dateutil-specific zoneinfo (which may be out of + date compared to the system zoneinfo). + + .. deprecated:: 2.6 + If you need to use a specific zoneinfofile over the system zoneinfo, + instantiate a :class:`dateutil.zoneinfo.ZoneInfoFile` object and call + :func:`dateutil.zoneinfo.ZoneInfoFile.get(name)` instead. + + Use :func:`get_zonefile_instance` to retrieve an instance of the + dateutil-provided zoneinfo. + """ + warnings.warn("zoneinfo.gettz() will be removed in future versions, " + "to use the dateutil-provided zoneinfo files, instantiate a " + "ZoneInfoFile object and use ZoneInfoFile.zones.get() " + "instead. See the documentation for details.", + DeprecationWarning) + + if len(_CLASS_ZONE_INSTANCE) == 0: + _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream())) + return _CLASS_ZONE_INSTANCE[0].zones.get(name) + + +def gettz_db_metadata(): + """ Get the zonefile metadata + + See `zonefile_metadata`_ + + :returns: + A dictionary with the database metadata + + .. deprecated:: 2.6 + See deprecation warning in :func:`zoneinfo.gettz`. To get metadata, + query the attribute ``zoneinfo.ZoneInfoFile.metadata``. + """ + warnings.warn("zoneinfo.gettz_db_metadata() will be removed in future " + "versions, to use the dateutil-provided zoneinfo files, " + "ZoneInfoFile object and query the 'metadata' attribute " + "instead. See the documentation for details.", + DeprecationWarning) + + if len(_CLASS_ZONE_INSTANCE) == 0: + _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream())) + return _CLASS_ZONE_INSTANCE[0].metadata diff --git a/env/lib/python3.8/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz b/env/lib/python3.8/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..89e83517b562451622cea7cbe1dbfac5c3d2513e GIT binary patch literal 153315 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%0D!KtMVr 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

yja~WxFc`yfrj%BE^ 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%0Ay}5phF%Yq4Q1qkIf-;CS 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 a$1xo%1ox9%9ceNF__ldZ2ky8&yz@WAsp(Gu literal 0 HcmV?d00001 diff --git a/env/lib/python3.8/site-packages/dateutil/zoneinfo/rebuild.py b/env/lib/python3.8/site-packages/dateutil/zoneinfo/rebuild.py new file mode 100644 index 000000000..78f0d1a0c --- /dev/null +++ b/env/lib/python3.8/site-packages/dateutil/zoneinfo/rebuild.py @@ -0,0 +1,53 @@ +import logging +import os +import tempfile +import shutil +import json +from subprocess import check_call +from tarfile import TarFile + +from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME + + +def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None): + """Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar* + + filename is the timezone tarball from ``ftp.iana.org/tz``. + + """ + tmpdir = tempfile.mkdtemp() + zonedir = os.path.join(tmpdir, "zoneinfo") + moduledir = os.path.dirname(__file__) + try: + with TarFile.open(filename) as tf: + for name in zonegroups: + tf.extract(name, tmpdir) + filepaths = [os.path.join(tmpdir, n) for n in zonegroups] + try: + check_call(["zic", "-d", zonedir] + filepaths) + except OSError as e: + _print_on_nosuchfile(e) + raise + # write metadata file + with open(os.path.join(zonedir, METADATA_FN), 'w') as f: + json.dump(metadata, f, indent=4, sort_keys=True) + target = os.path.join(moduledir, ZONEFILENAME) + with TarFile.open(target, "w:%s" % format) as tf: + for entry in os.listdir(zonedir): + entrypath = os.path.join(zonedir, entry) + tf.add(entrypath, entry) + finally: + shutil.rmtree(tmpdir) + + +def _print_on_nosuchfile(e): + """Print helpful troubleshooting message + + e is an exception raised by subprocess.check_call() + + """ + if e.errno == 2: + logging.error( + "Could not find zic. Perhaps you need to install " + "libc-bin or some other package that provides it, " + "or it's not in your PATH?") diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/COPYING.txt b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/COPYING.txt new file mode 100644 index 000000000..bfc893787 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/COPYING.txt @@ -0,0 +1,137 @@ +================== + Copying Docutils +================== + +:Author: David Goodger +:Contact: goodger@python.org +:Date: $Date: 2015-05-08 17:56:32 +0200 (Fr, 08. Mai 2015) $ +:Web site: http://docutils.sourceforge.net/ +:Copyright: This document has been placed in the public domain. + +Most of the files included in this project have been placed in the +public domain, and therefore have no license requirements and no +restrictions on copying or usage; see the `Public Domain Dedication`_ +below. There are a few exceptions_, listed below. +Files in the Sandbox_ are not distributed with Docutils releases and +may have different license terms. + + +Public Domain Dedication +======================== + +The persons who have associated their work with this project (the +"Dedicator": David Goodger and the many contributors to the Docutils +project) hereby dedicate the entire copyright, less the exceptions_ +listed below, in the work of authorship known as "Docutils" identified +below (the "Work") to the public domain. + +The primary repository for the Work is the Internet World Wide Web +site . The Work consists of the +files within the "docutils" module of the Docutils project Subversion +repository (Internet host docutils.svn.sourceforge.net, filesystem path +/svnroot/docutils), whose Internet web interface is located at +. Files dedicated to the +public domain may be identified by the inclusion, near the beginning +of each file, of a declaration of the form:: + + Copyright: This document/module/DTD/stylesheet/file/etc. has been + placed in the public domain. + +Dedicator makes this dedication for the benefit of the public at large +and to the detriment of Dedicator's heirs and successors. Dedicator +intends this dedication to be an overt act of relinquishment in +perpetuity of all present and future rights under copyright law, +whether vested or contingent, in the Work. Dedicator understands that +such relinquishment of all rights includes the relinquishment of all +rights to enforce (by lawsuit or otherwise) those copyrights in the +Work. + +Dedicator recognizes that, once placed in the public domain, the Work +may be freely reproduced, distributed, transmitted, used, modified, +built upon, or otherwise exploited by anyone for any purpose, +commercial or non-commercial, and in any way, including by methods +that have not yet been invented or conceived. + +(This dedication is derived from the text of the `Creative Commons +Public Domain Dedication`. [#]_) + +.. [#] Creative Commons has `retired this legal tool`__ and does not + recommend that it be applied to works: This tool is based on United + States law and may not be applicable outside the US. For dedicating new + works to the public domain, Creative Commons recommend the replacement + Public Domain Dedication CC0_ (CC zero, "No Rights Reserved"). So does + the Free Software Foundation in its license-list_. + + __ http://creativecommons.org/retiredlicenses + .. _CC0: http://creativecommons.org/about/cc0 + +Exceptions +========== + +The exceptions to the `Public Domain Dedication`_ above are: + +* docutils/writers/s5_html/themes/default/iepngfix.htc: + + IE5.5+ PNG Alpha Fix v1.0 by Angus Turnbull + . Free usage permitted as long as + this notice remains intact. + +* docutils/utils/math/__init__.py, + docutils/utils/math/latex2mathml.py, + docutils/writers/xetex/__init__.py, + docutils/writers/latex2e/docutils-05-compat.sty, + docs/user/docutils-05-compat.sty.txt, + docutils/utils/error_reporting.py, + docutils/test/transforms/test_smartquotes.py: + + Copyright © Günter Milde. + Released under the terms of the `2-Clause BSD license`_ + (`local copy `__). + +* docutils/utils/smartquotes.py + + Copyright © 2011 Günter Milde, + based on `SmartyPants`_ © 2003 John Gruber + (released under a 3-Clause BSD license included in the file) + and smartypants.py © 2004, 2007 Chad Miller. + Released under the terms of the `2-Clause BSD license`_ + (`local copy `__). + + .. _SmartyPants: http://daringfireball.net/projects/smartypants/ + +* docutils/utils/math/math2html.py, + docutils/writers/html4css1/math.css + + Copyright © Alex Fernández + These files are part of eLyXer_, released under the `GNU + General Public License`_ version 3 or later. The author relicensed + them for Docutils under the terms of the `2-Clause BSD license`_ + (`local copy `__). + + .. _eLyXer: http://www.nongnu.org/elyxer/ + +* docutils/utils/roman.py, copyright by Mark Pilgrim, released under the + `Python 2.1.1 license`_ (`local copy`__). + + __ licenses/python-2-1-1.txt + +* tools/editors/emacs/rst.el, copyright by Free Software Foundation, + Inc., released under the `GNU General Public License`_ version 3 or + later (`local copy`__). + + __ licenses/gpl-3-0.txt + +The `2-Clause BSD license`_ and the Python licenses are OSI-approved_ +and GPL-compatible_. + +Plaintext versions of all the linked-to licenses are provided in the +licenses_ directory. + +.. _sandbox: http://docutils.sourceforge.net/sandbox/README.html +.. _licenses: licenses/ +.. _Python 2.1.1 license: http://www.python.org/2.1.1/license.html +.. _GNU General Public License: http://www.gnu.org/copyleft/gpl.html +.. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause +.. _OSI-approved: http://opensource.org/licenses/ +.. _license-list: +.. _GPL-compatible: http://www.gnu.org/licenses/license-list.html diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/INSTALLER b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/METADATA b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/METADATA new file mode 100644 index 000000000..bac2ed6eb --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/METADATA @@ -0,0 +1,64 @@ +Metadata-Version: 2.1 +Name: docutils +Version: 0.16 +Summary: Docutils -- Python Documentation Utilities +Home-page: http://docutils.sourceforge.net/ +Author: David Goodger +Author-email: goodger@python.org +Maintainer: docutils-develop list +Maintainer-email: docutils-develop@lists.sourceforge.net +License: public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt) +Platform: OS-independent +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Intended Audience :: End Users/Desktop +Classifier: Intended Audience :: Other Audience +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: Public Domain +Classifier: License :: OSI Approved :: Python Software Foundation License +Classifier: License :: OSI Approved :: BSD License +Classifier: License :: OSI Approved :: GNU General Public License (GPL) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Topic :: Documentation +Classifier: Topic :: Software Development :: Documentation +Classifier: Topic :: Text Processing +Classifier: Natural Language :: English +Classifier: Natural Language :: Afrikaans +Classifier: Natural Language :: Catalan +Classifier: Natural Language :: Chinese (Simplified) +Classifier: Natural Language :: Chinese (Traditional) +Classifier: Natural Language :: Czech +Classifier: Natural Language :: Danish +Classifier: Natural Language :: Dutch +Classifier: Natural Language :: Esperanto +Classifier: Natural Language :: Finnish +Classifier: Natural Language :: French +Classifier: Natural Language :: Galician +Classifier: Natural Language :: German +Classifier: Natural Language :: Hebrew +Classifier: Natural Language :: Italian +Classifier: Natural Language :: Japanese +Classifier: Natural Language :: Korean +Classifier: Natural Language :: Latvian +Classifier: Natural Language :: Lithuanian +Classifier: Natural Language :: Persian +Classifier: Natural Language :: Polish +Classifier: Natural Language :: Portuguese (Brazilian) +Classifier: Natural Language :: Russian +Classifier: Natural Language :: Slovak +Classifier: Natural Language :: Spanish +Classifier: Natural Language :: Swedish +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + +Docutils is a modular system for processing documentation +into useful formats, such as HTML, XML, and LaTeX. For +input Docutils supports reStructuredText, an easy-to-read, +what-you-see-is-what-you-get plaintext markup syntax. + diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/RECORD b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/RECORD new file mode 100644 index 000000000..5b6e2f535 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/RECORD @@ -0,0 +1,332 @@ +../../../bin/__pycache__/rst2html.cpython-38.pyc,, +../../../bin/__pycache__/rst2html4.cpython-38.pyc,, +../../../bin/__pycache__/rst2html5.cpython-38.pyc,, +../../../bin/__pycache__/rst2latex.cpython-38.pyc,, +../../../bin/__pycache__/rst2man.cpython-38.pyc,, +../../../bin/__pycache__/rst2odt.cpython-38.pyc,, +../../../bin/__pycache__/rst2odt_prepstyles.cpython-38.pyc,, +../../../bin/__pycache__/rst2pseudoxml.cpython-38.pyc,, +../../../bin/__pycache__/rst2s5.cpython-38.pyc,, +../../../bin/__pycache__/rst2xetex.cpython-38.pyc,, +../../../bin/__pycache__/rst2xml.cpython-38.pyc,, +../../../bin/__pycache__/rstpep2html.cpython-38.pyc,, +../../../bin/rst2html.py,sha256=_ZSHNn9dmPKAx6L7qZ8XgfPAy3KZv5MNky6n_8V3xiI,584 +../../../bin/rst2html4.py,sha256=u5YWYGbe9xyegHW30S6gzVpAg8nTI9Xu_ZOeve5CbOo,704 +../../../bin/rst2html5.py,sha256=_r_cnR_zNKLHiLjSTXDkMBLZskLkxmrPt93InJbhkbA,1127 +../../../bin/rst2latex.py,sha256=nLGST5HE554VD4EbuhUn2_6kijGgDFcQgOMa4RrFngI,781 +../../../bin/rst2man.py,sha256=nPtkEv9P7LIoK8GJOeiA66yi1ApVM1gNOFdbOB0CIXM,589 +../../../bin/rst2odt.py,sha256=iH9HaLPbzEfJU599E2DvAW2n2py69TXfJDOIZEHRsyk,754 +../../../bin/rst2odt_prepstyles.py,sha256=B90_1J9aRI6eJlKTYYDiHGyFio8Dfmgli9vJmg9qXHs,1716 +../../../bin/rst2pseudoxml.py,sha256=9SwwDEOFNz3AqOSI4CEvhieDm_3TgTPN_3FDPz6b5ys,591 +../../../bin/rst2s5.py,sha256=zdT-5LNxruUZqMVe-Wjj1F-eXan9pLDBvxA1k38XRGw,627 +../../../bin/rst2xetex.py,sha256=SzPM2iz6wCAc8Ki3sEnhCq6318jTQziosToib4FIzEw,861 +../../../bin/rst2xml.py,sha256=MKbl4dkpIBjzh4GdITggzJpi-SMGoRaXdkbZs-yd05E,592 +../../../bin/rstpep2html.py,sha256=TlXeA4lyMxtICwwaEERXcrXTleXfwyQE5qbooZLtcSw,660 +docutils-0.16.dist-info/COPYING.txt,sha256=76DIWqmepbR4EkADGw0Cr1TXtVVMh60rK-qbpJD2Zj8,5538 +docutils-0.16.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +docutils-0.16.dist-info/METADATA,sha256=4IVnPgSLMJRQ5ZfIjKFlv0poher_Si1vM7QowzUC1dI,2749 +docutils-0.16.dist-info/RECORD,, +docutils-0.16.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110 +docutils-0.16.dist-info/top_level.txt,sha256=dPq3jQoxpMOEhrZ1tQh3_-9hqhdvOjUplSdSVDAc95A,9 +docutils/__init__.py,sha256=YIX4_xeGvPh3ZINoAqP1zx76lI2RCCEw39wbeigwYWU,7759 +docutils/__pycache__/__init__.cpython-38.pyc,, +docutils/__pycache__/core.cpython-38.pyc,, +docutils/__pycache__/examples.cpython-38.pyc,, +docutils/__pycache__/frontend.cpython-38.pyc,, +docutils/__pycache__/io.cpython-38.pyc,, +docutils/__pycache__/nodes.cpython-38.pyc,, +docutils/__pycache__/statemachine.cpython-38.pyc,, +docutils/core.py,sha256=PTD5CeE4Z42n5f9UJJUxXGBK27fRGQ5kanx5aMlZ5qA,29575 +docutils/examples.py,sha256=nlPe2PYXNvz5ZAVRu7xHHiV7qML7s-eyUu4Gun7j3SY,3959 +docutils/frontend.py,sha256=dxG9PqW_-snfcbR5S2vunCsUUwH1OTauqx0RJxnMPdQ,37086 +docutils/io.py,sha256=th8Zq_UUIWY27bDIB1sLMtYhdzBWE4qo4Gf9VEwL_gk,16765 +docutils/languages/__init__.py,sha256=oPqoleNr7_rp64XNjbg4gdL8owO_gLEZc1HWHKOA26k,1555 +docutils/languages/__pycache__/__init__.cpython-38.pyc,, +docutils/languages/__pycache__/af.cpython-38.pyc,, +docutils/languages/__pycache__/ca.cpython-38.pyc,, +docutils/languages/__pycache__/cs.cpython-38.pyc,, +docutils/languages/__pycache__/da.cpython-38.pyc,, +docutils/languages/__pycache__/de.cpython-38.pyc,, +docutils/languages/__pycache__/en.cpython-38.pyc,, +docutils/languages/__pycache__/eo.cpython-38.pyc,, +docutils/languages/__pycache__/es.cpython-38.pyc,, +docutils/languages/__pycache__/fa.cpython-38.pyc,, +docutils/languages/__pycache__/fi.cpython-38.pyc,, +docutils/languages/__pycache__/fr.cpython-38.pyc,, +docutils/languages/__pycache__/gl.cpython-38.pyc,, +docutils/languages/__pycache__/he.cpython-38.pyc,, +docutils/languages/__pycache__/it.cpython-38.pyc,, +docutils/languages/__pycache__/ja.cpython-38.pyc,, +docutils/languages/__pycache__/ko.cpython-38.pyc,, +docutils/languages/__pycache__/lt.cpython-38.pyc,, +docutils/languages/__pycache__/lv.cpython-38.pyc,, +docutils/languages/__pycache__/nl.cpython-38.pyc,, +docutils/languages/__pycache__/pl.cpython-38.pyc,, +docutils/languages/__pycache__/pt_br.cpython-38.pyc,, +docutils/languages/__pycache__/ru.cpython-38.pyc,, +docutils/languages/__pycache__/sk.cpython-38.pyc,, +docutils/languages/__pycache__/sv.cpython-38.pyc,, +docutils/languages/__pycache__/zh_cn.cpython-38.pyc,, +docutils/languages/__pycache__/zh_tw.cpython-38.pyc,, +docutils/languages/af.py,sha256=6wl-XbsF8wbSiBs5IORna4Lz-WPqnnye_6qr8Cbh_1c,1824 +docutils/languages/ca.py,sha256=7_XR5q5GEXaeI4O5ianMmdnjWY_sRQD1ynuRB_HxUok,1940 +docutils/languages/cs.py,sha256=GARzldc3tDZByhqf_R-cOh1QJDOrFvSJzqewRdWRNXw,1928 +docutils/languages/da.py,sha256=88ZPB6ppJPWqNsaFQKKAC1aEZVLYw13BFR44vecp4MU,1907 +docutils/languages/de.py,sha256=AQTUIl4j3x43kQi5800-lobZHsh06VOsrxfAjS5FHGM,1722 +docutils/languages/en.py,sha256=tWVrPr6593mIzFokX_4Hw1fC6ZWC8GPdgpc72jmQq1g,1848 +docutils/languages/eo.py,sha256=uGSGcjfeHFliqm-f9amMfsPIl3trHONYPXdGR_ybm8U,1948 +docutils/languages/es.py,sha256=nk0PUeVyjFEu_8cNJA9Llsdv-W3kKx-wgOeaYGllqgw,1962 +docutils/languages/fa.py,sha256=vsf5xJxJuzcPXyz8ad3Cuf9ntBoOND0zdhsE4dwJEjI,2044 +docutils/languages/fi.py,sha256=yrE6Zhs-LdknXCpf-WX15QACQ75DroMpET95r3JD_OM,2026 +docutils/languages/fr.py,sha256=FTaOYQQHvqFzkzuhbdFQPS7dPkcpGLUPMeStu0cjFGs,1893 +docutils/languages/gl.py,sha256=6Uoq9rYigieFN0-LeSgoRmB9_ROX60Oqul7faPROMYs,2040 +docutils/languages/he.py,sha256=BfiRLxQ5Y8pivYi7GbGQ5NJ-rEgUId9mstJR6YYkeAQ,2683 +docutils/languages/it.py,sha256=Z3eh86YrmB8aT_Dl56X7W2gqpJgYK0v0QnJ07hekXlM,1808 +docutils/languages/ja.py,sha256=VJc9fRk4H_OhD8wyx3-uGUay3qdqeAIHCZEF67EsMTQ,1942 +docutils/languages/ko.py,sha256=PsZlCPQ5uQsUC2Puk2POTDmTc83cJWOxHmLrnq3-s2U,1880 +docutils/languages/lt.py,sha256=Y1204UnrqJlvM1vyteckkrqkbU02dSvrnpHCB5b23oM,1940 +docutils/languages/lv.py,sha256=tEqF4ya9h4FznB-uiUKQnNLY2XDFRatxKt2evJPhsDM,1867 +docutils/languages/nl.py,sha256=3CjsGFeJgLZEw2xhHxAc4sYDKRW6ODUZsVyibjl7DmM,1865 +docutils/languages/pl.py,sha256=ImdSmS6l4SgZ7uEaWQR5_aLNmv4K5onOInEtinPqWJk,1900 +docutils/languages/pt_br.py,sha256=cW8OceiFMPzPICT6buhnjm3tvEEw4W1PG-GFC4MxhyI,1982 +docutils/languages/ru.py,sha256=AkDQVhcW4cbvP0je-z8UJafQ-s2Lwc-eAIqXGCFZzco,2155 +docutils/languages/sk.py,sha256=v4XMBxIx5d6zQY7ehjZdtgfUy9Hz999XdH9G9d7SxEc,1860 +docutils/languages/sv.py,sha256=yIVWV9He5dbCuMpegSDiuI75tD4GXm9VkN7ra0-xgMI,2103 +docutils/languages/zh_cn.py,sha256=kF2sokHa0Qr-3X45ZeWEb0mImZRlZpiX2TM6d9_GjpY,2026 +docutils/languages/zh_tw.py,sha256=Xwrbf8wSylyMwwaNH6xYeAjMrldiBbDB_LElv67hGPQ,2771 +docutils/nodes.py,sha256=RRwVFRtRtRUzbuoYIWkMoSBXBAfQ4Dc2Xtzvht7XwAY,81241 +docutils/parsers/__init__.py,sha256=aDrATsCPGo92zucFl_n2ludoFSfxOrmdF7U8oQV0uEQ,1584 +docutils/parsers/__pycache__/__init__.cpython-38.pyc,, +docutils/parsers/__pycache__/null.cpython-38.pyc,, +docutils/parsers/null.py,sha256=LtO7n-E6lNOs4mLXZ2SiShB3C630SoJ80ugd9fh1vXI,445 +docutils/parsers/rst/__init__.py,sha256=F6PQ5IyGtYcpxOi0YHekivCrob2iLQIn5JpaqTIME50,16208 +docutils/parsers/rst/__pycache__/__init__.cpython-38.pyc,, +docutils/parsers/rst/__pycache__/roles.cpython-38.pyc,, +docutils/parsers/rst/__pycache__/states.cpython-38.pyc,, +docutils/parsers/rst/__pycache__/tableparser.cpython-38.pyc,, +docutils/parsers/rst/directives/__init__.py,sha256=dk9-IEfhp-xsEcuEkW1PthgJYdkva87rMlAVMh8eRYs,14053 +docutils/parsers/rst/directives/__pycache__/__init__.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/admonitions.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/body.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/html.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/images.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/misc.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/parts.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/references.cpython-38.pyc,, +docutils/parsers/rst/directives/__pycache__/tables.cpython-38.pyc,, +docutils/parsers/rst/directives/admonitions.py,sha256=w38T7YfRc0isuF5qmaw-6wOQgHx9xGHJBqu_gDqQCdI,2413 +docutils/parsers/rst/directives/body.py,sha256=qkeqiZrbSbfd8bMxfSl1M0HJ_vCfZYg63HhUmdldpE0,9191 +docutils/parsers/rst/directives/html.py,sha256=CKHg2_lAFayH2DGoVD_t9--nNKVMh7aNuWmNTef7ffI,3235 +docutils/parsers/rst/directives/images.py,sha256=PthLb5pJJvltqvTLkQSOemWEzO_ZEQbjlbKBilZ03x0,6982 +docutils/parsers/rst/directives/misc.py,sha256=MVqSu3TutboCbNFLIXgJ8EXF2R8Z8K_k2nDJ73JY1_w,23872 +docutils/parsers/rst/directives/parts.py,sha256=Mx7y6BwTP1WAD_qnL-g0bjg1_O06NCXgqeYCPfP4JbI,4251 +docutils/parsers/rst/directives/references.py,sha256=1Y1yhe_O2PqLtQUSly-ny291nrQKJgQiO4Hu7Xew9Zo,831 +docutils/parsers/rst/directives/tables.py,sha256=QjxFrNMHdH6rgyIiqBcbVqWvy8ousjy5k6ZeDKeZh8s,22815 +docutils/parsers/rst/include/README.txt,sha256=_C6pSfeGShQ0evvKKKZUtx4bP4RFG9UoUlgHoMn06DU,666 +docutils/parsers/rst/include/isoamsa.txt,sha256=CioOAjUSuL_MG2JHqVHst0ceHzF0v3kupB6stgPMD2g,10925 +docutils/parsers/rst/include/isoamsb.txt,sha256=pSD9D42IRcGBcjYXrJUBFicIA7KRtfBhCKnFlJiytC0,7242 +docutils/parsers/rst/include/isoamsc.txt,sha256=wC2J-pHkHJMokFfOg6S5_6TX1LcibltUpLMWkm-OT3U,1723 +docutils/parsers/rst/include/isoamsn.txt,sha256=LPorblUlj9fua5tpigH-lAfqPYj_yXWQiOa91CpBD7w,6721 +docutils/parsers/rst/include/isoamso.txt,sha256=3CB6lhSNhRIAY-ST8hGPRrO-6wxI2jhYnWTU1_uBXyY,3825 +docutils/parsers/rst/include/isoamsr.txt,sha256=3qVvk1ueHuE6jnHp8ypn6UWtZH5Ly2njNDj09Xeh2qU,11763 +docutils/parsers/rst/include/isobox.txt,sha256=tYnVIj92mJ5jiY8H9-S3CzBprjU8scuJZ8BO_eWEdwc,3101 +docutils/parsers/rst/include/isocyr1.txt,sha256=-V1dpOyKxXBzNBxcW7IJp1W-SIkaXd0KVm8TP58a5B8,4241 +docutils/parsers/rst/include/isocyr2.txt,sha256=3pDslLms3yuJgQTcWtu8U1FMrMQ4KgxtDT18Ci6Mvz4,1882 +docutils/parsers/rst/include/isodia.txt,sha256=-qThXeZ-WFGztOuu_koRrlvDJpSkMVB4ivU9yyE2y7Y,869 +docutils/parsers/rst/include/isogrk1.txt,sha256=xnCDDphWarsNmum9SQRvntznPx7m547rRRuQs7PdYpQ,3010 +docutils/parsers/rst/include/isogrk2.txt,sha256=zbi3-LuRB6T0jGj_yffmgm_8_mwz-6ygAYvgie32ls0,1705 +docutils/parsers/rst/include/isogrk3.txt,sha256=X8fGxnVIG1ygvvc9hpYgUHt1d8ANdD-gxn6aKWEaRf0,2880 +docutils/parsers/rst/include/isogrk4-wide.txt,sha256=rpweSoCmHEC1vL44LEeIE8Re2tm5FEAWnae6CO2oe1I,3035 +docutils/parsers/rst/include/isogrk4.txt,sha256=zptf_ntrFuMsuk0OhEjUkRwYrz0YGDuD-_6ReIHOunY,372 +docutils/parsers/rst/include/isolat1.txt,sha256=F5R0rnBefjAbqWFCkWMFpxVKWoSec8VM0KU8DRtMCYI,4397 +docutils/parsers/rst/include/isolat2.txt,sha256=YBBbW3o9HD1JHV3QVfpaFeKnRsh2vPs0dNvpTJSEoSU,8466 +docutils/parsers/rst/include/isomfrk-wide.txt,sha256=EtzR0nFzhkCmf8CKR4hLWSAgbUjHs4sYfpJEyDp8CjY,3334 +docutils/parsers/rst/include/isomfrk.txt,sha256=zZy3M5BmklzpL02dImsAuWA1jVw7nxqx3xyZLKtILfA,519 +docutils/parsers/rst/include/isomopf-wide.txt,sha256=QUhEHzhyuCM3qzrqG5luXuL28Uoqt7I7v-CfzToG8sI,1931 +docutils/parsers/rst/include/isomopf.txt,sha256=MGuLb8WfrDm7GWvdmvYHsWtrWyh6MqRRo7wnpiaia0U,639 +docutils/parsers/rst/include/isomscr-wide.txt,sha256=VHq8miDC5nKS6Rlvv9aWpS1D_naXcfZd1CsEpJ2W8-g,3231 +docutils/parsers/rst/include/isomscr.txt,sha256=WvB9Zek3TqSyIDfw5QmE_uTvXNwjBpYU0EQttckdLJo,776 +docutils/parsers/rst/include/isonum.txt,sha256=DHWd87O6CCaSz10PEGZOxLqpDLHiMZ6--0VR9o0Yt-Q,4066 +docutils/parsers/rst/include/isopub.txt,sha256=oULMcx0Ugjk6EZAMcxHZpZM_MC7kNuzecu-sMAHVZro,4613 +docutils/parsers/rst/include/isotech.txt,sha256=h6z4dEMoVtarA9E489Zru1H29c01hWWGqbfD3wgUmiM,9726 +docutils/parsers/rst/include/mmlalias.txt,sha256=YxSvNJVNsrzgIGNjtAjtx2tVXUuby5twMZxr5Mq3PJo,45428 +docutils/parsers/rst/include/mmlextra-wide.txt,sha256=KKNjVkG-xHbeCagQfQDotJxY5oF6S6Bmk60bEv49NUQ,9010 +docutils/parsers/rst/include/mmlextra.txt,sha256=Y50tQh0fLYClCc0DUVrxr2loU5u5YaUaYbFc9PEya_c,6800 +docutils/parsers/rst/include/s5defs.txt,sha256=_5JOMpDtaufiZbdxh6QKpICqLvGpB9cypHM-SEt3sKA,1036 +docutils/parsers/rst/include/xhtml1-lat1.txt,sha256=-cEYtq3oOOoLQS6n2KmsAcIs3Y5s78mToBkUXuSrSKA,6112 +docutils/parsers/rst/include/xhtml1-special.txt,sha256=dVNILahp_Jkf0bQVX-gGFcQXst3oR-FvQmAt6lDSTpE,1945 +docutils/parsers/rst/include/xhtml1-symbol.txt,sha256=K-f7hr-LRv1NKOxjZtckBmtMQOiddlnJJ-6DG-YoAzI,7028 +docutils/parsers/rst/languages/__init__.py,sha256=sOTYRqWClRSCBOO1I46Z8-WYDJPgWtqwwqt9iIKXpls,1014 +docutils/parsers/rst/languages/__pycache__/__init__.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/af.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/ca.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/cs.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/da.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/de.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/en.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/eo.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/es.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/fa.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/fi.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/fr.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/gl.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/he.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/it.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/ja.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/ko.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/lt.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/lv.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/nl.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/pl.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/pt_br.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/ru.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/sk.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/sv.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/zh_cn.cpython-38.pyc,, +docutils/parsers/rst/languages/__pycache__/zh_tw.cpython-38.pyc,, +docutils/parsers/rst/languages/af.py,sha256=CKdMjiS3nx4yNRrzeuwCoT0XeeQmHm2_O8U34BZns7s,3677 +docutils/parsers/rst/languages/ca.py,sha256=7eAACvO9Dpnqujsc3BJZQktHk1RDjmwf4LeEvkV_66o,4467 +docutils/parsers/rst/languages/cs.py,sha256=7g4NgLXvV5RP7oOqQT_TM033xW48mDQVoGGHhKSwZ8I,4857 +docutils/parsers/rst/languages/da.py,sha256=u9zvTSVuqJBQ-KKlcZmi4SMAp_kQXNS6ZsHBEiVmXjY,3765 +docutils/parsers/rst/languages/de.py,sha256=wiBjwHBDmiDIRs9gTtpI63VTyp7zqds5DWy9Kdw9Ntg,3464 +docutils/parsers/rst/languages/en.py,sha256=z_J8xJ1gBTk5MX6u_bonFGoop_e8VF6jWgq9Tzl5gNY,3317 +docutils/parsers/rst/languages/eo.py,sha256=q0025TiEuSZ_8VGZz2n86ZK4o6GVTdus1HBgdxAgz0A,3898 +docutils/parsers/rst/languages/es.py,sha256=vranS55noGU_pSC0f7uyJ12szSoxMKgRJuEK-DQfhpk,4261 +docutils/parsers/rst/languages/fa.py,sha256=XWeO9UdNGKbHWpcsAhEOgBvuLMGxjQ76I5ed7i2szPw,3430 +docutils/parsers/rst/languages/fi.py,sha256=CiWQxGOSnLA05yONUB0tqsnv4IPCbvfPYU7obKRo-kU,3661 +docutils/parsers/rst/languages/fr.py,sha256=42D2mXBLYl1Vc7KnVGi-CFQbhe_DTEIpT26_f3gWknI,3709 +docutils/parsers/rst/languages/gl.py,sha256=48NwM1CfNZOfmSYkqfhUsAww2292kZLPlt_Ty5sGzxE,3711 +docutils/parsers/rst/languages/he.py,sha256=go2_5QONLkGd4KS7ZIBur2vP04GUlN95XnOTizfwZOc,3640 +docutils/parsers/rst/languages/it.py,sha256=ihEL_NivtrckGnU6dT_kTmOrafmPUIC7-e6KMUJ_y2Q,3270 +docutils/parsers/rst/languages/ja.py,sha256=jaRnNN5sTXciz9O9_-kl7rlrScCJC12S3msQWPg5yH0,3863 +docutils/parsers/rst/languages/ko.py,sha256=4cZFij5pbqx_RgKvwg_10TMMARQ9LR_edvLqlLmZbwE,3449 +docutils/parsers/rst/languages/lt.py,sha256=RWSEyHddq14wvtuIbDxRT-JnPuRh8Gk33hOHh5BEXFI,3584 +docutils/parsers/rst/languages/lv.py,sha256=OfnTo1Si1V1E_7yNAwkyQMe6y07FsOA_F-1H2Fb6vIU,3381 +docutils/parsers/rst/languages/nl.py,sha256=2yKY36FtTEkRl-YjBOm9KtLTQR8nTIGT5ORt1qhcWQk,3708 +docutils/parsers/rst/languages/pl.py,sha256=RsEunaFFi6fiko9CZrVTyWTS7MbEuJLd0eAC5EOWWWo,3427 +docutils/parsers/rst/languages/pt_br.py,sha256=wDfQWhP_ZikrL3o9T4SjyfhRmCg8Y9uIS6FnUrTASkw,3992 +docutils/parsers/rst/languages/ru.py,sha256=abw64X77S-WFpIhbbn2v_YzzjphGyjqbMhaQjnLL1N0,3306 +docutils/parsers/rst/languages/sk.py,sha256=dhy_kVHdIVSFW9aBnNBU3YTXstouhmeOMHzZsBQ7vfU,3979 +docutils/parsers/rst/languages/sv.py,sha256=S8vtO81rSQTvAV4rzrzP7XQ1Hg894gtjjlqJ8FcPRf8,3331 +docutils/parsers/rst/languages/zh_cn.py,sha256=6FyYegjPnIFguqQhR9cBu5xxlrkRszNQHWGXEByF05M,4007 +docutils/parsers/rst/languages/zh_tw.py,sha256=PswlAgKcAMvgQB2jbp1hDCpzG63ZfxgBwlJviK8KRHM,5172 +docutils/parsers/rst/roles.py,sha256=o7thTCx0_1-pMkdYseZt5UaYf6RK646ZzhkuRFAePhQ,14944 +docutils/parsers/rst/states.py,sha256=S80k_XG5kA9PNwQh9dlI-JLVDpuRMwObIvPhNxMaQ04,132111 +docutils/parsers/rst/tableparser.py,sha256=Zbvt0mR6LJYeiMR495xe0dgqlK43HK9JjIw20PvcqdM,21001 +docutils/readers/__init__.py,sha256=5alRbkyRVbNkq8njp1egI_OnGyXkxQBwMGa9MbxAoD4,3456 +docutils/readers/__pycache__/__init__.cpython-38.pyc,, +docutils/readers/__pycache__/doctree.cpython-38.pyc,, +docutils/readers/__pycache__/pep.cpython-38.pyc,, +docutils/readers/__pycache__/standalone.cpython-38.pyc,, +docutils/readers/doctree.py,sha256=9QNTk_8x46sDkcSjzQiyFZxN-m9CBO3XA5bLar7OA0Q,1607 +docutils/readers/pep.py,sha256=V9b6SUQ_h74KK11wq5k2icEPGWQuVDG5gCzhWlJdF3Y,1555 +docutils/readers/standalone.py,sha256=6kRgqKD_REEZ_zZE5AW0rLj_rqOhisubS2ADyLjOAJQ,2340 +docutils/statemachine.py,sha256=zneRqVNxZaSKK7RGag5QrlbCSAkuphG4qlZXu7CeEXw,57663 +docutils/transforms/__init__.py,sha256=KZ2cNaA87oQNs6Yi_UK2A3V3mUZz4AbZlzaCD-2fFnY,6504 +docutils/transforms/__pycache__/__init__.cpython-38.pyc,, +docutils/transforms/__pycache__/components.cpython-38.pyc,, +docutils/transforms/__pycache__/frontmatter.cpython-38.pyc,, +docutils/transforms/__pycache__/misc.cpython-38.pyc,, +docutils/transforms/__pycache__/parts.cpython-38.pyc,, +docutils/transforms/__pycache__/peps.cpython-38.pyc,, +docutils/transforms/__pycache__/references.cpython-38.pyc,, +docutils/transforms/__pycache__/universal.cpython-38.pyc,, +docutils/transforms/__pycache__/writer_aux.cpython-38.pyc,, +docutils/transforms/components.py,sha256=F0fXyOZsf_OA0QsX-jIAsk3RLCrkEW9GRR1-l0Nx13o,1993 +docutils/transforms/frontmatter.py,sha256=ooKzVho4qdgnkDqbjLql6AauIbJ8vHglQPnv3W4BEFU,20167 +docutils/transforms/misc.py,sha256=0jDAIndz8a7C5TVWLkC44N1pVfhwZu4nu-lnk1GmzGg,4882 +docutils/transforms/parts.py,sha256=jxs_CsaBH7uyvtCrxZqHQynLj4ktKax-_4d2xVDNNFs,6997 +docutils/transforms/peps.py,sha256=NdXwjk5gvzuzWDXred5OEbpPIDn2bWxECrBkYC_gF10,11056 +docutils/transforms/references.py,sha256=3094yQhcQa84BzcX1zjKTK7UGMjhOYejvwcv_8k7WZw,36478 +docutils/transforms/universal.py,sha256=tRcngG0usTWzQESOKqJeO4VCi3KlHzoUxHBw5ZJ_ljM,11380 +docutils/transforms/writer_aux.py,sha256=4Zd8z8s4jTG2J0xSnm5hj1kiZrKN6FqvGvpJ1cb09oU,2609 +docutils/utils/__init__.py,sha256=5VaDEvT45RFBaJvB_g5zbMilxQopc3hOMUa0SI0CRoY,28767 +docutils/utils/__pycache__/__init__.cpython-38.pyc,, +docutils/utils/__pycache__/code_analyzer.cpython-38.pyc,, +docutils/utils/__pycache__/error_reporting.cpython-38.pyc,, +docutils/utils/__pycache__/punctuation_chars.cpython-38.pyc,, +docutils/utils/__pycache__/roman.cpython-38.pyc,, +docutils/utils/__pycache__/smartquotes.cpython-38.pyc,, +docutils/utils/__pycache__/urischemes.cpython-38.pyc,, +docutils/utils/code_analyzer.py,sha256=wdT6BK7wcyYs13lu24KamEmXqRYi0fZgQBJCwE39ff0,5166 +docutils/utils/error_reporting.py,sha256=R0ViAzmz8GWr3Eayu51l6m9kCivbaJLCIf4NOiSPvqk,8460 +docutils/utils/math/__init__.py,sha256=TUGMP6ytwBzbQCHrFSxSl8OcDdbLGfCCkGteBdWm6l0,1755 +docutils/utils/math/__pycache__/__init__.cpython-38.pyc,, +docutils/utils/math/__pycache__/latex2mathml.cpython-38.pyc,, +docutils/utils/math/__pycache__/math2html.cpython-38.pyc,, +docutils/utils/math/__pycache__/tex2mathml_extern.cpython-38.pyc,, +docutils/utils/math/__pycache__/tex2unichar.cpython-38.pyc,, +docutils/utils/math/__pycache__/unichar2tex.cpython-38.pyc,, +docutils/utils/math/latex2mathml.py,sha256=JO-79izteHloIWN33QIhg3v-8cbI_kWGwvfQ32tbarc,17456 +docutils/utils/math/math2html.py,sha256=ibVwl7RbG2F--iwVVDhGoEqxnKj552Y-HYm7TybzREQ,184696 +docutils/utils/math/tex2mathml_extern.py,sha256=Zx-47MMnzGnbP9YLu_Yc6KM7dcuSgzJPfKZy_i0gj5I,5656 +docutils/utils/math/tex2unichar.py,sha256=0tXV29tatGECc6zDV78yvx-6vc5npfO1GukZrzbI5ps,35109 +docutils/utils/math/unichar2tex.py,sha256=pQsCi50-vC7hbl0DsfHEK5Xn9jhHOAOtG6D0tTWGAAY,17590 +docutils/utils/punctuation_chars.py,sha256=UPAtrr1Om1cJ0l3JpNLvnuNryfR8ybXNvOJNriO7PW0,6426 +docutils/utils/roman.py,sha256=nJRHm0rTPqrKFrwJNwOM8ywKIy81DKvAlXPdnOsefIU,2688 +docutils/utils/smartquotes.py,sha256=DuVPLCPUnn1Q_TPn0PzNLRTonSPPNOTgWbo1cc1kQY4,40050 +docutils/utils/urischemes.py,sha256=_wNIoSw8D_Ch4dLGMZmCTceF4mT6jnodFK_H2HDSRLA,6272 +docutils/writers/__init__.py,sha256=ybRAHTZrV29u5zCFTbAcQvh6ZZDRgQqliRn4cPMiVzw,4593 +docutils/writers/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/__pycache__/_html_base.cpython-38.pyc,, +docutils/writers/__pycache__/docutils_xml.cpython-38.pyc,, +docutils/writers/__pycache__/manpage.cpython-38.pyc,, +docutils/writers/__pycache__/null.cpython-38.pyc,, +docutils/writers/__pycache__/pseudoxml.cpython-38.pyc,, +docutils/writers/_html_base.py,sha256=h30bM3-CdDeK-lF1DM3-M1b_-4n7rAjl1N0VP_CRXpE,63552 +docutils/writers/docutils_xml.py,sha256=P8A8o8YnEZQXmHQrXF-D3vXCm29RZE185Fvd_sJWIXg,7134 +docutils/writers/html4css1/__init__.py,sha256=fFw4DkEEIZmPM8B90Gw15raeupFCQZ2dw61gMS4LV9k,33839 +docutils/writers/html4css1/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/html4css1/html4css1.css,sha256=BvqQaXs-bQ6Vx7TVsdXxxLwoiQeXQ-Wn1z7ZXRXk_q8,7210 +docutils/writers/html4css1/template.txt,sha256=HDzUUyAv7gT4ewGQTqfOE2_9HOVyGu9-wCRgsmoCmjQ,114 +docutils/writers/html5_polyglot/__init__.py,sha256=c_rbVRHUFlPFl6tBKv95WoC1DPeDbqL-2vazhCCVJ3k,9612 +docutils/writers/html5_polyglot/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/html5_polyglot/math.css,sha256=hGjowMetSh3oAlkm7_EA2pTtkv_Lg_TgwrBkyNs85Co,4783 +docutils/writers/html5_polyglot/minimal.css,sha256=pdv3dDbMH9X4VQS0aQO3Ufqg1h-waHnNJ0lFeBsy2Bs,7468 +docutils/writers/html5_polyglot/plain.css,sha256=pHd4urXyhNsneZq1MHvnScLIsRhEdyoU9X52L7fF3gM,6939 +docutils/writers/html5_polyglot/template.txt,sha256=HDzUUyAv7gT4ewGQTqfOE2_9HOVyGu9-wCRgsmoCmjQ,114 +docutils/writers/latex2e/__init__.py,sha256=aBoY6-pndI5_6o1Afw-RF2jHIxhKe36ECDEbO4WY3RA,130375 +docutils/writers/latex2e/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/latex2e/default.tex,sha256=KQFojDUG6AFGSZFGWVsQCslQrWT5-JVB29idVWiRtUA,422 +docutils/writers/latex2e/titlepage.tex,sha256=wxPKr4rylqUamK2U0EJXQTaVQ1392ua5DtSVGDqrNsI,534 +docutils/writers/latex2e/xelatex.tex,sha256=oUEz2Ze3wpoMp0X0iVELcUGNtKVre5Ug5Ujge7OiMgU,672 +docutils/writers/manpage.py,sha256=FEM_KtyyY8PgAScTa5R7dXLKlGCJPLbsaapNoI1SORg,36148 +docutils/writers/null.py,sha256=zyIuah_o8SlqvgbOWLRG9chpeNKky0D13lOTtR1E73U,450 +docutils/writers/odf_odt/__init__.py,sha256=8mr-TC7zljTp_mUUL-tZNhCCS5lezfojN1yadSDRqjQ,133436 +docutils/writers/odf_odt/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/odf_odt/__pycache__/pygmentsformatter.cpython-38.pyc,, +docutils/writers/odf_odt/pygmentsformatter.py,sha256=iBsRNxRe-v378-whp_F8CwgvuK7Ck4o_Tx4Kae8NlYw,4671 +docutils/writers/odf_odt/styles.odt,sha256=xKv9z2sd1qNxAH28X-5st5JuDZeTw6jyDOxXohsFrKY,16500 +docutils/writers/pep_html/__init__.py,sha256=gOJnTxuKLtM-81wdjIFbH5GyTFLV9m1_ZOu7Lys_MZc,3558 +docutils/writers/pep_html/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/pep_html/pep.css,sha256=UbFfiHHFSWusk2rEv7AUaTCS0r6TxfMzgLtW0VURwGw,6367 +docutils/writers/pep_html/template.txt,sha256=CfyVCCoqqB3Y8hOyt7Uxf0XeyTwtFf926L_hJeaS1wU,1294 +docutils/writers/pseudoxml.py,sha256=2bRL9zMleW8jDuGaINvM52siZiJWH1-zQfEELJE2oPE,772 +docutils/writers/s5_html/__init__.py,sha256=MUczVy19slU_C6s1akdizatEvt5KPi72Bmj2f46r-IU,14688 +docutils/writers/s5_html/__pycache__/__init__.cpython-38.pyc,, +docutils/writers/s5_html/themes/README.txt,sha256=wsty9ouRFxVMrZV2EUTOmfMS_bJJpmA5CqU23fpMccM,301 +docutils/writers/s5_html/themes/big-black/__base__,sha256=WeKnChXCPkrXDs7Xr-Qnf1i-bgFjkeaKJ-ilXV0R5lM,38 +docutils/writers/s5_html/themes/big-black/framing.css,sha256=RctE4TbWO_ctWsmE1LSPdCVRMT1QFlTrNmQNKC4wC2Y,911 +docutils/writers/s5_html/themes/big-black/pretty.css,sha256=VFK99wlPllRBKK0eQ2Yk6RC_-VDMREm-ue2Mp3YMs7A,3606 +docutils/writers/s5_html/themes/big-white/framing.css,sha256=6M4vVFfoErc5LKtuol1RqnId0166VecGy6rYu9cPY9c,906 +docutils/writers/s5_html/themes/big-white/pretty.css,sha256=YO7dDIRq7dXpIdC8pEOf7QaBb9nUvajfWkkQpxt3nJs,3566 +docutils/writers/s5_html/themes/default/blank.gif,sha256=L1YbAqSTduNnms1ZdeN5Cr3_Cey636HhhYx7om4__O8,49 +docutils/writers/s5_html/themes/default/framing.css,sha256=fcGapNDqnTT2w-2HpWTHb5yf9Yq-_31DJuazk7lCSQw,1003 +docutils/writers/s5_html/themes/default/iepngfix.htc,sha256=ve7IwOG4pkjDmYItcuQrUbESmVaY6ACDhhA5YP9d73c,1190 +docutils/writers/s5_html/themes/default/opera.css,sha256=guPZOg_BINv-LjV9_IAM7ILFQ-fKALNjlP1i06e5dmA,261 +docutils/writers/s5_html/themes/default/outline.css,sha256=z3ACJiW3_gnG8XFvX602PMTYvKhbRybqCeoWl3O_pA0,648 +docutils/writers/s5_html/themes/default/pretty.css,sha256=dUbMlVTFGx3ofvXGUmhnKAADhBkHsdU0ysWpxwX-70M,4384 +docutils/writers/s5_html/themes/default/print.css,sha256=INhYRMsY7y2wd9p7tqjcDWBREXHUMO-2ApAWvITyetI,818 +docutils/writers/s5_html/themes/default/s5-core.css,sha256=MrHjKxQ7P7ZFC2FmEq2BnkRWs59YVzUS_ZOw8CHC2Jk,451 +docutils/writers/s5_html/themes/default/slides.css,sha256=VKYQ1Oe8lZ8LHxzPqJiU79J0z295nkmIbzsXL-N_dfQ,283 +docutils/writers/s5_html/themes/default/slides.js,sha256=n6_977F6UKSfpYSDu5RKhS1g7iehHcmxm1jDLD17ME4,15800 +docutils/writers/s5_html/themes/medium-black/__base__,sha256=822LJG-LrdBZY6CA7wsLFCFzsYfxbyz2mr1j6rpb1UA,41 +docutils/writers/s5_html/themes/medium-black/pretty.css,sha256=zoRP67Cmy7JzwnXqKe02GwGzt0p5z509ymlbaxXuPoI,4031 +docutils/writers/s5_html/themes/medium-white/framing.css,sha256=nstQg2Fwdm6TTRHflpYRE7Q3b2jFO5p6tyDXJhsmi0I,944 +docutils/writers/s5_html/themes/medium-white/pretty.css,sha256=SafUPS2T_uel8lPQlvouTXUrgT9QY52nxnBJDt_pmP4,3991 +docutils/writers/s5_html/themes/small-black/__base__,sha256=WmiB80z49RfMsy_7tFI042AfUgyztL5OXI3tap9EfQM,40 +docutils/writers/s5_html/themes/small-black/pretty.css,sha256=G_e83H9lIDHXtUBJRCnsnxSiAhP0zaAafQwSviioUQ8,4030 +docutils/writers/s5_html/themes/small-white/framing.css,sha256=klf55tsjjL7FuzlWi0yY_4bHJWZZhlD36VCevg45o70,941 +docutils/writers/s5_html/themes/small-white/pretty.css,sha256=yaLNE-loYn_nSCuzvGVJWHAbh90dxdO5I06Cv-d4wcM,4001 +docutils/writers/xetex/__init__.py,sha256=ROox1G2bCAOJoht_UttnqAVgFckavEXjlkpBpQj8LFc,5797 +docutils/writers/xetex/__pycache__/__init__.cpython-38.pyc,, diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/WHEEL b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/WHEEL new file mode 100644 index 000000000..78e6f69d1 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.4) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/env/lib/python3.8/site-packages/docutils-0.16.dist-info/top_level.txt b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/top_level.txt new file mode 100644 index 000000000..5492d7670 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils-0.16.dist-info/top_level.txt @@ -0,0 +1 @@ +docutils diff --git a/env/lib/python3.8/site-packages/docutils/__init__.py b/env/lib/python3.8/site-packages/docutils/__init__.py new file mode 100644 index 000000000..5bb65047d --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/__init__.py @@ -0,0 +1,233 @@ +# $Id: __init__.py 8453 2020-01-12 13:28:32Z grubert $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +This is the Docutils (Python Documentation Utilities) package. + +Package Structure +================= + +Modules: + +- __init__.py: Contains component base classes, exception classes, and + Docutils version information. + +- core.py: Contains the ``Publisher`` class and ``publish_*()`` convenience + functions. + +- frontend.py: Runtime settings (command-line interface, configuration files) + processing, for Docutils front-ends. + +- io.py: Provides a uniform API for low-level input and output. + +- nodes.py: Docutils document tree (doctree) node class library. + +- statemachine.py: A finite state machine specialized for + regular-expression-based text filters. + +Subpackages: + +- languages: Language-specific mappings of terms. + +- parsers: Syntax-specific input parser modules or packages. + +- readers: Context-specific input handlers which understand the data + source and manage a parser. + +- transforms: Modules used by readers and writers to modify DPS + doctrees. + +- utils: Contains the ``Reporter`` system warning class and miscellaneous + utilities used by readers, writers, and transforms. + + utils/urischemes.py: Contains a complete mapping of known URI addressing + scheme names to descriptions. + +- utils/math: Contains functions for conversion of mathematical notation + between different formats (LaTeX, MathML, text, ...). + +- writers: Format-specific output translators. +""" + +import sys +from collections import namedtuple + + +__docformat__ = 'reStructuredText' + +__version__ = '0.16' +"""Docutils version identifier (complies with PEP 440):: + + major.minor[.micro][releaselevel[serial]][.dev] + +For version comparison operations, use `__version_info__` (see, below) +rather than parsing the text of `__version__`. + +See 'Version Numbering' in docs/dev/policies.txt. +""" + +VersionInfo = namedtuple( + 'VersionInfo', 'major minor micro releaselevel serial release') + +__version_info__ = VersionInfo( + major=0, + minor=16, + micro=0, + releaselevel='final', # one of 'alpha', 'beta', 'candidate', 'final' + # pre-release serial number (0 for final releases and active development): + serial=0, + release=True # True for official releases and pre-releases + ) +"""Comprehensive version information tuple. See 'Version Numbering' in +docs/dev/policies.txt.""" + +__version_details__ = 'release' +"""Optional extra version details (e.g. 'snapshot 2005-05-29, r3410'). +(For development and release status see `__version_info__`.) +""" + + +class ApplicationError(Exception): pass + +class DataError(ApplicationError): pass + + +class SettingsSpec(object): + + """ + Runtime setting specification base class. + + SettingsSpec subclass objects used by `docutils.frontend.OptionParser`. + """ + + settings_spec = () + """Runtime settings specification. Override in subclasses. + + Defines runtime settings and associated command-line options, as used by + `docutils.frontend.OptionParser`. This is a tuple of: + + - Option group title (string or `None` which implies no group, just a list + of single options). + + - Description (string or `None`). + + - A sequence of option tuples. Each consists of: + + - Help text (string) + + - List of option strings (e.g. ``['-Q', '--quux']``). + + - Dictionary of keyword arguments sent to the OptionParser/OptionGroup + ``add_option`` method. + + Runtime setting names are derived implicitly from long option names + ('--a-setting' becomes ``settings.a_setting``) or explicitly from the + 'dest' keyword argument. + + Most settings will also have a 'validator' keyword & function. The + validator function validates setting values (from configuration files + and command-line option arguments) and converts them to appropriate + types. For example, the ``docutils.frontend.validate_boolean`` + function, **required by all boolean settings**, converts true values + ('1', 'on', 'yes', and 'true') to 1 and false values ('0', 'off', + 'no', 'false', and '') to 0. Validators need only be set once per + setting. See the `docutils.frontend.validate_*` functions. + + See the optparse docs for more details. + + - More triples of group title, description, options, as many times as + needed. Thus, `settings_spec` tuples can be simply concatenated. + """ + + settings_defaults = None + """A dictionary of defaults for settings not in `settings_spec` (internal + settings, intended to be inaccessible by command-line and config file). + Override in subclasses.""" + + settings_default_overrides = None + """A dictionary of auxiliary defaults, to override defaults for settings + defined in other components. Override in subclasses.""" + + relative_path_settings = () + """Settings containing filesystem paths. Override in subclasses. + Settings listed here are to be interpreted relative to the current working + directory.""" + + config_section = None + """The name of the config file section specific to this component + (lowercase, no brackets). Override in subclasses.""" + + config_section_dependencies = None + """A list of names of config file sections that are to be applied before + `config_section`, in order (from general to specific). In other words, + the settings in `config_section` are to be overlaid on top of the settings + from these sections. The "general" section is assumed implicitly. + Override in subclasses.""" + + +class TransformSpec: + + """ + Runtime transform specification base class. + + TransformSpec subclass objects used by `docutils.transforms.Transformer`. + """ + + def get_transforms(self): + """Transforms required by this class. Override in subclasses.""" + if self.default_transforms != (): + import warnings + warnings.warn('default_transforms attribute deprecated.\n' + 'Use get_transforms() method instead.', + DeprecationWarning) + return list(self.default_transforms) + return [] + + # Deprecated; for compatibility. + default_transforms = () + + unknown_reference_resolvers = () + """List of functions to try to resolve unknown references. Unknown + references have a 'refname' attribute which doesn't correspond to any + target in the document. Called when the transforms in + `docutils.tranforms.references` are unable to find a correct target. The + list should contain functions which will try to resolve unknown + references, with the following signature:: + + def reference_resolver(node): + '''Returns boolean: true if resolved, false if not.''' + + If the function is able to resolve the reference, it should also remove + the 'refname' attribute and mark the node as resolved:: + + del node['refname'] + node.resolved = 1 + + Each function must have a "priority" attribute which will affect the order + the unknown_reference_resolvers are run:: + + reference_resolver.priority = 100 + + Override in subclasses.""" + + +class Component(SettingsSpec, TransformSpec): + + """Base class for Docutils components.""" + + component_type = None + """Name of the component type ('reader', 'parser', 'writer'). Override in + subclasses.""" + + supported = () + """Names for this component. Override in subclasses.""" + + def supports(self, format): + """ + Is `format` supported by this component? + + To be used by transforms to ask the dependent component if it supports + a certain input context or output format. + """ + return format in self.supported diff --git a/env/lib/python3.8/site-packages/docutils/core.py b/env/lib/python3.8/site-packages/docutils/core.py new file mode 100644 index 000000000..940391b02 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/core.py @@ -0,0 +1,666 @@ +# $Id: core.py 8367 2019-08-27 12:09:56Z milde $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +Calling the ``publish_*`` convenience functions (or instantiating a +`Publisher` object) with component names will result in default +behavior. For custom behavior (setting component options), create +custom component objects first, and pass *them* to +``publish_*``/`Publisher`. See `The Docutils Publisher`_. + +.. _The Docutils Publisher: http://docutils.sf.net/docs/api/publisher.html +""" +from __future__ import print_function + +__docformat__ = 'reStructuredText' + +import sys +import pprint +from docutils import __version__, __version_details__, SettingsSpec +from docutils import frontend, io, utils, readers, writers +from docutils.frontend import OptionParser +from docutils.transforms import Transformer +from docutils.utils.error_reporting import ErrorOutput, ErrorString +import docutils.readers.doctree + +class Publisher(object): + + """ + A facade encapsulating the high-level logic of a Docutils system. + """ + + def __init__(self, reader=None, parser=None, writer=None, + source=None, source_class=io.FileInput, + destination=None, destination_class=io.FileOutput, + settings=None): + """ + Initial setup. If any of `reader`, `parser`, or `writer` are not + specified, the corresponding ``set_...`` method should be called with + a component name (`set_reader` sets the parser as well). + """ + + self.document = None + """The document tree (`docutils.nodes` objects).""" + + self.reader = reader + """A `docutils.readers.Reader` instance.""" + + self.parser = parser + """A `docutils.parsers.Parser` instance.""" + + self.writer = writer + """A `docutils.writers.Writer` instance.""" + + for component in 'reader', 'parser', 'writer': + assert not isinstance(getattr(self, component), str), ( + 'passed string "%s" as "%s" parameter; pass an instance, ' + 'or use the "%s_name" parameter instead (in ' + 'docutils.core.publish_* convenience functions).' + % (getattr(self, component), component, component)) + + self.source = source + """The source of input data, a `docutils.io.Input` instance.""" + + self.source_class = source_class + """The class for dynamically created source objects.""" + + self.destination = destination + """The destination for docutils output, a `docutils.io.Output` + instance.""" + + self.destination_class = destination_class + """The class for dynamically created destination objects.""" + + self.settings = settings + """An object containing Docutils settings as instance attributes. + Set by `self.process_command_line()` or `self.get_settings()`.""" + + self._stderr = ErrorOutput() + + def set_reader(self, reader_name, parser, parser_name): + """Set `self.reader` by name.""" + reader_class = readers.get_reader_class(reader_name) + self.reader = reader_class(parser, parser_name) + self.parser = self.reader.parser + + def set_writer(self, writer_name): + """Set `self.writer` by name.""" + writer_class = writers.get_writer_class(writer_name) + self.writer = writer_class() + + def set_components(self, reader_name, parser_name, writer_name): + if self.reader is None: + self.set_reader(reader_name, self.parser, parser_name) + if self.parser is None: + if self.reader.parser is None: + self.reader.set_parser(parser_name) + self.parser = self.reader.parser + if self.writer is None: + self.set_writer(writer_name) + + def setup_option_parser(self, usage=None, description=None, + settings_spec=None, config_section=None, + **defaults): + if config_section: + if not settings_spec: + settings_spec = SettingsSpec() + settings_spec.config_section = config_section + parts = config_section.split() + if len(parts) > 1 and parts[-1] == 'application': + settings_spec.config_section_dependencies = ['applications'] + #@@@ Add self.source & self.destination to components in future? + option_parser = OptionParser( + components=(self.parser, self.reader, self.writer, settings_spec), + defaults=defaults, read_config_files=True, + usage=usage, description=description) + return option_parser + + def get_settings(self, usage=None, description=None, + settings_spec=None, config_section=None, **defaults): + """ + Set and return default settings (overrides in `defaults` dict). + + Set components first (`self.set_reader` & `self.set_writer`). + Explicitly setting `self.settings` disables command line option + processing from `self.publish()`. + """ + option_parser = self.setup_option_parser( + usage, description, settings_spec, config_section, **defaults) + self.settings = option_parser.get_default_values() + return self.settings + + def process_programmatic_settings(self, settings_spec, + settings_overrides, + config_section): + if self.settings is None: + defaults = (settings_overrides or {}).copy() + # Propagate exceptions by default when used programmatically: + defaults.setdefault('traceback', True) + self.get_settings(settings_spec=settings_spec, + config_section=config_section, + **defaults) + + def process_command_line(self, argv=None, usage=None, description=None, + settings_spec=None, config_section=None, + **defaults): + """ + Pass an empty list to `argv` to avoid reading `sys.argv` (the + default). + + Set components first (`self.set_reader` & `self.set_writer`). + """ + option_parser = self.setup_option_parser( + usage, description, settings_spec, config_section, **defaults) + if argv is None: + argv = sys.argv[1:] + # converting to Unicode (Python 3 does this automatically): + if sys.version_info < (3, 0): + # TODO: make this failsafe and reversible? + argv_encoding = (frontend.locale_encoding or 'ascii') + argv = [a.decode(argv_encoding) for a in argv] + self.settings = option_parser.parse_args(argv) + + def set_io(self, source_path=None, destination_path=None): + if self.source is None: + self.set_source(source_path=source_path) + if self.destination is None: + self.set_destination(destination_path=destination_path) + + def set_source(self, source=None, source_path=None): + if source_path is None: + source_path = self.settings._source + else: + self.settings._source = source_path + # Raise IOError instead of system exit with `tracback == True` + # TODO: change io.FileInput's default behaviour and remove this hack + try: + self.source = self.source_class( + source=source, source_path=source_path, + encoding=self.settings.input_encoding) + except TypeError: + self.source = self.source_class( + source=source, source_path=source_path, + encoding=self.settings.input_encoding) + + def set_destination(self, destination=None, destination_path=None): + if destination_path is None: + destination_path = self.settings._destination + else: + self.settings._destination = destination_path + self.destination = self.destination_class( + destination=destination, destination_path=destination_path, + encoding=self.settings.output_encoding, + error_handler=self.settings.output_encoding_error_handler) + + def apply_transforms(self): + self.document.transformer.populate_from_components( + (self.source, self.reader, self.reader.parser, self.writer, + self.destination)) + self.document.transformer.apply_transforms() + + def publish(self, argv=None, usage=None, description=None, + settings_spec=None, settings_overrides=None, + config_section=None, enable_exit_status=False): + """ + Process command line options and arguments (if `self.settings` not + already set), run `self.reader` and then `self.writer`. Return + `self.writer`'s output. + """ + exit = None + try: + if self.settings is None: + self.process_command_line( + argv, usage, description, settings_spec, config_section, + **(settings_overrides or {})) + self.set_io() + self.document = self.reader.read(self.source, self.parser, + self.settings) + self.apply_transforms() + output = self.writer.write(self.document, self.destination) + self.writer.assemble_parts() + except SystemExit as error: + exit = 1 + exit_status = error.code + except Exception as error: + if not self.settings: # exception too early to report nicely + raise + if self.settings.traceback: # Propagate exceptions? + self.debugging_dumps() + raise + self.report_Exception(error) + exit = True + exit_status = 1 + self.debugging_dumps() + if (enable_exit_status and self.document + and (self.document.reporter.max_level + >= self.settings.exit_status_level)): + sys.exit(self.document.reporter.max_level + 10) + elif exit: + sys.exit(exit_status) + return output + + def debugging_dumps(self): + if not self.document: + return + if self.settings.dump_settings: + print('\n::: Runtime settings:', file=self._stderr) + print(pprint.pformat(self.settings.__dict__), file=self._stderr) + if self.settings.dump_internals: + print('\n::: Document internals:', file=self._stderr) + print(pprint.pformat(self.document.__dict__), file=self._stderr) + if self.settings.dump_transforms: + print('\n::: Transforms applied:', file=self._stderr) + print(' (priority, transform class, pending node details, ' + 'keyword args)', file=self._stderr) + print(pprint.pformat( + [(priority, '%s.%s' % (xclass.__module__, xclass.__name__), + pending and pending.details, kwargs) + for priority, xclass, pending, kwargs + in self.document.transformer.applied]), file=self._stderr) + if self.settings.dump_pseudo_xml: + print('\n::: Pseudo-XML:', file=self._stderr) + print(self.document.pformat().encode( + 'raw_unicode_escape'), file=self._stderr) + + def report_Exception(self, error): + if isinstance(error, utils.SystemMessage): + self.report_SystemMessage(error) + elif isinstance(error, UnicodeEncodeError): + self.report_UnicodeError(error) + elif isinstance(error, io.InputError): + self._stderr.write(u'Unable to open source file for reading:\n' + u' %s\n' % ErrorString(error)) + elif isinstance(error, io.OutputError): + self._stderr.write( + u'Unable to open destination file for writing:\n' + u' %s\n' % ErrorString(error)) + else: + print(u'%s' % ErrorString(error), file=self._stderr) + print(("""\ +Exiting due to error. Use "--traceback" to diagnose. +Please report errors to . +Include "--traceback" output, Docutils version (%s%s), +Python version (%s), your OS type & version, and the +command line used.""" % (__version__, + docutils.__version_details__ and + ' [%s]'%docutils.__version_details__ or '', + sys.version.split()[0])), file=self._stderr) + + def report_SystemMessage(self, error): + print('Exiting due to level-%s (%s) system message.' % ( + error.level, utils.Reporter.levels[error.level]), + file=self._stderr) + + def report_UnicodeError(self, error): + data = error.object[error.start:error.end] + self._stderr.write( + '%s\n' + '\n' + 'The specified output encoding (%s) cannot\n' + 'handle all of the output.\n' + 'Try setting "--output-encoding-error-handler" to\n' + '\n' + '* "xmlcharrefreplace" (for HTML & XML output);\n' + ' the output will contain "%s" and should be usable.\n' + '* "backslashreplace" (for other output formats);\n' + ' look for "%s" in the output.\n' + '* "replace"; look for "?" in the output.\n' + '\n' + '"--output-encoding-error-handler" is currently set to "%s".\n' + '\n' + 'Exiting due to error. Use "--traceback" to diagnose.\n' + 'If the advice above doesn\'t eliminate the error,\n' + 'please report it to .\n' + 'Include "--traceback" output, Docutils version (%s),\n' + 'Python version (%s), your OS type & version, and the\n' + 'command line used.\n' + % (ErrorString(error), + self.settings.output_encoding, + data.encode('ascii', 'xmlcharrefreplace'), + data.encode('ascii', 'backslashreplace'), + self.settings.output_encoding_error_handler, + __version__, sys.version.split()[0])) + +default_usage = '%prog [options] [ []]' +default_description = ('Reads from (default is stdin) and writes to ' + ' (default is stdout). See ' + ' for ' + 'the full reference.') + +def publish_cmdline(reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=True, argv=None, + usage=default_usage, description=default_description): + """ + Set up & run a `Publisher` for command-line-based file I/O (input and + output file paths taken automatically from the command line). Return the + encoded string output also. + + Parameters: see `publish_programmatically` for the remainder. + + - `argv`: Command-line argument list to use instead of ``sys.argv[1:]``. + - `usage`: Usage string, output if there's a problem parsing the command + line. + - `description`: Program description, output for the "--help" option + (along with command-line option descriptions). + """ + pub = Publisher(reader, parser, writer, settings=settings) + pub.set_components(reader_name, parser_name, writer_name) + output = pub.publish( + argv, usage, description, settings_spec, settings_overrides, + config_section=config_section, enable_exit_status=enable_exit_status) + return output + +def publish_file(source=None, source_path=None, + destination=None, destination_path=None, + reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, settings_overrides=None, + config_section=None, enable_exit_status=False): + """ + Set up & run a `Publisher` for programmatic use with file-like I/O. + Return the encoded string output also. + + Parameters: see `publish_programmatically`. + """ + output, pub = publish_programmatically( + source_class=io.FileInput, source=source, source_path=source_path, + destination_class=io.FileOutput, + destination=destination, destination_path=destination_path, + reader=reader, reader_name=reader_name, + parser=parser, parser_name=parser_name, + writer=writer, writer_name=writer_name, + settings=settings, settings_spec=settings_spec, + settings_overrides=settings_overrides, + config_section=config_section, + enable_exit_status=enable_exit_status) + return output + +def publish_string(source, source_path=None, destination_path=None, + reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=False): + """ + Set up & run a `Publisher` for programmatic use with string I/O. Return + the encoded string or Unicode string output. + + For encoded string output, be sure to set the 'output_encoding' setting to + the desired encoding. Set it to 'unicode' for unencoded Unicode string + output. Here's one way:: + + publish_string(..., settings_overrides={'output_encoding': 'unicode'}) + + Similarly for Unicode string input (`source`):: + + publish_string(..., settings_overrides={'input_encoding': 'unicode'}) + + Parameters: see `publish_programmatically`. + """ + output, pub = publish_programmatically( + source_class=io.StringInput, source=source, source_path=source_path, + destination_class=io.StringOutput, + destination=None, destination_path=destination_path, + reader=reader, reader_name=reader_name, + parser=parser, parser_name=parser_name, + writer=writer, writer_name=writer_name, + settings=settings, settings_spec=settings_spec, + settings_overrides=settings_overrides, + config_section=config_section, + enable_exit_status=enable_exit_status) + return output + +def publish_parts(source, source_path=None, source_class=io.StringInput, + destination_path=None, + reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=False): + """ + Set up & run a `Publisher`, and return a dictionary of document parts. + Dictionary keys are the names of parts, and values are Unicode strings; + encoding is up to the client. For programmatic use with string I/O. + + For encoded string input, be sure to set the 'input_encoding' setting to + the desired encoding. Set it to 'unicode' for unencoded Unicode string + input. Here's how:: + + publish_parts(..., settings_overrides={'input_encoding': 'unicode'}) + + Parameters: see `publish_programmatically`. + """ + output, pub = publish_programmatically( + source=source, source_path=source_path, source_class=source_class, + destination_class=io.StringOutput, + destination=None, destination_path=destination_path, + reader=reader, reader_name=reader_name, + parser=parser, parser_name=parser_name, + writer=writer, writer_name=writer_name, + settings=settings, settings_spec=settings_spec, + settings_overrides=settings_overrides, + config_section=config_section, + enable_exit_status=enable_exit_status) + return pub.writer.parts + +def publish_doctree(source, source_path=None, + source_class=io.StringInput, + reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=False): + """ + Set up & run a `Publisher` for programmatic use with string I/O. + Return the document tree. + + For encoded string input, be sure to set the 'input_encoding' setting to + the desired encoding. Set it to 'unicode' for unencoded Unicode string + input. Here's one way:: + + publish_doctree(..., settings_overrides={'input_encoding': 'unicode'}) + + Parameters: see `publish_programmatically`. + """ + pub = Publisher(reader=reader, parser=parser, writer=None, + settings=settings, + source_class=source_class, + destination_class=io.NullOutput) + pub.set_components(reader_name, parser_name, 'null') + pub.process_programmatic_settings( + settings_spec, settings_overrides, config_section) + pub.set_source(source, source_path) + pub.set_destination(None, None) + output = pub.publish(enable_exit_status=enable_exit_status) + return pub.document + +def publish_from_doctree(document, destination_path=None, + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=False): + """ + Set up & run a `Publisher` to render from an existing document + tree data structure, for programmatic use with string I/O. Return + the encoded string output. + + Note that document.settings is overridden; if you want to use the settings + of the original `document`, pass settings=document.settings. + + Also, new document.transformer and document.reporter objects are + generated. + + For encoded string output, be sure to set the 'output_encoding' setting to + the desired encoding. Set it to 'unicode' for unencoded Unicode string + output. Here's one way:: + + publish_from_doctree( + ..., settings_overrides={'output_encoding': 'unicode'}) + + Parameters: `document` is a `docutils.nodes.document` object, an existing + document tree. + + Other parameters: see `publish_programmatically`. + """ + reader = docutils.readers.doctree.Reader(parser_name='null') + pub = Publisher(reader, None, writer, + source=io.DocTreeInput(document), + destination_class=io.StringOutput, settings=settings) + if not writer and writer_name: + pub.set_writer(writer_name) + pub.process_programmatic_settings( + settings_spec, settings_overrides, config_section) + pub.set_destination(None, destination_path) + return pub.publish(enable_exit_status=enable_exit_status) + +def publish_cmdline_to_binary(reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='pseudoxml', + settings=None, settings_spec=None, + settings_overrides=None, config_section=None, + enable_exit_status=True, argv=None, + usage=default_usage, description=default_description, + destination=None, destination_class=io.BinaryFileOutput + ): + """ + Set up & run a `Publisher` for command-line-based file I/O (input and + output file paths taken automatically from the command line). Return the + encoded string output also. + + This is just like publish_cmdline, except that it uses + io.BinaryFileOutput instead of io.FileOutput. + + Parameters: see `publish_programmatically` for the remainder. + + - `argv`: Command-line argument list to use instead of ``sys.argv[1:]``. + - `usage`: Usage string, output if there's a problem parsing the command + line. + - `description`: Program description, output for the "--help" option + (along with command-line option descriptions). + """ + pub = Publisher(reader, parser, writer, settings=settings, + destination_class=destination_class) + pub.set_components(reader_name, parser_name, writer_name) + output = pub.publish( + argv, usage, description, settings_spec, settings_overrides, + config_section=config_section, enable_exit_status=enable_exit_status) + return output + +def publish_programmatically(source_class, source, source_path, + destination_class, destination, destination_path, + reader, reader_name, + parser, parser_name, + writer, writer_name, + settings, settings_spec, + settings_overrides, config_section, + enable_exit_status): + """ + Set up & run a `Publisher` for custom programmatic use. Return the + encoded string output and the Publisher object. + + Applications should not need to call this function directly. If it does + seem to be necessary to call this function directly, please write to the + Docutils-develop mailing list + . + + Parameters: + + * `source_class` **required**: The class for dynamically created source + objects. Typically `io.FileInput` or `io.StringInput`. + + * `source`: Type depends on `source_class`: + + - If `source_class` is `io.FileInput`: Either a file-like object + (must have 'read' and 'close' methods), or ``None`` + (`source_path` is opened). If neither `source` nor + `source_path` are supplied, `sys.stdin` is used. + + - If `source_class` is `io.StringInput` **required**: The input + string, either an encoded 8-bit string (set the + 'input_encoding' setting to the correct encoding) or a Unicode + string (set the 'input_encoding' setting to 'unicode'). + + * `source_path`: Type depends on `source_class`: + + - `io.FileInput`: Path to the input file, opened if no `source` + supplied. + + - `io.StringInput`: Optional. Path to the file or object that produced + `source`. Only used for diagnostic output. + + * `destination_class` **required**: The class for dynamically created + destination objects. Typically `io.FileOutput` or `io.StringOutput`. + + * `destination`: Type depends on `destination_class`: + + - `io.FileOutput`: Either a file-like object (must have 'write' and + 'close' methods), or ``None`` (`destination_path` is opened). If + neither `destination` nor `destination_path` are supplied, + `sys.stdout` is used. + + - `io.StringOutput`: Not used; pass ``None``. + + * `destination_path`: Type depends on `destination_class`: + + - `io.FileOutput`: Path to the output file. Opened if no `destination` + supplied. + + - `io.StringOutput`: Path to the file or object which will receive the + output; optional. Used for determining relative paths (stylesheets, + source links, etc.). + + * `reader`: A `docutils.readers.Reader` object. + + * `reader_name`: Name or alias of the Reader class to be instantiated if + no `reader` supplied. + + * `parser`: A `docutils.parsers.Parser` object. + + * `parser_name`: Name or alias of the Parser class to be instantiated if + no `parser` supplied. + + * `writer`: A `docutils.writers.Writer` object. + + * `writer_name`: Name or alias of the Writer class to be instantiated if + no `writer` supplied. + + * `settings`: A runtime settings (`docutils.frontend.Values`) object, for + dotted-attribute access to runtime settings. It's the end result of the + `SettingsSpec`, config file, and option processing. If `settings` is + passed, it's assumed to be complete and no further setting/config/option + processing is done. + + * `settings_spec`: A `docutils.SettingsSpec` subclass or object. Provides + extra application-specific settings definitions independently of + components. In other words, the application becomes a component, and + its settings data is processed along with that of the other components. + Used only if no `settings` specified. + + * `settings_overrides`: A dictionary containing application-specific + settings defaults that override the defaults of other components. + Used only if no `settings` specified. + + * `config_section`: A string, the name of the configuration file section + for this application. Overrides the ``config_section`` attribute + defined by `settings_spec`. Used only if no `settings` specified. + + * `enable_exit_status`: Boolean; enable exit status at end of processing? + """ + pub = Publisher(reader, parser, writer, settings=settings, + source_class=source_class, + destination_class=destination_class) + pub.set_components(reader_name, parser_name, writer_name) + pub.process_programmatic_settings( + settings_spec, settings_overrides, config_section) + pub.set_source(source, source_path) + pub.set_destination(destination, destination_path) + output = pub.publish(enable_exit_status=enable_exit_status) + return output, pub diff --git a/env/lib/python3.8/site-packages/docutils/examples.py b/env/lib/python3.8/site-packages/docutils/examples.py new file mode 100644 index 000000000..395dbbf14 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/examples.py @@ -0,0 +1,97 @@ +# $Id: examples.py 7320 2012-01-19 22:33:02Z milde $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +This module contains practical examples of Docutils client code. + +Importing this module from client code is not recommended; its contents are +subject to change in future Docutils releases. Instead, it is recommended +that you copy and paste the parts you need into your own code, modifying as +necessary. +""" + +from docutils import core, io + + +def html_parts(input_string, source_path=None, destination_path=None, + input_encoding='unicode', doctitle=True, + initial_header_level=1): + """ + Given an input string, returns a dictionary of HTML document parts. + + Dictionary keys are the names of parts, and values are Unicode strings; + encoding is up to the client. + + Parameters: + + - `input_string`: A multi-line text string; required. + - `source_path`: Path to the source file or object. Optional, but useful + for diagnostic output (system messages). + - `destination_path`: Path to the file or object which will receive the + output; optional. Used for determining relative paths (stylesheets, + source links, etc.). + - `input_encoding`: The encoding of `input_string`. If it is an encoded + 8-bit string, provide the correct encoding. If it is a Unicode string, + use "unicode", the default. + - `doctitle`: Disable the promotion of a lone top-level section title to + document title (and subsequent section title to document subtitle + promotion); enabled by default. + - `initial_header_level`: The initial level for header elements (e.g. 1 + for "

\n' + self.in_document_title = len(self.body) + else: + assert isinstance(node.parent, nodes.section) + h_level = self.section_level + self.initial_header_level - 1 + atts = {} + if (len(node.parent) >= 2 and + isinstance(node.parent[1], nodes.subtitle)): + atts['CLASS'] = 'with-subtitle' + self.body.append( + self.starttag(node, 'h%s' % h_level, '', **atts)) + atts = {} + if node.hasattr('refid'): + atts['class'] = 'toc-backref' + atts['href'] = '#' + node['refid'] + if atts: + self.body.append(self.starttag({}, 'a', '', **atts)) + close_tag = '\n' % (h_level) + else: + close_tag = '\n' % (h_level) + self.context.append(close_tag) + + def depart_title(self, node): + self.body.append(self.context.pop()) + if self.in_document_title: + self.title = self.body[self.in_document_title:-1] + self.in_document_title = 0 + self.body_pre_docinfo.extend(self.body) + self.html_title.extend(self.body) + del self.body[:] + + def visit_title_reference(self, node): + self.body.append(self.starttag(node, 'cite', '')) + + def depart_title_reference(self, node): + self.body.append('') + + # TODO: use the new HTML5 element

"). + """ + overrides = {'input_encoding': input_encoding, + 'doctitle_xform': doctitle, + 'initial_header_level': initial_header_level} + parts = core.publish_parts( + source=input_string, source_path=source_path, + destination_path=destination_path, + writer_name='html', settings_overrides=overrides) + return parts + +def html_body(input_string, source_path=None, destination_path=None, + input_encoding='unicode', output_encoding='unicode', + doctitle=True, initial_header_level=1): + """ + Given an input string, returns an HTML fragment as a string. + + The return value is the contents of the element. + + Parameters (see `html_parts()` for the remainder): + + - `output_encoding`: The desired encoding of the output. If a Unicode + string is desired, use the default value of "unicode" . + """ + parts = html_parts( + input_string=input_string, source_path=source_path, + destination_path=destination_path, + input_encoding=input_encoding, doctitle=doctitle, + initial_header_level=initial_header_level) + fragment = parts['html_body'] + if output_encoding != 'unicode': + fragment = fragment.encode(output_encoding) + return fragment + +def internals(input_string, source_path=None, destination_path=None, + input_encoding='unicode', settings_overrides=None): + """ + Return the document tree and publisher, for exploring Docutils internals. + + Parameters: see `html_parts()`. + """ + if settings_overrides: + overrides = settings_overrides.copy() + else: + overrides = {} + overrides['input_encoding'] = input_encoding + output, pub = core.publish_programmatically( + source_class=io.StringInput, source=input_string, + source_path=source_path, + destination_class=io.NullOutput, destination=None, + destination_path=destination_path, + reader=None, reader_name='standalone', + parser=None, parser_name='restructuredtext', + writer=None, writer_name='null', + settings=None, settings_spec=None, settings_overrides=overrides, + config_section=None, enable_exit_status=None) + return pub.writer.document, pub diff --git a/env/lib/python3.8/site-packages/docutils/frontend.py b/env/lib/python3.8/site-packages/docutils/frontend.py new file mode 100644 index 000000000..ff571cc17 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/frontend.py @@ -0,0 +1,863 @@ +# $Id: frontend.py 8439 2019-12-13 17:02:41Z milde $ +# Author: David Goodger +# Copyright: This module has been placed in the public domain. + +""" +Command-line and common processing for Docutils front-end tools. + +Exports the following classes: + +* `OptionParser`: Standard Docutils command-line processing. +* `Option`: Customized version of `optparse.Option`; validation support. +* `Values`: Runtime settings; objects are simple structs + (``object.attribute``). Supports cumulative list settings (attributes). +* `ConfigParser`: Standard Docutils config file processing. + +Also exports the following functions: + +* Option callbacks: `store_multiple`, `read_config_file`. +* Setting validators: `validate_encoding`, + `validate_encoding_error_handler`, + `validate_encoding_and_error_handler`, + `validate_boolean`, `validate_ternary`, `validate_threshold`, + `validate_colon_separated_string_list`, + `validate_comma_separated_string_list`, + `validate_dependency_file`. +* `make_paths_absolute`. +* SettingSpec manipulation: `filter_settings_spec`. +""" + +__docformat__ = 'reStructuredText' + +import os +import os.path +import sys +import warnings +import codecs +import optparse +from optparse import SUPPRESS_HELP +if sys.version_info >= (3, 0): + from configparser import RawConfigParser + from os import getcwd +else: + from ConfigParser import RawConfigParser + from os import getcwdu as getcwd + +import docutils +import docutils.utils +import docutils.nodes +from docutils.utils.error_reporting import (locale_encoding, SafeString, + ErrorOutput, ErrorString) + +if sys.version_info >= (3, 0): + unicode = str # noqa + + +def store_multiple(option, opt, value, parser, *args, **kwargs): + """ + Store multiple values in `parser.values`. (Option callback.) + + Store `None` for each attribute named in `args`, and store the value for + each key (attribute name) in `kwargs`. + """ + for attribute in args: + setattr(parser.values, attribute, None) + for key, value in kwargs.items(): + setattr(parser.values, key, value) + +def read_config_file(option, opt, value, parser): + """ + Read a configuration file during option processing. (Option callback.) + """ + try: + new_settings = parser.get_config_file_settings(value) + except ValueError as error: + parser.error(error) + parser.values.update(new_settings, parser) + +def validate_encoding(setting, value, option_parser, + config_parser=None, config_section=None): + try: + codecs.lookup(value) + except LookupError: + raise LookupError('setting "%s": unknown encoding: "%s"' + % (setting, value)) + return value + +def validate_encoding_error_handler(setting, value, option_parser, + config_parser=None, config_section=None): + try: + codecs.lookup_error(value) + except LookupError: + raise LookupError( + 'unknown encoding error handler: "%s" (choices: ' + '"strict", "ignore", "replace", "backslashreplace", ' + '"xmlcharrefreplace", and possibly others; see documentation for ' + 'the Python ``codecs`` module)' % value) + return value + +def validate_encoding_and_error_handler( + setting, value, option_parser, config_parser=None, config_section=None): + """ + Side-effect: if an error handler is included in the value, it is inserted + into the appropriate place as if it was a separate setting/option. + """ + if ':' in value: + encoding, handler = value.split(':') + validate_encoding_error_handler( + setting + '_error_handler', handler, option_parser, + config_parser, config_section) + if config_parser: + config_parser.set(config_section, setting + '_error_handler', + handler) + else: + setattr(option_parser.values, setting + '_error_handler', handler) + else: + encoding = value + validate_encoding(setting, encoding, option_parser, + config_parser, config_section) + return encoding + +def validate_boolean(setting, value, option_parser, + config_parser=None, config_section=None): + """Check/normalize boolean settings: + True: '1', 'on', 'yes', 'true' + False: '0', 'off', 'no','false', '' + """ + if isinstance(value, bool): + return value + try: + return option_parser.booleans[value.strip().lower()] + except KeyError: + raise LookupError('unknown boolean value: "%s"' % value) + +def validate_ternary(setting, value, option_parser, + config_parser=None, config_section=None): + """Check/normalize three-value settings: + True: '1', 'on', 'yes', 'true' + False: '0', 'off', 'no','false', '' + any other value: returned as-is. + """ + if isinstance(value, bool) or value is None: + return value + try: + return option_parser.booleans[value.strip().lower()] + except KeyError: + return value + +def validate_nonnegative_int(setting, value, option_parser, + config_parser=None, config_section=None): + value = int(value) + if value < 0: + raise ValueError('negative value; must be positive or zero') + return value + +def validate_threshold(setting, value, option_parser, + config_parser=None, config_section=None): + try: + return int(value) + except ValueError: + try: + return option_parser.thresholds[value.lower()] + except (KeyError, AttributeError): + raise LookupError('unknown threshold: %r.' % value) + +def validate_colon_separated_string_list( + setting, value, option_parser, config_parser=None, config_section=None): + if not isinstance(value, list): + value = value.split(':') + else: + last = value.pop() + value.extend(last.split(':')) + return value + +def validate_comma_separated_list(setting, value, option_parser, + config_parser=None, config_section=None): + """Check/normalize list arguments (split at "," and strip whitespace). + """ + # `value` is already a ``list`` when given as command line option + # and "action" is "append" and ``unicode`` or ``str`` else. + if not isinstance(value, list): + value = [value] + # this function is called for every option added to `value` + # -> split the last item and append the result: + last = value.pop() + items = [i.strip(u' \t\n') for i in last.split(u',') if i.strip(u' \t\n')] + value.extend(items) + return value + +def validate_url_trailing_slash( + setting, value, option_parser, config_parser=None, config_section=None): + if not value: + return './' + elif value.endswith('/'): + return value + else: + return value + '/' + +def validate_dependency_file(setting, value, option_parser, + config_parser=None, config_section=None): + try: + return docutils.utils.DependencyList(value) + except IOError: + return docutils.utils.DependencyList(None) + +def validate_strip_class(setting, value, option_parser, + config_parser=None, config_section=None): + # value is a comma separated string list: + value = validate_comma_separated_list(setting, value, option_parser, + config_parser, config_section) + # validate list elements: + for cls in value: + normalized = docutils.nodes.make_id(cls) + if cls != normalized: + raise ValueError('Invalid class value %r (perhaps %r?)' + % (cls, normalized)) + return value + +def validate_smartquotes_locales(setting, value, option_parser, + config_parser=None, config_section=None): + """Check/normalize a comma separated list of smart quote definitions. + + Return a list of (language-tag, quotes) string tuples.""" + + # value is a comma separated string list: + value = validate_comma_separated_list(setting, value, option_parser, + config_parser, config_section) + # validate list elements + lc_quotes = [] + for item in value: + try: + lang, quotes = item.split(':', 1) + except AttributeError: + # this function is called for every option added to `value` + # -> ignore if already a tuple: + lc_quotes.append(item) + continue + except ValueError: + raise ValueError(u'Invalid value "%s".' + ' Format is ":".' + % item.encode('ascii', 'backslashreplace')) + # parse colon separated string list: + quotes = quotes.strip() + multichar_quotes = quotes.split(':') + if len(multichar_quotes) == 4: + quotes = multichar_quotes + elif len(quotes) != 4: + raise ValueError('Invalid value "%s". Please specify 4 quotes\n' + ' (primary open/close; secondary open/close).' + % item.encode('ascii', 'backslashreplace')) + lc_quotes.append((lang, quotes)) + return lc_quotes + +def make_paths_absolute(pathdict, keys, base_path=None): + """ + Interpret filesystem path settings relative to the `base_path` given. + + Paths are values in `pathdict` whose keys are in `keys`. Get `keys` from + `OptionParser.relative_path_settings`. + """ + if base_path is None: + base_path = getcwd() # type(base_path) == unicode + # to allow combining non-ASCII cwd with unicode values in `pathdict` + for key in keys: + if key in pathdict: + value = pathdict[key] + if isinstance(value, list): + value = [make_one_path_absolute(base_path, path) + for path in value] + elif value: + value = make_one_path_absolute(base_path, value) + pathdict[key] = value + +def make_one_path_absolute(base_path, path): + return os.path.abspath(os.path.join(base_path, path)) + +def filter_settings_spec(settings_spec, *exclude, **replace): + """Return a copy of `settings_spec` excluding/replacing some settings. + + `settings_spec` is a tuple of configuration settings with a structure + described for docutils.SettingsSpec.settings_spec. + + Optional positional arguments are names of to-be-excluded settings. + Keyword arguments are option specification replacements. + (See the html4strict writer for an example.) + """ + settings = list(settings_spec) + # every third item is a sequence of option tuples + for i in range(2, len(settings), 3): + newopts = [] + for opt_spec in settings[i]: + # opt_spec is ("", [
+ + ... + + into :: + + <node> + <title> + ... + + `node` is normally a document. + """ + # Type check + if not isinstance(node, nodes.Element): + raise TypeError('node must be of Element-derived type.') + + # `node` must not have a title yet. + assert not (len(node) and isinstance(node[0], nodes.title)) + section, index = self.candidate_index(node) + if index is None: + return False + + # Transfer the section's attributes to the node: + # NOTE: Change `replace` to False to NOT replace attributes that + # already exist in node with those in section. + # NOTE: Remove `and_source` to NOT copy the 'source' + # attribute from section + node.update_all_atts_concatenating(section, replace=True, and_source=True) + + # setup_child is called automatically for all nodes. + node[:] = (section[:1] # section title + + node[:index] # everything that was in the + # node before the section + + section[1:]) # everything that was in the section + assert isinstance(node[0], nodes.title) + return True + + def promote_subtitle(self, node): + """ + Transform the following node tree:: + + <node> + <title> + <section> + <title> + ... + + into :: + + <node> + <title> + <subtitle> + ... + """ + # Type check + if not isinstance(node, nodes.Element): + raise TypeError('node must be of Element-derived type.') + + subsection, index = self.candidate_index(node) + if index is None: + return False + subtitle = nodes.subtitle() + + # Transfer the subsection's attributes to the new subtitle + # NOTE: Change `replace` to False to NOT replace attributes + # that already exist in node with those in section. + # NOTE: Remove `and_source` to NOT copy the 'source' + # attribute from section. + subtitle.update_all_atts_concatenating(subsection, replace=True, and_source=True) + + # Transfer the contents of the subsection's title to the + # subtitle: + subtitle[:] = subsection[0][:] + node[:] = (node[:1] # title + + [subtitle] + # everything that was before the section: + + node[1:index] + # everything that was in the subsection: + + subsection[1:]) + return True + + def candidate_index(self, node): + """ + Find and return the promotion candidate and its index. + + Return (None, None) if no valid candidate was found. + """ + index = node.first_child_not_matching_class( + nodes.PreBibliographic) + if (index is None or len(node) > (index + 1) + or not isinstance(node[index], nodes.section)): + return None, None + else: + return node[index], index + + +class DocTitle(TitlePromoter): + + """ + In reStructuredText_, there is no way to specify a document title + and subtitle explicitly. Instead, we can supply the document title + (and possibly the subtitle as well) implicitly, and use this + two-step transform to "raise" or "promote" the title(s) (and their + corresponding section contents) to the document level. + + 1. If the document contains a single top-level section as its + first non-comment element, the top-level section's title + becomes the document's title, and the top-level section's + contents become the document's immediate contents. The lone + top-level section header must be the first non-comment element + in the document. + + For example, take this input text:: + + ================= + Top-Level Title + ================= + + A paragraph. + + Once parsed, it looks like this:: + + <document> + <section names="top-level title"> + <title> + Top-Level Title + <paragraph> + A paragraph. + + After running the DocTitle transform, we have:: + + <document names="top-level title"> + <title> + Top-Level Title + <paragraph> + A paragraph. + + 2. If step 1 successfully determines the document title, we + continue by checking for a subtitle. + + If the lone top-level section itself contains a single + second-level section as its first non-comment element, that + section's title is promoted to the document's subtitle, and + that section's contents become the document's immediate + contents. Given this input text:: + + ================= + Top-Level Title + ================= + + Second-Level Title + ~~~~~~~~~~~~~~~~~~ + + A paragraph. + + After parsing and running the Section Promotion transform, the + result is:: + + <document names="top-level title"> + <title> + Top-Level Title + <subtitle names="second-level title"> + Second-Level Title + <paragraph> + A paragraph. + + (Note that the implicit hyperlink target generated by the + "Second-Level Title" is preserved on the "subtitle" element + itself.) + + Any comment elements occurring before the document title or + subtitle are accumulated and inserted as the first body elements + after the title(s). + + This transform also sets the document's metadata title + (document['title']). + + .. _reStructuredText: http://docutils.sf.net/rst.html + """ + + default_priority = 320 + + def set_metadata(self): + """ + Set document['title'] metadata title from the following + sources, listed in order of priority: + + * Existing document['title'] attribute. + * "title" setting. + * Document title node (as promoted by promote_title). + """ + if not self.document.hasattr('title'): + if self.document.settings.title is not None: + self.document['title'] = self.document.settings.title + elif len(self.document) and isinstance(self.document[0], nodes.title): + self.document['title'] = self.document[0].astext() + + def apply(self): + if getattr(self.document.settings, 'doctitle_xform', 1): + # promote_(sub)title defined in TitlePromoter base class. + if self.promote_title(self.document): + # If a title has been promoted, also try to promote a + # subtitle. + self.promote_subtitle(self.document) + # Set document['title']. + self.set_metadata() + + +class SectionSubTitle(TitlePromoter): + + """ + This works like document subtitles, but for sections. For example, :: + + <section> + <title> + Title + <section> + <title> + Subtitle + ... + + is transformed into :: + + <section> + <title> + Title + <subtitle> + Subtitle + ... + + For details refer to the docstring of DocTitle. + """ + + default_priority = 350 + + def apply(self): + if not getattr(self.document.settings, 'sectsubtitle_xform', 1): + return + for section in self.document._traverse(nodes.section): + # On our way through the node tree, we are modifying it + # but only the not-yet-visited part, so that the iterator + # returned by _traverse() is not corrupted. + self.promote_subtitle(section) + + +class DocInfo(Transform): + + """ + This transform is specific to the reStructuredText_ markup syntax; + see "Bibliographic Fields" in the `reStructuredText Markup + Specification`_ for a high-level description. This transform + should be run *after* the `DocTitle` transform. + + Given a field list as the first non-comment element after the + document title and subtitle (if present), registered bibliographic + field names are transformed to the corresponding DTD elements, + becoming child elements of the "docinfo" element (except for a + dedication and/or an abstract, which become "topic" elements after + "docinfo"). + + For example, given this document fragment after parsing:: + + <document> + <title> + Document Title + <field_list> + <field> + <field_name> + Author + <field_body> + <paragraph> + A. Name + <field> + <field_name> + Status + <field_body> + <paragraph> + $RCSfile$ + ... + + After running the bibliographic field list transform, the + resulting document tree would look like this:: + + <document> + <title> + Document Title + <docinfo> + <author> + A. Name + <status> + frontmatter.py + ... + + The "Status" field contained an expanded RCS keyword, which is + normally (but optionally) cleaned up by the transform. The sole + contents of the field body must be a paragraph containing an + expanded RCS keyword of the form "$keyword: expansion text $". Any + RCS keyword can be processed in any bibliographic field. The + dollar signs and leading RCS keyword name are removed. Extra + processing is done for the following RCS keywords: + + - "RCSfile" expands to the name of the file in the RCS or CVS + repository, which is the name of the source file with a ",v" + suffix appended. The transform will remove the ",v" suffix. + + - "Date" expands to the format "YYYY/MM/DD hh:mm:ss" (in the UTC + time zone). The RCS Keywords transform will extract just the + date itself and transform it to an ISO 8601 format date, as in + "2000-12-31". + + (Since the source file for this text is itself stored under CVS, + we can't show an example of the "Date" RCS keyword because we + can't prevent any RCS keywords used in this explanation from + being expanded. Only the "RCSfile" keyword is stable; its + expansion text changes only if the file name changes.) + + .. _reStructuredText: http://docutils.sf.net/rst.html + .. _reStructuredText Markup Specification: + http://docutils.sf.net/docs/ref/rst/restructuredtext.html + """ + + default_priority = 340 + + biblio_nodes = { + 'author': nodes.author, + 'authors': nodes.authors, + 'organization': nodes.organization, + 'address': nodes.address, + 'contact': nodes.contact, + 'version': nodes.version, + 'revision': nodes.revision, + 'status': nodes.status, + 'date': nodes.date, + 'copyright': nodes.copyright, + 'dedication': nodes.topic, + 'abstract': nodes.topic} + """Canonical field name (lowcased) to node class name mapping for + bibliographic fields (field_list).""" + + def apply(self): + if not getattr(self.document.settings, 'docinfo_xform', 1): + return + document = self.document + index = document.first_child_not_matching_class( + nodes.PreBibliographic) + if index is None: + return + candidate = document[index] + if isinstance(candidate, nodes.field_list): + biblioindex = document.first_child_not_matching_class( + (nodes.Titular, nodes.Decorative)) + nodelist = self.extract_bibliographic(candidate) + del document[index] # untransformed field list (candidate) + document[biblioindex:biblioindex] = nodelist + + def extract_bibliographic(self, field_list): + docinfo = nodes.docinfo() + bibliofields = self.language.bibliographic_fields + labels = self.language.labels + topics = {'dedication': None, 'abstract': None} + for field in field_list: + try: + name = field[0][0].astext() + normedname = nodes.fully_normalize_name(name) + if not (len(field) == 2 and normedname in bibliofields + and self.check_empty_biblio_field(field, name)): + raise TransformError + canonical = bibliofields[normedname] + biblioclass = self.biblio_nodes[canonical] + if issubclass(biblioclass, nodes.TextElement): + if not self.check_compound_biblio_field(field, name): + raise TransformError + utils.clean_rcs_keywords( + field[1][0], self.rcs_keyword_substitutions) + docinfo.append(biblioclass('', '', *field[1][0])) + elif issubclass(biblioclass, nodes.authors): + self.extract_authors(field, name, docinfo) + elif issubclass(biblioclass, nodes.topic): + if topics[canonical]: + field[-1] += self.document.reporter.warning( + 'There can only be one "%s" field.' % name, + base_node=field) + raise TransformError + title = nodes.title(name, labels[canonical]) + title[0].rawsource = labels[canonical] + topics[canonical] = biblioclass( + '', title, classes=[canonical], *field[1].children) + else: + docinfo.append(biblioclass('', *field[1].children)) + except TransformError: + if len(field[-1]) == 1 \ + and isinstance(field[-1][0], nodes.paragraph): + utils.clean_rcs_keywords( + field[-1][0], self.rcs_keyword_substitutions) + # if normedname not in bibliofields: + classvalue = nodes.make_id(normedname) + if classvalue: + field['classes'].append(classvalue) + docinfo.append(field) + nodelist = [] + if len(docinfo) != 0: + nodelist.append(docinfo) + for name in ('dedication', 'abstract'): + if topics[name]: + nodelist.append(topics[name]) + return nodelist + + def check_empty_biblio_field(self, field, name): + if len(field[-1]) < 1: + field[-1] += self.document.reporter.warning( + 'Cannot extract empty bibliographic field "%s".' % name, + base_node=field) + return None + return 1 + + def check_compound_biblio_field(self, field, name): + if len(field[-1]) > 1: + field[-1] += self.document.reporter.warning( + 'Cannot extract compound bibliographic field "%s".' % name, + base_node=field) + return None + if not isinstance(field[-1][0], nodes.paragraph): + field[-1] += self.document.reporter.warning( + 'Cannot extract bibliographic field "%s" containing ' + 'anything other than a single paragraph.' % name, + base_node=field) + return None + return 1 + + rcs_keyword_substitutions = [ + (re.compile(r'\$' r'Date: (\d\d\d\d)[-/](\d\d)[-/](\d\d)[ T][\d:]+' + r'[^$]* \$', re.IGNORECASE), r'\1-\2-\3'), + (re.compile(r'\$' r'RCSfile: (.+),v \$', re.IGNORECASE), r'\1'), + (re.compile(r'\$[a-zA-Z]+: (.+) \$'), r'\1'),] + + def extract_authors(self, field, name, docinfo): + try: + if len(field[1]) == 1: + if isinstance(field[1][0], nodes.paragraph): + authors = self.authors_from_one_paragraph(field) + elif isinstance(field[1][0], nodes.bullet_list): + authors = self.authors_from_bullet_list(field) + else: + raise TransformError + else: + authors = self.authors_from_paragraphs(field) + authornodes = [nodes.author('', '', *author) + for author in authors if author] + if len(authornodes) >= 1: + docinfo.append(nodes.authors('', *authornodes)) + else: + raise TransformError + except TransformError: + field[-1] += self.document.reporter.warning( + 'Bibliographic field "%s" incompatible with extraction: ' + 'it must contain either a single paragraph (with authors ' + 'separated by one of "%s"), multiple paragraphs (one per ' + 'author), or a bullet list with one paragraph (one author) ' + 'per item.' + % (name, ''.join(self.language.author_separators)), + base_node=field) + raise + + def authors_from_one_paragraph(self, field): + """Return list of Text nodes for authornames. + + The set of separators is locale dependent (default: ";"- or ","). + """ + # @@ keep original formatting? (e.g. ``:authors: A. Test, *et-al*``) + text = ''.join(unicode(node) + for node in field[1].traverse(nodes.Text)) + if not text: + raise TransformError + for authorsep in self.language.author_separators: + # don't split at escaped `authorsep`: + pattern = '(?<!\x00)%s' % authorsep + authornames = re.split(pattern, text) + if len(authornames) > 1: + break + authornames = (name.strip() for name in authornames) + authors = [[nodes.Text(name, utils.unescape(name, True))] + for name in authornames if name] + return authors + + def authors_from_bullet_list(self, field): + authors = [] + for item in field[1][0]: + if isinstance(item, nodes.comment): + continue + if len(item) != 1 or not isinstance(item[0], nodes.paragraph): + raise TransformError + authors.append(item[0].children) + if not authors: + raise TransformError + return authors + + def authors_from_paragraphs(self, field): + for item in field[1]: + if not isinstance(item, (nodes.paragraph, nodes.comment)): + raise TransformError + authors = [item.children for item in field[1] + if not isinstance(item, nodes.comment)] + return authors diff --git a/env/lib/python3.8/site-packages/docutils/transforms/misc.py b/env/lib/python3.8/site-packages/docutils/transforms/misc.py new file mode 100644 index 000000000..cd68ee150 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/misc.py @@ -0,0 +1,144 @@ +# $Id: misc.py 6314 2010-04-26 10:04:17Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +Miscellaneous transforms. +""" + +__docformat__ = 'reStructuredText' + +from docutils import nodes +from docutils.transforms import Transform, TransformError + + +class CallBack(Transform): + + """ + Inserts a callback into a document. The callback is called when the + transform is applied, which is determined by its priority. + + For use with `nodes.pending` elements. Requires a ``details['callback']`` + entry, a bound method or function which takes one parameter: the pending + node. Other data can be stored in the ``details`` attribute or in the + object hosting the callback method. + """ + + default_priority = 990 + + def apply(self): + pending = self.startnode + pending.details['callback'](pending) + pending.parent.remove(pending) + + +class ClassAttribute(Transform): + + """ + Move the "class" attribute specified in the "pending" node into the + immediately following non-comment element. + """ + + default_priority = 210 + + def apply(self): + pending = self.startnode + parent = pending.parent + child = pending + while parent: + # Check for appropriate following siblings: + for index in range(parent.index(child) + 1, len(parent)): + element = parent[index] + if (isinstance(element, nodes.Invisible) or + isinstance(element, nodes.system_message)): + continue + element['classes'] += pending.details['class'] + pending.parent.remove(pending) + return + else: + # At end of section or container; apply to sibling + child = parent + parent = parent.parent + error = self.document.reporter.error( + 'No suitable element following "%s" directive' + % pending.details['directive'], + nodes.literal_block(pending.rawsource, pending.rawsource), + line=pending.line) + pending.replace_self(error) + + +class Transitions(Transform): + + """ + Move transitions at the end of sections up the tree. Complain + on transitions after a title, at the beginning or end of the + document, and after another transition. + + For example, transform this:: + + <section> + ... + <transition> + <section> + ... + + into this:: + + <section> + ... + <transition> + <section> + ... + """ + + default_priority = 830 + + def apply(self): + for node in self.document.traverse(nodes.transition): + self.visit_transition(node) + + def visit_transition(self, node): + index = node.parent.index(node) + error = None + if (index == 0 or + isinstance(node.parent[0], nodes.title) and + (index == 1 or + isinstance(node.parent[1], nodes.subtitle) and + index == 2)): + assert (isinstance(node.parent, nodes.document) or + isinstance(node.parent, nodes.section)) + error = self.document.reporter.error( + 'Document or section may not begin with a transition.', + source=node.source, line=node.line) + elif isinstance(node.parent[index - 1], nodes.transition): + error = self.document.reporter.error( + 'At least one body element must separate transitions; ' + 'adjacent transitions are not allowed.', + source=node.source, line=node.line) + if error: + # Insert before node and update index. + node.parent.insert(index, error) + index += 1 + assert index < len(node.parent) + if index != len(node.parent) - 1: + # No need to move the node. + return + # Node behind which the transition is to be moved. + sibling = node + # While sibling is the last node of its parent. + while index == len(sibling.parent) - 1: + sibling = sibling.parent + # If sibling is the whole document (i.e. it has no parent). + if sibling.parent is None: + # Transition at the end of document. Do not move the + # transition up, and place an error behind. + error = self.document.reporter.error( + 'Document may not end with a transition.', + line=node.line) + node.parent.insert(node.parent.index(node) + 1, error) + return + index = sibling.parent.index(sibling) + # Remove the original transition node. + node.parent.remove(node) + # Insert the transition after the sibling. + sibling.parent.insert(index + 1, node) diff --git a/env/lib/python3.8/site-packages/docutils/transforms/parts.py b/env/lib/python3.8/site-packages/docutils/transforms/parts.py new file mode 100644 index 000000000..27efc8d45 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/parts.py @@ -0,0 +1,180 @@ +# $Id: parts.py 8403 2019-10-11 10:09:53Z milde $ +# Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer; Dmitry Jemerov +# Copyright: This module has been placed in the public domain. + +""" +Transforms related to document parts. +""" + +__docformat__ = 'reStructuredText' + + +import re +import sys +from docutils import nodes, utils +from docutils.transforms import TransformError, Transform + + +class SectNum(Transform): + + """ + Automatically assigns numbers to the titles of document sections. + + It is possible to limit the maximum section level for which the numbers + are added. For those sections that are auto-numbered, the "autonum" + attribute is set, informing the contents table generator that a different + form of the TOC should be used. + """ + + default_priority = 710 + """Should be applied before `Contents`.""" + + def apply(self): + self.maxdepth = self.startnode.details.get('depth', None) + self.startvalue = self.startnode.details.get('start', 1) + self.prefix = self.startnode.details.get('prefix', '') + self.suffix = self.startnode.details.get('suffix', '') + self.startnode.parent.remove(self.startnode) + if self.document.settings.sectnum_xform: + if self.maxdepth is None: + self.maxdepth = sys.maxsize + self.update_section_numbers(self.document) + else: # store details for eventual section numbering by the writer + self.document.settings.sectnum_depth = self.maxdepth + self.document.settings.sectnum_start = self.startvalue + self.document.settings.sectnum_prefix = self.prefix + self.document.settings.sectnum_suffix = self.suffix + + def update_section_numbers(self, node, prefix=(), depth=0): + depth += 1 + if prefix: + sectnum = 1 + else: + sectnum = self.startvalue + for child in node: + if isinstance(child, nodes.section): + numbers = prefix + (str(sectnum),) + title = child[0] + # Use   for spacing: + generated = nodes.generated( + '', (self.prefix + '.'.join(numbers) + self.suffix + + u'\u00a0' * 3), + classes=['sectnum']) + title.insert(0, generated) + title['auto'] = 1 + if depth < self.maxdepth: + self.update_section_numbers(child, numbers, depth) + sectnum += 1 + + +class Contents(Transform): + + """ + This transform generates a table of contents from the entire document tree + or from a single branch. It locates "section" elements and builds them + into a nested bullet list, which is placed within a "topic" created by the + contents directive. A title is either explicitly specified, taken from + the appropriate language module, or omitted (local table of contents). + The depth may be specified. Two-way references between the table of + contents and section titles are generated (requires Writer support). + + This transform requires a startnode, which contains generation + options and provides the location for the generated table of contents (the + startnode is replaced by the table of contents "topic"). + """ + + default_priority = 720 + + def apply(self): + try: # let the writer (or output software) build the contents list? + toc_by_writer = self.document.settings.use_latex_toc + except AttributeError: + toc_by_writer = False + details = self.startnode.details + if 'local' in details: + startnode = self.startnode.parent.parent + while not (isinstance(startnode, nodes.section) + or isinstance(startnode, nodes.document)): + # find the ToC root: a direct ancestor of startnode + startnode = startnode.parent + else: + startnode = self.document + self.toc_id = self.startnode.parent['ids'][0] + if 'backlinks' in details: + self.backlinks = details['backlinks'] + else: + self.backlinks = self.document.settings.toc_backlinks + if toc_by_writer: + # move customization settings to the parent node + self.startnode.parent.attributes.update(details) + self.startnode.parent.remove(self.startnode) + else: + contents = self.build_contents(startnode) + if len(contents): + self.startnode.replace_self(contents) + else: + self.startnode.parent.parent.remove(self.startnode.parent) + + def build_contents(self, node, level=0): + level += 1 + sections = [sect for sect in node if isinstance(sect, nodes.section)] + entries = [] + autonum = 0 + depth = self.startnode.details.get('depth', sys.maxsize) + for section in sections: + title = section[0] + auto = title.get('auto') # May be set by SectNum. + entrytext = self.copy_and_filter(title) + reference = nodes.reference('', '', refid=section['ids'][0], + *entrytext) + ref_id = self.document.set_id(reference, + suggested_prefix='toc-entry') + entry = nodes.paragraph('', '', reference) + item = nodes.list_item('', entry) + if ( self.backlinks in ('entry', 'top') + and title.next_node(nodes.reference) is None): + if self.backlinks == 'entry': + title['refid'] = ref_id + elif self.backlinks == 'top': + title['refid'] = self.toc_id + if level < depth: + subsects = self.build_contents(section, level) + item += subsects + entries.append(item) + if entries: + contents = nodes.bullet_list('', *entries) + if auto: + contents['classes'].append('auto-toc') + return contents + else: + return [] + + def copy_and_filter(self, node): + """Return a copy of a title, with references, images, etc. removed.""" + visitor = ContentsFilter(self.document) + node.walkabout(visitor) + return visitor.get_entry_text() + + +class ContentsFilter(nodes.TreeCopyVisitor): + + def get_entry_text(self): + return self.get_tree_copy().children + + def visit_citation_reference(self, node): + raise nodes.SkipNode + + def visit_footnote_reference(self, node): + raise nodes.SkipNode + + def visit_image(self, node): + if node.hasattr('alt'): + self.parent.append(nodes.Text(node['alt'])) + raise nodes.SkipNode + + def ignore_node_but_process_children(self, node): + raise nodes.SkipDeparture + + visit_problematic = ignore_node_but_process_children + visit_reference = ignore_node_but_process_children + visit_target = ignore_node_but_process_children diff --git a/env/lib/python3.8/site-packages/docutils/transforms/peps.py b/env/lib/python3.8/site-packages/docutils/transforms/peps.py new file mode 100644 index 000000000..94b47c173 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/peps.py @@ -0,0 +1,305 @@ +# $Id: peps.py 7995 2016-12-10 17:50:59Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +Transforms for PEP processing. + +- `Headers`: Used to transform a PEP's initial RFC-2822 header. It remains a + field list, but some entries get processed. +- `Contents`: Auto-inserts a table of contents. +- `PEPZero`: Special processing for PEP 0. +""" + +__docformat__ = 'reStructuredText' + +import sys +import os +import re +import time +from docutils import nodes, utils, languages +from docutils import ApplicationError, DataError +from docutils.transforms import Transform, TransformError +from docutils.transforms import parts, references, misc + + +class Headers(Transform): + + """ + Process fields in a PEP's initial RFC-2822 header. + """ + + default_priority = 360 + + pep_url = 'pep-%04d' + pep_cvs_url = ('http://hg.python.org/' + '/peps/file/default/pep-%04d.txt') + rcs_keyword_substitutions = ( + (re.compile(r'\$' r'RCSfile: (.+),v \$$', re.IGNORECASE), r'\1'), + (re.compile(r'\$[a-zA-Z]+: (.+) \$$'), r'\1'),) + + def apply(self): + if not len(self.document): + # @@@ replace these DataErrors with proper system messages + raise DataError('Document tree is empty.') + header = self.document[0] + if not isinstance(header, nodes.field_list) or \ + 'rfc2822' not in header['classes']: + raise DataError('Document does not begin with an RFC-2822 ' + 'header; it is not a PEP.') + pep = None + for field in header: + if field[0].astext().lower() == 'pep': # should be the first field + value = field[1].astext() + try: + pep = int(value) + cvs_url = self.pep_cvs_url % pep + except ValueError: + pep = value + cvs_url = None + msg = self.document.reporter.warning( + '"PEP" header must contain an integer; "%s" is an ' + 'invalid value.' % pep, base_node=field) + msgid = self.document.set_id(msg) + prb = nodes.problematic(value, value or '(none)', + refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + if len(field[1]): + field[1][0][:] = [prb] + else: + field[1] += nodes.paragraph('', '', prb) + break + if pep is None: + raise DataError('Document does not contain an RFC-2822 "PEP" ' + 'header.') + if pep == 0: + # Special processing for PEP 0. + pending = nodes.pending(PEPZero) + self.document.insert(1, pending) + self.document.note_pending(pending) + if len(header) < 2 or header[1][0].astext().lower() != 'title': + raise DataError('No title!') + for field in header: + name = field[0].astext().lower() + body = field[1] + if len(body) > 1: + raise DataError('PEP header field body contains multiple ' + 'elements:\n%s' % field.pformat(level=1)) + elif len(body) == 1: + if not isinstance(body[0], nodes.paragraph): + raise DataError('PEP header field body may only contain ' + 'a single paragraph:\n%s' + % field.pformat(level=1)) + elif name == 'last-modified': + date = time.strftime( + '%d-%b-%Y', + time.localtime(os.stat(self.document['source'])[8])) + if cvs_url: + body += nodes.paragraph( + '', '', nodes.reference('', date, refuri=cvs_url)) + else: + # empty + continue + para = body[0] + if name == 'author': + for node in para: + if isinstance(node, nodes.reference): + node.replace_self(mask_email(node)) + elif name == 'discussions-to': + for node in para: + if isinstance(node, nodes.reference): + node.replace_self(mask_email(node, pep)) + elif name in ('replaces', 'replaced-by', 'requires'): + newbody = [] + space = nodes.Text(' ') + for refpep in re.split(r',?\s+', body.astext()): + pepno = int(refpep) + newbody.append(nodes.reference( + refpep, refpep, + refuri=(self.document.settings.pep_base_url + + self.pep_url % pepno))) + newbody.append(space) + para[:] = newbody[:-1] # drop trailing space + elif name == 'last-modified': + utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions) + if cvs_url: + date = para.astext() + para[:] = [nodes.reference('', date, refuri=cvs_url)] + elif name == 'content-type': + pep_type = para.astext() + uri = self.document.settings.pep_base_url + self.pep_url % 12 + para[:] = [nodes.reference('', pep_type, refuri=uri)] + elif name == 'version' and len(body): + utils.clean_rcs_keywords(para, self.rcs_keyword_substitutions) + + +class Contents(Transform): + + """ + Insert an empty table of contents topic and a transform placeholder into + the document after the RFC 2822 header. + """ + + default_priority = 380 + + def apply(self): + language = languages.get_language(self.document.settings.language_code, + self.document.reporter) + name = language.labels['contents'] + title = nodes.title('', name) + topic = nodes.topic('', title, classes=['contents']) + name = nodes.fully_normalize_name(name) + if not self.document.has_name(name): + topic['names'].append(name) + self.document.note_implicit_target(topic) + pending = nodes.pending(parts.Contents) + topic += pending + self.document.insert(1, topic) + self.document.note_pending(pending) + + +class TargetNotes(Transform): + + """ + Locate the "References" section, insert a placeholder for an external + target footnote insertion transform at the end, and schedule the + transform to run immediately. + """ + + default_priority = 520 + + def apply(self): + doc = self.document + i = len(doc) - 1 + refsect = copyright = None + while i >= 0 and isinstance(doc[i], nodes.section): + title_words = doc[i][0].astext().lower().split() + if 'references' in title_words: + refsect = doc[i] + break + elif 'copyright' in title_words: + copyright = i + i -= 1 + if not refsect: + refsect = nodes.section() + refsect += nodes.title('', 'References') + doc.set_id(refsect) + if copyright: + # Put the new "References" section before "Copyright": + doc.insert(copyright, refsect) + else: + # Put the new "References" section at end of doc: + doc.append(refsect) + pending = nodes.pending(references.TargetNotes) + refsect.append(pending) + self.document.note_pending(pending, 0) + pending = nodes.pending(misc.CallBack, + details={'callback': self.cleanup_callback}) + refsect.append(pending) + self.document.note_pending(pending, 1) + + def cleanup_callback(self, pending): + """ + Remove an empty "References" section. + + Called after the `references.TargetNotes` transform is complete. + """ + if len(pending.parent) == 2: # <title> and <pending> + pending.parent.parent.remove(pending.parent) + + +class PEPZero(Transform): + + """ + Special processing for PEP 0. + """ + + default_priority =760 + + def apply(self): + visitor = PEPZeroSpecial(self.document) + self.document.walk(visitor) + self.startnode.parent.remove(self.startnode) + + +class PEPZeroSpecial(nodes.SparseNodeVisitor): + + """ + Perform the special processing needed by PEP 0: + + - Mask email addresses. + + - Link PEP numbers in the second column of 4-column tables to the PEPs + themselves. + """ + + pep_url = Headers.pep_url + + def unknown_visit(self, node): + pass + + def visit_reference(self, node): + node.replace_self(mask_email(node)) + + def visit_field_list(self, node): + if 'rfc2822' in node['classes']: + raise nodes.SkipNode + + def visit_tgroup(self, node): + self.pep_table = node['cols'] == 4 + self.entry = 0 + + def visit_colspec(self, node): + self.entry += 1 + if self.pep_table and self.entry == 2: + node['classes'].append('num') + + def visit_row(self, node): + self.entry = 0 + + def visit_entry(self, node): + self.entry += 1 + if self.pep_table and self.entry == 2 and len(node) == 1: + node['classes'].append('num') + p = node[0] + if isinstance(p, nodes.paragraph) and len(p) == 1: + text = p.astext() + try: + pep = int(text) + ref = (self.document.settings.pep_base_url + + self.pep_url % pep) + p[0] = nodes.reference(text, text, refuri=ref) + except ValueError: + pass + + +non_masked_addresses = ('peps@python.org', + 'python-list@python.org', + 'python-dev@python.org') + +def mask_email(ref, pepno=None): + """ + Mask the email address in `ref` and return a replacement node. + + `ref` is returned unchanged if it contains no email address. + + For email addresses such as "user@host", mask the address as "user at + host" (text) to thwart simple email address harvesters (except for those + listed in `non_masked_addresses`). If a PEP number (`pepno`) is given, + return a reference including a default email subject. + """ + if ref.hasattr('refuri') and ref['refuri'].startswith('mailto:'): + if ref['refuri'][8:] in non_masked_addresses: + replacement = ref[0] + else: + replacement_text = ref.astext().replace('@', ' at ') + replacement = nodes.raw('', replacement_text, format='html') + if pepno is None: + return replacement + else: + ref['refuri'] += '?subject=PEP%%20%s' % pepno + ref[:] = [replacement] + return ref + else: + return ref diff --git a/env/lib/python3.8/site-packages/docutils/transforms/references.py b/env/lib/python3.8/site-packages/docutils/transforms/references.py new file mode 100644 index 000000000..e6f61495e --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/references.py @@ -0,0 +1,911 @@ +# $Id: references.py 8387 2019-09-06 13:16:34Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +Transforms for resolving references. +""" + +__docformat__ = 'reStructuredText' + +import sys +import re +from docutils import nodes, utils +from docutils.transforms import TransformError, Transform + + +class PropagateTargets(Transform): + + """ + Propagate empty internal targets to the next element. + + Given the following nodes:: + + <target ids="internal1" names="internal1"> + <target anonymous="1" ids="id1"> + <target ids="internal2" names="internal2"> + <paragraph> + This is a test. + + PropagateTargets propagates the ids and names of the internal + targets preceding the paragraph to the paragraph itself:: + + <target refid="internal1"> + <target anonymous="1" refid="id1"> + <target refid="internal2"> + <paragraph ids="internal2 id1 internal1" names="internal2 internal1"> + This is a test. + """ + + default_priority = 260 + + def apply(self): + for target in self.document.traverse(nodes.target): + # Only block-level targets without reference (like ".. target:"): + if (isinstance(target.parent, nodes.TextElement) or + (target.hasattr('refid') or target.hasattr('refuri') or + target.hasattr('refname'))): + continue + assert len(target) == 0, 'error: block-level target has children' + next_node = target.next_node(ascend=True) + # Do not move names and ids into Invisibles (we'd lose the + # attributes) or different Targetables (e.g. footnotes). + if (next_node is not None and + ((not isinstance(next_node, nodes.Invisible) and + not isinstance(next_node, nodes.Targetable)) or + isinstance(next_node, nodes.target))): + next_node['ids'].extend(target['ids']) + next_node['names'].extend(target['names']) + # Set defaults for next_node.expect_referenced_by_name/id. + if not hasattr(next_node, 'expect_referenced_by_name'): + next_node.expect_referenced_by_name = {} + if not hasattr(next_node, 'expect_referenced_by_id'): + next_node.expect_referenced_by_id = {} + for id in target['ids']: + # Update IDs to node mapping. + self.document.ids[id] = next_node + # If next_node is referenced by id ``id``, this + # target shall be marked as referenced. + next_node.expect_referenced_by_id[id] = target + for name in target['names']: + next_node.expect_referenced_by_name[name] = target + # If there are any expect_referenced_by_... attributes + # in target set, copy them to next_node. + next_node.expect_referenced_by_name.update( + getattr(target, 'expect_referenced_by_name', {})) + next_node.expect_referenced_by_id.update( + getattr(target, 'expect_referenced_by_id', {})) + # Set refid to point to the first former ID of target + # which is now an ID of next_node. + target['refid'] = target['ids'][0] + # Clear ids and names; they have been moved to + # next_node. + target['ids'] = [] + target['names'] = [] + self.document.note_refid(target) + + +class AnonymousHyperlinks(Transform): + + """ + Link anonymous references to targets. Given:: + + <paragraph> + <reference anonymous="1"> + internal + <reference anonymous="1"> + external + <target anonymous="1" ids="id1"> + <target anonymous="1" ids="id2" refuri="http://external/"> + + Corresponding references are linked via "refid" or resolved via "refuri":: + + <paragraph> + <reference anonymous="1" refid="id1"> + text + <reference anonymous="1" refuri="http://external/"> + external + <target anonymous="1" ids="id1"> + <target anonymous="1" ids="id2" refuri="http://external/"> + """ + + default_priority = 440 + + def apply(self): + anonymous_refs = [] + anonymous_targets = [] + for node in self.document.traverse(nodes.reference): + if node.get('anonymous'): + anonymous_refs.append(node) + for node in self.document.traverse(nodes.target): + if node.get('anonymous'): + anonymous_targets.append(node) + if len(anonymous_refs) \ + != len(anonymous_targets): + msg = self.document.reporter.error( + 'Anonymous hyperlink mismatch: %s references but %s ' + 'targets.\nSee "backrefs" attribute for IDs.' + % (len(anonymous_refs), len(anonymous_targets))) + msgid = self.document.set_id(msg) + for ref in anonymous_refs: + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + return + for ref, target in zip(anonymous_refs, anonymous_targets): + target.referenced = 1 + while True: + if target.hasattr('refuri'): + ref['refuri'] = target['refuri'] + ref.resolved = 1 + break + else: + if not target['ids']: + # Propagated target. + target = self.document.ids[target['refid']] + continue + ref['refid'] = target['ids'][0] + self.document.note_refid(ref) + break + + +class IndirectHyperlinks(Transform): + + """ + a) Indirect external references:: + + <paragraph> + <reference refname="indirect external"> + indirect external + <target id="id1" name="direct external" + refuri="http://indirect/"> + <target id="id2" name="indirect external" + refname="direct external"> + + The "refuri" attribute is migrated back to all indirect targets + from the final direct target (i.e. a target not referring to + another indirect target):: + + <paragraph> + <reference refname="indirect external"> + indirect external + <target id="id1" name="direct external" + refuri="http://indirect/"> + <target id="id2" name="indirect external" + refuri="http://indirect/"> + + Once the attribute is migrated, the preexisting "refname" attribute + is dropped. + + b) Indirect internal references:: + + <target id="id1" name="final target"> + <paragraph> + <reference refname="indirect internal"> + indirect internal + <target id="id2" name="indirect internal 2" + refname="final target"> + <target id="id3" name="indirect internal" + refname="indirect internal 2"> + + Targets which indirectly refer to an internal target become one-hop + indirect (their "refid" attributes are directly set to the internal + target's "id"). References which indirectly refer to an internal + target become direct internal references:: + + <target id="id1" name="final target"> + <paragraph> + <reference refid="id1"> + indirect internal + <target id="id2" name="indirect internal 2" refid="id1"> + <target id="id3" name="indirect internal" refid="id1"> + """ + + default_priority = 460 + + def apply(self): + for target in self.document.indirect_targets: + if not target.resolved: + self.resolve_indirect_target(target) + self.resolve_indirect_references(target) + + def resolve_indirect_target(self, target): + refname = target.get('refname') + if refname is None: + reftarget_id = target['refid'] + else: + reftarget_id = self.document.nameids.get(refname) + if not reftarget_id: + # Check the unknown_reference_resolvers + for resolver_function in \ + self.document.transformer.unknown_reference_resolvers: + if resolver_function(target): + break + else: + self.nonexistent_indirect_target(target) + return + reftarget = self.document.ids[reftarget_id] + reftarget.note_referenced_by(id=reftarget_id) + if isinstance(reftarget, nodes.target) \ + and not reftarget.resolved and reftarget.hasattr('refname'): + if hasattr(target, 'multiply_indirect'): + #and target.multiply_indirect): + #del target.multiply_indirect + self.circular_indirect_reference(target) + return + target.multiply_indirect = 1 + self.resolve_indirect_target(reftarget) # multiply indirect + del target.multiply_indirect + if reftarget.hasattr('refuri'): + target['refuri'] = reftarget['refuri'] + if 'refid' in target: + del target['refid'] + elif reftarget.hasattr('refid'): + target['refid'] = reftarget['refid'] + self.document.note_refid(target) + else: + if reftarget['ids']: + target['refid'] = reftarget_id + self.document.note_refid(target) + else: + self.nonexistent_indirect_target(target) + return + if refname is not None: + del target['refname'] + target.resolved = 1 + + def nonexistent_indirect_target(self, target): + if target['refname'] in self.document.nameids: + self.indirect_target_error(target, 'which is a duplicate, and ' + 'cannot be used as a unique reference') + else: + self.indirect_target_error(target, 'which does not exist') + + def circular_indirect_reference(self, target): + self.indirect_target_error(target, 'forming a circular reference') + + def indirect_target_error(self, target, explanation): + naming = '' + reflist = [] + if target['names']: + naming = '"%s" ' % target['names'][0] + for name in target['names']: + reflist.extend(self.document.refnames.get(name, [])) + for id in target['ids']: + reflist.extend(self.document.refids.get(id, [])) + if target['ids']: + naming += '(id="%s")' % target['ids'][0] + msg = self.document.reporter.error( + 'Indirect hyperlink target %s refers to target "%s", %s.' + % (naming, target['refname'], explanation), base_node=target) + msgid = self.document.set_id(msg) + for ref in utils.uniq(reflist): + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + target.resolved = 1 + + def resolve_indirect_references(self, target): + if target.hasattr('refid'): + attname = 'refid' + call_method = self.document.note_refid + elif target.hasattr('refuri'): + attname = 'refuri' + call_method = None + else: + return + attval = target[attname] + for name in target['names']: + reflist = self.document.refnames.get(name, []) + if reflist: + target.note_referenced_by(name=name) + for ref in reflist: + if ref.resolved: + continue + del ref['refname'] + ref[attname] = attval + if call_method: + call_method(ref) + ref.resolved = 1 + if isinstance(ref, nodes.target): + self.resolve_indirect_references(ref) + for id in target['ids']: + reflist = self.document.refids.get(id, []) + if reflist: + target.note_referenced_by(id=id) + for ref in reflist: + if ref.resolved: + continue + del ref['refid'] + ref[attname] = attval + if call_method: + call_method(ref) + ref.resolved = 1 + if isinstance(ref, nodes.target): + self.resolve_indirect_references(ref) + + +class ExternalTargets(Transform): + + """ + Given:: + + <paragraph> + <reference refname="direct external"> + direct external + <target id="id1" name="direct external" refuri="http://direct/"> + + The "refname" attribute is replaced by the direct "refuri" attribute:: + + <paragraph> + <reference refuri="http://direct/"> + direct external + <target id="id1" name="direct external" refuri="http://direct/"> + """ + + default_priority = 640 + + def apply(self): + for target in self.document.traverse(nodes.target): + if target.hasattr('refuri'): + refuri = target['refuri'] + for name in target['names']: + reflist = self.document.refnames.get(name, []) + if reflist: + target.note_referenced_by(name=name) + for ref in reflist: + if ref.resolved: + continue + del ref['refname'] + ref['refuri'] = refuri + ref.resolved = 1 + + +class InternalTargets(Transform): + + default_priority = 660 + + def apply(self): + for target in self.document.traverse(nodes.target): + if not target.hasattr('refuri') and not target.hasattr('refid'): + self.resolve_reference_ids(target) + + def resolve_reference_ids(self, target): + """ + Given:: + + <paragraph> + <reference refname="direct internal"> + direct internal + <target id="id1" name="direct internal"> + + The "refname" attribute is replaced by "refid" linking to the target's + "id":: + + <paragraph> + <reference refid="id1"> + direct internal + <target id="id1" name="direct internal"> + """ + for name in target['names']: + refid = self.document.nameids.get(name) + reflist = self.document.refnames.get(name, []) + if reflist: + target.note_referenced_by(name=name) + for ref in reflist: + if ref.resolved: + continue + if refid: + del ref['refname'] + ref['refid'] = refid + ref.resolved = 1 + + +class Footnotes(Transform): + + """ + Assign numbers to autonumbered footnotes, and resolve links to footnotes, + citations, and their references. + + Given the following ``document`` as input:: + + <document> + <paragraph> + A labeled autonumbered footnote referece: + <footnote_reference auto="1" id="id1" refname="footnote"> + <paragraph> + An unlabeled autonumbered footnote referece: + <footnote_reference auto="1" id="id2"> + <footnote auto="1" id="id3"> + <paragraph> + Unlabeled autonumbered footnote. + <footnote auto="1" id="footnote" name="footnote"> + <paragraph> + Labeled autonumbered footnote. + + Auto-numbered footnotes have attribute ``auto="1"`` and no label. + Auto-numbered footnote_references have no reference text (they're + empty elements). When resolving the numbering, a ``label`` element + is added to the beginning of the ``footnote``, and reference text + to the ``footnote_reference``. + + The transformed result will be:: + + <document> + <paragraph> + A labeled autonumbered footnote referece: + <footnote_reference auto="1" id="id1" refid="footnote"> + 2 + <paragraph> + An unlabeled autonumbered footnote referece: + <footnote_reference auto="1" id="id2" refid="id3"> + 1 + <footnote auto="1" id="id3" backrefs="id2"> + <label> + 1 + <paragraph> + Unlabeled autonumbered footnote. + <footnote auto="1" id="footnote" name="footnote" backrefs="id1"> + <label> + 2 + <paragraph> + Labeled autonumbered footnote. + + Note that the footnotes are not in the same order as the references. + + The labels and reference text are added to the auto-numbered ``footnote`` + and ``footnote_reference`` elements. Footnote elements are backlinked to + their references via "refids" attributes. References are assigned "id" + and "refid" attributes. + + After adding labels and reference text, the "auto" attributes can be + ignored. + """ + + default_priority = 620 + + autofootnote_labels = None + """Keep track of unlabeled autonumbered footnotes.""" + + symbols = [ + # Entries 1-4 and 6 below are from section 12.51 of + # The Chicago Manual of Style, 14th edition. + '*', # asterisk/star + u'\u2020', # dagger † + u'\u2021', # double dagger ‡ + u'\u00A7', # section mark § + u'\u00B6', # paragraph mark (pilcrow) ¶ + # (parallels ['||'] in CMoS) + '#', # number sign + # The entries below were chosen arbitrarily. + u'\u2660', # spade suit ♠ + u'\u2665', # heart suit ♥ + u'\u2666', # diamond suit ♦ + u'\u2663', # club suit ♣ + ] + + def apply(self): + self.autofootnote_labels = [] + startnum = self.document.autofootnote_start + self.document.autofootnote_start = self.number_footnotes(startnum) + self.number_footnote_references(startnum) + self.symbolize_footnotes() + self.resolve_footnotes_and_citations() + + def number_footnotes(self, startnum): + """ + Assign numbers to autonumbered footnotes. + + For labeled autonumbered footnotes, copy the number over to + corresponding footnote references. + """ + for footnote in self.document.autofootnotes: + while True: + label = str(startnum) + startnum += 1 + if label not in self.document.nameids: + break + footnote.insert(0, nodes.label('', label)) + for name in footnote['names']: + for ref in self.document.footnote_refs.get(name, []): + ref += nodes.Text(label) + ref.delattr('refname') + assert len(footnote['ids']) == len(ref['ids']) == 1 + ref['refid'] = footnote['ids'][0] + footnote.add_backref(ref['ids'][0]) + self.document.note_refid(ref) + ref.resolved = 1 + if not footnote['names'] and not footnote['dupnames']: + footnote['names'].append(label) + self.document.note_explicit_target(footnote, footnote) + self.autofootnote_labels.append(label) + return startnum + + def number_footnote_references(self, startnum): + """Assign numbers to autonumbered footnote references.""" + i = 0 + for ref in self.document.autofootnote_refs: + if ref.resolved or ref.hasattr('refid'): + continue + try: + label = self.autofootnote_labels[i] + except IndexError: + msg = self.document.reporter.error( + 'Too many autonumbered footnote references: only %s ' + 'corresponding footnotes available.' + % len(self.autofootnote_labels), base_node=ref) + msgid = self.document.set_id(msg) + for ref in self.document.autofootnote_refs[i:]: + if ref.resolved or ref.hasattr('refname'): + continue + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + break + ref += nodes.Text(label) + id = self.document.nameids[label] + footnote = self.document.ids[id] + ref['refid'] = id + self.document.note_refid(ref) + assert len(ref['ids']) == 1 + footnote.add_backref(ref['ids'][0]) + ref.resolved = 1 + i += 1 + + def symbolize_footnotes(self): + """Add symbols indexes to "[*]"-style footnotes and references.""" + labels = [] + for footnote in self.document.symbol_footnotes: + reps, index = divmod(self.document.symbol_footnote_start, + len(self.symbols)) + labeltext = self.symbols[index] * (reps + 1) + labels.append(labeltext) + footnote.insert(0, nodes.label('', labeltext)) + self.document.symbol_footnote_start += 1 + self.document.set_id(footnote) + i = 0 + for ref in self.document.symbol_footnote_refs: + try: + ref += nodes.Text(labels[i]) + except IndexError: + msg = self.document.reporter.error( + 'Too many symbol footnote references: only %s ' + 'corresponding footnotes available.' % len(labels), + base_node=ref) + msgid = self.document.set_id(msg) + for ref in self.document.symbol_footnote_refs[i:]: + if ref.resolved or ref.hasattr('refid'): + continue + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + break + footnote = self.document.symbol_footnotes[i] + assert len(footnote['ids']) == 1 + ref['refid'] = footnote['ids'][0] + self.document.note_refid(ref) + footnote.add_backref(ref['ids'][0]) + i += 1 + + def resolve_footnotes_and_citations(self): + """ + Link manually-labeled footnotes and citations to/from their + references. + """ + for footnote in self.document.footnotes: + for label in footnote['names']: + if label in self.document.footnote_refs: + reflist = self.document.footnote_refs[label] + self.resolve_references(footnote, reflist) + for citation in self.document.citations: + for label in citation['names']: + if label in self.document.citation_refs: + reflist = self.document.citation_refs[label] + self.resolve_references(citation, reflist) + + def resolve_references(self, note, reflist): + assert len(note['ids']) == 1 + id = note['ids'][0] + for ref in reflist: + if ref.resolved: + continue + ref.delattr('refname') + ref['refid'] = id + assert len(ref['ids']) == 1 + note.add_backref(ref['ids'][0]) + ref.resolved = 1 + note.resolved = 1 + + +class CircularSubstitutionDefinitionError(Exception): pass + + +class Substitutions(Transform): + + """ + Given the following ``document`` as input:: + + <document> + <paragraph> + The + <substitution_reference refname="biohazard"> + biohazard + symbol is deservedly scary-looking. + <substitution_definition name="biohazard"> + <image alt="biohazard" uri="biohazard.png"> + + The ``substitution_reference`` will simply be replaced by the + contents of the corresponding ``substitution_definition``. + + The transformed result will be:: + + <document> + <paragraph> + The + <image alt="biohazard" uri="biohazard.png"> + symbol is deservedly scary-looking. + <substitution_definition name="biohazard"> + <image alt="biohazard" uri="biohazard.png"> + """ + + default_priority = 220 + """The Substitutions transform has to be applied very early, before + `docutils.tranforms.frontmatter.DocTitle` and others.""" + + def apply(self): + defs = self.document.substitution_defs + normed = self.document.substitution_names + subreflist = list(self.document.traverse(nodes.substitution_reference)) + nested = {} + for ref in subreflist: + refname = ref['refname'] + key = None + if refname in defs: + key = refname + else: + normed_name = refname.lower() + if normed_name in normed: + key = normed[normed_name] + if key is None: + msg = self.document.reporter.error( + 'Undefined substitution referenced: "%s".' + % refname, base_node=ref) + msgid = self.document.set_id(msg) + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + else: + subdef = defs[key] + parent = ref.parent + index = parent.index(ref) + if ('ltrim' in subdef.attributes + or 'trim' in subdef.attributes): + if index > 0 and isinstance(parent[index - 1], + nodes.Text): + parent[index - 1] = parent[index - 1].rstrip() + if ('rtrim' in subdef.attributes + or 'trim' in subdef.attributes): + if (len(parent) > index + 1 + and isinstance(parent[index + 1], nodes.Text)): + parent[index + 1] = parent[index + 1].lstrip() + subdef_copy = subdef.deepcopy() + try: + # Take care of nested substitution references: + for nested_ref in subdef_copy.traverse( + nodes.substitution_reference): + nested_name = normed[nested_ref['refname'].lower()] + if nested_name in nested.setdefault(nested_name, []): + raise CircularSubstitutionDefinitionError + else: + nested[nested_name].append(key) + nested_ref['ref-origin'] = ref + subreflist.append(nested_ref) + except CircularSubstitutionDefinitionError: + parent = ref.parent + if isinstance(parent, nodes.substitution_definition): + msg = self.document.reporter.error( + 'Circular substitution definition detected:', + nodes.literal_block(parent.rawsource, + parent.rawsource), + line=parent.line, base_node=parent) + parent.replace_self(msg) + else: + # find original ref substitution which cased this error + ref_origin = ref + while ref_origin.hasattr('ref-origin'): + ref_origin = ref_origin['ref-origin'] + msg = self.document.reporter.error( + 'Circular substitution definition referenced: ' + '"%s".' % refname, base_node=ref_origin) + msgid = self.document.set_id(msg) + prb = nodes.problematic( + ref.rawsource, ref.rawsource, refid=msgid) + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + ref.replace_self(prb) + else: + ref.replace_self(subdef_copy.children) + # register refname of the replacment node(s) + # (needed for resolution of references) + for node in subdef_copy.children: + if isinstance(node, nodes.Referential): + # HACK: verify refname attribute exists. + # Test with docs/dev/todo.txt, see. |donate| + if 'refname' in node: + self.document.note_refname(node) + + +class TargetNotes(Transform): + + """ + Creates a footnote for each external target in the text, and corresponding + footnote references after each reference. + """ + + default_priority = 540 + """The TargetNotes transform has to be applied after `IndirectHyperlinks` + but before `Footnotes`.""" + + + def __init__(self, document, startnode): + Transform.__init__(self, document, startnode=startnode) + + self.classes = startnode.details.get('class', []) + + def apply(self): + notes = {} + nodelist = [] + for target in self.document.traverse(nodes.target): + # Only external targets. + if not target.hasattr('refuri'): + continue + names = target['names'] + refs = [] + for name in names: + refs.extend(self.document.refnames.get(name, [])) + if not refs: + continue + footnote = self.make_target_footnote(target['refuri'], refs, + notes) + if target['refuri'] not in notes: + notes[target['refuri']] = footnote + nodelist.append(footnote) + # Take care of anonymous references. + for ref in self.document.traverse(nodes.reference): + if not ref.get('anonymous'): + continue + if ref.hasattr('refuri'): + footnote = self.make_target_footnote(ref['refuri'], [ref], + notes) + if ref['refuri'] not in notes: + notes[ref['refuri']] = footnote + nodelist.append(footnote) + self.startnode.replace_self(nodelist) + + def make_target_footnote(self, refuri, refs, notes): + if refuri in notes: # duplicate? + footnote = notes[refuri] + assert len(footnote['names']) == 1 + footnote_name = footnote['names'][0] + else: # original + footnote = nodes.footnote() + footnote_id = self.document.set_id(footnote) + # Use uppercase letters and a colon; they can't be + # produced inside names by the parser. + footnote_name = 'TARGET_NOTE: ' + footnote_id + footnote['auto'] = 1 + footnote['names'] = [footnote_name] + footnote_paragraph = nodes.paragraph() + footnote_paragraph += nodes.reference('', refuri, refuri=refuri) + footnote += footnote_paragraph + self.document.note_autofootnote(footnote) + self.document.note_explicit_target(footnote, footnote) + for ref in refs: + if isinstance(ref, nodes.target): + continue + refnode = nodes.footnote_reference(refname=footnote_name, auto=1) + refnode['classes'] += self.classes + self.document.note_autofootnote_ref(refnode) + self.document.note_footnote_ref(refnode) + index = ref.parent.index(ref) + 1 + reflist = [refnode] + if not utils.get_trim_footnote_ref_space(self.document.settings): + if self.classes: + reflist.insert(0, nodes.inline(text=' ', Classes=self.classes)) + else: + reflist.insert(0, nodes.Text(' ')) + ref.parent.insert(index, reflist) + return footnote + + +class DanglingReferences(Transform): + + """ + Check for dangling references (incl. footnote & citation) and for + unreferenced targets. + """ + + default_priority = 850 + + def apply(self): + visitor = DanglingReferencesVisitor( + self.document, + self.document.transformer.unknown_reference_resolvers) + self.document.walk(visitor) + # *After* resolving all references, check for unreferenced + # targets: + for target in self.document.traverse(nodes.target): + if not target.referenced: + if target.get('anonymous'): + # If we have unreferenced anonymous targets, there + # is already an error message about anonymous + # hyperlink mismatch; no need to generate another + # message. + continue + if target['names']: + naming = target['names'][0] + elif target['ids']: + naming = target['ids'][0] + else: + # Hack: Propagated targets always have their refid + # attribute set. + naming = target['refid'] + self.document.reporter.info( + 'Hyperlink target "%s" is not referenced.' + % naming, base_node=target) + + +class DanglingReferencesVisitor(nodes.SparseNodeVisitor): + + def __init__(self, document, unknown_reference_resolvers): + nodes.SparseNodeVisitor.__init__(self, document) + self.document = document + self.unknown_reference_resolvers = unknown_reference_resolvers + + def unknown_visit(self, node): + pass + + def visit_reference(self, node): + if node.resolved or not node.hasattr('refname'): + return + refname = node['refname'] + id = self.document.nameids.get(refname) + if id is None: + for resolver_function in self.unknown_reference_resolvers: + if resolver_function(node): + break + else: + if refname in self.document.nameids: + msg = self.document.reporter.error( + 'Duplicate target name, cannot be used as a unique ' + 'reference: "%s".' % (node['refname']), base_node=node) + else: + msg = self.document.reporter.error( + 'Unknown target name: "%s".' % (node['refname']), + base_node=node) + msgid = self.document.set_id(msg) + prb = nodes.problematic( + node.rawsource, node.rawsource, refid=msgid) + try: + prbid = node['ids'][0] + except IndexError: + prbid = self.document.set_id(prb) + msg.add_backref(prbid) + node.replace_self(prb) + else: + del node['refname'] + node['refid'] = id + self.document.ids[id].note_referenced_by(id=id) + node.resolved = 1 + + visit_footnote_reference = visit_citation_reference = visit_reference diff --git a/env/lib/python3.8/site-packages/docutils/transforms/universal.py b/env/lib/python3.8/site-packages/docutils/transforms/universal.py new file mode 100644 index 000000000..d8a47495a --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/universal.py @@ -0,0 +1,320 @@ +# $Id: universal.py 8393 2019-09-18 10:13:00Z milde $ +# -*- coding: utf-8 -*- +# Authors: David Goodger <goodger@python.org>; Ueli Schlaepfer; Günter Milde +# Maintainer: docutils-develop@lists.sourceforge.net +# Copyright: This module has been placed in the public domain. + +""" +Transforms needed by most or all documents: + +- `Decorations`: Generate a document's header & footer. +- `Messages`: Placement of system messages stored in + `nodes.document.transform_messages`. +- `TestMessages`: Like `Messages`, used on test runs. +- `FinalReferences`: Resolve remaining references. +""" + +__docformat__ = 'reStructuredText' + +import re +import sys +import time +from docutils import nodes, utils +from docutils.transforms import TransformError, Transform +from docutils.utils import smartquotes + + +if sys.version_info >= (3, 0): + unicode = str # noqa + + +class Decorations(Transform): + + """ + Populate a document's decoration element (header, footer). + """ + + default_priority = 820 + + def apply(self): + header_nodes = self.generate_header() + if header_nodes: + decoration = self.document.get_decoration() + header = decoration.get_header() + header.extend(header_nodes) + footer_nodes = self.generate_footer() + if footer_nodes: + decoration = self.document.get_decoration() + footer = decoration.get_footer() + footer.extend(footer_nodes) + + def generate_header(self): + return None + + def generate_footer(self): + # @@@ Text is hard-coded for now. + # Should be made dynamic (language-dependent). + # @@@ Use timestamp from the `SOURCE_DATE_EPOCH`_ environment variable + # for the datestamp? + # See https://sourceforge.net/p/docutils/patches/132/ + # and https://reproducible-builds.org/specs/source-date-epoch/ + settings = self.document.settings + if settings.generator or settings.datestamp or settings.source_link \ + or settings.source_url: + text = [] + if settings.source_link and settings._source \ + or settings.source_url: + if settings.source_url: + source = settings.source_url + else: + source = utils.relative_path(settings._destination, + settings._source) + text.extend([ + nodes.reference('', 'View document source', + refuri=source), + nodes.Text('.\n')]) + if settings.datestamp: + datestamp = time.strftime(settings.datestamp, time.gmtime()) + text.append(nodes.Text('Generated on: ' + datestamp + '.\n')) + if settings.generator: + text.extend([ + nodes.Text('Generated by '), + nodes.reference('', 'Docutils', refuri= + 'http://docutils.sourceforge.net/'), + nodes.Text(' from '), + nodes.reference('', 'reStructuredText', refuri='http://' + 'docutils.sourceforge.net/rst.html'), + nodes.Text(' source.\n')]) + return [nodes.paragraph('', '', *text)] + else: + return None + + +class ExposeInternals(Transform): + + """ + Expose internal attributes if ``expose_internals`` setting is set. + """ + + default_priority = 840 + + def not_Text(self, node): + return not isinstance(node, nodes.Text) + + def apply(self): + if self.document.settings.expose_internals: + for node in self.document.traverse(self.not_Text): + for att in self.document.settings.expose_internals: + value = getattr(node, att, None) + if value is not None: + node['internal:' + att] = value + + +class Messages(Transform): + + """ + Place any system messages generated after parsing into a dedicated section + of the document. + """ + + default_priority = 860 + + def apply(self): + unfiltered = self.document.transform_messages + threshold = self.document.reporter.report_level + messages = [] + for msg in unfiltered: + if msg['level'] >= threshold and not msg.parent: + messages.append(msg) + if messages: + section = nodes.section(classes=['system-messages']) + # @@@ get this from the language module? + section += nodes.title('', 'Docutils System Messages') + section += messages + self.document.transform_messages[:] = [] + self.document += section + + +class FilterMessages(Transform): + + """ + Remove system messages below verbosity threshold. + """ + + default_priority = 870 + + def apply(self): + for node in tuple(self.document.traverse(nodes.system_message)): + if node['level'] < self.document.reporter.report_level: + node.parent.remove(node) + + +class TestMessages(Transform): + + """ + Append all post-parse system messages to the end of the document. + + Used for testing purposes. + """ + + default_priority = 880 + + def apply(self): + for msg in self.document.transform_messages: + if not msg.parent: + self.document += msg + + +class StripComments(Transform): + + """ + Remove comment elements from the document tree (only if the + ``strip_comments`` setting is enabled). + """ + + default_priority = 740 + + def apply(self): + if self.document.settings.strip_comments: + for node in tuple(self.document.traverse(nodes.comment)): + node.parent.remove(node) + + +class StripClassesAndElements(Transform): + + """ + Remove from the document tree all elements with classes in + `self.document.settings.strip_elements_with_classes` and all "classes" + attribute values in `self.document.settings.strip_classes`. + """ + + default_priority = 420 + + def apply(self): + if self.document.settings.strip_elements_with_classes: + self.strip_elements = set( + self.document.settings.strip_elements_with_classes) + # Iterate over a tuple as removing the current node + # corrupts the iterator returned by `traverse`: + for node in tuple(self.document.traverse(self.check_classes)): + node.parent.remove(node) + + if not self.document.settings.strip_classes: + return + strip_classes = self.document.settings.strip_classes + for node in self.document.traverse(nodes.Element): + for class_value in strip_classes: + try: + node['classes'].remove(class_value) + except ValueError: + pass + + def check_classes(self, node): + if not isinstance(node, nodes.Element): + return False + for class_value in node['classes'][:]: + if class_value in self.strip_elements: + return True + return False + + +class SmartQuotes(Transform): + + """ + Replace ASCII quotation marks with typographic form. + + Also replace multiple dashes with em-dash/en-dash characters. + """ + + default_priority = 850 + + nodes_to_skip = (nodes.FixedTextElement, nodes.Special) + """Do not apply "smartquotes" to instances of these block-level nodes.""" + + literal_nodes = (nodes.FixedTextElement, nodes.Special, + nodes.image, nodes.literal, nodes.math, + nodes.raw, nodes.problematic) + """Do apply smartquotes to instances of these inline nodes.""" + + smartquotes_action = 'qDe' + """Setting to select smartquote transformations. + + The default 'qDe' educates normal quote characters: (", '), + em- and en-dashes (---, --) and ellipses (...). + """ + + def __init__(self, document, startnode): + Transform.__init__(self, document, startnode=startnode) + self.unsupported_languages = set() + + def get_tokens(self, txtnodes): + # A generator that yields ``(texttype, nodetext)`` tuples for a list + # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). + for node in txtnodes: + if (isinstance(node.parent, self.literal_nodes) + or isinstance(node.parent.parent, self.literal_nodes)): + yield ('literal', unicode(node)) + else: + # SmartQuotes uses backslash escapes instead of null-escapes + txt = re.sub('(?<=\x00)([-\\\'".`])', r'\\\1', unicode(node)) + yield ('plain', txt) + + def apply(self): + smart_quotes = self.document.settings.smart_quotes + if not smart_quotes: + return + try: + alternative = smart_quotes.startswith('alt') + except AttributeError: + alternative = False + + document_language = self.document.settings.language_code + lc_smartquotes = self.document.settings.smartquotes_locales + if lc_smartquotes: + smartquotes.smartchars.quotes.update(dict(lc_smartquotes)) + + # "Educate" quotes in normal text. Handle each block of text + # (TextElement node) as a unit to keep context around inline nodes: + for node in self.document.traverse(nodes.TextElement): + # skip preformatted text blocks and special elements: + if isinstance(node, self.nodes_to_skip): + continue + # nested TextElements are not "block-level" elements: + if isinstance(node.parent, nodes.TextElement): + continue + + # list of text nodes in the "text block": + txtnodes = [txtnode for txtnode in node.traverse(nodes.Text) + if not isinstance(txtnode.parent, + nodes.option_string)] + + # language: use typographical quotes for language "lang" + lang = node.get_language_code(document_language) + # use alternative form if `smart-quotes` setting starts with "alt": + if alternative: + if '-x-altquot' in lang: + lang = lang.replace('-x-altquot', '') + else: + lang += '-x-altquot' + # drop unsupported subtags: + for tag in utils.normalize_language_tag(lang): + if tag in smartquotes.smartchars.quotes: + lang = tag + break + else: # language not supported: (keep ASCII quotes) + if lang not in self.unsupported_languages: + self.document.reporter.warning('No smart quotes ' + 'defined for language "%s".'%lang, base_node=node) + self.unsupported_languages.add(lang) + lang = '' + + # Iterator educating quotes in plain text: + # (see "utils/smartquotes.py" for the attribute setting) + teacher = smartquotes.educate_tokens(self.get_tokens(txtnodes), + attr=self.smartquotes_action, language=lang) + + for txtnode, newtext in zip(txtnodes, teacher): + txtnode.parent.replace(txtnode, nodes.Text(newtext, + rawsource=txtnode.rawsource)) + + self.unsupported_languages = set() # reset diff --git a/env/lib/python3.8/site-packages/docutils/transforms/writer_aux.py b/env/lib/python3.8/site-packages/docutils/transforms/writer_aux.py new file mode 100644 index 000000000..c5818d9c1 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/transforms/writer_aux.py @@ -0,0 +1,88 @@ +# $Id: writer_aux.py 7808 2015-02-27 17:03:32Z milde $ +# Author: Lea Wiemann <LeWiemann@gmail.com> +# Copyright: This module has been placed in the public domain. + +""" +Auxiliary transforms mainly to be used by Writer components. + +This module is called "writer_aux" because otherwise there would be +conflicting imports like this one:: + + from docutils import writers + from docutils.transforms import writers +""" + +__docformat__ = 'reStructuredText' + +from docutils import nodes, utils, languages +from docutils.transforms import Transform + + +class Compound(Transform): + + """ + Flatten all compound paragraphs. For example, transform :: + + <compound> + <paragraph> + <literal_block> + <paragraph> + + into :: + + <paragraph> + <literal_block classes="continued"> + <paragraph classes="continued"> + """ + + default_priority = 910 + + def apply(self): + for compound in self.document.traverse(nodes.compound): + first_child = True + for child in compound: + if first_child: + if not isinstance(child, nodes.Invisible): + first_child = False + else: + child['classes'].append('continued') + # Substitute children for compound. + compound.replace_self(compound[:]) + + +class Admonitions(Transform): + + """ + Transform specific admonitions, like this: + + <note> + <paragraph> + Note contents ... + + into generic admonitions, like this:: + + <admonition classes="note"> + <title> + Note + <paragraph> + Note contents ... + + The admonition title is localized. + """ + + default_priority = 920 + + def apply(self): + language = languages.get_language(self.document.settings.language_code, + self.document.reporter) + for node in self.document.traverse(nodes.Admonition): + node_name = node.__class__.__name__ + # Set class, so that we know what node this admonition came from. + node['classes'].append(node_name) + if not isinstance(node, nodes.admonition): + # Specific admonition. Transform into a generic admonition. + admonition = nodes.admonition(node.rawsource, *node.children, + **node.attributes) + title = nodes.title('', language.labels[node_name]) + admonition.insert(0, title) + node.replace_self(admonition) diff --git a/env/lib/python3.8/site-packages/docutils/utils/__init__.py b/env/lib/python3.8/site-packages/docutils/utils/__init__.py new file mode 100644 index 000000000..0744b4a5a --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/__init__.py @@ -0,0 +1,797 @@ +# coding: utf-8 +# $Id: __init__.py 8376 2019-08-27 19:49:29Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +Miscellaneous utilities for the documentation utilities. +""" + +__docformat__ = 'reStructuredText' + +import sys +import os +import os.path +import re +import itertools +import warnings +import unicodedata +from docutils import ApplicationError, DataError, __version_info__ +from docutils import nodes +from docutils.nodes import unescape +import docutils.io +from docutils.utils.error_reporting import ErrorOutput, SafeString + +if sys.version_info >= (3, 0): + unicode = str + + +class SystemMessage(ApplicationError): + + def __init__(self, system_message, level): + Exception.__init__(self, system_message.astext()) + self.level = level + + +class SystemMessagePropagation(ApplicationError): pass + + +class Reporter(object): + + """ + Info/warning/error reporter and ``system_message`` element generator. + + Five levels of system messages are defined, along with corresponding + methods: `debug()`, `info()`, `warning()`, `error()`, and `severe()`. + + There is typically one Reporter object per process. A Reporter object is + instantiated with thresholds for reporting (generating warnings) and + halting processing (raising exceptions), a switch to turn debug output on + or off, and an I/O stream for warnings. These are stored as instance + attributes. + + When a system message is generated, its level is compared to the stored + thresholds, and a warning or error is generated as appropriate. Debug + messages are produced if the stored debug switch is on, independently of + other thresholds. Message output is sent to the stored warning stream if + not set to ''. + + The Reporter class also employs a modified form of the "Observer" pattern + [GoF95]_ to track system messages generated. The `attach_observer` method + should be called before parsing, with a bound method or function which + accepts system messages. The observer can be removed with + `detach_observer`, and another added in its place. + + .. [GoF95] Gamma, Helm, Johnson, Vlissides. *Design Patterns: Elements of + Reusable Object-Oriented Software*. Addison-Wesley, Reading, MA, USA, + 1995. + """ + + levels = 'DEBUG INFO WARNING ERROR SEVERE'.split() + """List of names for system message levels, indexed by level.""" + + # system message level constants: + (DEBUG_LEVEL, + INFO_LEVEL, + WARNING_LEVEL, + ERROR_LEVEL, + SEVERE_LEVEL) = range(5) + + def __init__(self, source, report_level, halt_level, stream=None, + debug=False, encoding=None, error_handler='backslashreplace'): + """ + :Parameters: + - `source`: The path to or description of the source data. + - `report_level`: The level at or above which warning output will + be sent to `stream`. + - `halt_level`: The level at or above which `SystemMessage` + exceptions will be raised, halting execution. + - `debug`: Show debug (level=0) system messages? + - `stream`: Where warning output is sent. Can be file-like (has a + ``.write`` method), a string (file name, opened for writing), + '' (empty string) or `False` (for discarding all stream messages) + or `None` (implies `sys.stderr`; default). + - `encoding`: The output encoding. + - `error_handler`: The error handler for stderr output encoding. + """ + + self.source = source + """The path to or description of the source data.""" + + self.error_handler = error_handler + """The character encoding error handler.""" + + self.debug_flag = debug + """Show debug (level=0) system messages?""" + + self.report_level = report_level + """The level at or above which warning output will be sent + to `self.stream`.""" + + self.halt_level = halt_level + """The level at or above which `SystemMessage` exceptions + will be raised, halting execution.""" + + if not isinstance(stream, ErrorOutput): + stream = ErrorOutput(stream, encoding, error_handler) + + self.stream = stream + """Where warning output is sent.""" + + self.encoding = encoding or getattr(stream, 'encoding', 'ascii') + """The output character encoding.""" + + self.observers = [] + """List of bound methods or functions to call with each system_message + created.""" + + self.max_level = -1 + """The highest level system message generated so far.""" + + def set_conditions(self, category, report_level, halt_level, + stream=None, debug=False): + warnings.warn('docutils.utils.Reporter.set_conditions deprecated; ' + 'set attributes via configuration settings or directly', + DeprecationWarning, stacklevel=2) + self.report_level = report_level + self.halt_level = halt_level + if not isinstance(stream, ErrorOutput): + stream = ErrorOutput(stream, self.encoding, self.error_handler) + self.stream = stream + self.debug_flag = debug + + def attach_observer(self, observer): + """ + The `observer` parameter is a function or bound method which takes one + argument, a `nodes.system_message` instance. + """ + self.observers.append(observer) + + def detach_observer(self, observer): + self.observers.remove(observer) + + def notify_observers(self, message): + for observer in self.observers: + observer(message) + + def system_message(self, level, message, *children, **kwargs): + """ + Return a system_message object. + + Raise an exception or generate a warning if appropriate. + """ + # `message` can be a `string`, `unicode`, or `Exception` instance. + if isinstance(message, Exception): + message = SafeString(message) + + attributes = kwargs.copy() + if 'base_node' in kwargs: + source, line = get_source_line(kwargs['base_node']) + del attributes['base_node'] + if source is not None: + attributes.setdefault('source', source) + if line is not None: + attributes.setdefault('line', line) + # assert source is not None, "node has line- but no source-argument" + if not 'source' in attributes: # 'line' is absolute line number + try: # look up (source, line-in-source) + source, line = self.get_source_and_line(attributes.get('line')) + except AttributeError: + source, line = None, None + if source is not None: + attributes['source'] = source + if line is not None: + attributes['line'] = line + # assert attributes['line'] is not None, (message, kwargs) + # assert attributes['source'] is not None, (message, kwargs) + attributes.setdefault('source', self.source) + + msg = nodes.system_message(message, level=level, + type=self.levels[level], + *children, **attributes) + if self.stream and (level >= self.report_level + or self.debug_flag and level == self.DEBUG_LEVEL + or level >= self.halt_level): + self.stream.write(msg.astext() + '\n') + if level >= self.halt_level: + raise SystemMessage(msg, level) + if level > self.DEBUG_LEVEL or self.debug_flag: + self.notify_observers(msg) + self.max_level = max(level, self.max_level) + return msg + + def debug(self, *args, **kwargs): + """ + Level-0, "DEBUG": an internal reporting issue. Typically, there is no + effect on the processing. Level-0 system messages are handled + separately from the others. + """ + if self.debug_flag: + return self.system_message(self.DEBUG_LEVEL, *args, **kwargs) + + def info(self, *args, **kwargs): + """ + Level-1, "INFO": a minor issue that can be ignored. Typically there is + no effect on processing, and level-1 system messages are not reported. + """ + return self.system_message(self.INFO_LEVEL, *args, **kwargs) + + def warning(self, *args, **kwargs): + """ + Level-2, "WARNING": an issue that should be addressed. If ignored, + there may be unpredictable problems with the output. + """ + return self.system_message(self.WARNING_LEVEL, *args, **kwargs) + + def error(self, *args, **kwargs): + """ + Level-3, "ERROR": an error that should be addressed. If ignored, the + output will contain errors. + """ + return self.system_message(self.ERROR_LEVEL, *args, **kwargs) + + def severe(self, *args, **kwargs): + """ + Level-4, "SEVERE": a severe error that must be addressed. If ignored, + the output will contain severe errors. Typically level-4 system + messages are turned into exceptions which halt processing. + """ + return self.system_message(self.SEVERE_LEVEL, *args, **kwargs) + + +class ExtensionOptionError(DataError): pass +class BadOptionError(ExtensionOptionError): pass +class BadOptionDataError(ExtensionOptionError): pass +class DuplicateOptionError(ExtensionOptionError): pass + + +def extract_extension_options(field_list, options_spec): + """ + Return a dictionary mapping extension option names to converted values. + + :Parameters: + - `field_list`: A flat field list without field arguments, where each + field body consists of a single paragraph only. + - `options_spec`: Dictionary mapping known option names to a + conversion function such as `int` or `float`. + + :Exceptions: + - `KeyError` for unknown option names. + - `ValueError` for invalid option values (raised by the conversion + function). + - `TypeError` for invalid option value types (raised by conversion + function). + - `DuplicateOptionError` for duplicate options. + - `BadOptionError` for invalid fields. + - `BadOptionDataError` for invalid option data (missing name, + missing data, bad quotes, etc.). + """ + option_list = extract_options(field_list) + option_dict = assemble_option_dict(option_list, options_spec) + return option_dict + +def extract_options(field_list): + """ + Return a list of option (name, value) pairs from field names & bodies. + + :Parameter: + `field_list`: A flat field list, where each field name is a single + word and each field body consists of a single paragraph only. + + :Exceptions: + - `BadOptionError` for invalid fields. + - `BadOptionDataError` for invalid option data (missing name, + missing data, bad quotes, etc.). + """ + option_list = [] + for field in field_list: + if len(field[0].astext().split()) != 1: + raise BadOptionError( + 'extension option field name may not contain multiple words') + name = str(field[0].astext().lower()) + body = field[1] + if len(body) == 0: + data = None + elif len(body) > 1 or not isinstance(body[0], nodes.paragraph) \ + or len(body[0]) != 1 or not isinstance(body[0][0], nodes.Text): + raise BadOptionDataError( + 'extension option field body may contain\n' + 'a single paragraph only (option "%s")' % name) + else: + data = body[0][0].astext() + option_list.append((name, data)) + return option_list + +def assemble_option_dict(option_list, options_spec): + """ + Return a mapping of option names to values. + + :Parameters: + - `option_list`: A list of (name, value) pairs (the output of + `extract_options()`). + - `options_spec`: Dictionary mapping known option names to a + conversion function such as `int` or `float`. + + :Exceptions: + - `KeyError` for unknown option names. + - `DuplicateOptionError` for duplicate options. + - `ValueError` for invalid option values (raised by conversion + function). + - `TypeError` for invalid option value types (raised by conversion + function). + """ + options = {} + for name, value in option_list: + convertor = options_spec[name] # raises KeyError if unknown + if convertor is None: + raise KeyError(name) # or if explicitly disabled + if name in options: + raise DuplicateOptionError('duplicate option "%s"' % name) + try: + options[name] = convertor(value) + except (ValueError, TypeError) as detail: + raise detail.__class__('(option: "%s"; value: %r)\n%s' + % (name, value, ' '.join(detail.args))) + return options + + +class NameValueError(DataError): pass + + +def decode_path(path): + """ + Ensure `path` is Unicode. Return `nodes.reprunicode` object. + + Decode file/path string in a failsave manner if not already done. + """ + # see also http://article.gmane.org/gmane.text.docutils.user/2905 + if isinstance(path, unicode): + return path + try: + path = path.decode(sys.getfilesystemencoding(), 'strict') + except AttributeError: # default value None has no decode method + return nodes.reprunicode(path) + except UnicodeDecodeError: + try: + path = path.decode('utf-8', 'strict') + except UnicodeDecodeError: + path = path.decode('ascii', 'replace') + return nodes.reprunicode(path) + + +def extract_name_value(line): + """ + Return a list of (name, value) from a line of the form "name=value ...". + + :Exception: + `NameValueError` for invalid input (missing name, missing data, bad + quotes, etc.). + """ + attlist = [] + while line: + equals = line.find('=') + if equals == -1: + raise NameValueError('missing "="') + attname = line[:equals].strip() + if equals == 0 or not attname: + raise NameValueError( + 'missing attribute name before "="') + line = line[equals+1:].lstrip() + if not line: + raise NameValueError( + 'missing value after "%s="' % attname) + if line[0] in '\'"': + endquote = line.find(line[0], 1) + if endquote == -1: + raise NameValueError( + 'attribute "%s" missing end quote (%s)' + % (attname, line[0])) + if len(line) > endquote + 1 and line[endquote + 1].strip(): + raise NameValueError( + 'attribute "%s" end quote (%s) not followed by ' + 'whitespace' % (attname, line[0])) + data = line[1:endquote] + line = line[endquote+1:].lstrip() + else: + space = line.find(' ') + if space == -1: + data = line + line = '' + else: + data = line[:space] + line = line[space+1:].lstrip() + attlist.append((attname.lower(), data)) + return attlist + +def new_reporter(source_path, settings): + """ + Return a new Reporter object. + + :Parameters: + `source` : string + The path to or description of the source text of the document. + `settings` : optparse.Values object + Runtime settings. + """ + reporter = Reporter( + source_path, settings.report_level, settings.halt_level, + stream=settings.warning_stream, debug=settings.debug, + encoding=settings.error_encoding, + error_handler=settings.error_encoding_error_handler) + return reporter + +def new_document(source_path, settings=None): + """ + Return a new empty document object. + + :Parameters: + `source_path` : string + The path to or description of the source text of the document. + `settings` : optparse.Values object + Runtime settings. If none are provided, a default core set will + be used. If you will use the document object with any Docutils + components, you must provide their default settings as well. For + example, if parsing, at least provide the parser settings, + obtainable as follows:: + + settings = docutils.frontend.OptionParser( + components=(docutils.parsers.rst.Parser,) + ).get_default_values() + """ + from docutils import frontend + if settings is None: + settings = frontend.OptionParser().get_default_values() + source_path = decode_path(source_path) + reporter = new_reporter(source_path, settings) + document = nodes.document(settings, reporter, source=source_path) + document.note_source(source_path, -1) + return document + +def clean_rcs_keywords(paragraph, keyword_substitutions): + if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text): + textnode = paragraph[0] + for pattern, substitution in keyword_substitutions: + match = pattern.search(textnode) + if match: + paragraph[0] = nodes.Text(pattern.sub(substitution, textnode)) + return + +def relative_path(source, target): + """ + Build and return a path to `target`, relative to `source` (both files). + + If there is no common prefix, return the absolute path to `target`. + """ + source_parts = os.path.abspath(source or type(target)('dummy_file') + ).split(os.sep) + target_parts = os.path.abspath(target).split(os.sep) + # Check first 2 parts because '/dir'.split('/') == ['', 'dir']: + if source_parts[:2] != target_parts[:2]: + # Nothing in common between paths. + # Return absolute path, using '/' for URLs: + return '/'.join(target_parts) + source_parts.reverse() + target_parts.reverse() + while (source_parts and target_parts + and source_parts[-1] == target_parts[-1]): + # Remove path components in common: + source_parts.pop() + target_parts.pop() + target_parts.reverse() + parts = ['..'] * (len(source_parts) - 1) + target_parts + return '/'.join(parts) + +def get_stylesheet_reference(settings, relative_to=None): + """ + Retrieve a stylesheet reference from the settings object. + + Deprecated. Use get_stylesheet_list() instead to + enable specification of multiple stylesheets as a comma-separated + list. + """ + if settings.stylesheet_path: + assert not settings.stylesheet, ( + 'stylesheet and stylesheet_path are mutually exclusive.') + if relative_to == None: + relative_to = settings._destination + return relative_path(relative_to, settings.stylesheet_path) + else: + return settings.stylesheet + +# Return 'stylesheet' or 'stylesheet_path' arguments as list. +# +# The original settings arguments are kept unchanged: you can test +# with e.g. ``if settings.stylesheet_path:`` +# +# Differences to ``get_stylesheet_reference``: +# * return value is a list +# * no re-writing of the path (and therefore no optional argument) +# (if required, use ``utils.relative_path(source, target)`` +# in the calling script) +def get_stylesheet_list(settings): + """ + Retrieve list of stylesheet references from the settings object. + """ + assert not (settings.stylesheet and settings.stylesheet_path), ( + 'stylesheet and stylesheet_path are mutually exclusive.') + stylesheets = settings.stylesheet_path or settings.stylesheet or [] + # programmatically set default can be string or unicode: + if not isinstance(stylesheets, list): + stylesheets = [path.strip() for path in stylesheets.split(',')] + # expand relative paths if found in stylesheet-dirs: + return [find_file_in_dirs(path, settings.stylesheet_dirs) + for path in stylesheets] + +def find_file_in_dirs(path, dirs): + """ + Search for `path` in the list of directories `dirs`. + + Return the first expansion that matches an existing file. + """ + if os.path.isabs(path): + return path + for d in dirs: + if d == '.': + f = path + else: + d = os.path.expanduser(d) + f = os.path.join(d, path) + if os.path.exists(f): + return f + return path + +def get_trim_footnote_ref_space(settings): + """ + Return whether or not to trim footnote space. + + If trim_footnote_reference_space is not None, return it. + + If trim_footnote_reference_space is None, return False unless the + footnote reference style is 'superscript'. + """ + if settings.trim_footnote_reference_space is None: + return hasattr(settings, 'footnote_references') and \ + settings.footnote_references == 'superscript' + else: + return settings.trim_footnote_reference_space + +def get_source_line(node): + """ + Return the "source" and "line" attributes from the `node` given or from + its closest ancestor. + """ + while node: + if node.source or node.line: + return node.source, node.line + node = node.parent + return None, None + +def escape2null(text): + """Return a string with escape-backslashes converted to nulls.""" + parts = [] + start = 0 + while True: + found = text.find('\\', start) + if found == -1: + parts.append(text[start:]) + return ''.join(parts) + parts.append(text[start:found]) + parts.append('\x00' + text[found+1:found+2]) + start = found + 2 # skip character after escape + +# `unescape` definition moved to `nodes` to avoid circular import dependency. + +def split_escaped_whitespace(text): + """ + Split `text` on escaped whitespace (null+space or null+newline). + Return a list of strings. + """ + strings = text.split('\x00 ') + strings = [string.split('\x00\n') for string in strings] + # flatten list of lists of strings to list of strings: + return list(itertools.chain(*strings)) + +def strip_combining_chars(text): + if isinstance(text, str) and sys.version_info < (3, 0): + return text + return u''.join([c for c in text if not unicodedata.combining(c)]) + +def find_combining_chars(text): + """Return indices of all combining chars in Unicode string `text`. + + >>> from docutils.utils import find_combining_chars + >>> find_combining_chars(u'A t̆ab̆lĕ') + [3, 6, 9] + + """ + if isinstance(text, str) and sys.version_info < (3, 0): + return [] + return [i for i,c in enumerate(text) if unicodedata.combining(c)] + +def column_indices(text): + """Indices of Unicode string `text` when skipping combining characters. + + >>> from docutils.utils import column_indices + >>> column_indices(u'A t̆ab̆lĕ') + [0, 1, 2, 4, 5, 7, 8] + + """ + # TODO: account for asian wide chars here instead of using dummy + # replacements in the tableparser? + string_indices = list(range(len(text))) + for index in find_combining_chars(text): + string_indices[index] = None + return [i for i in string_indices if i is not None] + +east_asian_widths = {'W': 2, # Wide + 'F': 2, # Full-width (wide) + 'Na': 1, # Narrow + 'H': 1, # Half-width (narrow) + 'N': 1, # Neutral (not East Asian, treated as narrow) + 'A': 1} # Ambiguous (s/b wide in East Asian context, + # narrow otherwise, but that doesn't work) +"""Mapping of result codes from `unicodedata.east_asian_widt()` to character +column widths.""" + +def column_width(text): + """Return the column width of text. + + Correct ``len(text)`` for wide East Asian and combining Unicode chars. + """ + if isinstance(text, str) and sys.version_info < (3, 0): + return len(text) + width = sum([east_asian_widths[unicodedata.east_asian_width(c)] + for c in text]) + # correction for combining chars: + width -= len(find_combining_chars(text)) + return width + +def uniq(L): + r = [] + for item in L: + if not item in r: + r.append(item) + return r + +def unique_combinations(items, n): + """Return `itertools.combinations`.""" + warnings.warn('docutils.utils.unique_combinations is deprecated; ' + 'use itertools.combinations directly.', + DeprecationWarning, stacklevel=2) + return itertools.combinations(items, n) + +def normalize_language_tag(tag): + """Return a list of normalized combinations for a `BCP 47` language tag. + + Example: + + >>> from docutils.utils import normalize_language_tag + >>> normalize_language_tag('de_AT-1901') + ['de-at-1901', 'de-at', 'de-1901', 'de'] + >>> normalize_language_tag('de-CH-x_altquot') + ['de-ch-x-altquot', 'de-ch', 'de-x-altquot', 'de'] + + """ + # normalize: + tag = tag.lower().replace('-', '_') + # split (except singletons, which mark the following tag as non-standard): + tag = re.sub(r'_([a-zA-Z0-9])_', r'_\1-', tag) + subtags = [subtag for subtag in tag.split('_')] + base_tag = (subtags.pop(0),) + # find all combinations of subtags + taglist = [] + for n in range(len(subtags), 0, -1): + # for tags in unique_combinations(subtags, n): + for tags in itertools.combinations(subtags, n): + taglist.append('-'.join(base_tag+tags)) + taglist += base_tag + return taglist + + +class DependencyList(object): + + """ + List of dependencies, with file recording support. + + Note that the output file is not automatically closed. You have + to explicitly call the close() method. + """ + + def __init__(self, output_file=None, dependencies=[]): + """ + Initialize the dependency list, automatically setting the + output file to `output_file` (see `set_output()`) and adding + all supplied dependencies. + """ + self.set_output(output_file) + for i in dependencies: + self.add(i) + + def set_output(self, output_file): + """ + Set the output file and clear the list of already added + dependencies. + + `output_file` must be a string. The specified file is + immediately overwritten. + + If output_file is '-', the output will be written to stdout. + If it is None, no file output is done when calling add(). + """ + self.list = [] + if output_file: + if output_file == '-': + of = None + else: + of = output_file + self.file = docutils.io.FileOutput(destination_path=of, + encoding='utf8', autoclose=False) + else: + self.file = None + + def add(self, *filenames): + """ + If the dependency `filename` has not already been added, + append it to self.list and print it to self.file if self.file + is not None. + """ + for filename in filenames: + if not filename in self.list: + self.list.append(filename) + if self.file is not None: + self.file.write(filename+'\n') + + def close(self): + """ + Close the output file. + """ + self.file.close() + self.file = None + + def __repr__(self): + try: + output_file = self.file.name + except AttributeError: + output_file = None + return '%s(%r, %s)' % (self.__class__.__name__, output_file, self.list) + + +release_level_abbreviations = { + 'alpha': 'a', + 'beta': 'b', + 'candidate': 'rc', + 'final': '',} + +def version_identifier(version_info=None): + """ + Return a version identifier string built from `version_info`, a + `docutils.VersionInfo` namedtuple instance or compatible tuple. If + `version_info` is not provided, by default return a version identifier + string based on `docutils.__version_info__` (i.e. the current Docutils + version). + """ + if version_info is None: + version_info = __version_info__ + if version_info.micro: + micro = '.%s' % version_info.micro + else: + # 0 is omitted: + micro = '' + releaselevel = release_level_abbreviations[version_info.releaselevel] + if version_info.serial: + serial = version_info.serial + else: + # 0 is omitted: + serial = '' + if version_info.release: + dev = '' + else: + dev = '.dev' + version = '%s.%s%s%s%s%s' % ( + version_info.major, + version_info.minor, + micro, + releaselevel, + serial, + dev) + return version diff --git a/env/lib/python3.8/site-packages/docutils/utils/code_analyzer.py b/env/lib/python3.8/site-packages/docutils/utils/code_analyzer.py new file mode 100644 index 000000000..834fc073e --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/code_analyzer.py @@ -0,0 +1,142 @@ +#!/usr/bin/python +# coding: utf-8 + +"""Lexical analysis of formal languages (i.e. code) using Pygments.""" + +# :Author: Georg Brandl; Felix Wiemann; Günter Milde +# :Date: $Date: 2019-08-26 18:46:50 +0200 (Mo, 26. Aug 2019) $ +# :Copyright: This module has been placed in the public domain. + +from docutils import ApplicationError +try: + from pkg_resources import DistributionNotFound as ResourceError +except (ImportError, RuntimeError): + class ResourceError(ApplicationError): + pass # stub +try: + import pygments + from pygments.lexers import get_lexer_by_name + from pygments.formatters.html import _get_ttype_class + with_pygments = True +except ImportError: + with_pygments = False + +# Filter the following token types from the list of class arguments: +unstyled_tokens = ['token', # Token (base token type) + 'text', # Token.Text + ''] # short name for Token and Text +# (Add, e.g., Token.Punctuation with ``unstyled_tokens += 'punctuation'``.) + +class LexerError(ApplicationError): + pass + +class Lexer(object): + """Parse `code` lines and yield "classified" tokens. + + Arguments + + code -- string of source code to parse, + language -- formal language the code is written in, + tokennames -- either 'long', 'short', or '' (see below). + + Merge subsequent tokens of the same token-type. + + Iterating over an instance yields the tokens as ``(tokentype, value)`` + tuples. The value of `tokennames` configures the naming of the tokentype: + + 'long': downcased full token type name, + 'short': short name defined by pygments.token.STANDARD_TYPES + (= class argument used in pygments html output), + 'none': skip lexical analysis. + """ + + def __init__(self, code, language, tokennames='short'): + """ + Set up a lexical analyzer for `code` in `language`. + """ + self.code = code + self.language = language + self.tokennames = tokennames + self.lexer = None + # get lexical analyzer for `language`: + if language in ('', 'text') or tokennames == 'none': + return + if not with_pygments: + raise LexerError('Cannot analyze code. ' + 'Pygments package not found.') + try: + self.lexer = get_lexer_by_name(self.language) + except (pygments.util.ClassNotFound, ResourceError): + raise LexerError('Cannot analyze code. ' + 'No Pygments lexer found for "%s".' % language) + # self.lexer.add_filter('tokenmerge') + # Since version 1.2. (released Jan 01, 2010) Pygments has a + # TokenMergeFilter. # ``self.merge(tokens)`` in __iter__ could + # be replaced by ``self.lexer.add_filter('tokenmerge')`` in __init__. + # However, `merge` below also strips a final newline added by pygments. + # + # self.lexer.add_filter('tokenmerge') + + def merge(self, tokens): + """Merge subsequent tokens of same token-type. + + Also strip the final newline (added by pygments). + """ + tokens = iter(tokens) + (lasttype, lastval) = next(tokens) + for ttype, value in tokens: + if ttype is lasttype: + lastval += value + else: + yield(lasttype, lastval) + (lasttype, lastval) = (ttype, value) + if lastval.endswith('\n'): + lastval = lastval[:-1] + if lastval: + yield(lasttype, lastval) + + def __iter__(self): + """Parse self.code and yield "classified" tokens. + """ + if self.lexer is None: + yield ([], self.code) + return + tokens = pygments.lex(self.code, self.lexer) + for tokentype, value in self.merge(tokens): + if self.tokennames == 'long': # long CSS class args + classes = str(tokentype).lower().split('.') + else: # short CSS class args + classes = [_get_ttype_class(tokentype)] + classes = [cls for cls in classes if cls not in unstyled_tokens] + yield (classes, value) + + +class NumberLines(object): + """Insert linenumber-tokens at the start of every code line. + + Arguments + + tokens -- iterable of ``(classes, value)`` tuples + startline -- first line number + endline -- last line number + + Iterating over an instance yields the tokens with a + ``(['ln'], '<the line number>')`` token added for every code line. + Multi-line tokens are splitted.""" + + def __init__(self, tokens, startline, endline): + self.tokens = tokens + self.startline = startline + # pad linenumbers, e.g. endline == 100 -> fmt_str = '%3d ' + self.fmt_str = '%%%dd ' % len(str(endline)) + + def __iter__(self): + lineno = self.startline + yield (['ln'], self.fmt_str % lineno) + for ttype, value in self.tokens: + lines = value.split('\n') + for line in lines[:-1]: + yield (ttype, line + '\n') + lineno += 1 + yield (['ln'], self.fmt_str % lineno) + yield (ttype, lines[-1]) diff --git a/env/lib/python3.8/site-packages/docutils/utils/error_reporting.py b/env/lib/python3.8/site-packages/docutils/utils/error_reporting.py new file mode 100644 index 000000000..64cd953fe --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/error_reporting.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# :Id: $Id: error_reporting.py 8367 2019-08-27 12:09:56Z milde $ +# :Copyright: © 2011 Günter Milde. +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + +""" +Error reporting should be safe from encoding/decoding errors. +However, implicit conversions of strings and exceptions like + +>>> u'%s world: %s' % ('H\xe4llo', Exception(u'H\xe4llo') + +fail in some Python versions: + +* In Python <= 2.6, ``unicode(<exception instance>)`` uses + `__str__` and fails with non-ASCII chars in`unicode` arguments. + (work around http://bugs.python.org/issue2517): + +* In Python 2, unicode(<exception instance>) fails, with non-ASCII + chars in arguments. (Use case: in some locales, the errstr + argument of IOError contains non-ASCII chars.) + +* In Python 2, str(<exception instance>) fails, with non-ASCII chars + in `unicode` arguments. + +The `SafeString`, `ErrorString` and `ErrorOutput` classes handle +common exceptions. +""" + +import codecs +import sys + +# Guess the locale's encoding. +# If no valid guess can be made, locale_encoding is set to `None`: +try: + import locale # module missing in Jython +except ImportError: + locale_encoding = None +else: + try: + locale_encoding = locale.getlocale()[1] or locale.getdefaultlocale()[1] + # locale.getpreferredencoding([do_setlocale=True|False]) + # has side-effects | might return a wrong guess. + # (cf. Update 1 in http://stackoverflow.com/questions/4082645/using-python-2-xs-locale-module-to-format-numbers-and-currency) + except ValueError as error: # OS X may set UTF-8 without language code + # see http://bugs.python.org/issue18378 + # and https://sourceforge.net/p/docutils/bugs/298/ + if "unknown locale: UTF-8" in error.args: + locale_encoding = "UTF-8" + else: + locale_encoding = None + except: # any other problems determining the locale -> use None + locale_encoding = None + try: + codecs.lookup(locale_encoding or '') # None -> '' + except LookupError: + locale_encoding = None + + +if sys.version_info >= (3, 0): + unicode = str # noqa + + +class SafeString(object): + """ + A wrapper providing robust conversion to `str` and `unicode`. + """ + + def __init__(self, data, encoding=None, encoding_errors='backslashreplace', + decoding_errors='replace'): + self.data = data + self.encoding = (encoding or getattr(data, 'encoding', None) or + locale_encoding or 'ascii') + self.encoding_errors = encoding_errors + self.decoding_errors = decoding_errors + + + def __str__(self): + try: + return str(self.data) + except UnicodeEncodeError: + if isinstance(self.data, Exception): + args = [str(SafeString(arg, self.encoding, + self.encoding_errors)) + for arg in self.data.args] + return ', '.join(args) + if isinstance(self.data, unicode): + if sys.version_info > (3, 0): + return self.data + else: + return self.data.encode(self.encoding, + self.encoding_errors) + raise + + def __unicode__(self): + """ + Return unicode representation of `self.data`. + + Try ``unicode(self.data)``, catch `UnicodeError` and + + * if `self.data` is an Exception instance, work around + http://bugs.python.org/issue2517 with an emulation of + Exception.__unicode__, + + * else decode with `self.encoding` and `self.decoding_errors`. + """ + try: + u = unicode(self.data) + if isinstance(self.data, EnvironmentError): + u = u.replace(": u'", ": '") # normalize filename quoting + return u + except UnicodeError as error: # catch ..Encode.. and ..Decode.. errors + if isinstance(self.data, EnvironmentError): + return u"[Errno %s] %s: '%s'" % (self.data.errno, + SafeString(self.data.strerror, self.encoding, + self.decoding_errors), + SafeString(self.data.filename, self.encoding, + self.decoding_errors)) + if isinstance(self.data, Exception): + args = [unicode(SafeString(arg, self.encoding, + decoding_errors=self.decoding_errors)) + for arg in self.data.args] + return u', '.join(args) + if isinstance(error, UnicodeDecodeError): + return unicode(self.data, self.encoding, self.decoding_errors) + raise + +class ErrorString(SafeString): + """ + Safely report exception type and message. + """ + def __str__(self): + return '%s: %s' % (self.data.__class__.__name__, + super(ErrorString, self).__str__()) + + def __unicode__(self): + return u'%s: %s' % (self.data.__class__.__name__, + super(ErrorString, self).__unicode__()) + + +class ErrorOutput(object): + """ + Wrapper class for file-like error streams with + failsave de- and encoding of `str`, `bytes`, `unicode` and + `Exception` instances. + """ + + def __init__(self, stream=None, encoding=None, + encoding_errors='backslashreplace', + decoding_errors='replace'): + """ + :Parameters: + - `stream`: a file-like object, + a string (path to a file), + `None` (write to `sys.stderr`, default), or + evaluating to `False` (write() requests are ignored). + - `encoding`: `stream` text encoding. Guessed if None. + - `encoding_errors`: how to treat encoding errors. + """ + if stream is None: + stream = sys.stderr + elif not(stream): + stream = False + # if `stream` is a file name, open it + elif isinstance(stream, str): + stream = open(stream, 'w') + elif isinstance(stream, unicode): + stream = open(stream.encode(sys.getfilesystemencoding()), 'w') + + self.stream = stream + """Where warning output is sent.""" + + self.encoding = (encoding or getattr(stream, 'encoding', None) or + locale_encoding or 'ascii') + """The output character encoding.""" + + self.encoding_errors = encoding_errors + """Encoding error handler.""" + + self.decoding_errors = decoding_errors + """Decoding error handler.""" + + def write(self, data): + """ + Write `data` to self.stream. Ignore, if self.stream is False. + + `data` can be a `string`, `unicode`, or `Exception` instance. + """ + if self.stream is False: + return + if isinstance(data, Exception): + data = unicode(SafeString(data, self.encoding, + self.encoding_errors, self.decoding_errors)) + try: + self.stream.write(data) + except UnicodeEncodeError: + self.stream.write(data.encode(self.encoding, self.encoding_errors)) + except TypeError: + if isinstance(data, unicode): # passed stream may expect bytes + self.stream.write(data.encode(self.encoding, + self.encoding_errors)) + return + if self.stream in (sys.stderr, sys.stdout): + self.stream.buffer.write(data) # write bytes to raw stream + else: + self.stream.write(unicode(data, self.encoding, + self.decoding_errors)) + + def close(self): + """ + Close the error-output stream. + + Ignored if the stream is` sys.stderr` or `sys.stdout` or has no + close() method. + """ + if self.stream in (sys.stdout, sys.stderr): + return + try: + self.stream.close() + except AttributeError: + pass diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/__init__.py b/env/lib/python3.8/site-packages/docutils/utils/math/__init__.py new file mode 100644 index 000000000..673f93e37 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/__init__.py @@ -0,0 +1,48 @@ +# :Id: $Id: __init__.py 7865 2015-04-12 10:06:43Z milde $ +# :Author: Guenter Milde. +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + +""" +This is the Docutils (Python Documentation Utilities) "math" sub-package. + +It contains various modules for conversion between different math formats +(LaTeX, MathML, HTML). + +:math2html: LaTeX math -> HTML conversion from eLyXer +:latex2mathml: LaTeX math -> presentational MathML +:unichar2tex: Unicode character to LaTeX math translation table +:tex2unichar: LaTeX math to Unicode character translation dictionaries +:tex2mathml_extern: Wrapper for TeX -> MathML command line converters +""" + +# helpers for Docutils math support +# ================================= + +def pick_math_environment(code, numbered=False): + """Return the right math environment to display `code`. + + The test simply looks for line-breaks (``\\``) outside environments. + Multi-line formulae are set with ``align``, one-liners with + ``equation``. + + If `numbered` evaluates to ``False``, the "starred" versions are used + to suppress numbering. + """ + # cut out environment content: + chunks = code.split(r'\begin{') + toplevel_code = ''.join([chunk.split(r'\end{')[-1] + for chunk in chunks]) + if toplevel_code.find(r'\\') >= 0: + env = 'align' + else: + env = 'equation' + if not numbered: + env += '*' + return env diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/latex2mathml.py b/env/lib/python3.8/site-packages/docutils/utils/math/latex2mathml.py new file mode 100644 index 000000000..dc8549ee5 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/latex2mathml.py @@ -0,0 +1,568 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# :Id: $Id: latex2mathml.py 8366 2019-08-27 12:09:19Z milde $ +# :Copyright: © 2010 Günter Milde. +# Based on rst2mathml.py from the latex_math sandbox project +# © 2005 Jens Jørgen Mortensen +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + + +"""Convert LaTex math code into presentational MathML""" + +# Based on the `latex_math` sandbox project by Jens Jørgen Mortensen + +import docutils.utils.math.tex2unichar as tex2unichar + +# TeX spacing combining +over = {'acute': u'\u00B4', # u'\u0301', + 'bar': u'\u00AF', # u'\u0304', + 'breve': u'\u02D8', # u'\u0306', + 'check': u'\u02C7', # u'\u030C', + 'dot': u'\u02D9', # u'\u0307', + 'ddot': u'\u00A8', # u'\u0308', + 'dddot': u'\u20DB', + 'grave': u'`', # u'\u0300', + 'hat': u'^', # u'\u0302', + 'mathring': u'\u02DA', # u'\u030A', + 'overleftrightarrow': u'\u20e1', + # 'overline': # u'\u0305', + 'tilde': u'\u02DC', # u'\u0303', + 'vec': u'\u20D7'} + +Greek = { # Capital Greek letters: (upright in TeX style) + 'Phi':u'\u03a6', 'Xi':u'\u039e', 'Sigma':u'\u03a3', + 'Psi':u'\u03a8', 'Delta':u'\u0394', 'Theta':u'\u0398', + 'Upsilon':u'\u03d2', 'Pi':u'\u03a0', 'Omega':u'\u03a9', + 'Gamma':u'\u0393', 'Lambda':u'\u039b'} + +letters = tex2unichar.mathalpha + +special = tex2unichar.mathbin # Binary symbols +special.update(tex2unichar.mathrel) # Relation symbols, arrow symbols +special.update(tex2unichar.mathord) # Miscellaneous symbols +special.update(tex2unichar.mathop) # Variable-sized symbols +special.update(tex2unichar.mathopen) # Braces +special.update(tex2unichar.mathclose) # Braces +special.update(tex2unichar.mathfence) + +sumintprod = ''.join([special[symbol] for symbol in + ['sum', 'int', 'oint', 'prod']]) + +functions = ['arccos', 'arcsin', 'arctan', 'arg', 'cos', 'cosh', + 'cot', 'coth', 'csc', 'deg', 'det', 'dim', + 'exp', 'gcd', 'hom', 'inf', 'ker', 'lg', + 'lim', 'liminf', 'limsup', 'ln', 'log', 'max', + 'min', 'Pr', 'sec', 'sin', 'sinh', 'sup', + 'tan', 'tanh', + 'injlim', 'varinjlim', 'varlimsup', + 'projlim', 'varliminf', 'varprojlim'] + + +mathbb = { + 'A': u'\U0001D538', + 'B': u'\U0001D539', + 'C': u'\u2102', + 'D': u'\U0001D53B', + 'E': u'\U0001D53C', + 'F': u'\U0001D53D', + 'G': u'\U0001D53E', + 'H': u'\u210D', + 'I': u'\U0001D540', + 'J': u'\U0001D541', + 'K': u'\U0001D542', + 'L': u'\U0001D543', + 'M': u'\U0001D544', + 'N': u'\u2115', + 'O': u'\U0001D546', + 'P': u'\u2119', + 'Q': u'\u211A', + 'R': u'\u211D', + 'S': u'\U0001D54A', + 'T': u'\U0001D54B', + 'U': u'\U0001D54C', + 'V': u'\U0001D54D', + 'W': u'\U0001D54E', + 'X': u'\U0001D54F', + 'Y': u'\U0001D550', + 'Z': u'\u2124', + } + +mathscr = { + 'A': u'\U0001D49C', + 'B': u'\u212C', # bernoulli function + 'C': u'\U0001D49E', + 'D': u'\U0001D49F', + 'E': u'\u2130', + 'F': u'\u2131', + 'G': u'\U0001D4A2', + 'H': u'\u210B', # hamiltonian + 'I': u'\u2110', + 'J': u'\U0001D4A5', + 'K': u'\U0001D4A6', + 'L': u'\u2112', # lagrangian + 'M': u'\u2133', # physics m-matrix + 'N': u'\U0001D4A9', + 'O': u'\U0001D4AA', + 'P': u'\U0001D4AB', + 'Q': u'\U0001D4AC', + 'R': u'\u211B', + 'S': u'\U0001D4AE', + 'T': u'\U0001D4AF', + 'U': u'\U0001D4B0', + 'V': u'\U0001D4B1', + 'W': u'\U0001D4B2', + 'X': u'\U0001D4B3', + 'Y': u'\U0001D4B4', + 'Z': u'\U0001D4B5', + 'a': u'\U0001D4B6', + 'b': u'\U0001D4B7', + 'c': u'\U0001D4B8', + 'd': u'\U0001D4B9', + 'e': u'\u212F', + 'f': u'\U0001D4BB', + 'g': u'\u210A', + 'h': u'\U0001D4BD', + 'i': u'\U0001D4BE', + 'j': u'\U0001D4BF', + 'k': u'\U0001D4C0', + 'l': u'\U0001D4C1', + 'm': u'\U0001D4C2', + 'n': u'\U0001D4C3', + 'o': u'\u2134', # order of + 'p': u'\U0001D4C5', + 'q': u'\U0001D4C6', + 'r': u'\U0001D4C7', + 's': u'\U0001D4C8', + 't': u'\U0001D4C9', + 'u': u'\U0001D4CA', + 'v': u'\U0001D4CB', + 'w': u'\U0001D4CC', + 'x': u'\U0001D4CD', + 'y': u'\U0001D4CE', + 'z': u'\U0001D4CF', + } + +negatables = {'=': u'\u2260', + r'\in': u'\u2209', + r'\equiv': u'\u2262'} + +# LaTeX to MathML translation stuff: +class math(object): + """Base class for MathML elements.""" + + nchildren = 1000000 + """Required number of children""" + + def __init__(self, children=None, inline=None): + """math([children]) -> MathML element + + children can be one child or a list of children.""" + + self.children = [] + if children is not None: + if isinstance(children, list): + for child in children: + self.append(child) + else: + # Only one child: + self.append(children) + + if inline is not None: + self.inline = inline + + def __repr__(self): + if hasattr(self, 'children'): + return self.__class__.__name__ + '(%s)' % \ + ','.join([repr(child) for child in self.children]) + else: + return self.__class__.__name__ + + def full(self): + """Room for more children?""" + + return len(self.children) >= self.nchildren + + def append(self, child): + """append(child) -> element + + Appends child and returns self if self is not full or first + non-full parent.""" + + assert not self.full() + self.children.append(child) + child.parent = self + node = self + while node.full(): + node = node.parent + return node + + def delete_child(self): + """delete_child() -> child + + Delete last child and return it.""" + + child = self.children[-1] + del self.children[-1] + return child + + def close(self): + """close() -> parent + + Close element and return first non-full element.""" + + parent = self.parent + while parent.full(): + parent = parent.parent + return parent + + def xml(self): + """xml() -> xml-string""" + + return self.xml_start() + self.xml_body() + self.xml_end() + + def xml_start(self): + if not hasattr(self, 'inline'): + return ['<%s>' % self.__class__.__name__] + xmlns = 'http://www.w3.org/1998/Math/MathML' + if self.inline: + return ['<math xmlns="%s">' % xmlns] + else: + return ['<math xmlns="%s" mode="display">' % xmlns] + + def xml_end(self): + return ['</%s>' % self.__class__.__name__] + + def xml_body(self): + xml = [] + for child in self.children: + xml.extend(child.xml()) + return xml + +class mrow(math): + def xml_start(self): + return ['\n<%s>' % self.__class__.__name__] + +class mtable(math): + def xml_start(self): + return ['\n<%s>' % self.__class__.__name__] + +class mtr(mrow): pass +class mtd(mrow): pass + +class mx(math): + """Base class for mo, mi, and mn""" + + nchildren = 0 + def __init__(self, data): + self.data = data + + def xml_body(self): + return [self.data] + +class mo(mx): + translation = {'<': '<', '>': '>'} + def xml_body(self): + return [self.translation.get(self.data, self.data)] + +class mi(mx): pass +class mn(mx): pass + +class msub(math): + nchildren = 2 + +class msup(math): + nchildren = 2 + +class msqrt(math): + nchildren = 1 + +class mroot(math): + nchildren = 2 + +class mfrac(math): + nchildren = 2 + +class msubsup(math): + nchildren = 3 + def __init__(self, children=None, reversed=False): + self.reversed = reversed + math.__init__(self, children) + + def xml(self): + if self.reversed: +## self.children[1:3] = self.children[2:0:-1] + self.children[1:3] = [self.children[2], self.children[1]] + self.reversed = False + return math.xml(self) + +class mfenced(math): + translation = {'\\{': '{', '\\langle': u'\u2329', + '\\}': '}', '\\rangle': u'\u232A', + '.': ''} + def __init__(self, par): + self.openpar = par + math.__init__(self) + + def xml_start(self): + open = self.translation.get(self.openpar, self.openpar) + close = self.translation.get(self.closepar, self.closepar) + return ['<mfenced open="%s" close="%s">' % (open, close)] + +class mspace(math): + nchildren = 0 + +class mstyle(math): + def __init__(self, children=None, nchildren=None, **kwargs): + if nchildren is not None: + self.nchildren = nchildren + math.__init__(self, children) + self.attrs = kwargs + + def xml_start(self): + return ['<mstyle '] + ['%s="%s"' % item + for item in self.attrs.items()] + ['>'] + +class mover(math): + nchildren = 2 + def __init__(self, children=None, reversed=False): + self.reversed = reversed + math.__init__(self, children) + + def xml(self): + if self.reversed: + self.children.reverse() + self.reversed = False + return math.xml(self) + +class munder(math): + nchildren = 2 + +class munderover(math): + nchildren = 3 + def __init__(self, children=None): + math.__init__(self, children) + +class mtext(math): + nchildren = 0 + def __init__(self, text): + self.text = text + + def xml_body(self): + return [self.text] + +def parse_latex_math(string, inline=True): + """parse_latex_math(string [,inline]) -> MathML-tree + + Returns a MathML-tree parsed from string. inline=True is for + inline math and inline=False is for displayed math. + + tree is the whole tree and node is the current element.""" + + # Normalize white-space: + string = ' '.join(string.split()) + + if inline: + node = mrow() + tree = math(node, inline=True) + else: + node = mtd() + tree = math(mtable(mtr(node)), inline=False) + + while len(string) > 0: + n = len(string) + c = string[0] + skip = 1 # number of characters consumed + if n > 1: + c2 = string[1] + else: + c2 = '' + if c == ' ': + pass + elif c == '\\': + if c2 in '{}': + node = node.append(mo(c2)) + skip = 2 + elif c2 == ' ': + node = node.append(mspace()) + skip = 2 + elif c2 == ',': # TODO: small space + node = node.append(mspace()) + skip = 2 + elif c2.isalpha(): + # We have a LaTeX-name: + i = 2 + while i < n and string[i].isalpha(): + i += 1 + name = string[1:i] + node, skip = handle_keyword(name, node, string[i:]) + skip += i + elif c2 == '\\': + # End of a row: + entry = mtd() + row = mtr(entry) + node.close().close().append(row) + node = entry + skip = 2 + else: + raise SyntaxError(u'Syntax error: "%s%s"' % (c, c2)) + elif c.isalpha(): + node = node.append(mi(c)) + elif c.isdigit(): + node = node.append(mn(c)) + elif c in "+-*/=()[]|<>,.!?':;@": + node = node.append(mo(c)) + elif c == '_': + child = node.delete_child() + if isinstance(child, msup): + sub = msubsup(child.children, reversed=True) + elif isinstance(child, mo) and child.data in sumintprod: + sub = munder(child) + else: + sub = msub(child) + node.append(sub) + node = sub + elif c == '^': + child = node.delete_child() + if isinstance(child, msub): + sup = msubsup(child.children) + elif isinstance(child, mo) and child.data in sumintprod: + sup = mover(child) + elif (isinstance(child, munder) and + child.children[0].data in sumintprod): + sup = munderover(child.children) + else: + sup = msup(child) + node.append(sup) + node = sup + elif c == '{': + row = mrow() + node.append(row) + node = row + elif c == '}': + node = node.close() + elif c == '&': + entry = mtd() + node.close().append(entry) + node = entry + else: + raise SyntaxError(u'Illegal character: "%s"' % c) + string = string[skip:] + return tree + + +def handle_keyword(name, node, string): + skip = 0 + if len(string) > 0 and string[0] == ' ': + string = string[1:] + skip = 1 + if name == 'begin': + if not string.startswith('{matrix}'): + raise SyntaxError(u'Environment not supported! ' + u'Supported environment: "matrix".') + skip += 8 + entry = mtd() + table = mtable(mtr(entry)) + node.append(table) + node = entry + elif name == 'end': + if not string.startswith('{matrix}'): + raise SyntaxError(u'Expected "\\end{matrix}"!') + skip += 8 + node = node.close().close().close() + elif name in ('text', 'mathrm'): + if string[0] != '{': + raise SyntaxError(u'Expected "\\text{...}"!') + i = string.find('}') + if i == -1: + raise SyntaxError(u'Expected "\\text{...}"!') + node = node.append(mtext(string[1:i])) + skip += i + 1 + elif name == 'sqrt': + sqrt = msqrt() + node.append(sqrt) + node = sqrt + elif name == 'frac': + frac = mfrac() + node.append(frac) + node = frac + elif name == 'left': + for par in ['(', '[', '|', '\\{', '\\langle', '.']: + if string.startswith(par): + break + else: + raise SyntaxError(u'Missing left-brace!') + fenced = mfenced(par) + node.append(fenced) + row = mrow() + fenced.append(row) + node = row + skip += len(par) + elif name == 'right': + for par in [')', ']', '|', '\\}', '\\rangle', '.']: + if string.startswith(par): + break + else: + raise SyntaxError(u'Missing right-brace!') + node = node.close() + node.closepar = par + node = node.close() + skip += len(par) + elif name == 'not': + for operator in negatables: + if string.startswith(operator): + break + else: + raise SyntaxError(u'Expected something to negate: "\\not ..."!') + node = node.append(mo(negatables[operator])) + skip += len(operator) + elif name == 'mathbf': + style = mstyle(nchildren=1, fontweight='bold') + node.append(style) + node = style + elif name == 'mathbb': + if string[0] != '{' or not string[1].isupper() or string[2] != '}': + raise SyntaxError(u'Expected something like "\\mathbb{A}"!') + node = node.append(mi(mathbb[string[1]])) + skip += 3 + elif name in ('mathscr', 'mathcal'): + if string[0] != '{' or string[2] != '}': + raise SyntaxError(u'Expected something like "\\mathscr{A}"!') + node = node.append(mi(mathscr[string[1]])) + skip += 3 + elif name == 'colon': # "normal" colon, not binary operator + node = node.append(mo(':')) # TODO: add ``lspace="0pt"`` + elif name in Greek: # Greek capitals (upright in "TeX style") + node = node.append(mo(Greek[name])) + # TODO: "ISO style" sets them italic. Could we use a class argument + # to enable styling via CSS? + elif name in letters: + node = node.append(mi(letters[name])) + elif name in special: + node = node.append(mo(special[name])) + elif name in functions: + node = node.append(mo(name)) + elif name in over: + ovr = mover(mo(over[name]), reversed=True) + node.append(ovr) + node = ovr + else: + raise SyntaxError(u'Unknown LaTeX command: ' + name) + + return node, skip + +def tex2mathml(tex_math, inline=True): + """Return string with MathML code corresponding to `tex_math`. + + `inline`=True is for inline math and `inline`=False for displayed math. + """ + + mathml_tree = parse_latex_math(tex_math, inline=inline) + return ''.join(mathml_tree.xml()) diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/math2html.py b/env/lib/python3.8/site-packages/docutils/utils/math/math2html.py new file mode 100644 index 000000000..ca7092c2f --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/math2html.py @@ -0,0 +1,5383 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- + +# math2html: convert LaTeX equations to HTML output. +# +# Copyright (C) 2009-2011 Alex Fernández +# +# Released under the terms of the `2-Clause BSD license'_, in short: +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + +# Based on eLyXer: convert LyX source files to HTML output. +# http://alexfernandez.github.io/elyxer/ + +# --end-- +# Alex 20101110 +# eLyXer standalone formula conversion to HTML. + +import codecs +import datetime +import gettext +import io +import os.path +import sys +import unicodedata + +if sys.version_info >= (3, 0): + from urllib.parse import quote_plus +else: + from urllib import quote_plus + + +if sys.version_info >= (3, 0): + unicode = str #noqa + basestring = str # noqa + file = io.IOBase # noqa + + +class Trace(object): + "A tracing class" + + debugmode = False + quietmode = False + showlinesmode = False + + prefix = None + + def debug(cls, message): + "Show a debug message" + if not Trace.debugmode or Trace.quietmode: + return + Trace.show(message, sys.stdout) + + def message(cls, message): + "Show a trace message" + if Trace.quietmode: + return + if Trace.prefix and Trace.showlinesmode: + message = Trace.prefix + message + Trace.show(message, sys.stdout) + + def error(cls, message): + "Show an error message" + message = '* ' + message + if Trace.prefix and Trace.showlinesmode: + message = Trace.prefix + message + Trace.show(message, sys.stderr) + + def fatal(cls, message): + "Show an error message and terminate" + Trace.error('FATAL: ' + message) + exit(-1) + + def show(cls, message, channel): + "Show a message out of a channel" + if sys.version_info < (3, 0): + message = message.encode('utf-8') + channel.write(message + '\n') + + debug = classmethod(debug) + message = classmethod(message) + error = classmethod(error) + fatal = classmethod(fatal) + show = classmethod(show) + + +class BibStylesConfig(object): + "Configuration class from elyxer.config file" + + abbrvnat = { + u'@article': u'$authors. $title. <i>$journal</i>,{ {$volume:}$pages,} $month $year.{ doi: $doi.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$surname($year)', + u'default': u'$authors. <i>$title</i>. $publisher, $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + + alpha = { + u'@article': u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{: $pages}{, $year}.}{ <a href="http://github.com/$url">$url</a>.}{ <a href="http://github.com/$filename">$filename</a>.}{ $note.}', + u'cite': u'$Sur$YY', + u'default': u'$authors. $title.{ <i>$journal</i>,} $year.{ <a href="http://github.com/$url">$url</a>.}{ <a href="http://github.com/$filename">$filename</a>.}{ $note.}', + } + + authordate2 = { + u'@article': u'$authors. $year. $title. <i>$journal</i>, <b>$volume</b>($number), $pages.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@book': u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$surname, $year', + u'default': u'$authors. $year. <i>$title</i>. $publisher.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + + default = { + u'@article': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@book': u'{$authors: }<i>$title</i>{ ($editor, ed.)}.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@booklet': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@conference': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@inbook': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@incollection': u'$authors: <i>$title</i>{ in <i>$booktitle</i>{ ($editor, ed.)}}.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@inproceedings': u'$authors: “$title”, <i>$booktitle</i>,{ pp. $pages,} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@manual': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@mastersthesis': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@misc': u'$authors: <i>$title</i>.{{ $publisher,}{ $howpublished,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@phdthesis': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@proceedings': u'$authors: “$title”, <i>$journal</i>,{ pp. $pages,} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@techreport': u'$authors: <i>$title</i>, $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@unpublished': u'$authors: “$title”, <i>$journal</i>, $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$index', + u'default': u'$authors: <i>$title</i>.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + + defaulttags = { + u'YY': u'??', u'authors': u'', u'surname': u'', + } + + ieeetr = { + u'@article': u'$authors, “$title”, <i>$journal</i>, vol. $volume, no. $number, pp. $pages, $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@book': u'$authors, <i>$title</i>. $publisher, $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$index', + u'default': u'$authors, “$title”. $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + + plain = { + u'@article': u'$authors. $title.{ <i>$journal</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@book': u'$authors. <i>$title</i>. $publisher,{ $month} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@incollection': u'$authors. $title.{ In <i>$booktitle</i> {($editor, ed.)}.} $publisher,{ $month} $year.{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@inproceedings': u'$authors. $title. { <i>$booktitle</i>{, {$volume}{($number)}}{:$pages}{, $year}.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$index', + u'default': u'{$authors. }$title.{{ $publisher,} $year.}{ URL <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + + vancouver = { + u'@article': u'$authors. $title. <i>$journal</i>, $year{;{<b>$volume</b>}{($number)}{:$pages}}.{ URL: <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'@book': u'$authors. $title. {$publisher, }$year.{ URL: <a href="http://github.com/$url">$url</a>.}{ $note.}', + u'cite': u'$index', + u'default': u'$authors. $title; {$publisher, }$year.{ $howpublished.}{ URL: <a href="http://github.com/$url">$url</a>.}{ $note.}', + } + +class BibTeXConfig(object): + "Configuration class from elyxer.config file" + + replaced = { + u'--': u'—', u'..': u'.', + } + +class ContainerConfig(object): + "Configuration class from elyxer.config file" + + endings = { + u'Align': u'\\end_layout', u'BarredText': u'\\bar', + u'BoldText': u'\\series', u'Cell': u'</cell', + u'ChangeDeleted': u'\\change_unchanged', + u'ChangeInserted': u'\\change_unchanged', u'ColorText': u'\\color', + u'EmphaticText': u'\\emph', u'Hfill': u'\\hfill', u'Inset': u'\\end_inset', + u'Layout': u'\\end_layout', u'LyXFooter': u'\\end_document', + u'LyXHeader': u'\\end_header', u'Row': u'</row', u'ShapedText': u'\\shape', + u'SizeText': u'\\size', u'StrikeOut': u'\\strikeout', + u'TextFamily': u'\\family', u'VersalitasText': u'\\noun', + } + + extracttext = { + u'allowed': [u'StringContainer', u'Constant', u'FormulaConstant',], + u'cloned': [u'',], + u'extracted': [u'PlainLayout', u'TaggedText', u'Align', u'Caption', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula', u'Bracket', u'RawText', u'BibTag', u'FormulaNumber', u'AlphaCommand', u'EmptyCommand', u'OneParamFunction', u'SymbolFunction', u'TextFunction', u'FontFunction', u'CombiningFunction', u'DecoratingFunction', u'FormulaSymbol', u'BracketCommand', u'TeXCode',], + } + + startendings = { + u'\\begin_deeper': u'\\end_deeper', u'\\begin_inset': u'\\end_inset', + u'\\begin_layout': u'\\end_layout', + } + + starts = { + u'': u'StringContainer', u'#LyX': u'BlackBox', u'</lyxtabular': u'BlackBox', + u'<cell': u'Cell', u'<column': u'Column', u'<row': u'Row', + u'\\align': u'Align', u'\\bar': u'BarredText', + u'\\bar default': u'BlackBox', u'\\bar no': u'BlackBox', + u'\\begin_body': u'BlackBox', u'\\begin_deeper': u'DeeperList', + u'\\begin_document': u'BlackBox', u'\\begin_header': u'LyXHeader', + u'\\begin_inset Argument': u'ShortTitle', + u'\\begin_inset Box': u'BoxInset', u'\\begin_inset Branch': u'Branch', + u'\\begin_inset Caption': u'Caption', + u'\\begin_inset CommandInset bibitem': u'BiblioEntry', + u'\\begin_inset CommandInset bibtex': u'BibTeX', + u'\\begin_inset CommandInset citation': u'BiblioCitation', + u'\\begin_inset CommandInset href': u'URL', + u'\\begin_inset CommandInset include': u'IncludeInset', + u'\\begin_inset CommandInset index_print': u'PrintIndex', + u'\\begin_inset CommandInset label': u'Label', + u'\\begin_inset CommandInset line': u'LineInset', + u'\\begin_inset CommandInset nomencl_print': u'PrintNomenclature', + u'\\begin_inset CommandInset nomenclature': u'NomenclatureEntry', + u'\\begin_inset CommandInset ref': u'Reference', + u'\\begin_inset CommandInset toc': u'TableOfContents', + u'\\begin_inset ERT': u'ERT', u'\\begin_inset Flex': u'FlexInset', + u'\\begin_inset Flex Chunkref': u'NewfangledChunkRef', + u'\\begin_inset Flex Marginnote': u'SideNote', + u'\\begin_inset Flex Sidenote': u'SideNote', + u'\\begin_inset Flex URL': u'FlexURL', u'\\begin_inset Float': u'Float', + u'\\begin_inset FloatList': u'ListOf', u'\\begin_inset Foot': u'Footnote', + u'\\begin_inset Formula': u'Formula', + u'\\begin_inset FormulaMacro': u'FormulaMacro', + u'\\begin_inset Graphics': u'Image', + u'\\begin_inset Index': u'IndexReference', + u'\\begin_inset Info': u'InfoInset', + u'\\begin_inset LatexCommand bibitem': u'BiblioEntry', + u'\\begin_inset LatexCommand bibtex': u'BibTeX', + u'\\begin_inset LatexCommand cite': u'BiblioCitation', + u'\\begin_inset LatexCommand citealt': u'BiblioCitation', + u'\\begin_inset LatexCommand citep': u'BiblioCitation', + u'\\begin_inset LatexCommand citet': u'BiblioCitation', + u'\\begin_inset LatexCommand htmlurl': u'URL', + u'\\begin_inset LatexCommand index': u'IndexReference', + u'\\begin_inset LatexCommand label': u'Label', + u'\\begin_inset LatexCommand nomenclature': u'NomenclatureEntry', + u'\\begin_inset LatexCommand prettyref': u'Reference', + u'\\begin_inset LatexCommand printindex': u'PrintIndex', + u'\\begin_inset LatexCommand printnomenclature': u'PrintNomenclature', + u'\\begin_inset LatexCommand ref': u'Reference', + u'\\begin_inset LatexCommand tableofcontents': u'TableOfContents', + u'\\begin_inset LatexCommand url': u'URL', + u'\\begin_inset LatexCommand vref': u'Reference', + u'\\begin_inset Marginal': u'SideNote', + u'\\begin_inset Newline': u'NewlineInset', + u'\\begin_inset Newpage': u'NewPageInset', u'\\begin_inset Note': u'Note', + u'\\begin_inset OptArg': u'ShortTitle', + u'\\begin_inset Phantom': u'PhantomText', + u'\\begin_inset Quotes': u'QuoteContainer', + u'\\begin_inset Tabular': u'Table', u'\\begin_inset Text': u'InsetText', + u'\\begin_inset VSpace': u'VerticalSpace', u'\\begin_inset Wrap': u'Wrap', + u'\\begin_inset listings': u'Listing', + u'\\begin_inset script': u'ScriptInset', u'\\begin_inset space': u'Space', + u'\\begin_layout': u'Layout', u'\\begin_layout Abstract': u'Abstract', + u'\\begin_layout Author': u'Author', + u'\\begin_layout Bibliography': u'Bibliography', + u'\\begin_layout Chunk': u'NewfangledChunk', + u'\\begin_layout Description': u'Description', + u'\\begin_layout Enumerate': u'ListItem', + u'\\begin_layout Itemize': u'ListItem', u'\\begin_layout List': u'List', + u'\\begin_layout LyX-Code': u'LyXCode', + u'\\begin_layout Plain': u'PlainLayout', + u'\\begin_layout Standard': u'StandardLayout', + u'\\begin_layout Title': u'Title', u'\\begin_preamble': u'LyXPreamble', + u'\\change_deleted': u'ChangeDeleted', + u'\\change_inserted': u'ChangeInserted', + u'\\change_unchanged': u'BlackBox', u'\\color': u'ColorText', + u'\\color inherit': u'BlackBox', u'\\color none': u'BlackBox', + u'\\emph default': u'BlackBox', u'\\emph off': u'BlackBox', + u'\\emph on': u'EmphaticText', u'\\emph toggle': u'EmphaticText', + u'\\end_body': u'LyXFooter', u'\\family': u'TextFamily', + u'\\family default': u'BlackBox', u'\\family roman': u'BlackBox', + u'\\hfill': u'Hfill', u'\\labelwidthstring': u'BlackBox', + u'\\lang': u'LangLine', u'\\length': u'InsetLength', + u'\\lyxformat': u'LyXFormat', u'\\lyxline': u'LyXLine', + u'\\newline': u'Newline', u'\\newpage': u'NewPage', + u'\\noindent': u'BlackBox', u'\\noun default': u'BlackBox', + u'\\noun off': u'BlackBox', u'\\noun on': u'VersalitasText', + u'\\paragraph_spacing': u'BlackBox', u'\\series bold': u'BoldText', + u'\\series default': u'BlackBox', u'\\series medium': u'BlackBox', + u'\\shape': u'ShapedText', u'\\shape default': u'BlackBox', + u'\\shape up': u'BlackBox', u'\\size': u'SizeText', + u'\\size normal': u'BlackBox', u'\\start_of_appendix': u'StartAppendix', + u'\\strikeout default': u'BlackBox', u'\\strikeout on': u'StrikeOut', + } + + string = { + u'startcommand': u'\\', + } + + table = { + u'headers': [u'<lyxtabular', u'<features',], + } + +class EscapeConfig(object): + "Configuration class from elyxer.config file" + + chars = { + u'\n': u'', u' -- ': u' — ', u' --- ': u' — ', u'\'': u'’', u'`': u'‘', + } + + commands = { + u'\\InsetSpace \\space{}': u' ', u'\\InsetSpace \\thinspace{}': u' ', + u'\\InsetSpace ~': u' ', u'\\SpecialChar \\-': u'', + u'\\SpecialChar \\@.': u'.', u'\\SpecialChar \\ldots{}': u'…', + u'\\SpecialChar \\menuseparator': u' ▷ ', + u'\\SpecialChar \\nobreakdash-': u'-', u'\\SpecialChar \\slash{}': u'/', + u'\\SpecialChar \\textcompwordmark{}': u'', u'\\backslash': u'\\', + } + + entities = { + u'&': u'&', u'<': u'<', u'>': u'>', + } + + html = { + u'/>': u'>', + } + + iso885915 = { + u' ': u' ', u' ': u' ', u' ': u' ', + } + + nonunicode = { + u' ': u' ', + } + +class FormulaConfig(object): + "Configuration class from elyxer.config file" + + alphacommands = { + u'\\AA': u'Å', u'\\AE': u'Æ', + u'\\AmS': u'<span class="versalitas">AmS</span>', u'\\Angstroem': u'Å', + u'\\DH': u'Ð', u'\\Koppa': u'Ϟ', u'\\L': u'Ł', u'\\Micro': u'µ', u'\\O': u'Ø', + u'\\OE': u'Œ', u'\\Sampi': u'Ϡ', u'\\Stigma': u'Ϛ', u'\\TH': u'Þ', + u'\\aa': u'å', u'\\ae': u'æ', u'\\alpha': u'α', u'\\beta': u'β', + u'\\delta': u'δ', u'\\dh': u'ð', u'\\digamma': u'ϝ', u'\\epsilon': u'ϵ', + u'\\eta': u'η', u'\\eth': u'ð', u'\\gamma': u'γ', u'\\i': u'ı', + u'\\imath': u'ı', u'\\iota': u'ι', u'\\j': u'ȷ', u'\\jmath': u'ȷ', + u'\\kappa': u'κ', u'\\koppa': u'ϟ', u'\\l': u'ł', u'\\lambda': u'λ', + u'\\mu': u'μ', u'\\nu': u'ν', u'\\o': u'ø', u'\\oe': u'œ', u'\\omega': u'ω', + u'\\phi': u'φ', u'\\pi': u'π', u'\\psi': u'ψ', u'\\rho': u'ρ', + u'\\sampi': u'ϡ', u'\\sigma': u'σ', u'\\ss': u'ß', u'\\stigma': u'ϛ', + u'\\tau': u'τ', u'\\tcohm': u'Ω', u'\\textcrh': u'ħ', u'\\th': u'þ', + u'\\theta': u'θ', u'\\upsilon': u'υ', u'\\varDelta': u'∆', + u'\\varGamma': u'Γ', u'\\varLambda': u'Λ', u'\\varOmega': u'Ω', + u'\\varPhi': u'Φ', u'\\varPi': u'Π', u'\\varPsi': u'Ψ', u'\\varSigma': u'Σ', + u'\\varTheta': u'Θ', u'\\varUpsilon': u'Υ', u'\\varXi': u'Ξ', + u'\\varbeta': u'ϐ', u'\\varepsilon': u'ε', u'\\varkappa': u'ϰ', + u'\\varphi': u'φ', u'\\varpi': u'ϖ', u'\\varrho': u'ϱ', u'\\varsigma': u'ς', + u'\\vartheta': u'ϑ', u'\\xi': u'ξ', u'\\zeta': u'ζ', + } + + array = { + u'begin': u'\\begin', u'cellseparator': u'&', u'end': u'\\end', + u'rowseparator': u'\\\\', + } + + bigbrackets = { + u'(': [u'⎛', u'⎜', u'⎝',], u')': [u'⎞', u'⎟', u'⎠',], u'[': [u'⎡', u'⎢', u'⎣',], + u']': [u'⎤', u'⎥', u'⎦',], u'{': [u'⎧', u'⎪', u'⎨', u'⎩',], u'|': [u'|',], + u'}': [u'⎫', u'⎪', u'⎬', u'⎭',], u'∥': [u'∥',], + } + + bigsymbols = { + u'∑': [u'⎲', u'⎳',], u'∫': [u'⌠', u'⌡',], + } + + bracketcommands = { + u'\\left': u'span class="symbol"', + u'\\left.': u'<span class="leftdot"></span>', + u'\\middle': u'span class="symbol"', u'\\right': u'span class="symbol"', + u'\\right.': u'<span class="rightdot"></span>', + } + + combiningfunctions = { + u'\\"': u'̈', u'\\\'': u'́', u'\\^': u'̂', u'\\`': u'̀', u'\\acute': u'́', + u'\\bar': u'̄', u'\\breve': u'̆', u'\\c': u'̧', u'\\check': u'̌', + u'\\dddot': u'⃛', u'\\ddot': u'̈', u'\\dot': u'̇', u'\\grave': u'̀', + u'\\hat': u'̂', u'\\mathring': u'̊', u'\\overleftarrow': u'⃖', + u'\\overrightarrow': u'⃗', u'\\r': u'̊', u'\\s': u'̩', + u'\\textcircled': u'⃝', u'\\textsubring': u'̥', u'\\tilde': u'̃', + u'\\v': u'̌', u'\\vec': u'⃗', u'\\~': u'̃', + } + + commands = { + u'\\ ': u' ', u'\\!': u'', u'\\#': u'#', u'\\$': u'$', u'\\%': u'%', + u'\\&': u'&', u'\\,': u' ', u'\\:': u' ', u'\\;': u' ', u'\\AC': u'∿', + u'\\APLcomment': u'⍝', u'\\APLdownarrowbox': u'⍗', u'\\APLinput': u'⍞', + u'\\APLinv': u'⌹', u'\\APLleftarrowbox': u'⍇', u'\\APLlog': u'⍟', + u'\\APLrightarrowbox': u'⍈', u'\\APLuparrowbox': u'⍐', u'\\Box': u'□', + u'\\Bumpeq': u'≎', u'\\CIRCLE': u'●', u'\\Cap': u'⋒', + u'\\CapitalDifferentialD': u'ⅅ', u'\\CheckedBox': u'☑', u'\\Circle': u'○', + u'\\Coloneqq': u'⩴', u'\\ComplexI': u'ⅈ', u'\\ComplexJ': u'ⅉ', + u'\\Corresponds': u'≙', u'\\Cup': u'⋓', u'\\Delta': u'Δ', u'\\Diamond': u'◇', + u'\\Diamondblack': u'◆', u'\\Diamonddot': u'⟐', u'\\DifferentialD': u'ⅆ', + u'\\Downarrow': u'⇓', u'\\EUR': u'€', u'\\Euler': u'ℇ', + u'\\ExponetialE': u'ⅇ', u'\\Finv': u'Ⅎ', u'\\Game': u'⅁', u'\\Gamma': u'Γ', + u'\\Im': u'ℑ', u'\\Join': u'⨝', u'\\LEFTCIRCLE': u'◖', u'\\LEFTcircle': u'◐', + u'\\LHD': u'◀', u'\\Lambda': u'Λ', u'\\Lbag': u'⟅', u'\\Leftarrow': u'⇐', + u'\\Lleftarrow': u'⇚', u'\\Longleftarrow': u'⟸', + u'\\Longleftrightarrow': u'⟺', u'\\Longrightarrow': u'⟹', u'\\Lparen': u'⦅', + u'\\Lsh': u'↰', u'\\Mapsfrom': u'⇐|', u'\\Mapsto': u'|⇒', u'\\Omega': u'Ω', + u'\\P': u'¶', u'\\Phi': u'Φ', u'\\Pi': u'Π', u'\\Pr': u'Pr', u'\\Psi': u'Ψ', + u'\\Qoppa': u'Ϙ', u'\\RHD': u'▶', u'\\RIGHTCIRCLE': u'◗', + u'\\RIGHTcircle': u'◑', u'\\Rbag': u'⟆', u'\\Re': u'ℜ', u'\\Rparen': u'⦆', + u'\\Rrightarrow': u'⇛', u'\\Rsh': u'↱', u'\\S': u'§', u'\\Sigma': u'Σ', + u'\\Square': u'☐', u'\\Subset': u'⋐', u'\\Sun': u'☉', u'\\Supset': u'⋑', + u'\\Theta': u'Θ', u'\\Uparrow': u'⇑', u'\\Updownarrow': u'⇕', + u'\\Upsilon': u'Υ', u'\\Vdash': u'⊩', u'\\Vert': u'∥', u'\\Vvdash': u'⊪', + u'\\XBox': u'☒', u'\\Xi': u'Ξ', u'\\Yup': u'⅄', u'\\\\': u'<br/>', + u'\\_': u'_', u'\\aleph': u'ℵ', u'\\amalg': u'∐', u'\\anchor': u'⚓', + u'\\angle': u'∠', u'\\aquarius': u'♒', u'\\arccos': u'arccos', + u'\\arcsin': u'arcsin', u'\\arctan': u'arctan', u'\\arg': u'arg', + u'\\aries': u'♈', u'\\arrowbullet': u'➢', u'\\ast': u'∗', u'\\asymp': u'≍', + u'\\backepsilon': u'∍', u'\\backprime': u'‵', u'\\backsimeq': u'⋍', + u'\\backslash': u'\\', u'\\ballotx': u'✗', u'\\barwedge': u'⊼', + u'\\because': u'∵', u'\\beth': u'ℶ', u'\\between': u'≬', u'\\bigcap': u'∩', + u'\\bigcirc': u'○', u'\\bigcup': u'∪', u'\\bigodot': u'⊙', + u'\\bigoplus': u'⊕', u'\\bigotimes': u'⊗', u'\\bigsqcup': u'⊔', + u'\\bigstar': u'★', u'\\bigtriangledown': u'▽', u'\\bigtriangleup': u'△', + u'\\biguplus': u'⊎', u'\\bigvee': u'∨', u'\\bigwedge': u'∧', + u'\\biohazard': u'☣', u'\\blacklozenge': u'⧫', u'\\blacksmiley': u'☻', + u'\\blacksquare': u'■', u'\\blacktriangle': u'▲', + u'\\blacktriangledown': u'▼', u'\\blacktriangleleft': u'◂', + u'\\blacktriangleright': u'▶', u'\\blacktriangleup': u'▴', u'\\bot': u'⊥', + u'\\bowtie': u'⋈', u'\\box': u'▫', u'\\boxast': u'⧆', u'\\boxbar': u'◫', + u'\\boxbox': u'⧈', u'\\boxbslash': u'⧅', u'\\boxcircle': u'⧇', + u'\\boxdot': u'⊡', u'\\boxminus': u'⊟', u'\\boxplus': u'⊞', + u'\\boxslash': u'⧄', u'\\boxtimes': u'⊠', u'\\bullet': u'•', + u'\\bumpeq': u'≏', u'\\cancer': u'♋', u'\\cap': u'∩', u'\\capricornus': u'♑', + u'\\cat': u'⁀', u'\\cdot': u'⋅', u'\\cdots': u'⋯', u'\\cent': u'¢', + u'\\centerdot': u'∙', u'\\checkmark': u'✓', u'\\chi': u'χ', u'\\circ': u'∘', + u'\\circeq': u'≗', u'\\circlearrowleft': u'↺', u'\\circlearrowright': u'↻', + u'\\circledR': u'®', u'\\circledast': u'⊛', u'\\circledbslash': u'⦸', + u'\\circledcirc': u'⊚', u'\\circleddash': u'⊝', u'\\circledgtr': u'⧁', + u'\\circledless': u'⧀', u'\\clubsuit': u'♣', u'\\colon': u': ', u'\\coloneqq': u'≔', + u'\\complement': u'∁', u'\\cong': u'≅', u'\\coprod': u'∐', + u'\\copyright': u'©', u'\\cos': u'cos', u'\\cosh': u'cosh', u'\\cot': u'cot', + u'\\coth': u'coth', u'\\csc': u'csc', u'\\cup': u'∪', u'\\curlyvee': u'⋎', + u'\\curlywedge': u'⋏', u'\\curvearrowleft': u'↶', + u'\\curvearrowright': u'↷', u'\\dag': u'†', u'\\dagger': u'†', + u'\\daleth': u'ℸ', u'\\dashleftarrow': u'⇠', u'\\dashv': u'⊣', + u'\\ddag': u'‡', u'\\ddagger': u'‡', u'\\ddots': u'⋱', u'\\deg': u'deg', + u'\\det': u'det', u'\\diagdown': u'╲', u'\\diagup': u'╱', + u'\\diameter': u'⌀', u'\\diamond': u'◇', u'\\diamondsuit': u'♦', + u'\\dim': u'dim', u'\\div': u'÷', u'\\divideontimes': u'⋇', + u'\\dotdiv': u'∸', u'\\doteq': u'≐', u'\\doteqdot': u'≑', u'\\dotplus': u'∔', + u'\\dots': u'…', u'\\doublebarwedge': u'⌆', u'\\downarrow': u'↓', + u'\\downdownarrows': u'⇊', u'\\downharpoonleft': u'⇃', + u'\\downharpoonright': u'⇂', u'\\dsub': u'⩤', u'\\earth': u'♁', + u'\\eighthnote': u'♪', u'\\ell': u'ℓ', u'\\emptyset': u'∅', + u'\\eqcirc': u'≖', u'\\eqcolon': u'≕', u'\\eqsim': u'≂', u'\\euro': u'€', + u'\\exists': u'∃', u'\\exp': u'exp', u'\\fallingdotseq': u'≒', + u'\\fcmp': u'⨾', u'\\female': u'♀', u'\\flat': u'♭', u'\\forall': u'∀', + u'\\fourth': u'⁗', u'\\frown': u'⌢', u'\\frownie': u'☹', u'\\gcd': u'gcd', + u'\\gemini': u'♊', u'\\geq)': u'≥', u'\\geqq': u'≧', u'\\geqslant': u'≥', + u'\\gets': u'←', u'\\gg': u'≫', u'\\ggg': u'⋙', u'\\gimel': u'ℷ', + u'\\gneqq': u'≩', u'\\gnsim': u'⋧', u'\\gtrdot': u'⋗', u'\\gtreqless': u'⋚', + u'\\gtreqqless': u'⪌', u'\\gtrless': u'≷', u'\\gtrsim': u'≳', + u'\\guillemotleft': u'«', u'\\guillemotright': u'»', u'\\hbar': u'ℏ', + u'\\heartsuit': u'♥', u'\\hfill': u'<span class="hfill"> </span>', + u'\\hom': u'hom', u'\\hookleftarrow': u'↩', u'\\hookrightarrow': u'↪', + u'\\hslash': u'ℏ', u'\\idotsint': u'<span class="bigsymbol">∫⋯∫</span>', + u'\\iiint': u'<span class="bigsymbol">∭</span>', + u'\\iint': u'<span class="bigsymbol">∬</span>', u'\\imath': u'ı', + u'\\inf': u'inf', u'\\infty': u'∞', u'\\intercal': u'⊺', + u'\\interleave': u'⫴', u'\\invamp': u'⅋', u'\\invneg': u'⌐', + u'\\jmath': u'ȷ', u'\\jupiter': u'♃', u'\\ker': u'ker', u'\\land': u'∧', + u'\\landupint': u'<span class="bigsymbol">∱</span>', u'\\lang': u'⟪', + u'\\langle': u'⟨', u'\\lblot': u'⦉', u'\\lbrace': u'{', u'\\lbrace)': u'{', + u'\\lbrack': u'[', u'\\lceil': u'⌈', u'\\ldots': u'…', u'\\leadsto': u'⇝', + u'\\leftarrow)': u'←', u'\\leftarrowtail': u'↢', u'\\leftarrowtobar': u'⇤', + u'\\leftharpoondown': u'↽', u'\\leftharpoonup': u'↼', + u'\\leftleftarrows': u'⇇', u'\\leftleftharpoons': u'⥢', u'\\leftmoon': u'☾', + u'\\leftrightarrow': u'↔', u'\\leftrightarrows': u'⇆', + u'\\leftrightharpoons': u'⇋', u'\\leftthreetimes': u'⋋', u'\\leo': u'♌', + u'\\leq)': u'≤', u'\\leqq': u'≦', u'\\leqslant': u'≤', u'\\lessdot': u'⋖', + u'\\lesseqgtr': u'⋛', u'\\lesseqqgtr': u'⪋', u'\\lessgtr': u'≶', + u'\\lesssim': u'≲', u'\\lfloor': u'⌊', u'\\lg': u'lg', u'\\lgroup': u'⟮', + u'\\lhd': u'⊲', u'\\libra': u'♎', u'\\lightning': u'↯', u'\\limg': u'⦇', + u'\\liminf': u'liminf', u'\\limsup': u'limsup', u'\\ll': u'≪', + u'\\llbracket': u'⟦', u'\\llcorner': u'⌞', u'\\lll': u'⋘', u'\\ln': u'ln', + u'\\lneqq': u'≨', u'\\lnot': u'¬', u'\\lnsim': u'⋦', u'\\log': u'log', + u'\\longleftarrow': u'⟵', u'\\longleftrightarrow': u'⟷', + u'\\longmapsto': u'⟼', u'\\longrightarrow': u'⟶', u'\\looparrowleft': u'↫', + u'\\looparrowright': u'↬', u'\\lor': u'∨', u'\\lozenge': u'◊', + u'\\lrcorner': u'⌟', u'\\ltimes': u'⋉', u'\\lyxlock': u'', u'\\male': u'♂', + u'\\maltese': u'✠', u'\\mapsfrom': u'↤', u'\\mapsto': u'↦', + u'\\mathcircumflex': u'^', u'\\max': u'max', u'\\measuredangle': u'∡', + u'\\medbullet': u'⚫', u'\\medcirc': u'⚪', u'\\mercury': u'☿', u'\\mho': u'℧', + u'\\mid': u'∣', u'\\min': u'min', u'\\models': u'⊨', u'\\mp': u'∓', + u'\\multimap': u'⊸', u'\\nLeftarrow': u'⇍', u'\\nLeftrightarrow': u'⇎', + u'\\nRightarrow': u'⇏', u'\\nVDash': u'⊯', u'\\nabla': u'∇', + u'\\napprox': u'≉', u'\\natural': u'♮', u'\\ncong': u'≇', u'\\nearrow': u'↗', + u'\\neg': u'¬', u'\\neg)': u'¬', u'\\neptune': u'♆', u'\\nequiv': u'≢', + u'\\newline': u'<br/>', u'\\nexists': u'∄', u'\\ngeqslant': u'≱', + u'\\ngtr': u'≯', u'\\ngtrless': u'≹', u'\\ni': u'∋', u'\\ni)': u'∋', + u'\\nleftarrow': u'↚', u'\\nleftrightarrow': u'↮', u'\\nleqslant': u'≰', + u'\\nless': u'≮', u'\\nlessgtr': u'≸', u'\\nmid': u'∤', u'\\nolimits': u'', + u'\\nonumber': u'', u'\\not': u'¬', u'\\not<': u'≮', u'\\not=': u'≠', + u'\\not>': u'≯', u'\\notbackslash': u'⍀', u'\\notin': u'∉', u'\\notni': u'∌', + u'\\notslash': u'⌿', u'\\nparallel': u'∦', u'\\nprec': u'⊀', + u'\\nrightarrow': u'↛', u'\\nsim': u'≁', u'\\nsimeq': u'≄', + u'\\nsqsubset': u'⊏̸', u'\\nsubseteq': u'⊈', u'\\nsucc': u'⊁', + u'\\nsucccurlyeq': u'⋡', u'\\nsupset': u'⊅', u'\\nsupseteq': u'⊉', + u'\\ntriangleleft': u'⋪', u'\\ntrianglelefteq': u'⋬', + u'\\ntriangleright': u'⋫', u'\\ntrianglerighteq': u'⋭', u'\\nvDash': u'⊭', + u'\\nvdash': u'⊬', u'\\nwarrow': u'↖', u'\\odot': u'⊙', + u'\\officialeuro': u'€', u'\\oiiint': u'<span class="bigsymbol">∰</span>', + u'\\oiint': u'<span class="bigsymbol">∯</span>', + u'\\oint': u'<span class="bigsymbol">∮</span>', + u'\\ointclockwise': u'<span class="bigsymbol">∲</span>', + u'\\ointctrclockwise': u'<span class="bigsymbol">∳</span>', + u'\\ominus': u'⊖', u'\\oplus': u'⊕', u'\\oslash': u'⊘', u'\\otimes': u'⊗', + u'\\owns': u'∋', u'\\parallel': u'∥', u'\\partial': u'∂', u'\\pencil': u'✎', + u'\\perp': u'⊥', u'\\pisces': u'♓', u'\\pitchfork': u'⋔', u'\\pluto': u'♇', + u'\\pm': u'±', u'\\pointer': u'➪', u'\\pointright': u'☞', u'\\pounds': u'£', + u'\\prec': u'≺', u'\\preccurlyeq': u'≼', u'\\preceq': u'≼', + u'\\precsim': u'≾', u'\\prime': u'′', u'\\prompto': u'∝', u'\\qoppa': u'ϙ', + u'\\qquad': u' ', u'\\quad': u' ', u'\\quarternote': u'♩', + u'\\radiation': u'☢', u'\\rang': u'⟫', u'\\rangle': u'⟩', u'\\rblot': u'⦊', + u'\\rbrace': u'}', u'\\rbrace)': u'}', u'\\rbrack': u']', u'\\rceil': u'⌉', + u'\\recycle': u'♻', u'\\rfloor': u'⌋', u'\\rgroup': u'⟯', u'\\rhd': u'⊳', + u'\\rightangle': u'∟', u'\\rightarrow)': u'→', u'\\rightarrowtail': u'↣', + u'\\rightarrowtobar': u'⇥', u'\\rightharpoondown': u'⇁', + u'\\rightharpoonup': u'⇀', u'\\rightharpooondown': u'⇁', + u'\\rightharpooonup': u'⇀', u'\\rightleftarrows': u'⇄', + u'\\rightleftharpoons': u'⇌', u'\\rightmoon': u'☽', + u'\\rightrightarrows': u'⇉', u'\\rightrightharpoons': u'⥤', + u'\\rightthreetimes': u'⋌', u'\\rimg': u'⦈', u'\\risingdotseq': u'≓', + u'\\rrbracket': u'⟧', u'\\rsub': u'⩥', u'\\rtimes': u'⋊', + u'\\sagittarius': u'♐', u'\\saturn': u'♄', u'\\scorpio': u'♏', + u'\\searrow': u'↘', u'\\sec': u'sec', u'\\second': u'″', u'\\setminus': u'∖', + u'\\sharp': u'♯', u'\\simeq': u'≃', u'\\sin': u'sin', u'\\sinh': u'sinh', + u'\\sixteenthnote': u'♬', u'\\skull': u'☠', u'\\slash': u'∕', + u'\\smallsetminus': u'∖', u'\\smalltriangledown': u'▿', + u'\\smalltriangleleft': u'◃', u'\\smalltriangleright': u'▹', + u'\\smalltriangleup': u'▵', u'\\smile': u'⌣', u'\\smiley': u'☺', + u'\\spadesuit': u'♠', u'\\spddot': u'¨', u'\\sphat': u'', + u'\\sphericalangle': u'∢', u'\\spot': u'⦁', u'\\sptilde': u'~', + u'\\sqcap': u'⊓', u'\\sqcup': u'⊔', u'\\sqsubset': u'⊏', + u'\\sqsubseteq': u'⊑', u'\\sqsupset': u'⊐', u'\\sqsupseteq': u'⊒', + u'\\square': u'□', u'\\sslash': u'⫽', u'\\star': u'⋆', u'\\steaming': u'☕', + u'\\subseteqq': u'⫅', u'\\subsetneqq': u'⫋', u'\\succ': u'≻', + u'\\succcurlyeq': u'≽', u'\\succeq': u'≽', u'\\succnsim': u'⋩', + u'\\succsim': u'≿', u'\\sun': u'☼', u'\\sup': u'sup', u'\\supseteqq': u'⫆', + u'\\supsetneqq': u'⫌', u'\\surd': u'√', u'\\swarrow': u'↙', + u'\\swords': u'⚔', u'\\talloblong': u'⫾', u'\\tan': u'tan', + u'\\tanh': u'tanh', u'\\taurus': u'♉', u'\\textasciicircum': u'^', + u'\\textasciitilde': u'~', u'\\textbackslash': u'\\', + u'\\textcopyright': u'©\'', u'\\textdegree': u'°', u'\\textellipsis': u'…', + u'\\textemdash': u'—', u'\\textendash': u'—', u'\\texteuro': u'€', + u'\\textgreater': u'>', u'\\textless': u'<', u'\\textordfeminine': u'ª', + u'\\textordmasculine': u'º', u'\\textquotedblleft': u'“', + u'\\textquotedblright': u'”', u'\\textquoteright': u'’', + u'\\textregistered': u'®', u'\\textrightarrow': u'→', + u'\\textsection': u'§', u'\\texttrademark': u'™', + u'\\texttwosuperior': u'²', u'\\textvisiblespace': u' ', + u'\\therefore': u'∴', u'\\third': u'‴', u'\\top': u'⊤', u'\\triangle': u'△', + u'\\triangleleft': u'⊲', u'\\trianglelefteq': u'⊴', u'\\triangleq': u'≜', + u'\\triangleright': u'▷', u'\\trianglerighteq': u'⊵', + u'\\twoheadleftarrow': u'↞', u'\\twoheadrightarrow': u'↠', + u'\\twonotes': u'♫', u'\\udot': u'⊍', u'\\ulcorner': u'⌜', u'\\unlhd': u'⊴', + u'\\unrhd': u'⊵', u'\\unrhl': u'⊵', u'\\uparrow': u'↑', + u'\\updownarrow': u'↕', u'\\upharpoonleft': u'↿', u'\\upharpoonright': u'↾', + u'\\uplus': u'⊎', u'\\upuparrows': u'⇈', u'\\uranus': u'♅', + u'\\urcorner': u'⌝', u'\\vDash': u'⊨', u'\\varclubsuit': u'♧', + u'\\vardiamondsuit': u'♦', u'\\varheartsuit': u'♥', u'\\varnothing': u'∅', + u'\\varspadesuit': u'♤', u'\\vdash': u'⊢', u'\\vdots': u'⋮', u'\\vee': u'∨', + u'\\vee)': u'∨', u'\\veebar': u'⊻', u'\\vert': u'∣', u'\\virgo': u'♍', + u'\\warning': u'⚠', u'\\wasylozenge': u'⌑', u'\\wedge': u'∧', + u'\\wedge)': u'∧', u'\\wp': u'℘', u'\\wr': u'≀', u'\\yen': u'¥', + u'\\yinyang': u'☯', u'\\{': u'{', u'\\|': u'∥', u'\\}': u'}', + } + + decoratedcommand = { + } + + decoratingfunctions = { + u'\\overleftarrow': u'⟵', u'\\overrightarrow': u'⟶', u'\\widehat': u'^', + } + + endings = { + u'bracket': u'}', u'complex': u'\\]', u'endafter': u'}', + u'endbefore': u'\\end{', u'squarebracket': u']', + } + + environments = { + u'align': [u'r', u'l',], u'eqnarray': [u'r', u'c', u'l',], + u'gathered': [u'l', u'l',], + } + + fontfunctions = { + u'\\boldsymbol': u'b', u'\\mathbb': u'span class="blackboard"', + u'\\mathbb{A}': u'𝔸', u'\\mathbb{B}': u'𝔹', u'\\mathbb{C}': u'ℂ', + u'\\mathbb{D}': u'𝔻', u'\\mathbb{E}': u'𝔼', u'\\mathbb{F}': u'𝔽', + u'\\mathbb{G}': u'𝔾', u'\\mathbb{H}': u'ℍ', u'\\mathbb{J}': u'𝕁', + u'\\mathbb{K}': u'𝕂', u'\\mathbb{L}': u'𝕃', u'\\mathbb{N}': u'ℕ', + u'\\mathbb{O}': u'𝕆', u'\\mathbb{P}': u'ℙ', u'\\mathbb{Q}': u'ℚ', + u'\\mathbb{R}': u'ℝ', u'\\mathbb{S}': u'𝕊', u'\\mathbb{T}': u'𝕋', + u'\\mathbb{W}': u'𝕎', u'\\mathbb{Z}': u'ℤ', u'\\mathbf': u'b', + u'\\mathcal': u'span class="scriptfont"', u'\\mathcal{B}': u'ℬ', + u'\\mathcal{E}': u'ℰ', u'\\mathcal{F}': u'ℱ', u'\\mathcal{H}': u'ℋ', + u'\\mathcal{I}': u'ℐ', u'\\mathcal{L}': u'ℒ', u'\\mathcal{M}': u'ℳ', + u'\\mathcal{R}': u'ℛ', u'\\mathfrak': u'span class="fraktur"', + u'\\mathfrak{C}': u'ℭ', u'\\mathfrak{F}': u'𝔉', u'\\mathfrak{H}': u'ℌ', + u'\\mathfrak{I}': u'ℑ', u'\\mathfrak{R}': u'ℜ', u'\\mathfrak{Z}': u'ℨ', + u'\\mathit': u'i', u'\\mathring{A}': u'Å', u'\\mathring{U}': u'Ů', + u'\\mathring{a}': u'å', u'\\mathring{u}': u'ů', u'\\mathring{w}': u'ẘ', + u'\\mathring{y}': u'ẙ', u'\\mathrm': u'span class="mathrm"', + u'\\mathscr': u'span class="scriptfont"', u'\\mathscr{B}': u'ℬ', + u'\\mathscr{E}': u'ℰ', u'\\mathscr{F}': u'ℱ', u'\\mathscr{H}': u'ℋ', + u'\\mathscr{I}': u'ℐ', u'\\mathscr{L}': u'ℒ', u'\\mathscr{M}': u'ℳ', + u'\\mathscr{R}': u'ℛ', u'\\mathsf': u'span class="mathsf"', + u'\\mathtt': u'tt', + } + + hybridfunctions = { + u'\\addcontentsline': [u'{$p!}{$q!}{$r!}', u'f0{}', u'ignored',], + u'\\addtocontents': [u'{$p!}{$q!}', u'f0{}', u'ignored',], + u'\\backmatter': [u'', u'f0{}', u'ignored',], + u'\\binom': [u'{$1}{$2}', u'f2{(}f0{f1{$1}f1{$2}}f2{)}', u'span class="binom"', u'span class="binomstack"', u'span class="bigsymbol"',], + u'\\boxed': [u'{$1}', u'f0{$1}', u'span class="boxed"',], + u'\\cfrac': [u'[$p!]{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fullfraction"', u'span class="numerator align-$p"', u'span class="denominator"', u'span class="ignored"',], + u'\\color': [u'{$p!}{$1}', u'f0{$1}', u'span style="color: $p;"',], + u'\\colorbox': [u'{$p!}{$1}', u'f0{$1}', u'span class="colorbox" style="background: $p;"',], + u'\\dbinom': [u'{$1}{$2}', u'(f0{f1{f2{$1}}f1{f2{ }}f1{f2{$2}}})', u'span class="binomial"', u'span class="binomrow"', u'span class="binomcell"',], + u'\\dfrac': [u'{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fullfraction"', u'span class="numerator"', u'span class="denominator"', u'span class="ignored"',], + u'\\displaystyle': [u'{$1}', u'f0{$1}', u'span class="displaystyle"',], + u'\\fancyfoot': [u'[$p!]{$q!}', u'f0{}', u'ignored',], + u'\\fancyhead': [u'[$p!]{$q!}', u'f0{}', u'ignored',], + u'\\fbox': [u'{$1}', u'f0{$1}', u'span class="fbox"',], + u'\\fboxrule': [u'{$p!}', u'f0{}', u'ignored',], + u'\\fboxsep': [u'{$p!}', u'f0{}', u'ignored',], + u'\\fcolorbox': [u'{$p!}{$q!}{$1}', u'f0{$1}', u'span class="boxed" style="border-color: $p; background: $q;"',], + u'\\frac': [u'{$1}{$2}', u'f0{f3{(}f1{$1}f3{)/(}f2{$2}f3{)}}', u'span class="fraction"', u'span class="numerator"', u'span class="denominator"', u'span class="ignored"',], + u'\\framebox': [u'[$p!][$q!]{$1}', u'f0{$1}', u'span class="framebox align-$q" style="width: $p;"',], + u'\\frontmatter': [u'', u'f0{}', u'ignored',], + u'\\href': [u'[$o]{$u!}{$t!}', u'f0{$t}', u'a href="http://github.com/$u"',], + u'\\hspace': [u'{$p!}', u'f0{ }', u'span class="hspace" style="width: $p;"',], + u'\\leftroot': [u'{$p!}', u'f0{ }', u'span class="leftroot" style="width: $p;px"',], + u'\\mainmatter': [u'', u'f0{}', u'ignored',], + u'\\markboth': [u'{$p!}{$q!}', u'f0{}', u'ignored',], + u'\\markright': [u'{$p!}', u'f0{}', u'ignored',], + u'\\nicefrac': [u'{$1}{$2}', u'f0{f1{$1}⁄f2{$2}}', u'span class="fraction"', u'sup class="numerator"', u'sub class="denominator"', u'span class="ignored"',], + u'\\parbox': [u'[$p!]{$w!}{$1}', u'f0{1}', u'div class="Boxed" style="width: $w;"',], + u'\\raisebox': [u'{$p!}{$1}', u'f0{$1.font}', u'span class="raisebox" style="vertical-align: $p;"',], + u'\\renewenvironment': [u'{$1!}{$2!}{$3!}', u'',], + u'\\rule': [u'[$v!]{$w!}{$h!}', u'f0/', u'hr class="line" style="width: $w; height: $h;"',], + u'\\scriptscriptstyle': [u'{$1}', u'f0{$1}', u'span class="scriptscriptstyle"',], + u'\\scriptstyle': [u'{$1}', u'f0{$1}', u'span class="scriptstyle"',], + u'\\sqrt': [u'[$0]{$1}', u'f0{f1{$0}f2{√}f4{(}f3{$1}f4{)}}', u'span class="sqrt"', u'sup class="root"', u'span class="radical"', u'span class="root"', u'span class="ignored"',], + u'\\stackrel': [u'{$1}{$2}', u'f0{f1{$1}f2{$2}}', u'span class="stackrel"', u'span class="upstackrel"', u'span class="downstackrel"',], + u'\\tbinom': [u'{$1}{$2}', u'(f0{f1{f2{$1}}f1{f2{ }}f1{f2{$2}}})', u'span class="binomial"', u'span class="binomrow"', u'span class="binomcell"',], + u'\\textcolor': [u'{$p!}{$1}', u'f0{$1}', u'span style="color: $p;"',], + u'\\textstyle': [u'{$1}', u'f0{$1}', u'span class="textstyle"',], + u'\\thispagestyle': [u'{$p!}', u'f0{}', u'ignored',], + u'\\unit': [u'[$0]{$1}', u'$0f0{$1.font}', u'span class="unit"',], + u'\\unitfrac': [u'[$0]{$1}{$2}', u'$0f0{f1{$1.font}⁄f2{$2.font}}', u'span class="fraction"', u'sup class="unit"', u'sub class="unit"',], + u'\\uproot': [u'{$p!}', u'f0{ }', u'span class="uproot" style="width: $p;px"',], + u'\\url': [u'{$u!}', u'f0{$u}', u'a href="http://github.com/$u"',], + u'\\vspace': [u'{$p!}', u'f0{ }', u'span class="vspace" style="height: $p;"',], + } + + hybridsizes = { + u'\\binom': u'$1+$2', u'\\cfrac': u'$1+$2', u'\\dbinom': u'$1+$2+1', + u'\\dfrac': u'$1+$2', u'\\frac': u'$1+$2', u'\\tbinom': u'$1+$2+1', + } + + labelfunctions = { + u'\\label': u'a name="#"', + } + + limitcommands = { + u'\\biginterleave': u'⫼', u'\\bigsqcap': u'⨅', u'\\fint': u'⨏', + u'\\iiiint': u'⨌', u'\\int': u'∫', u'\\intop': u'∫', u'\\lim': u'lim', + u'\\prod': u'∏', u'\\smallint': u'∫', u'\\sqint': u'⨖', u'\\sum': u'∑', + u'\\varointclockwise': u'∲', u'\\varprod': u'⨉', u'\\zcmp': u'⨟', + u'\\zhide': u'⧹', u'\\zpipe': u'⨠', u'\\zproject': u'⨡', + } + + misccommands = { + u'\\limits': u'LimitPreviousCommand', u'\\newcommand': u'MacroDefinition', + u'\\renewcommand': u'MacroDefinition', + u'\\setcounter': u'SetCounterFunction', u'\\tag': u'FormulaTag', + u'\\tag*': u'FormulaTag', u'\\today': u'TodayCommand', + } + + modified = { + u'\n': u'', u' ': u'', u'$': u'', u'&': u' ', u'\'': u'’', u'+': u' + ', + u',': u', ', u'-': u' − ', u'/': u' ⁄ ', u':': u' : ', u'<': u' < ', + u'=': u' = ', u'>': u' > ', u'@': u'', u'~': u'', + } + + onefunctions = { + u'\\Big': u'span class="bigsymbol"', u'\\Bigg': u'span class="hugesymbol"', + u'\\bar': u'span class="bar"', u'\\begin{array}': u'span class="arraydef"', + u'\\big': u'span class="symbol"', u'\\bigg': u'span class="largesymbol"', + u'\\bigl': u'span class="bigsymbol"', u'\\bigr': u'span class="bigsymbol"', + u'\\centering': u'span class="align-center"', + u'\\ensuremath': u'span class="ensuremath"', + u'\\hphantom': u'span class="phantom"', + u'\\noindent': u'span class="noindent"', + u'\\overbrace': u'span class="overbrace"', + u'\\overline': u'span class="overline"', + u'\\phantom': u'span class="phantom"', + u'\\underbrace': u'span class="underbrace"', u'\\underline': u'u', + u'\\vphantom': u'span class="phantom"', + } + + spacedcommands = { + u'\\Bot': u'⫫', u'\\Doteq': u'≑', u'\\DownArrowBar': u'⤓', + u'\\DownLeftTeeVector': u'⥞', u'\\DownLeftVectorBar': u'⥖', + u'\\DownRightTeeVector': u'⥟', u'\\DownRightVectorBar': u'⥗', + u'\\Equal': u'⩵', u'\\LeftArrowBar': u'⇤', u'\\LeftDownTeeVector': u'⥡', + u'\\LeftDownVectorBar': u'⥙', u'\\LeftTeeVector': u'⥚', + u'\\LeftTriangleBar': u'⧏', u'\\LeftUpTeeVector': u'⥠', + u'\\LeftUpVectorBar': u'⥘', u'\\LeftVectorBar': u'⥒', + u'\\Leftrightarrow': u'⇔', u'\\Longmapsfrom': u'⟽', u'\\Longmapsto': u'⟾', + u'\\MapsDown': u'↧', u'\\MapsUp': u'↥', u'\\Nearrow': u'⇗', + u'\\NestedGreaterGreater': u'⪢', u'\\NestedLessLess': u'⪡', + u'\\NotGreaterLess': u'≹', u'\\NotGreaterTilde': u'≵', + u'\\NotLessTilde': u'≴', u'\\Nwarrow': u'⇖', u'\\Proportion': u'∷', + u'\\RightArrowBar': u'⇥', u'\\RightDownTeeVector': u'⥝', + u'\\RightDownVectorBar': u'⥕', u'\\RightTeeVector': u'⥛', + u'\\RightTriangleBar': u'⧐', u'\\RightUpTeeVector': u'⥜', + u'\\RightUpVectorBar': u'⥔', u'\\RightVectorBar': u'⥓', + u'\\Rightarrow': u'⇒', u'\\Same': u'⩶', u'\\Searrow': u'⇘', + u'\\Swarrow': u'⇙', u'\\Top': u'⫪', u'\\UpArrowBar': u'⤒', u'\\VDash': u'⊫', + u'\\approx': u'≈', u'\\approxeq': u'≊', u'\\backsim': u'∽', u'\\barin': u'⋶', + u'\\barleftharpoon': u'⥫', u'\\barrightharpoon': u'⥭', u'\\bij': u'⤖', + u'\\coloneq': u'≔', u'\\corresponds': u'≙', u'\\curlyeqprec': u'⋞', + u'\\curlyeqsucc': u'⋟', u'\\dashrightarrow': u'⇢', u'\\dlsh': u'↲', + u'\\downdownharpoons': u'⥥', u'\\downuparrows': u'⇵', + u'\\downupharpoons': u'⥯', u'\\drsh': u'↳', u'\\eqslantgtr': u'⪖', + u'\\eqslantless': u'⪕', u'\\equiv': u'≡', u'\\ffun': u'⇻', u'\\finj': u'⤕', + u'\\ge': u'≥', u'\\geq': u'≥', u'\\ggcurly': u'⪼', u'\\gnapprox': u'⪊', + u'\\gneq': u'⪈', u'\\gtrapprox': u'⪆', u'\\hash': u'⋕', u'\\iddots': u'⋰', + u'\\implies': u' ⇒ ', u'\\in': u'∈', u'\\le': u'≤', u'\\leftarrow': u'←', + u'\\leftarrowtriangle': u'⇽', u'\\leftbarharpoon': u'⥪', + u'\\leftrightarrowtriangle': u'⇿', u'\\leftrightharpoon': u'⥊', + u'\\leftrightharpoondown': u'⥐', u'\\leftrightharpoonup': u'⥎', + u'\\leftrightsquigarrow': u'↭', u'\\leftslice': u'⪦', + u'\\leftsquigarrow': u'⇜', u'\\leftupdownharpoon': u'⥑', u'\\leq': u'≤', + u'\\lessapprox': u'⪅', u'\\llcurly': u'⪻', u'\\lnapprox': u'⪉', + u'\\lneq': u'⪇', u'\\longmapsfrom': u'⟻', u'\\multimapboth': u'⧟', + u'\\multimapdotbothA': u'⊶', u'\\multimapdotbothB': u'⊷', + u'\\multimapinv': u'⟜', u'\\nVdash': u'⊮', u'\\ne': u'≠', u'\\neq': u'≠', + u'\\ngeq': u'≱', u'\\nleq': u'≰', u'\\nni': u'∌', u'\\not\\in': u'∉', + u'\\notasymp': u'≭', u'\\npreceq': u'⋠', u'\\nsqsubseteq': u'⋢', + u'\\nsqsupseteq': u'⋣', u'\\nsubset': u'⊄', u'\\nsucceq': u'⋡', + u'\\pfun': u'⇸', u'\\pinj': u'⤔', u'\\precapprox': u'⪷', u'\\preceqq': u'⪳', + u'\\precnapprox': u'⪹', u'\\precnsim': u'⋨', u'\\propto': u'∝', + u'\\psur': u'⤀', u'\\rightarrow': u'→', u'\\rightarrowtriangle': u'⇾', + u'\\rightbarharpoon': u'⥬', u'\\rightleftharpoon': u'⥋', + u'\\rightslice': u'⪧', u'\\rightsquigarrow': u'⇝', + u'\\rightupdownharpoon': u'⥏', u'\\sim': u'~', u'\\strictfi': u'⥼', + u'\\strictif': u'⥽', u'\\subset': u'⊂', u'\\subseteq': u'⊆', + u'\\subsetneq': u'⊊', u'\\succapprox': u'⪸', u'\\succeqq': u'⪴', + u'\\succnapprox': u'⪺', u'\\supset': u'⊃', u'\\supseteq': u'⊇', + u'\\supsetneq': u'⊋', u'\\times': u'×', u'\\to': u'→', + u'\\updownarrows': u'⇅', u'\\updownharpoons': u'⥮', u'\\upupharpoons': u'⥣', + u'\\vartriangleleft': u'⊲', u'\\vartriangleright': u'⊳', + } + + starts = { + u'beginafter': u'}', u'beginbefore': u'\\begin{', u'bracket': u'{', + u'command': u'\\', u'comment': u'%', u'complex': u'\\[', u'simple': u'$', + u'squarebracket': u'[', u'unnumbered': u'*', + } + + symbolfunctions = { + u'^': u'sup', u'_': u'sub', + } + + textfunctions = { + u'\\mbox': u'span class="mbox"', u'\\text': u'span class="text"', + u'\\textbf': u'b', u'\\textipa': u'span class="textipa"', u'\\textit': u'i', + u'\\textnormal': u'span class="textnormal"', + u'\\textrm': u'span class="textrm"', + u'\\textsc': u'span class="versalitas"', + u'\\textsf': u'span class="textsf"', u'\\textsl': u'i', u'\\texttt': u'tt', + u'\\textup': u'span class="normal"', + } + + unmodified = { + u'characters': [u'.', u'*', u'€', u'(', u')', u'[', u']', u'·', u'!', u';', u'|', u'§', u'"',], + } + + urls = { + u'googlecharts': u'http://chart.googleapis.com/chart?cht=tx&chl=', + } + +class GeneralConfig(object): + "Configuration class from elyxer.config file" + + version = { + u'date': u'2015-02-26', u'lyxformat': u'413', u'number': u'1.2.5', + } + +class HeaderConfig(object): + "Configuration class from elyxer.config file" + + parameters = { + u'beginpreamble': u'\\begin_preamble', u'branch': u'\\branch', + u'documentclass': u'\\textclass', u'endbranch': u'\\end_branch', + u'endpreamble': u'\\end_preamble', u'language': u'\\language', + u'lstset': u'\\lstset', u'outputchanges': u'\\output_changes', + u'paragraphseparation': u'\\paragraph_separation', + u'pdftitle': u'\\pdf_title', u'secnumdepth': u'\\secnumdepth', + u'tocdepth': u'\\tocdepth', + } + + styles = { + u'article': [u'article', u'aastex', u'aapaper', u'acmsiggraph', u'sigplanconf', u'achemso', u'amsart', u'apa', u'arab-article', u'armenian-article', u'article-beamer', u'chess', u'dtk', u'elsarticle', u'heb-article', u'IEEEtran', u'iopart', u'kluwer', u'scrarticle-beamer', u'scrartcl', u'extarticle', u'paper', u'mwart', u'revtex4', u'spie', u'svglobal3', u'ltugboat', u'agu-dtd', u'jgrga', u'agums', u'entcs', u'egs', u'ijmpc', u'ijmpd', u'singlecol-new', u'doublecol-new', u'isprs', u'tarticle', u'jsarticle', u'jarticle', u'jss', u'literate-article', u'siamltex', u'cl2emult', u'llncs', u'svglobal', u'svjog', u'svprobth',], + u'book': [u'book', u'amsbook', u'scrbook', u'extbook', u'tufte-book', u'report', u'extreport', u'scrreprt', u'memoir', u'tbook', u'jsbook', u'jbook', u'mwbk', u'svmono', u'svmult', u'treport', u'jreport', u'mwrep',], + } + +class ImageConfig(object): + "Configuration class from elyxer.config file" + + converters = { + u'imagemagick': u'convert[ -density $scale][ -define $format:use-cropbox=true] "$input" "$output"', + u'inkscape': u'inkscape "$input" --export-png="$output"', + u'lyx': u'lyx -C "$input" "$output"', + } + + cropboxformats = { + u'.eps': u'ps', u'.pdf': u'pdf', u'.ps': u'ps', + } + + formats = { + u'default': u'.png', u'vector': [u'.svg', u'.eps',], + } + +class LayoutConfig(object): + "Configuration class from elyxer.config file" + + groupable = { + u'allowed': [u'StringContainer', u'Constant', u'TaggedText', u'Align', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',], + } + +class NewfangleConfig(object): + "Configuration class from elyxer.config file" + + constants = { + u'chunkref': u'chunkref{', u'endcommand': u'}', u'endmark': u'>', + u'startcommand': u'\\', u'startmark': u'=<', + } + +class NumberingConfig(object): + "Configuration class from elyxer.config file" + + layouts = { + u'ordered': [u'Chapter', u'Section', u'Subsection', u'Subsubsection', u'Paragraph',], + u'roman': [u'Part', u'Book',], + } + + sequence = { + u'symbols': [u'*', u'**', u'†', u'‡', u'§', u'§§', u'¶', u'¶¶', u'#', u'##',], + } + +class StyleConfig(object): + "Configuration class from elyxer.config file" + + hspaces = { + u'\\enskip{}': u' ', u'\\hfill{}': u'<span class="hfill"> </span>', + u'\\hspace*{\\fill}': u' ', u'\\hspace*{}': u'', u'\\hspace{}': u' ', + u'\\negthinspace{}': u'', u'\\qquad{}': u'  ', u'\\quad{}': u' ', + u'\\space{}': u' ', u'\\thinspace{}': u' ', u'~': u' ', + } + + quotes = { + u'ald': u'»', u'als': u'›', u'ard': u'«', u'ars': u'‹', u'eld': u'“', + u'els': u'‘', u'erd': u'”', u'ers': u'’', u'fld': u'«', + u'fls': u'‹', u'frd': u'»', u'frs': u'›', u'gld': u'„', u'gls': u'‚', + u'grd': u'“', u'grs': u'‘', u'pld': u'„', u'pls': u'‚', u'prd': u'”', + u'prs': u'’', u'sld': u'”', u'srd': u'”', + } + + referenceformats = { + u'eqref': u'(@↕)', u'formatted': u'¶↕', u'nameref': u'$↕', u'pageref': u'#↕', + u'ref': u'@↕', u'vpageref': u'on-page#↕', u'vref': u'@on-page#↕', + } + + size = { + u'ignoredtexts': [u'col', u'text', u'line', u'page', u'theight', u'pheight',], + } + + vspaces = { + u'bigskip': u'<div class="bigskip"> </div>', + u'defskip': u'<div class="defskip"> </div>', + u'medskip': u'<div class="medskip"> </div>', + u'smallskip': u'<div class="smallskip"> </div>', + u'vfill': u'<div class="vfill"> </div>', + } + +class TOCConfig(object): + "Configuration class from elyxer.config file" + + extractplain = { + u'allowed': [u'StringContainer', u'Constant', u'TaggedText', u'Align', u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',], + u'cloned': [u'',], u'extracted': [u'',], + } + + extracttitle = { + u'allowed': [u'StringContainer', u'Constant', u'Space',], + u'cloned': [u'TextFamily', u'EmphaticText', u'VersalitasText', u'BarredText', u'SizeText', u'ColorText', u'LangLine', u'Formula',], + u'extracted': [u'PlainLayout', u'TaggedText', u'Align', u'Caption', u'StandardLayout', u'FlexInset',], + } + +class TagConfig(object): + "Configuration class from elyxer.config file" + + barred = { + u'under': u'u', + } + + family = { + u'sans': u'span class="sans"', u'typewriter': u'tt', + } + + flex = { + u'CharStyle:Code': u'span class="code"', + u'CharStyle:MenuItem': u'span class="menuitem"', + u'Code': u'span class="code"', u'MenuItem': u'span class="menuitem"', + u'Noun': u'span class="noun"', u'Strong': u'span class="strong"', + } + + group = { + u'layouts': [u'Quotation', u'Quote',], + } + + layouts = { + u'Center': u'div', u'Chapter': u'h?', u'Date': u'h2', u'Paragraph': u'div', + u'Part': u'h1', u'Quotation': u'blockquote', u'Quote': u'blockquote', + u'Section': u'h?', u'Subsection': u'h?', u'Subsubsection': u'h?', + } + + listitems = { + u'Enumerate': u'ol', u'Itemize': u'ul', + } + + notes = { + u'Comment': u'', u'Greyedout': u'span class="greyedout"', u'Note': u'', + } + + script = { + u'subscript': u'sub', u'superscript': u'sup', + } + + shaped = { + u'italic': u'i', u'slanted': u'i', u'smallcaps': u'span class="versalitas"', + } + +class TranslationConfig(object): + "Configuration class from elyxer.config file" + + constants = { + u'Appendix': u'Appendix', u'Book': u'Book', u'Chapter': u'Chapter', + u'Paragraph': u'Paragraph', u'Part': u'Part', u'Section': u'Section', + u'Subsection': u'Subsection', u'Subsubsection': u'Subsubsection', + u'abstract': u'Abstract', u'bibliography': u'Bibliography', + u'figure': u'figure', u'float-algorithm': u'Algorithm ', + u'float-figure': u'Figure ', u'float-listing': u'Listing ', + u'float-table': u'Table ', u'float-tableau': u'Tableau ', + u'footnotes': u'Footnotes', u'generated-by': u'Document generated by ', + u'generated-on': u' on ', u'index': u'Index', + u'jsmath-enable': u'Please enable JavaScript on your browser.', + u'jsmath-requires': u' requires JavaScript to correctly process the mathematics on this page. ', + u'jsmath-warning': u'Warning: ', u'list-algorithm': u'List of Algorithms', + u'list-figure': u'List of Figures', u'list-table': u'List of Tables', + u'list-tableau': u'List of Tableaux', u'main-page': u'Main page', + u'next': u'Next', u'nomenclature': u'Nomenclature', + u'on-page': u' on page ', u'prev': u'Prev', u'references': u'References', + u'toc': u'Table of Contents', u'toc-for': u'Contents for ', u'up': u'Up', + } + + languages = { + u'american': u'en', u'british': u'en', u'deutsch': u'de', u'dutch': u'nl', + u'english': u'en', u'french': u'fr', u'ngerman': u'de', u'russian': u'ru', + u'spanish': u'es', + } + + +class CommandLineParser(object): + "A parser for runtime options" + + def __init__(self, options): + self.options = options + + def parseoptions(self, args): + "Parse command line options" + if len(args) == 0: + return None + while len(args) > 0 and args[0].startswith('--'): + key, value = self.readoption(args) + if not key: + return 'Option ' + value + ' not recognized' + if not value: + return 'Option ' + key + ' needs a value' + setattr(self.options, key, value) + return None + + def readoption(self, args): + "Read the key and value for an option" + arg = args[0][2:] + del args[0] + if '=' in arg: + key = self.readequalskey(arg, args) + else: + key = arg.replace('-', '') + if not hasattr(self.options, key): + return None, key + current = getattr(self.options, key) + if isinstance(current, bool): + return key, True + # read value + if len(args) == 0: + return key, None + if args[0].startswith('"'): + initial = args[0] + del args[0] + return key, self.readquoted(args, initial) + value = args[0].decode('utf-8') + del args[0] + if isinstance(current, list): + current.append(value) + return key, current + return key, value + + def readquoted(self, args, initial): + "Read a value between quotes" + Trace.error('Oops') + value = initial[1:] + while len(args) > 0 and not args[0].endswith('"') and not args[0].startswith('--'): + Trace.error('Appending ' + args[0]) + value += ' ' + args[0] + del args[0] + if len(args) == 0 or args[0].startswith('--'): + return None + value += ' ' + args[0:-1] + return value + + def readequalskey(self, arg, args): + "Read a key using equals" + split = arg.split('=', 1) + key = split[0] + value = split[1] + args.insert(0, value) + return key + + +class Options(object): + "A set of runtime options" + + instance = None + + location = None + nocopy = False + copyright = False + debug = False + quiet = False + version = False + hardversion = False + versiondate = False + html = False + help = False + showlines = True + unicode = False + iso885915 = False + css = [] + favicon = '' + title = None + directory = None + destdirectory = None + toc = False + toctarget = '' + tocfor = None + forceformat = None + lyxformat = False + target = None + splitpart = None + memory = True + lowmem = False + nobib = False + converter = 'imagemagick' + raw = False + jsmath = None + mathjax = None + nofooter = False + simplemath = False + template = None + noconvert = False + notoclabels = False + letterfoot = True + numberfoot = False + symbolfoot = False + hoverfoot = True + marginfoot = False + endfoot = False + supfoot = True + alignfoot = False + footnotes = None + imageformat = None + copyimages = False + googlecharts = False + embedcss = [] + + branches = dict() + + def parseoptions(self, args): + "Parse command line options" + Options.location = args[0] + del args[0] + parser = CommandLineParser(Options) + result = parser.parseoptions(args) + if result: + Trace.error(result) + self.usage() + self.processoptions() + + def processoptions(self): + "Process all options parsed." + if Options.help: + self.usage() + if Options.version: + self.showversion() + if Options.hardversion: + self.showhardversion() + if Options.versiondate: + self.showversiondate() + if Options.lyxformat: + self.showlyxformat() + if Options.splitpart: + try: + Options.splitpart = int(Options.splitpart) + if Options.splitpart <= 0: + Trace.error('--splitpart requires a number bigger than zero') + self.usage() + except: + Trace.error('--splitpart needs a numeric argument, not ' + Options.splitpart) + self.usage() + if Options.lowmem or Options.toc or Options.tocfor: + Options.memory = False + self.parsefootnotes() + if Options.forceformat and not Options.imageformat: + Options.imageformat = Options.forceformat + if Options.imageformat == 'copy': + Options.copyimages = True + if Options.css == []: + Options.css = ['http://elyxer.nongnu.org/lyx.css'] + if Options.favicon == '': + pass # no default favicon + if Options.html: + Options.simplemath = True + if Options.toc and not Options.tocfor: + Trace.error('Option --toc is deprecated; use --tocfor "page" instead') + Options.tocfor = Options.toctarget + if Options.nocopy: + Trace.error('Option --nocopy is deprecated; it is no longer needed') + if Options.jsmath: + Trace.error('Option --jsmath is deprecated; use --mathjax instead') + # set in Trace if necessary + for param in dir(Trace): + if param.endswith('mode'): + setattr(Trace, param, getattr(self, param[:-4])) + + def usage(self): + "Show correct usage" + Trace.error('Usage: ' + os.path.basename(Options.location) + ' [options] [filein] [fileout]') + Trace.error('Convert LyX input file "filein" to HTML file "fileout".') + Trace.error('If filein (or fileout) is not given use standard input (or output).') + Trace.error('Main program of the eLyXer package (http://elyxer.nongnu.org/).') + self.showoptions() + + def parsefootnotes(self): + "Parse footnotes options." + if not Options.footnotes: + return + Options.marginfoot = False + Options.letterfoot = False + Options.hoverfoot = False + options = Options.footnotes.split(',') + for option in options: + footoption = option + 'foot' + if hasattr(Options, footoption): + setattr(Options, footoption, True) + else: + Trace.error('Unknown footnotes option: ' + option) + if not Options.endfoot and not Options.marginfoot and not Options.hoverfoot: + Options.hoverfoot = True + if not Options.numberfoot and not Options.symbolfoot: + Options.letterfoot = True + + def showoptions(self): + "Show all possible options" + Trace.error(' Common options:') + Trace.error(' --help: show this online help') + Trace.error(' --quiet: disables all runtime messages') + Trace.error('') + Trace.error(' Advanced options:') + Trace.error(' --debug: enable debugging messages (for developers)') + Trace.error(' --version: show version number and release date') + Trace.error(' --lyxformat: return the highest LyX version supported') + Trace.error(' Options for HTML output:') + Trace.error(' --title "title": set the generated page title') + Trace.error(' --css "file.css": use a custom CSS file') + Trace.error(' --embedcss "file.css": embed styles from a CSS file into the output') + Trace.error(' --favicon "icon.ico": insert the specified favicon in the header.') + Trace.error(' --html: output HTML 4.0 instead of the default XHTML') + Trace.error(' --unicode: full Unicode output') + Trace.error(' --iso885915: output a document with ISO-8859-15 encoding') + Trace.error(' --nofooter: remove the footer "generated by eLyXer"') + Trace.error(' --simplemath: do not generate fancy math constructions') + Trace.error(' Options for image output:') + Trace.error(' --directory "img_dir": look for images in the specified directory') + Trace.error(' --destdirectory "dest": put converted images into this directory') + Trace.error(' --imageformat ".ext": image output format, or "copy" to copy images') + Trace.error(' --noconvert: do not convert images, use in original locations') + Trace.error(' --converter "inkscape": use an alternative program to convert images') + Trace.error(' Options for footnote display:') + Trace.error(' --numberfoot: mark footnotes with numbers instead of letters') + Trace.error(' --symbolfoot: mark footnotes with symbols (*, **...)') + Trace.error(' --hoverfoot: show footnotes as hovering text (default)') + Trace.error(' --marginfoot: show footnotes on the page margin') + Trace.error(' --endfoot: show footnotes at the end of the page') + Trace.error(' --supfoot: use superscript for footnote markers (default)') + Trace.error(' --alignfoot: use aligned text for footnote markers') + Trace.error(' --footnotes "options": specify several comma-separated footnotes options') + Trace.error(' Available options are: "number", "symbol", "hover", "margin", "end",') + Trace.error(' "sup", "align"') + Trace.error(' Advanced output options:') + Trace.error(' --splitpart "depth": split the resulting webpage at the given depth') + Trace.error(' --tocfor "page": generate a TOC that points to the given page') + Trace.error(' --target "frame": make all links point to the given frame') + Trace.error(' --notoclabels: omit the part labels in the TOC, such as Chapter') + Trace.error(' --lowmem: do the conversion on the fly (conserve memory)') + Trace.error(' --raw: generate HTML without header or footer.') + Trace.error(' --mathjax remote: use MathJax remotely to display equations') + Trace.error(' --mathjax "URL": use MathJax from the given URL to display equations') + Trace.error(' --googlecharts: use Google Charts to generate formula images') + Trace.error(' --template "file": use a template, put everything in <!--$content-->') + Trace.error(' --copyright: add a copyright notice at the bottom') + Trace.error(' Deprecated options:') + Trace.error(' --toc: (deprecated) create a table of contents') + Trace.error(' --toctarget "page": (deprecated) generate a TOC for the given page') + Trace.error(' --nocopy: (deprecated) maintained for backwards compatibility') + Trace.error(' --jsmath "URL": use jsMath from the given URL to display equations') + sys.exit() + + def showversion(self): + "Return the current eLyXer version string" + string = 'eLyXer version ' + GeneralConfig.version['number'] + string += ' (' + GeneralConfig.version['date'] + ')' + Trace.error(string) + sys.exit() + + def showhardversion(self): + "Return just the version string" + Trace.message(GeneralConfig.version['number']) + sys.exit() + + def showversiondate(self): + "Return just the version dte" + Trace.message(GeneralConfig.version['date']) + sys.exit() + + def showlyxformat(self): + "Return just the lyxformat parameter" + Trace.message(GeneralConfig.version['lyxformat']) + sys.exit() + +class BranchOptions(object): + "A set of options for a branch" + + def __init__(self, name): + self.name = name + self.options = {'color':'#ffffff'} + + def set(self, key, value): + "Set a branch option" + if not key.startswith(ContainerConfig.string['startcommand']): + Trace.error('Invalid branch option ' + key) + return + key = key.replace(ContainerConfig.string['startcommand'], '') + self.options[key] = value + + def isselected(self): + "Return if the branch is selected" + if not 'selected' in self.options: + return False + return self.options['selected'] == '1' + + def __unicode__(self): + "String representation" + return 'options for ' + self.name + ': ' + unicode(self.options) + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class Cloner(object): + "An object used to clone other objects." + + def clone(cls, original): + "Return an exact copy of an object." + "The original object must have an empty constructor." + return cls.create(original.__class__) + + def create(cls, type): + "Create an object of a given class." + clone = type.__new__(type) + clone.__init__() + return clone + + clone = classmethod(clone) + create = classmethod(create) + +class ContainerExtractor(object): + "A class to extract certain containers." + + def __init__(self, config): + "The config parameter is a map containing three lists: allowed, copied and extracted." + "Each of the three is a list of class names for containers." + "Allowed containers are included as is into the result." + "Cloned containers are cloned and placed into the result." + "Extracted containers are looked into." + "All other containers are silently ignored." + self.allowed = config['allowed'] + self.cloned = config['cloned'] + self.extracted = config['extracted'] + + def extract(self, container): + "Extract a group of selected containers from elyxer.a container." + list = [] + locate = lambda c: c.__class__.__name__ in self.allowed + self.cloned + recursive = lambda c: c.__class__.__name__ in self.extracted + process = lambda c: self.process(c, list) + container.recursivesearch(locate, recursive, process) + return list + + def process(self, container, list): + "Add allowed containers, clone cloned containers and add the clone." + name = container.__class__.__name__ + if name in self.allowed: + list.append(container) + elif name in self.cloned: + list.append(self.safeclone(container)) + else: + Trace.error('Unknown container class ' + name) + + def safeclone(self, container): + "Return a new container with contents only in a safe list, recursively." + clone = Cloner.clone(container) + clone.output = container.output + clone.contents = self.extract(container) + return clone + + + + + + +class Parser(object): + "A generic parser" + + def __init__(self): + self.begin = 0 + self.parameters = dict() + + def parseheader(self, reader): + "Parse the header" + header = reader.currentline().split() + reader.nextline() + self.begin = reader.linenumber + return header + + def parseparameter(self, reader): + "Parse a parameter" + if reader.currentline().strip().startswith('<'): + key, value = self.parsexml(reader) + self.parameters[key] = value + return + split = reader.currentline().strip().split(' ', 1) + reader.nextline() + if len(split) == 0: + return + key = split[0] + if len(split) == 1: + self.parameters[key] = True + return + if not '"' in split[1]: + self.parameters[key] = split[1].strip() + return + doublesplit = split[1].split('"') + self.parameters[key] = doublesplit[1] + + def parsexml(self, reader): + "Parse a parameter in xml form: <param attr1=value...>" + strip = reader.currentline().strip() + reader.nextline() + if not strip.endswith('>'): + Trace.error('XML parameter ' + strip + ' should be <...>') + split = strip[1:-1].split() + if len(split) == 0: + Trace.error('Empty XML parameter <>') + return None, None + key = split[0] + del split[0] + if len(split) == 0: + return key, dict() + attrs = dict() + for attr in split: + if not '=' in attr: + Trace.error('Erroneous attribute for ' + key + ': ' + attr) + attr += '="0"' + parts = attr.split('=') + attrkey = parts[0] + value = parts[1].split('"')[1] + attrs[attrkey] = value + return key, attrs + + def parseending(self, reader, process): + "Parse until the current ending is found" + if not self.ending: + Trace.error('No ending for ' + unicode(self)) + return + while not reader.currentline().startswith(self.ending): + process() + + def parsecontainer(self, reader, contents): + container = self.factory.createcontainer(reader) + if container: + container.parent = self.parent + contents.append(container) + + def __unicode__(self): + "Return a description" + return self.__class__.__name__ + ' (' + unicode(self.begin) + ')' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class LoneCommand(Parser): + "A parser for just one command line" + + def parse(self, reader): + "Read nothing" + return [] + +class TextParser(Parser): + "A parser for a command and a bit of text" + + stack = [] + + def __init__(self, container): + Parser.__init__(self) + self.ending = None + if container.__class__.__name__ in ContainerConfig.endings: + self.ending = ContainerConfig.endings[container.__class__.__name__] + self.endings = [] + + def parse(self, reader): + "Parse lines as long as they are text" + TextParser.stack.append(self.ending) + self.endings = TextParser.stack + [ContainerConfig.endings['Layout'], + ContainerConfig.endings['Inset'], self.ending] + contents = [] + while not self.isending(reader): + self.parsecontainer(reader, contents) + return contents + + def isending(self, reader): + "Check if text is ending" + current = reader.currentline().split() + if len(current) == 0: + return False + if current[0] in self.endings: + if current[0] in TextParser.stack: + TextParser.stack.remove(current[0]) + else: + TextParser.stack = [] + return True + return False + +class ExcludingParser(Parser): + "A parser that excludes the final line" + + def parse(self, reader): + "Parse everything up to (and excluding) the final line" + contents = [] + self.parseending(reader, lambda: self.parsecontainer(reader, contents)) + return contents + +class BoundedParser(ExcludingParser): + "A parser bound by a final line" + + def parse(self, reader): + "Parse everything, including the final line" + contents = ExcludingParser.parse(self, reader) + # skip last line + reader.nextline() + return contents + +class BoundedDummy(Parser): + "A bound parser that ignores everything" + + def parse(self, reader): + "Parse the contents of the container" + self.parseending(reader, lambda: reader.nextline()) + # skip last line + reader.nextline() + return [] + +class StringParser(Parser): + "Parses just a string" + + def parseheader(self, reader): + "Do nothing, just take note" + self.begin = reader.linenumber + 1 + return [] + + def parse(self, reader): + "Parse a single line" + contents = reader.currentline() + reader.nextline() + return contents + +class InsetParser(BoundedParser): + "Parses a LyX inset" + + def parse(self, reader): + "Parse inset parameters into a dictionary" + startcommand = ContainerConfig.string['startcommand'] + while reader.currentline() != '' and not reader.currentline().startswith(startcommand): + self.parseparameter(reader) + return BoundedParser.parse(self, reader) + + + + + + +class ContainerOutput(object): + "The generic HTML output for a container." + + def gethtml(self, container): + "Show an error." + Trace.error('gethtml() not implemented for ' + unicode(self)) + + def isempty(self): + "Decide if the output is empty: by default, not empty." + return False + +class EmptyOutput(ContainerOutput): + + def gethtml(self, container): + "Return empty HTML code." + return [] + + def isempty(self): + "This output is particularly empty." + return True + +class FixedOutput(ContainerOutput): + "Fixed output" + + def gethtml(self, container): + "Return constant HTML code" + return container.html + +class ContentsOutput(ContainerOutput): + "Outputs the contents converted to HTML" + + def gethtml(self, container): + "Return the HTML code" + html = [] + if container.contents == None: + return html + for element in container.contents: + if not hasattr(element, 'gethtml'): + Trace.error('No html in ' + element.__class__.__name__ + ': ' + unicode(element)) + return html + html += element.gethtml() + return html + +class TaggedOutput(ContentsOutput): + "Outputs an HTML tag surrounding the contents." + + tag = None + breaklines = False + empty = False + + def settag(self, tag, breaklines=False, empty=False): + "Set the value for the tag and other attributes." + self.tag = tag + if breaklines: + self.breaklines = breaklines + if empty: + self.empty = empty + return self + + def setbreaklines(self, breaklines): + "Set the value for breaklines." + self.breaklines = breaklines + return self + + def gethtml(self, container): + "Return the HTML code." + if self.empty: + return [self.selfclosing(container)] + html = [self.open(container)] + html += ContentsOutput.gethtml(self, container) + html.append(self.close(container)) + return html + + def open(self, container): + "Get opening line." + if not self.checktag(container): + return '' + open = '<' + self.tag + '>' + if self.breaklines: + return open + '\n' + return open + + def close(self, container): + "Get closing line." + if not self.checktag(container): + return '' + close = '</' + self.tag.split()[0] + '>' + if self.breaklines: + return '\n' + close + '\n' + return close + + def selfclosing(self, container): + "Get self-closing line." + if not self.checktag(container): + return '' + selfclosing = '<' + self.tag + '/>' + if self.breaklines: + return selfclosing + '\n' + return selfclosing + + def checktag(self, container): + "Check that the tag is valid." + if not self.tag: + Trace.error('No tag in ' + unicode(container)) + return False + if self.tag == '': + return False + return True + +class FilteredOutput(ContentsOutput): + "Returns the output in the contents, but filtered:" + "some strings are replaced by others." + + def __init__(self): + "Initialize the filters." + self.filters = [] + + def addfilter(self, original, replacement): + "Add a new filter: replace the original by the replacement." + self.filters.append((original, replacement)) + + def gethtml(self, container): + "Return the HTML code" + result = [] + html = ContentsOutput.gethtml(self, container) + for line in html: + result.append(self.filter(line)) + return result + + def filter(self, line): + "Filter a single line with all available filters." + for original, replacement in self.filters: + if original in line: + line = line.replace(original, replacement) + return line + +class StringOutput(ContainerOutput): + "Returns a bare string as output" + + def gethtml(self, container): + "Return a bare string" + return [container.string] + + +class LineReader(object): + "Reads a file line by line" + + def __init__(self, filename): + if isinstance(filename, file): + self.file = filename + else: + self.file = codecs.open(filename, 'rU', 'utf-8') + self.linenumber = 1 + self.lastline = None + self.current = None + self.mustread = True + self.depleted = False + try: + self.readline() + except UnicodeDecodeError: + # try compressed file + import gzip + self.file = gzip.open(filename, 'rb') + self.readline() + + def setstart(self, firstline): + "Set the first line to read." + for i in range(firstline): + self.file.readline() + self.linenumber = firstline + + def setend(self, lastline): + "Set the last line to read." + self.lastline = lastline + + def currentline(self): + "Get the current line" + if self.mustread: + self.readline() + return self.current + + def nextline(self): + "Go to next line" + if self.depleted: + Trace.fatal('Read beyond file end') + self.mustread = True + + def readline(self): + "Read a line from elyxer.file" + self.current = self.file.readline() + if not isinstance(self.file, codecs.StreamReaderWriter): + self.current = self.current.decode('utf-8') + if len(self.current) == 0: + self.depleted = True + self.current = self.current.rstrip('\n\r') + self.linenumber += 1 + self.mustread = False + Trace.prefix = 'Line ' + unicode(self.linenumber) + ': ' + if self.linenumber % 1000 == 0: + Trace.message('Parsing') + + def finished(self): + "Find out if the file is finished" + if self.lastline and self.linenumber == self.lastline: + return True + if self.mustread: + self.readline() + return self.depleted + + def close(self): + self.file.close() + +class LineWriter(object): + "Writes a file as a series of lists" + + file = False + + def __init__(self, filename): + if isinstance(filename, file): + self.file = filename + self.filename = None + else: + self.filename = filename + + def write(self, strings): + "Write a list of strings" + for string in strings: + if not isinstance(string, basestring): + Trace.error('Not a string: ' + unicode(string) + ' in ' + unicode(strings)) + return + self.writestring(string) + + def writestring(self, string): + "Write a string" + if not self.file: + self.file = codecs.open(self.filename, 'w', "utf-8") + if self.file == sys.stdout and sys.version_info < (3, 0): + string = string.encode('utf-8') + self.file.write(string) + + def writeline(self, line): + "Write a line to file" + self.writestring(line + '\n') + + def close(self): + self.file.close() + + + + + + +class Globable(object): + """A bit of text which can be globbed (lumped together in bits). + Methods current(), skipcurrent(), checkfor() and isout() have to be + implemented by subclasses.""" + + leavepending = False + + def __init__(self): + self.endinglist = EndingList() + + def checkbytemark(self): + "Check for a Unicode byte mark and skip it." + if self.finished(): + return + if ord(self.current()) == 0xfeff: + self.skipcurrent() + + def isout(self): + "Find out if we are out of the position yet." + Trace.error('Unimplemented isout()') + return True + + def current(self): + "Return the current character." + Trace.error('Unimplemented current()') + return '' + + def checkfor(self, string): + "Check for the given string in the current position." + Trace.error('Unimplemented checkfor()') + return False + + def finished(self): + "Find out if the current text has finished." + if self.isout(): + if not self.leavepending: + self.endinglist.checkpending() + return True + return self.endinglist.checkin(self) + + def skipcurrent(self): + "Return the current character and skip it." + Trace.error('Unimplemented skipcurrent()') + return '' + + def glob(self, currentcheck): + "Glob a bit of text that satisfies a check on the current char." + glob = '' + while not self.finished() and currentcheck(): + glob += self.skipcurrent() + return glob + + def globalpha(self): + "Glob a bit of alpha text" + return self.glob(lambda: self.current().isalpha()) + + def globnumber(self): + "Glob a row of digits." + return self.glob(lambda: self.current().isdigit()) + + def isidentifier(self): + "Return if the current character is alphanumeric or _." + if self.current().isalnum() or self.current() == '_': + return True + return False + + def globidentifier(self): + "Glob alphanumeric and _ symbols." + return self.glob(self.isidentifier) + + def isvalue(self): + "Return if the current character is a value character:" + "not a bracket or a space." + if self.current().isspace(): + return False + if self.current() in '{}()': + return False + return True + + def globvalue(self): + "Glob a value: any symbols but brackets." + return self.glob(self.isvalue) + + def skipspace(self): + "Skip all whitespace at current position." + return self.glob(lambda: self.current().isspace()) + + def globincluding(self, magicchar): + "Glob a bit of text up to (including) the magic char." + glob = self.glob(lambda: self.current() != magicchar) + magicchar + self.skip(magicchar) + return glob + + def globexcluding(self, excluded): + "Glob a bit of text up until (excluding) any excluded character." + return self.glob(lambda: self.current() not in excluded) + + def pushending(self, ending, optional = False): + "Push a new ending to the bottom" + self.endinglist.add(ending, optional) + + def popending(self, expected = None): + "Pop the ending found at the current position" + if self.isout() and self.leavepending: + return expected + ending = self.endinglist.pop(self) + if expected and expected != ending: + Trace.error('Expected ending ' + expected + ', got ' + ending) + self.skip(ending) + return ending + + def nextending(self): + "Return the next ending in the queue." + nextending = self.endinglist.findending(self) + if not nextending: + return None + return nextending.ending + +class EndingList(object): + "A list of position endings" + + def __init__(self): + self.endings = [] + + def add(self, ending, optional = False): + "Add a new ending to the list" + self.endings.append(PositionEnding(ending, optional)) + + def pickpending(self, pos): + "Pick any pending endings from a parse position." + self.endings += pos.endinglist.endings + + def checkin(self, pos): + "Search for an ending" + if self.findending(pos): + return True + return False + + def pop(self, pos): + "Remove the ending at the current position" + if pos.isout(): + Trace.error('No ending out of bounds') + return '' + ending = self.findending(pos) + if not ending: + Trace.error('No ending at ' + pos.current()) + return '' + for each in reversed(self.endings): + self.endings.remove(each) + if each == ending: + return each.ending + elif not each.optional: + Trace.error('Removed non-optional ending ' + each) + Trace.error('No endings left') + return '' + + def findending(self, pos): + "Find the ending at the current position" + if len(self.endings) == 0: + return None + for index, ending in enumerate(reversed(self.endings)): + if ending.checkin(pos): + return ending + if not ending.optional: + return None + return None + + def checkpending(self): + "Check if there are any pending endings" + if len(self.endings) != 0: + Trace.error('Pending ' + unicode(self) + ' left open') + + def __unicode__(self): + "Printable representation" + string = 'endings [' + for ending in self.endings: + string += unicode(ending) + ',' + if len(self.endings) > 0: + string = string[:-1] + return string + ']' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class PositionEnding(object): + "An ending for a parsing position" + + def __init__(self, ending, optional): + self.ending = ending + self.optional = optional + + def checkin(self, pos): + "Check for the ending" + return pos.checkfor(self.ending) + + def __unicode__(self): + "Printable representation" + string = 'Ending ' + self.ending + if self.optional: + string += ' (optional)' + return string + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class Position(Globable): + """A position in a text to parse. + Including those in Globable, functions to implement by subclasses are: + skip(), identifier(), extract(), isout() and current().""" + + def __init__(self): + Globable.__init__(self) + + def skip(self, string): + "Skip a string" + Trace.error('Unimplemented skip()') + + def identifier(self): + "Return an identifier for the current position." + Trace.error('Unimplemented identifier()') + return 'Error' + + def extract(self, length): + "Extract the next string of the given length, or None if not enough text," + "without advancing the parse position." + Trace.error('Unimplemented extract()') + return None + + def checkfor(self, string): + "Check for a string at the given position." + return string == self.extract(len(string)) + + def checkforlower(self, string): + "Check for a string in lower case." + extracted = self.extract(len(string)) + if not extracted: + return False + return string.lower() == self.extract(len(string)).lower() + + def skipcurrent(self): + "Return the current character and skip it." + current = self.current() + self.skip(current) + return current + + def __next__(self): + "Advance the position and return the next character." + self.skipcurrent() + return self.current() + + if sys.version_info < (3, 0): + next = __next__ + + def checkskip(self, string): + "Check for a string at the given position; if there, skip it" + if not self.checkfor(string): + return False + self.skip(string) + return True + + def error(self, message): + "Show an error message and the position identifier." + Trace.error(message + ': ' + self.identifier()) + +class TextPosition(Position): + "A parse position based on a raw text." + + def __init__(self, text): + "Create the position from elyxer.some text." + Position.__init__(self) + self.pos = 0 + self.text = text + self.checkbytemark() + + def skip(self, string): + "Skip a string of characters." + self.pos += len(string) + + def identifier(self): + "Return a sample of the remaining text." + length = 30 + if self.pos + length > len(self.text): + length = len(self.text) - self.pos + return '*' + self.text[self.pos:self.pos + length] + '*' + + def isout(self): + "Find out if we are out of the text yet." + return self.pos >= len(self.text) + + def current(self): + "Return the current character, assuming we are not out." + return self.text[self.pos] + + def extract(self, length): + "Extract the next string of the given length, or None if not enough text." + if self.pos + length > len(self.text): + return None + return self.text[self.pos : self.pos + length] + +class FilePosition(Position): + "A parse position based on an underlying file." + + def __init__(self, filename): + "Create the position from a file." + Position.__init__(self) + self.reader = LineReader(filename) + self.pos = 0 + self.checkbytemark() + + def skip(self, string): + "Skip a string of characters." + length = len(string) + while self.pos + length > len(self.reader.currentline()): + length -= len(self.reader.currentline()) - self.pos + 1 + self.nextline() + self.pos += length + + def currentline(self): + "Get the current line of the underlying file." + return self.reader.currentline() + + def nextline(self): + "Go to the next line." + self.reader.nextline() + self.pos = 0 + + def linenumber(self): + "Return the line number of the file." + return self.reader.linenumber + 1 + + def identifier(self): + "Return the current line and line number in the file." + before = self.reader.currentline()[:self.pos - 1] + after = self.reader.currentline()[self.pos:] + return 'line ' + unicode(self.getlinenumber()) + ': ' + before + '*' + after + + def isout(self): + "Find out if we are out of the text yet." + if self.pos > len(self.reader.currentline()): + if self.pos > len(self.reader.currentline()) + 1: + Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos)) + self.nextline() + return self.reader.finished() + + def current(self): + "Return the current character, assuming we are not out." + if self.pos == len(self.reader.currentline()): + return '\n' + if self.pos > len(self.reader.currentline()): + Trace.error('Out of the line ' + self.reader.currentline() + ': ' + unicode(self.pos)) + return '*' + return self.reader.currentline()[self.pos] + + def extract(self, length): + "Extract the next string of the given length, or None if not enough text." + if self.pos + length > len(self.reader.currentline()): + return None + return self.reader.currentline()[self.pos : self.pos + length] + + + +class Container(object): + "A container for text and objects in a lyx file" + + partkey = None + parent = None + begin = None + + def __init__(self): + self.contents = list() + + def process(self): + "Process contents" + pass + + def gethtml(self): + "Get the resulting HTML" + html = self.output.gethtml(self) + if isinstance(html, basestring): + Trace.error('Raw string ' + html) + html = [html] + return self.escapeall(html) + + def escapeall(self, lines): + "Escape all lines in an array according to the output options." + result = [] + for line in lines: + if Options.html: + line = self.escape(line, EscapeConfig.html) + if Options.iso885915: + line = self.escape(line, EscapeConfig.iso885915) + line = self.escapeentities(line) + elif not Options.unicode: + line = self.escape(line, EscapeConfig.nonunicode) + result.append(line) + return result + + def escape(self, line, replacements = EscapeConfig.entities): + "Escape a line with replacements from elyxer.a map" + pieces = sorted(replacements.keys()) + # do them in order + for piece in pieces: + if piece in line: + line = line.replace(piece, replacements[piece]) + return line + + def escapeentities(self, line): + "Escape all Unicode characters to HTML entities." + result = '' + pos = TextPosition(line) + while not pos.finished(): + if ord(pos.current()) > 128: + codepoint = hex(ord(pos.current())) + if codepoint == '0xd835': + codepoint = hex(ord(next(pos)) + 0xf800) + result += '&#' + codepoint[1:] + ';' + else: + result += pos.current() + pos.skipcurrent() + return result + + def searchall(self, type): + "Search for all embedded containers of a given type" + list = [] + self.searchprocess(type, lambda container: list.append(container)) + return list + + def searchremove(self, type): + "Search for all containers of a type and remove them" + list = self.searchall(type) + for container in list: + container.parent.contents.remove(container) + return list + + def searchprocess(self, type, process): + "Search for elements of a given type and process them" + self.locateprocess(lambda container: isinstance(container, type), process) + + def locateprocess(self, locate, process): + "Search for all embedded containers and process them" + for container in self.contents: + container.locateprocess(locate, process) + if locate(container): + process(container) + + def recursivesearch(self, locate, recursive, process): + "Perform a recursive search in the container." + for container in self.contents: + if recursive(container): + container.recursivesearch(locate, recursive, process) + if locate(container): + process(container) + + def extracttext(self): + "Extract all text from elyxer.allowed containers." + result = '' + constants = ContainerExtractor(ContainerConfig.extracttext).extract(self) + for constant in constants: + result += constant.string + return result + + def group(self, index, group, isingroup): + "Group some adjoining elements into a group" + if index >= len(self.contents): + return + if hasattr(self.contents[index], 'grouped'): + return + while index < len(self.contents) and isingroup(self.contents[index]): + self.contents[index].grouped = True + group.contents.append(self.contents[index]) + self.contents.pop(index) + self.contents.insert(index, group) + + def remove(self, index): + "Remove a container but leave its contents" + container = self.contents[index] + self.contents.pop(index) + while len(container.contents) > 0: + self.contents.insert(index, container.contents.pop()) + + def tree(self, level = 0): + "Show in a tree" + Trace.debug(" " * level + unicode(self)) + for container in self.contents: + container.tree(level + 1) + + def getparameter(self, name): + "Get the value of a parameter, if present." + if not name in self.parameters: + return None + return self.parameters[name] + + def getparameterlist(self, name): + "Get the value of a comma-separated parameter as a list." + paramtext = self.getparameter(name) + if not paramtext: + return [] + return paramtext.split(',') + + def hasemptyoutput(self): + "Check if the parent's output is empty." + current = self.parent + while current: + if current.output.isempty(): + return True + current = current.parent + return False + + def __unicode__(self): + "Get a description" + if not self.begin: + return self.__class__.__name__ + return self.__class__.__name__ + '@' + unicode(self.begin) + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class BlackBox(Container): + "A container that does not output anything" + + def __init__(self): + self.parser = LoneCommand() + self.output = EmptyOutput() + self.contents = [] + +class LyXFormat(BlackBox): + "Read the lyxformat command" + + def process(self): + "Show warning if version < 276" + version = int(self.header[1]) + if version < 276: + Trace.error('Warning: unsupported old format version ' + str(version)) + if version > int(GeneralConfig.version['lyxformat']): + Trace.error('Warning: unsupported new format version ' + str(version)) + +class StringContainer(Container): + "A container for a single string" + + parsed = None + + def __init__(self): + self.parser = StringParser() + self.output = StringOutput() + self.string = '' + + def process(self): + "Replace special chars from elyxer.the contents." + if self.parsed: + self.string = self.replacespecial(self.parsed) + self.parsed = None + + def replacespecial(self, line): + "Replace all special chars from elyxer.a line" + replaced = self.escape(line, EscapeConfig.entities) + replaced = self.changeline(replaced) + if ContainerConfig.string['startcommand'] in replaced and len(replaced) > 1: + # unprocessed commands + if self.begin: + message = 'Unknown command at ' + unicode(self.begin) + ': ' + else: + message = 'Unknown command: ' + Trace.error(message + replaced.strip()) + return replaced + + def changeline(self, line): + line = self.escape(line, EscapeConfig.chars) + if not ContainerConfig.string['startcommand'] in line: + return line + line = self.escape(line, EscapeConfig.commands) + return line + + def extracttext(self): + "Return all text." + return self.string + + def __unicode__(self): + "Return a printable representation." + result = 'StringContainer' + if self.begin: + result += '@' + unicode(self.begin) + ellipsis = '...' + if len(self.string.strip()) <= 15: + ellipsis = '' + return result + ' (' + self.string.strip()[:15] + ellipsis + ')' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class Constant(StringContainer): + "A constant string" + + def __init__(self, text): + self.contents = [] + self.string = text + self.output = StringOutput() + + def __unicode__(self): + return 'Constant: ' + self.string + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class TaggedText(Container): + "Text inside a tag" + + output = None + + def __init__(self): + self.parser = TextParser(self) + self.output = TaggedOutput() + + def complete(self, contents, tag, breaklines=False): + "Complete the tagged text and return it" + self.contents = contents + self.output.tag = tag + self.output.breaklines = breaklines + return self + + def constant(self, text, tag, breaklines=False): + "Complete the tagged text with a constant" + constant = Constant(text) + return self.complete([constant], tag, breaklines) + + def __unicode__(self): + "Return a printable representation." + if not hasattr(self.output, 'tag'): + return 'Emtpy tagged text' + if not self.output.tag: + return 'Tagged <unknown tag>' + return 'Tagged <' + self.output.tag + '>' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class DocumentParameters(object): + "Global parameters for the document." + + pdftitle = None + indentstandard = False + tocdepth = 10 + startinglevel = 0 + maxdepth = 10 + language = None + bibliography = None + outputchanges = False + displaymode = False + + + + + + +class FormulaParser(Parser): + "Parses a formula" + + def parseheader(self, reader): + "See if the formula is inlined" + self.begin = reader.linenumber + 1 + type = self.parsetype(reader) + if not type: + reader.nextline() + type = self.parsetype(reader) + if not type: + Trace.error('Unknown formula type in ' + reader.currentline().strip()) + return ['unknown'] + return [type] + + def parsetype(self, reader): + "Get the formula type from the first line." + if reader.currentline().find(FormulaConfig.starts['simple']) >= 0: + return 'inline' + if reader.currentline().find(FormulaConfig.starts['complex']) >= 0: + return 'block' + if reader.currentline().find(FormulaConfig.starts['unnumbered']) >= 0: + return 'block' + if reader.currentline().find(FormulaConfig.starts['beginbefore']) >= 0: + return 'numbered' + return None + + def parse(self, reader): + "Parse the formula until the end" + formula = self.parseformula(reader) + while not reader.currentline().startswith(self.ending): + stripped = reader.currentline().strip() + if len(stripped) > 0: + Trace.error('Unparsed formula line ' + stripped) + reader.nextline() + reader.nextline() + return formula + + def parseformula(self, reader): + "Parse the formula contents" + simple = FormulaConfig.starts['simple'] + if simple in reader.currentline(): + rest = reader.currentline().split(simple, 1)[1] + if simple in rest: + # formula is $...$ + return self.parsesingleliner(reader, simple, simple) + # formula is multiline $...$ + return self.parsemultiliner(reader, simple, simple) + if FormulaConfig.starts['complex'] in reader.currentline(): + # formula of the form \[...\] + return self.parsemultiliner(reader, FormulaConfig.starts['complex'], + FormulaConfig.endings['complex']) + beginbefore = FormulaConfig.starts['beginbefore'] + beginafter = FormulaConfig.starts['beginafter'] + if beginbefore in reader.currentline(): + if reader.currentline().strip().endswith(beginafter): + current = reader.currentline().strip() + endsplit = current.split(beginbefore)[1].split(beginafter) + startpiece = beginbefore + endsplit[0] + beginafter + endbefore = FormulaConfig.endings['endbefore'] + endafter = FormulaConfig.endings['endafter'] + endpiece = endbefore + endsplit[0] + endafter + return startpiece + self.parsemultiliner(reader, startpiece, endpiece) + endpiece + Trace.error('Missing ' + beginafter + ' in ' + reader.currentline()) + return '' + begincommand = FormulaConfig.starts['command'] + beginbracket = FormulaConfig.starts['bracket'] + if begincommand in reader.currentline() and beginbracket in reader.currentline(): + endbracket = FormulaConfig.endings['bracket'] + return self.parsemultiliner(reader, beginbracket, endbracket) + Trace.error('Formula beginning ' + reader.currentline() + ' is unknown') + return '' + + def parsesingleliner(self, reader, start, ending): + "Parse a formula in one line" + line = reader.currentline().strip() + if not start in line: + Trace.error('Line ' + line + ' does not contain formula start ' + start) + return '' + if not line.endswith(ending): + Trace.error('Formula ' + line + ' does not end with ' + ending) + return '' + index = line.index(start) + rest = line[index + len(start):-len(ending)] + reader.nextline() + return rest + + def parsemultiliner(self, reader, start, ending): + "Parse a formula in multiple lines" + formula = '' + line = reader.currentline() + if not start in line: + Trace.error('Line ' + line.strip() + ' does not contain formula start ' + start) + return '' + index = line.index(start) + line = line[index + len(start):].strip() + while not line.endswith(ending): + formula += line + '\n' + reader.nextline() + line = reader.currentline() + formula += line[:-len(ending)] + reader.nextline() + return formula + +class MacroParser(FormulaParser): + "A parser for a formula macro." + + def parseheader(self, reader): + "See if the formula is inlined" + self.begin = reader.linenumber + 1 + return ['inline'] + + def parse(self, reader): + "Parse the formula until the end" + formula = self.parsemultiliner(reader, self.parent.start, self.ending) + reader.nextline() + return formula + + +class FormulaBit(Container): + "A bit of a formula" + + type = None + size = 1 + original = '' + + def __init__(self): + "The formula bit type can be 'alpha', 'number', 'font'." + self.contents = [] + self.output = ContentsOutput() + + def setfactory(self, factory): + "Set the internal formula factory." + self.factory = factory + return self + + def add(self, bit): + "Add any kind of formula bit already processed" + self.contents.append(bit) + self.original += bit.original + bit.parent = self + + def skiporiginal(self, string, pos): + "Skip a string and add it to the original formula" + self.original += string + if not pos.checkskip(string): + Trace.error('String ' + string + ' not at ' + pos.identifier()) + + def computesize(self): + "Compute the size of the bit as the max of the sizes of all contents." + if len(self.contents) == 0: + return 1 + self.size = max([element.size for element in self.contents]) + return self.size + + def clone(self): + "Return a copy of itself." + return self.factory.parseformula(self.original) + + def __unicode__(self): + "Get a string representation" + return self.__class__.__name__ + ' read in ' + self.original + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class TaggedBit(FormulaBit): + "A tagged string in a formula" + + def constant(self, constant, tag): + "Set the constant and the tag" + self.output = TaggedOutput().settag(tag) + self.add(FormulaConstant(constant)) + return self + + def complete(self, contents, tag, breaklines = False): + "Set the constant and the tag" + self.contents = contents + self.output = TaggedOutput().settag(tag, breaklines) + return self + + def selfcomplete(self, tag): + "Set the self-closing tag, no contents (as in <hr/>)." + self.output = TaggedOutput().settag(tag, empty = True) + return self + +class FormulaConstant(Constant): + "A constant string in a formula" + + def __init__(self, string): + "Set the constant string" + Constant.__init__(self, string) + self.original = string + self.size = 1 + self.type = None + + def computesize(self): + "Compute the size of the constant: always 1." + return self.size + + def clone(self): + "Return a copy of itself." + return FormulaConstant(self.original) + + def __unicode__(self): + "Return a printable representation." + return 'Formula constant: ' + self.string + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class RawText(FormulaBit): + "A bit of text inside a formula" + + def detect(self, pos): + "Detect a bit of raw text" + return pos.current().isalpha() + + def parsebit(self, pos): + "Parse alphabetic text" + alpha = pos.globalpha() + self.add(FormulaConstant(alpha)) + self.type = 'alpha' + +class FormulaSymbol(FormulaBit): + "A symbol inside a formula" + + modified = FormulaConfig.modified + unmodified = FormulaConfig.unmodified['characters'] + + def detect(self, pos): + "Detect a symbol" + if pos.current() in FormulaSymbol.unmodified: + return True + if pos.current() in FormulaSymbol.modified: + return True + return False + + def parsebit(self, pos): + "Parse the symbol" + if pos.current() in FormulaSymbol.unmodified: + self.addsymbol(pos.current(), pos) + return + if pos.current() in FormulaSymbol.modified: + self.addsymbol(FormulaSymbol.modified[pos.current()], pos) + return + Trace.error('Symbol ' + pos.current() + ' not found') + + def addsymbol(self, symbol, pos): + "Add a symbol" + self.skiporiginal(pos.current(), pos) + self.contents.append(FormulaConstant(symbol)) + +class FormulaNumber(FormulaBit): + "A string of digits in a formula" + + def detect(self, pos): + "Detect a digit" + return pos.current().isdigit() + + def parsebit(self, pos): + "Parse a bunch of digits" + digits = pos.glob(lambda: pos.current().isdigit()) + self.add(FormulaConstant(digits)) + self.type = 'number' + +class Comment(FormulaBit): + "A LaTeX comment: % to the end of the line." + + start = FormulaConfig.starts['comment'] + + def detect(self, pos): + "Detect the %." + return pos.current() == self.start + + def parsebit(self, pos): + "Parse to the end of the line." + self.original += pos.globincluding('\n') + +class WhiteSpace(FormulaBit): + "Some white space inside a formula." + + def detect(self, pos): + "Detect the white space." + return pos.current().isspace() + + def parsebit(self, pos): + "Parse all whitespace." + self.original += pos.skipspace() + + def __unicode__(self): + "Return a printable representation." + return 'Whitespace: *' + self.original + '*' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class Bracket(FormulaBit): + "A {} bracket inside a formula" + + start = FormulaConfig.starts['bracket'] + ending = FormulaConfig.endings['bracket'] + + def __init__(self): + "Create a (possibly literal) new bracket" + FormulaBit.__init__(self) + self.inner = None + + def detect(self, pos): + "Detect the start of a bracket" + return pos.checkfor(self.start) + + def parsebit(self, pos): + "Parse the bracket" + self.parsecomplete(pos, self.innerformula) + return self + + def parsetext(self, pos): + "Parse a text bracket" + self.parsecomplete(pos, self.innertext) + return self + + def parseliteral(self, pos): + "Parse a literal bracket" + self.parsecomplete(pos, self.innerliteral) + return self + + def parsecomplete(self, pos, innerparser): + "Parse the start and end marks" + if not pos.checkfor(self.start): + Trace.error('Bracket should start with ' + self.start + ' at ' + pos.identifier()) + return None + self.skiporiginal(self.start, pos) + pos.pushending(self.ending) + innerparser(pos) + self.original += pos.popending(self.ending) + self.computesize() + + def innerformula(self, pos): + "Parse a whole formula inside the bracket" + while not pos.finished(): + self.add(self.factory.parseany(pos)) + + def innertext(self, pos): + "Parse some text inside the bracket, following textual rules." + specialchars = list(FormulaConfig.symbolfunctions.keys()) + specialchars.append(FormulaConfig.starts['command']) + specialchars.append(FormulaConfig.starts['bracket']) + specialchars.append(Comment.start) + while not pos.finished(): + if pos.current() in specialchars: + self.add(self.factory.parseany(pos)) + if pos.checkskip(' '): + self.original += ' ' + else: + self.add(FormulaConstant(pos.skipcurrent())) + + def innerliteral(self, pos): + "Parse a literal inside the bracket, which does not generate HTML." + self.literal = '' + while not pos.finished() and not pos.current() == self.ending: + if pos.current() == self.start: + self.parseliteral(pos) + else: + self.literal += pos.skipcurrent() + self.original += self.literal + +class SquareBracket(Bracket): + "A [] bracket inside a formula" + + start = FormulaConfig.starts['squarebracket'] + ending = FormulaConfig.endings['squarebracket'] + + def clone(self): + "Return a new square bracket with the same contents." + bracket = SquareBracket() + bracket.contents = self.contents + return bracket + + +class MathsProcessor(object): + "A processor for a maths construction inside the FormulaProcessor." + + def process(self, contents, index): + "Process an element inside a formula." + Trace.error('Unimplemented process() in ' + unicode(self)) + + def __unicode__(self): + "Return a printable description." + return 'Maths processor ' + self.__class__.__name__ + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class FormulaProcessor(object): + "A processor specifically for formulas." + + processors = [] + + def process(self, bit): + "Process the contents of every formula bit, recursively." + self.processcontents(bit) + self.processinsides(bit) + self.traversewhole(bit) + + def processcontents(self, bit): + "Process the contents of a formula bit." + if not isinstance(bit, FormulaBit): + return + bit.process() + for element in bit.contents: + self.processcontents(element) + + def processinsides(self, bit): + "Process the insides (limits, brackets) in a formula bit." + if not isinstance(bit, FormulaBit): + return + for index, element in enumerate(bit.contents): + for processor in self.processors: + processor.process(bit.contents, index) + # continue with recursive processing + self.processinsides(element) + + def traversewhole(self, formula): + "Traverse over the contents to alter variables and space units." + last = None + for bit, contents in self.traverse(formula): + if bit.type == 'alpha': + self.italicize(bit, contents) + elif bit.type == 'font' and last and last.type == 'number': + bit.contents.insert(0, FormulaConstant(u' ')) + last = bit + + def traverse(self, bit): + "Traverse a formula and yield a flattened structure of (bit, list) pairs." + for element in bit.contents: + if hasattr(element, 'type') and element.type: + yield (element, bit.contents) + elif isinstance(element, FormulaBit): + for pair in self.traverse(element): + yield pair + + def italicize(self, bit, contents): + "Italicize the given bit of text." + index = contents.index(bit) + contents[index] = TaggedBit().complete([bit], 'i') + + + + +class Formula(Container): + "A LaTeX formula" + + def __init__(self): + self.parser = FormulaParser() + self.output = TaggedOutput().settag('span class="formula"') + + def process(self): + "Convert the formula to tags" + if self.header[0] == 'inline': + DocumentParameters.displaymode = False + else: + DocumentParameters.displaymode = True + self.output.settag('div class="formula"', True) + if Options.jsmath: + self.jsmath() + elif Options.mathjax: + self.mathjax() + elif Options.googlecharts: + self.googlecharts() + else: + self.classic() + + def jsmath(self): + "Make the contents for jsMath." + if self.header[0] != 'inline': + self.output = TaggedOutput().settag('div class="math"') + else: + self.output = TaggedOutput().settag('span class="math"') + self.contents = [Constant(self.parsed)] + + def mathjax(self): + "Make the contents for MathJax." + self.output.tag = 'span class="MathJax_Preview"' + tag = 'script type="math/tex' + if self.header[0] != 'inline': + tag += ';mode=display' + self.contents = [TaggedText().constant(self.parsed, tag + '"', True)] + + def googlecharts(self): + "Make the contents using Google Charts http://code.google.com/apis/chart/." + url = FormulaConfig.urls['googlecharts'] + quote_plus(self.parsed) + img = '<img class="chart" src="' + url + '" alt="' + self.parsed + '"/>' + self.contents = [Constant(img)] + + def classic(self): + "Make the contents using classic output generation with XHTML and CSS." + whole = FormulaFactory().parseformula(self.parsed) + FormulaProcessor().process(whole) + whole.parent = self + self.contents = [whole] + + def parse(self, pos): + "Parse using a parse position instead of self.parser." + if pos.checkskip('$$'): + self.parsedollarblock(pos) + elif pos.checkskip('$'): + self.parsedollarinline(pos) + elif pos.checkskip('\\('): + self.parseinlineto(pos, '\\)') + elif pos.checkskip('\\['): + self.parseblockto(pos, '\\]') + else: + pos.error('Unparseable formula') + self.process() + return self + + def parsedollarinline(self, pos): + "Parse a $...$ formula." + self.header = ['inline'] + self.parsedollar(pos) + + def parsedollarblock(self, pos): + "Parse a $$...$$ formula." + self.header = ['block'] + self.parsedollar(pos) + if not pos.checkskip('$'): + pos.error('Formula should be $$...$$, but last $ is missing.') + + def parsedollar(self, pos): + "Parse to the next $." + pos.pushending('$') + self.parsed = pos.globexcluding('$') + pos.popending('$') + + def parseinlineto(self, pos, limit): + "Parse a \\(...\\) formula." + self.header = ['inline'] + self.parseupto(pos, limit) + + def parseblockto(self, pos, limit): + "Parse a \\[...\\] formula." + self.header = ['block'] + self.parseupto(pos, limit) + + def parseupto(self, pos, limit): + "Parse a formula that ends with the given command." + pos.pushending(limit) + self.parsed = pos.glob(lambda: True) + pos.popending(limit) + + def __unicode__(self): + "Return a printable representation." + if self.partkey and self.partkey.number: + return 'Formula (' + self.partkey.number + ')' + return 'Unnumbered formula' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class WholeFormula(FormulaBit): + "Parse a whole formula" + + def detect(self, pos): + "Not outside the formula is enough." + return not pos.finished() + + def parsebit(self, pos): + "Parse with any formula bit" + while not pos.finished(): + self.add(self.factory.parseany(pos)) + +class FormulaFactory(object): + "Construct bits of formula" + + # bit types will be appended later + types = [FormulaSymbol, RawText, FormulaNumber, Bracket, Comment, WhiteSpace] + skippedtypes = [Comment, WhiteSpace] + defining = False + + def __init__(self): + "Initialize the map of instances." + self.instances = dict() + + def detecttype(self, type, pos): + "Detect a bit of a given type." + if pos.finished(): + return False + return self.instance(type).detect(pos) + + def instance(self, type): + "Get an instance of the given type." + if not type in self.instances or not self.instances[type]: + self.instances[type] = self.create(type) + return self.instances[type] + + def create(self, type): + "Create a new formula bit of the given type." + return Cloner.create(type).setfactory(self) + + def clearskipped(self, pos): + "Clear any skipped types." + while not pos.finished(): + if not self.skipany(pos): + return + return + + def skipany(self, pos): + "Skip any skipped types." + for type in self.skippedtypes: + if self.instance(type).detect(pos): + return self.parsetype(type, pos) + return None + + def parseany(self, pos): + "Parse any formula bit at the current location." + for type in self.types + self.skippedtypes: + if self.detecttype(type, pos): + return self.parsetype(type, pos) + Trace.error('Unrecognized formula at ' + pos.identifier()) + return FormulaConstant(pos.skipcurrent()) + + def parsetype(self, type, pos): + "Parse the given type and return it." + bit = self.instance(type) + self.instances[type] = None + returnedbit = bit.parsebit(pos) + if returnedbit: + return returnedbit.setfactory(self) + return bit + + def parseformula(self, formula): + "Parse a string of text that contains a whole formula." + pos = TextPosition(formula) + whole = self.create(WholeFormula) + if whole.detect(pos): + whole.parsebit(pos) + return whole + # no formula found + if not pos.finished(): + Trace.error('Unknown formula at: ' + pos.identifier()) + whole.add(TaggedBit().constant(formula, 'span class="unknown"')) + return whole + + +class Translator(object): + "Reads the configuration file and tries to find a translation." + "Otherwise falls back to the messages in the config file." + + instance = None + + def translate(cls, key): + "Get the translated message for a key." + return cls.instance.getmessage(key) + + translate = classmethod(translate) + + def __init__(self): + self.translation = None + self.first = True + + def findtranslation(self): + "Find the translation for the document language." + self.langcodes = None + if not DocumentParameters.language: + Trace.error('No language in document') + return + if not DocumentParameters.language in TranslationConfig.languages: + Trace.error('Unknown language ' + DocumentParameters.language) + return + if TranslationConfig.languages[DocumentParameters.language] == 'en': + return + langcodes = [TranslationConfig.languages[DocumentParameters.language]] + try: + self.translation = gettext.translation('elyxer', None, langcodes) + except IOError: + Trace.error('No translation for ' + unicode(langcodes)) + + def getmessage(self, key): + "Get the translated message for the given key." + if self.first: + self.findtranslation() + self.first = False + message = self.getuntranslated(key) + if not self.translation: + return message + try: + message = self.translation.ugettext(message) + except IOError: + pass + return message + + def getuntranslated(self, key): + "Get the untranslated message." + if not key in TranslationConfig.constants: + Trace.error('Cannot translate ' + key) + return key + return TranslationConfig.constants[key] + +Translator.instance = Translator() + + + +class NumberCounter(object): + "A counter for numbers (by default)." + "The type can be changed to return letters, roman numbers..." + + name = None + value = None + mode = None + master = None + + letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + symbols = NumberingConfig.sequence['symbols'] + romannumerals = [ + ('M', 1000), ('CM', 900), ('D', 500), ('CD', 400), ('C', 100), + ('XC', 90), ('L', 50), ('XL', 40), ('X', 10), ('IX', 9), ('V', 5), + ('IV', 4), ('I', 1) + ] + + def __init__(self, name): + "Give a name to the counter." + self.name = name + + def setmode(self, mode): + "Set the counter mode. Can be changed at runtime." + self.mode = mode + return self + + def init(self, value): + "Set an initial value." + self.value = value + + def gettext(self): + "Get the next value as a text string." + return unicode(self.value) + + def getletter(self): + "Get the next value as a letter." + return self.getsequence(self.letters) + + def getsymbol(self): + "Get the next value as a symbol." + return self.getsequence(self.symbols) + + def getsequence(self, sequence): + "Get the next value from elyxer.a sequence." + return sequence[(self.value - 1) % len(sequence)] + + def getroman(self): + "Get the next value as a roman number." + result = '' + number = self.value + for numeral, value in self.romannumerals: + if number >= value: + result += numeral * (number / value) + number = number % value + return result + + def getvalue(self): + "Get the current value as configured in the current mode." + if not self.mode or self.mode in ['text', '1']: + return self.gettext() + if self.mode == 'A': + return self.getletter() + if self.mode == 'a': + return self.getletter().lower() + if self.mode == 'I': + return self.getroman() + if self.mode == '*': + return self.getsymbol() + Trace.error('Unknown counter mode ' + self.mode) + return self.gettext() + + def getnext(self): + "Increase the current value and get the next value as configured." + if not self.value: + self.value = 0 + self.value += 1 + return self.getvalue() + + def reset(self): + "Reset the counter." + self.value = 0 + + def __unicode__(self): + "Return a printable representation." + result = 'Counter ' + self.name + if self.mode: + result += ' in mode ' + self.mode + return result + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class DependentCounter(NumberCounter): + "A counter which depends on another one (the master)." + + def setmaster(self, master): + "Set the master counter." + self.master = master + self.last = self.master.getvalue() + return self + + def getnext(self): + "Increase or, if the master counter has changed, restart." + if self.last != self.master.getvalue(): + self.reset() + value = NumberCounter.getnext(self) + self.last = self.master.getvalue() + return value + + def getvalue(self): + "Get the value of the combined counter: master.dependent." + return self.master.getvalue() + '.' + NumberCounter.getvalue(self) + +class NumberGenerator(object): + "A number generator for unique sequences and hierarchical structures. Used in:" + " * ordered part numbers: Chapter 3, Section 5.3." + " * unique part numbers: Footnote 15, Bibliography cite [15]." + " * chaptered part numbers: Figure 3.15, Equation (8.3)." + " * unique roman part numbers: Part I, Book IV." + + chaptered = None + generator = None + + romanlayouts = [x.lower() for x in NumberingConfig.layouts['roman']] + orderedlayouts = [x.lower() for x in NumberingConfig.layouts['ordered']] + + counters = dict() + appendix = None + + def deasterisk(self, type): + "Remove the possible asterisk in a layout type." + return type.replace('*', '') + + def isunique(self, type): + "Find out if the layout type corresponds to a unique part." + return self.isroman(type) + + def isroman(self, type): + "Find out if the layout type should have roman numeration." + return self.deasterisk(type).lower() in self.romanlayouts + + def isinordered(self, type): + "Find out if the layout type corresponds to an (un)ordered part." + return self.deasterisk(type).lower() in self.orderedlayouts + + def isnumbered(self, type): + "Find out if the type for a layout corresponds to a numbered layout." + if '*' in type: + return False + if self.isroman(type): + return True + if not self.isinordered(type): + return False + if self.getlevel(type) > DocumentParameters.maxdepth: + return False + return True + + def isunordered(self, type): + "Find out if the type contains an asterisk, basically." + return '*' in type + + def getlevel(self, type): + "Get the level that corresponds to a layout type." + if self.isunique(type): + return 0 + if not self.isinordered(type): + Trace.error('Unknown layout type ' + type) + return 0 + type = self.deasterisk(type).lower() + level = self.orderedlayouts.index(type) + 1 + return level - DocumentParameters.startinglevel + + def getparttype(self, type): + "Obtain the type for the part: without the asterisk, " + "and switched to Appendix if necessary." + if NumberGenerator.appendix and self.getlevel(type) == 1: + return 'Appendix' + return self.deasterisk(type) + + def generate(self, type): + "Generate a number for a layout type." + "Unique part types such as Part or Book generate roman numbers: Part I." + "Ordered part types return dot-separated tuples: Chapter 5, Subsection 2.3.5." + "Everything else generates unique numbers: Bibliography [1]." + "Each invocation results in a new number." + return self.getcounter(type).getnext() + + def getcounter(self, type): + "Get the counter for the given type." + type = type.lower() + if not type in self.counters: + self.counters[type] = self.create(type) + return self.counters[type] + + def create(self, type): + "Create a counter for the given type." + if self.isnumbered(type) and self.getlevel(type) > 1: + index = self.orderedlayouts.index(type) + above = self.orderedlayouts[index - 1] + master = self.getcounter(above) + return self.createdependent(type, master) + counter = NumberCounter(type) + if self.isroman(type): + counter.setmode('I') + return counter + + def getdependentcounter(self, type, master): + "Get (or create) a counter of the given type that depends on another." + if not type in self.counters or not self.counters[type].master: + self.counters[type] = self.createdependent(type, master) + return self.counters[type] + + def createdependent(self, type, master): + "Create a dependent counter given the master." + return DependentCounter(type).setmaster(master) + + def startappendix(self): + "Start appendices here." + firsttype = self.orderedlayouts[DocumentParameters.startinglevel] + counter = self.getcounter(firsttype) + counter.setmode('A').reset() + NumberGenerator.appendix = True + +class ChapteredGenerator(NumberGenerator): + "Generate chaptered numbers, as in Chapter.Number." + "Used in equations, figures: Equation (5.3), figure 8.15." + + def generate(self, type): + "Generate a number which goes with first-level numbers (chapters). " + "For the article classes a unique number is generated." + if DocumentParameters.startinglevel > 0: + return NumberGenerator.generator.generate(type) + chapter = self.getcounter('Chapter') + return self.getdependentcounter(type, chapter).getnext() + + +NumberGenerator.chaptered = ChapteredGenerator() +NumberGenerator.generator = NumberGenerator() + + + + + + +class ContainerSize(object): + "The size of a container." + + width = None + height = None + maxwidth = None + maxheight = None + scale = None + + def set(self, width = None, height = None): + "Set the proper size with width and height." + self.setvalue('width', width) + self.setvalue('height', height) + return self + + def setmax(self, maxwidth = None, maxheight = None): + "Set max width and/or height." + self.setvalue('maxwidth', maxwidth) + self.setvalue('maxheight', maxheight) + return self + + def readparameters(self, container): + "Read some size parameters off a container." + self.setparameter(container, 'width') + self.setparameter(container, 'height') + self.setparameter(container, 'scale') + self.checkvalidheight(container) + return self + + def setparameter(self, container, name): + "Read a size parameter off a container, and set it if present." + value = container.getparameter(name) + self.setvalue(name, value) + + def setvalue(self, name, value): + "Set the value of a parameter name, only if it's valid." + value = self.processparameter(value) + if value: + setattr(self, name, value) + + def checkvalidheight(self, container): + "Check if the height parameter is valid; otherwise erase it." + heightspecial = container.getparameter('height_special') + if self.height and self.extractnumber(self.height) == '1' and heightspecial == 'totalheight': + self.height = None + + def processparameter(self, value): + "Do the full processing on a parameter." + if not value: + return None + if self.extractnumber(value) == '0': + return None + for ignored in StyleConfig.size['ignoredtexts']: + if ignored in value: + value = value.replace(ignored, '') + return value + + def extractnumber(self, text): + "Extract the first number in the given text." + result = '' + decimal = False + for char in text: + if char.isdigit(): + result += char + elif char == '.' and not decimal: + result += char + decimal = True + else: + return result + return result + + def checkimage(self, width, height): + "Check image dimensions, set them if possible." + if width: + self.maxwidth = unicode(width) + 'px' + if self.scale and not self.width: + self.width = self.scalevalue(width) + if height: + self.maxheight = unicode(height) + 'px' + if self.scale and not self.height: + self.height = self.scalevalue(height) + if self.width and not self.height: + self.height = 'auto' + if self.height and not self.width: + self.width = 'auto' + + def scalevalue(self, value): + "Scale the value according to the image scale and return it as unicode." + scaled = value * int(self.scale) / 100 + return unicode(int(scaled)) + 'px' + + def removepercentwidth(self): + "Remove percent width if present, to set it at the figure level." + if not self.width: + return None + if not '%' in self.width: + return None + width = self.width + self.width = None + if self.height == 'auto': + self.height = None + return width + + def addstyle(self, container): + "Add the proper style attribute to the output tag." + if not isinstance(container.output, TaggedOutput): + Trace.error('No tag to add style, in ' + unicode(container)) + if not self.width and not self.height and not self.maxwidth and not self.maxheight: + # nothing to see here; move along + return + tag = ' style="' + tag += self.styleparameter('width') + tag += self.styleparameter('maxwidth') + tag += self.styleparameter('height') + tag += self.styleparameter('maxheight') + if tag[-1] == ' ': + tag = tag[:-1] + tag += '"' + container.output.tag += tag + + def styleparameter(self, name): + "Get the style for a single parameter." + value = getattr(self, name) + if value: + return name.replace('max', 'max-') + ': ' + value + '; ' + return '' + + + +class QuoteContainer(Container): + "A container for a pretty quote" + + def __init__(self): + self.parser = BoundedParser() + self.output = FixedOutput() + + def process(self): + "Process contents" + self.type = self.header[2] + if not self.type in StyleConfig.quotes: + Trace.error('Quote type ' + self.type + ' not found') + self.html = ['"'] + return + self.html = [StyleConfig.quotes[self.type]] + +class LyXLine(Container): + "A Lyx line" + + def __init__(self): + self.parser = LoneCommand() + self.output = FixedOutput() + + def process(self): + self.html = ['<hr class="line" />'] + +class EmphaticText(TaggedText): + "Text with emphatic mode" + + def process(self): + self.output.tag = 'i' + +class ShapedText(TaggedText): + "Text shaped (italic, slanted)" + + def process(self): + self.type = self.header[1] + if not self.type in TagConfig.shaped: + Trace.error('Unrecognized shape ' + self.header[1]) + self.output.tag = 'span' + return + self.output.tag = TagConfig.shaped[self.type] + +class VersalitasText(TaggedText): + "Text in versalitas" + + def process(self): + self.output.tag = 'span class="versalitas"' + +class ColorText(TaggedText): + "Colored text" + + def process(self): + self.color = self.header[1] + self.output.tag = 'span class="' + self.color + '"' + +class SizeText(TaggedText): + "Sized text" + + def process(self): + self.size = self.header[1] + self.output.tag = 'span class="' + self.size + '"' + +class BoldText(TaggedText): + "Bold text" + + def process(self): + self.output.tag = 'b' + +class TextFamily(TaggedText): + "A bit of text from elyxer.a different family" + + def process(self): + "Parse the type of family" + self.type = self.header[1] + if not self.type in TagConfig.family: + Trace.error('Unrecognized family ' + type) + self.output.tag = 'span' + return + self.output.tag = TagConfig.family[self.type] + +class Hfill(TaggedText): + "Horizontall fill" + + def process(self): + self.output.tag = 'span class="hfill"' + +class BarredText(TaggedText): + "Text with a bar somewhere" + + def process(self): + "Parse the type of bar" + self.type = self.header[1] + if not self.type in TagConfig.barred: + Trace.error('Unknown bar type ' + self.type) + self.output.tag = 'span' + return + self.output.tag = TagConfig.barred[self.type] + +class LangLine(TaggedText): + "A line with language information" + + def process(self): + "Only generate a span with lang info when the language is recognized." + lang = self.header[1] + if not lang in TranslationConfig.languages: + self.output = ContentsOutput() + return + isolang = TranslationConfig.languages[lang] + self.output = TaggedOutput().settag('span lang="' + isolang + '"', False) + +class InsetLength(BlackBox): + "A length measure inside an inset." + + def process(self): + self.length = self.header[1] + +class Space(Container): + "A space of several types" + + def __init__(self): + self.parser = InsetParser() + self.output = FixedOutput() + + def process(self): + self.type = self.header[2] + if self.type not in StyleConfig.hspaces: + Trace.error('Unknown space type ' + self.type) + self.html = [' '] + return + self.html = [StyleConfig.hspaces[self.type]] + length = self.getlength() + if not length: + return + self.output = TaggedOutput().settag('span class="hspace"', False) + ContainerSize().set(length).addstyle(self) + + def getlength(self): + "Get the space length from elyxer.the contents or parameters." + if len(self.contents) == 0 or not isinstance(self.contents[0], InsetLength): + return None + return self.contents[0].length + +class VerticalSpace(Container): + "An inset that contains a vertical space." + + def __init__(self): + self.parser = InsetParser() + self.output = FixedOutput() + + def process(self): + "Set the correct tag" + self.type = self.header[2] + if self.type not in StyleConfig.vspaces: + self.output = TaggedOutput().settag('div class="vspace" style="height: ' + self.type + ';"', True) + return + self.html = [StyleConfig.vspaces[self.type]] + +class Align(Container): + "Bit of aligned text" + + def __init__(self): + self.parser = ExcludingParser() + self.output = TaggedOutput().setbreaklines(True) + + def process(self): + self.output.tag = 'div class="' + self.header[1] + '"' + +class Newline(Container): + "A newline" + + def __init__(self): + self.parser = LoneCommand() + self.output = FixedOutput() + + def process(self): + "Process contents" + self.html = ['<br/>\n'] + +class NewPage(Newline): + "A new page" + + def process(self): + "Process contents" + self.html = ['<p><br/>\n</p>\n'] + +class Separator(Container): + "A separator string which is not extracted by extracttext()." + + def __init__(self, constant): + self.output = FixedOutput() + self.contents = [] + self.html = [constant] + +class StrikeOut(TaggedText): + "Striken out text." + + def process(self): + "Set the output tag to strike." + self.output.tag = 'strike' + +class StartAppendix(BlackBox): + "Mark to start an appendix here." + "From this point on, all chapters become appendices." + + def process(self): + "Activate the special numbering scheme for appendices, using letters." + NumberGenerator.generator.startappendix() + + + + + + +class Link(Container): + "A link to another part of the document" + + anchor = None + url = None + type = None + page = None + target = None + destination = None + title = None + + def __init__(self): + "Initialize the link, add target if configured." + self.contents = [] + self.parser = InsetParser() + self.output = LinkOutput() + if Options.target: + self.target = Options.target + + def complete(self, text, anchor = None, url = None, type = None, title = None): + "Complete the link." + self.contents = [Constant(text)] + if anchor: + self.anchor = anchor + if url: + self.url = url + if type: + self.type = type + if title: + self.title = title + return self + + def computedestination(self): + "Use the destination link to fill in the destination URL." + if not self.destination: + return + self.url = '' + if self.destination.anchor: + self.url = '#' + self.destination.anchor + if self.destination.page: + self.url = self.destination.page + self.url + + def setmutualdestination(self, destination): + "Set another link as destination, and set its destination to this one." + self.destination = destination + destination.destination = self + + def __unicode__(self): + "Return a printable representation." + result = 'Link' + if self.anchor: + result += ' #' + self.anchor + if self.url: + result += ' to ' + self.url + return result + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class URL(Link): + "A clickable URL" + + def process(self): + "Read URL from elyxer.parameters" + target = self.escape(self.getparameter('target')) + self.url = target + type = self.getparameter('type') + if type: + self.url = self.escape(type) + target + name = self.getparameter('name') + if not name: + name = target + self.contents = [Constant(name)] + +class FlexURL(URL): + "A flexible URL" + + def process(self): + "Read URL from elyxer.contents" + self.url = self.extracttext() + +class LinkOutput(ContainerOutput): + "A link pointing to some destination" + "Or an anchor (destination)" + + def gethtml(self, link): + "Get the HTML code for the link" + type = link.__class__.__name__ + if link.type: + type = link.type + tag = 'a class="' + type + '"' + if link.anchor: + tag += ' name="' + link.anchor + '"' + if link.destination: + link.computedestination() + if link.url: + tag += ' href="' + link.url + '"' + if link.target: + tag += ' target="' + link.target + '"' + if link.title: + tag += ' title="' + link.title + '"' + return TaggedOutput().settag(tag).gethtml(link) + + + + + +class Postprocessor(object): + "Postprocess a container keeping some context" + + stages = [] + + def __init__(self): + self.stages = StageDict(Postprocessor.stages, self) + self.current = None + self.last = None + + def postprocess(self, next): + "Postprocess a container and its contents." + self.postrecursive(self.current) + result = self.postcurrent(next) + self.last = self.current + self.current = next + return result + + def postrecursive(self, container): + "Postprocess the container contents recursively" + if not hasattr(container, 'contents'): + return + if len(container.contents) == 0: + return + if hasattr(container, 'postprocess'): + if not container.postprocess: + return + postprocessor = Postprocessor() + contents = [] + for element in container.contents: + post = postprocessor.postprocess(element) + if post: + contents.append(post) + # two rounds to empty the pipeline + for i in range(2): + post = postprocessor.postprocess(None) + if post: + contents.append(post) + container.contents = contents + + def postcurrent(self, next): + "Postprocess the current element taking into account next and last." + stage = self.stages.getstage(self.current) + if not stage: + return self.current + return stage.postprocess(self.last, self.current, next) + +class StageDict(object): + "A dictionary of stages corresponding to classes" + + def __init__(self, classes, postprocessor): + "Instantiate an element from elyxer.each class and store as a dictionary" + instances = self.instantiate(classes, postprocessor) + self.stagedict = dict([(x.processedclass, x) for x in instances]) + + def instantiate(self, classes, postprocessor): + "Instantiate an element from elyxer.each class" + stages = [x.__new__(x) for x in classes] + for element in stages: + element.__init__() + element.postprocessor = postprocessor + return stages + + def getstage(self, element): + "Get the stage for a given element, if the type is in the dict" + if not element.__class__ in self.stagedict: + return None + return self.stagedict[element.__class__] + + + +class Label(Link): + "A label to be referenced" + + names = dict() + lastlayout = None + + def __init__(self): + Link.__init__(self) + self.lastnumbered = None + + def process(self): + "Process a label container." + key = self.getparameter('name') + self.create(' ', key) + self.lastnumbered = Label.lastlayout + + def create(self, text, key, type = 'Label'): + "Create the label for a given key." + self.key = key + self.complete(text, anchor = key, type = type) + Label.names[key] = self + if key in Reference.references: + for reference in Reference.references[key]: + reference.destination = self + return self + + def findpartkey(self): + "Get the part key for the latest numbered container seen." + numbered = self.numbered(self) + if numbered and numbered.partkey: + return numbered.partkey + return '' + + def numbered(self, container): + "Get the numbered container for the label." + if container.partkey: + return container + if not container.parent: + if self.lastnumbered: + return self.lastnumbered + return None + return self.numbered(container.parent) + + def __unicode__(self): + "Return a printable representation." + if not hasattr(self, 'key'): + return 'Unnamed label' + return 'Label ' + self.key + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class Reference(Link): + "A reference to a label." + + references = dict() + key = 'none' + + def process(self): + "Read the reference and set the arrow." + self.key = self.getparameter('reference') + if self.key in Label.names: + self.direction = u'↑' + label = Label.names[self.key] + else: + self.direction = u'↓' + label = Label().complete(' ', self.key, 'preref') + self.destination = label + self.formatcontents() + if not self.key in Reference.references: + Reference.references[self.key] = [] + Reference.references[self.key].append(self) + + def formatcontents(self): + "Format the reference contents." + formatkey = self.getparameter('LatexCommand') + if not formatkey: + formatkey = 'ref' + self.formatted = u'↕' + if formatkey in StyleConfig.referenceformats: + self.formatted = StyleConfig.referenceformats[formatkey] + else: + Trace.error('Unknown reference format ' + formatkey) + self.replace(u'↕', self.direction) + self.replace('#', '1') + self.replace('on-page', Translator.translate('on-page')) + partkey = self.destination.findpartkey() + # only if partkey and partkey.number are not null, send partkey.number + self.replace('@', partkey and partkey.number) + self.replace(u'¶', partkey and partkey.tocentry) + if not '$' in self.formatted or not partkey or not partkey.titlecontents: + # there is a $ left, but it should go away on preprocessing + self.contents = [Constant(self.formatted)] + return + pieces = self.formatted.split('$') + self.contents = [Constant(pieces[0])] + for piece in pieces[1:]: + self.contents += partkey.titlecontents + self.contents.append(Constant(piece)) + + def replace(self, key, value): + "Replace a key in the format template with a value." + if not key in self.formatted: + return + if not value: + value = '' + self.formatted = self.formatted.replace(key, value) + + def __unicode__(self): + "Return a printable representation." + return 'Reference ' + self.key + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class FormulaCommand(FormulaBit): + "A LaTeX command inside a formula" + + types = [] + start = FormulaConfig.starts['command'] + commandmap = None + + def detect(self, pos): + "Find the current command." + return pos.checkfor(FormulaCommand.start) + + def parsebit(self, pos): + "Parse the command." + command = self.extractcommand(pos) + bit = self.parsewithcommand(command, pos) + if bit: + return bit + if command.startswith('\\up') or command.startswith('\\Up'): + upgreek = self.parseupgreek(command, pos) + if upgreek: + return upgreek + if not self.factory.defining: + Trace.error('Unknown command ' + command) + self.output = TaggedOutput().settag('span class="unknown"') + self.add(FormulaConstant(command)) + return None + + def parsewithcommand(self, command, pos): + "Parse the command type once we have the command." + for type in FormulaCommand.types: + if command in type.commandmap: + return self.parsecommandtype(command, type, pos) + return None + + def parsecommandtype(self, command, type, pos): + "Parse a given command type." + bit = self.factory.create(type) + bit.setcommand(command) + returned = bit.parsebit(pos) + if returned: + return returned + return bit + + def extractcommand(self, pos): + "Extract the command from elyxer.the current position." + if not pos.checkskip(FormulaCommand.start): + pos.error('Missing command start ' + FormulaCommand.start) + return + if pos.finished(): + return self.emptycommand(pos) + if pos.current().isalpha(): + # alpha command + command = FormulaCommand.start + pos.globalpha() + # skip mark of short command + pos.checkskip('*') + return command + # symbol command + return FormulaCommand.start + pos.skipcurrent() + + def emptycommand(self, pos): + """Check for an empty command: look for command disguised as ending. + Special case against '{ \\{ \\} }' situation.""" + command = '' + if not pos.isout(): + ending = pos.nextending() + if ending and pos.checkskip(ending): + command = ending + return FormulaCommand.start + command + + def parseupgreek(self, command, pos): + "Parse the Greek \\up command.." + if len(command) < 4: + return None + if command.startswith('\\up'): + upcommand = '\\' + command[3:] + elif pos.checkskip('\\Up'): + upcommand = '\\' + command[3:4].upper() + command[4:] + else: + Trace.error('Impossible upgreek command: ' + command) + return + upgreek = self.parsewithcommand(upcommand, pos) + if upgreek: + upgreek.type = 'font' + return upgreek + +class CommandBit(FormulaCommand): + "A formula bit that includes a command" + + def setcommand(self, command): + "Set the command in the bit" + self.command = command + if self.commandmap: + self.original += command + self.translated = self.commandmap[self.command] + + def parseparameter(self, pos): + "Parse a parameter at the current position" + self.factory.clearskipped(pos) + if pos.finished(): + return None + parameter = self.factory.parseany(pos) + self.add(parameter) + return parameter + + def parsesquare(self, pos): + "Parse a square bracket" + self.factory.clearskipped(pos) + if not self.factory.detecttype(SquareBracket, pos): + return None + bracket = self.factory.parsetype(SquareBracket, pos) + self.add(bracket) + return bracket + + def parseliteral(self, pos): + "Parse a literal bracket." + self.factory.clearskipped(pos) + if not self.factory.detecttype(Bracket, pos): + if not pos.isvalue(): + Trace.error('No literal parameter found at: ' + pos.identifier()) + return None + return pos.globvalue() + bracket = Bracket().setfactory(self.factory) + self.add(bracket.parseliteral(pos)) + return bracket.literal + + def parsesquareliteral(self, pos): + "Parse a square bracket literally." + self.factory.clearskipped(pos) + if not self.factory.detecttype(SquareBracket, pos): + return None + bracket = SquareBracket().setfactory(self.factory) + self.add(bracket.parseliteral(pos)) + return bracket.literal + + def parsetext(self, pos): + "Parse a text parameter." + self.factory.clearskipped(pos) + if not self.factory.detecttype(Bracket, pos): + Trace.error('No text parameter for ' + self.command) + return None + bracket = Bracket().setfactory(self.factory).parsetext(pos) + self.add(bracket) + return bracket + +class EmptyCommand(CommandBit): + "An empty command (without parameters)" + + commandmap = FormulaConfig.commands + + def parsebit(self, pos): + "Parse a command without parameters" + self.contents = [FormulaConstant(self.translated)] + +class SpacedCommand(CommandBit): + "An empty command which should have math spacing in formulas." + + commandmap = FormulaConfig.spacedcommands + + def parsebit(self, pos): + "Place as contents the command translated and spaced." + self.contents = [FormulaConstant(u' ' + self.translated + u' ')] + +class AlphaCommand(EmptyCommand): + "A command without paramters whose result is alphabetical" + + commandmap = FormulaConfig.alphacommands + + def parsebit(self, pos): + "Parse the command and set type to alpha" + EmptyCommand.parsebit(self, pos) + self.type = 'alpha' + +class OneParamFunction(CommandBit): + "A function of one parameter" + + commandmap = FormulaConfig.onefunctions + simplified = False + + def parsebit(self, pos): + "Parse a function with one parameter" + self.output = TaggedOutput().settag(self.translated) + self.parseparameter(pos) + self.simplifyifpossible() + + def simplifyifpossible(self): + "Try to simplify to a single character." + if self.original in self.commandmap: + self.output = FixedOutput() + self.html = [self.commandmap[self.original]] + self.simplified = True + +class SymbolFunction(CommandBit): + "Find a function which is represented by a symbol (like _ or ^)" + + commandmap = FormulaConfig.symbolfunctions + + def detect(self, pos): + "Find the symbol" + return pos.current() in SymbolFunction.commandmap + + def parsebit(self, pos): + "Parse the symbol" + self.setcommand(pos.current()) + pos.skip(self.command) + self.output = TaggedOutput().settag(self.translated) + self.parseparameter(pos) + +class TextFunction(CommandBit): + "A function where parameters are read as text." + + commandmap = FormulaConfig.textfunctions + + def parsebit(self, pos): + "Parse a text parameter" + self.output = TaggedOutput().settag(self.translated) + self.parsetext(pos) + + def process(self): + "Set the type to font" + self.type = 'font' + +class LabelFunction(CommandBit): + "A function that acts as a label" + + commandmap = FormulaConfig.labelfunctions + + def parsebit(self, pos): + "Parse a literal parameter" + self.key = self.parseliteral(pos) + + def process(self): + "Add an anchor with the label contents." + self.type = 'font' + self.label = Label().create(' ', self.key, type = 'eqnumber') + self.contents = [self.label] + # store as a Label so we know it's been seen + Label.names[self.key] = self.label + +class FontFunction(OneParamFunction): + "A function of one parameter that changes the font" + + commandmap = FormulaConfig.fontfunctions + + def process(self): + "Simplify if possible using a single character." + self.type = 'font' + self.simplifyifpossible() + +FormulaFactory.types += [FormulaCommand, SymbolFunction] +FormulaCommand.types = [ + AlphaCommand, EmptyCommand, OneParamFunction, FontFunction, LabelFunction, + TextFunction, SpacedCommand, + ] + + + + + + + + + + + + +class BigSymbol(object): + "A big symbol generator." + + symbols = FormulaConfig.bigsymbols + + def __init__(self, symbol): + "Create the big symbol." + self.symbol = symbol + + def getpieces(self): + "Get an array with all pieces." + if not self.symbol in self.symbols: + return [self.symbol] + if self.smalllimit(): + return [self.symbol] + return self.symbols[self.symbol] + + def smalllimit(self): + "Decide if the limit should be a small, one-line symbol." + if not DocumentParameters.displaymode: + return True + if len(self.symbols[self.symbol]) == 1: + return True + return Options.simplemath + +class BigBracket(BigSymbol): + "A big bracket generator." + + def __init__(self, size, bracket, alignment='l'): + "Set the size and symbol for the bracket." + self.size = size + self.original = bracket + self.alignment = alignment + self.pieces = None + if bracket in FormulaConfig.bigbrackets: + self.pieces = FormulaConfig.bigbrackets[bracket] + + def getpiece(self, index): + "Return the nth piece for the bracket." + function = getattr(self, 'getpiece' + unicode(len(self.pieces))) + return function(index) + + def getpiece1(self, index): + "Return the only piece for a single-piece bracket." + return self.pieces[0] + + def getpiece3(self, index): + "Get the nth piece for a 3-piece bracket: parenthesis or square bracket." + if index == 0: + return self.pieces[0] + if index == self.size - 1: + return self.pieces[-1] + return self.pieces[1] + + def getpiece4(self, index): + "Get the nth piece for a 4-piece bracket: curly bracket." + if index == 0: + return self.pieces[0] + if index == self.size - 1: + return self.pieces[3] + if index == (self.size - 1)/2: + return self.pieces[2] + return self.pieces[1] + + def getcell(self, index): + "Get the bracket piece as an array cell." + piece = self.getpiece(index) + span = 'span class="bracket align-' + self.alignment + '"' + return TaggedBit().constant(piece, span) + + def getcontents(self): + "Get the bracket as an array or as a single bracket." + if self.size == 1 or not self.pieces: + return self.getsinglebracket() + rows = [] + for index in range(self.size): + cell = self.getcell(index) + rows.append(TaggedBit().complete([cell], 'span class="arrayrow"')) + return [TaggedBit().complete(rows, 'span class="array"')] + + def getsinglebracket(self): + "Return the bracket as a single sign." + if self.original == '.': + return [TaggedBit().constant('', 'span class="emptydot"')] + return [TaggedBit().constant(self.original, 'span class="symbol"')] + + + + + + +class FormulaEquation(CommandBit): + "A simple numbered equation." + + piece = 'equation' + + def parsebit(self, pos): + "Parse the array" + self.output = ContentsOutput() + self.add(self.factory.parsetype(WholeFormula, pos)) + +class FormulaCell(FormulaCommand): + "An array cell inside a row" + + def setalignment(self, alignment): + self.alignment = alignment + self.output = TaggedOutput().settag('span class="arraycell align-' + alignment +'"', True) + return self + + def parsebit(self, pos): + self.factory.clearskipped(pos) + if pos.finished(): + return + self.add(self.factory.parsetype(WholeFormula, pos)) + +class FormulaRow(FormulaCommand): + "An array row inside an array" + + cellseparator = FormulaConfig.array['cellseparator'] + + def setalignments(self, alignments): + self.alignments = alignments + self.output = TaggedOutput().settag('span class="arrayrow"', True) + return self + + def parsebit(self, pos): + "Parse a whole row" + index = 0 + pos.pushending(self.cellseparator, optional=True) + while not pos.finished(): + cell = self.createcell(index) + cell.parsebit(pos) + self.add(cell) + index += 1 + pos.checkskip(self.cellseparator) + if len(self.contents) == 0: + self.output = EmptyOutput() + + def createcell(self, index): + "Create the cell that corresponds to the given index." + alignment = self.alignments[index % len(self.alignments)] + return self.factory.create(FormulaCell).setalignment(alignment) + +class MultiRowFormula(CommandBit): + "A formula with multiple rows." + + def parserows(self, pos): + "Parse all rows, finish when no more row ends" + self.rows = [] + first = True + for row in self.iteraterows(pos): + if first: + first = False + else: + # intersparse empty rows + self.addempty() + row.parsebit(pos) + self.addrow(row) + self.size = len(self.rows) + + def iteraterows(self, pos): + "Iterate over all rows, end when no more row ends" + rowseparator = FormulaConfig.array['rowseparator'] + while True: + pos.pushending(rowseparator, True) + row = self.factory.create(FormulaRow) + yield row.setalignments(self.alignments) + if pos.checkfor(rowseparator): + self.original += pos.popending(rowseparator) + else: + return + + def addempty(self): + "Add an empty row." + row = self.factory.create(FormulaRow).setalignments(self.alignments) + for index, originalcell in enumerate(self.rows[-1].contents): + cell = row.createcell(index) + cell.add(FormulaConstant(u' ')) + row.add(cell) + self.addrow(row) + + def addrow(self, row): + "Add a row to the contents and to the list of rows." + self.rows.append(row) + self.add(row) + +class FormulaArray(MultiRowFormula): + "An array within a formula" + + piece = 'array' + + def parsebit(self, pos): + "Parse the array" + self.output = TaggedOutput().settag('span class="array"', False) + self.parsealignments(pos) + self.parserows(pos) + + def parsealignments(self, pos): + "Parse the different alignments" + # vertical + self.valign = 'c' + literal = self.parsesquareliteral(pos) + if literal: + self.valign = literal + # horizontal + literal = self.parseliteral(pos) + self.alignments = [] + for l in literal: + self.alignments.append(l) + +class FormulaMatrix(MultiRowFormula): + "A matrix (array with center alignment)." + + piece = 'matrix' + + def parsebit(self, pos): + "Parse the matrix, set alignments to 'c'." + self.output = TaggedOutput().settag('span class="array"', False) + self.valign = 'c' + self.alignments = ['c'] + self.parserows(pos) + +class FormulaCases(MultiRowFormula): + "A cases statement" + + piece = 'cases' + + def parsebit(self, pos): + "Parse the cases" + self.output = ContentsOutput() + self.alignments = ['l', 'l'] + self.parserows(pos) + for row in self.contents: + for cell in row.contents: + cell.output.settag('span class="case align-l"', True) + cell.contents.append(FormulaConstant(u' ')) + array = TaggedBit().complete(self.contents, 'span class="bracketcases"', True) + brace = BigBracket(len(self.contents), '{', 'l') + self.contents = brace.getcontents() + [array] + +class EquationEnvironment(MultiRowFormula): + "A \\begin{}...\\end equation environment with rows and cells." + + def parsebit(self, pos): + "Parse the whole environment." + self.output = TaggedOutput().settag('span class="environment"', False) + environment = self.piece.replace('*', '') + if environment in FormulaConfig.environments: + self.alignments = FormulaConfig.environments[environment] + else: + Trace.error('Unknown equation environment ' + self.piece) + self.alignments = ['l'] + self.parserows(pos) + +class BeginCommand(CommandBit): + "A \\begin{}...\\end command and what it entails (array, cases, aligned)" + + commandmap = {FormulaConfig.array['begin']:''} + + types = [FormulaEquation, FormulaArray, FormulaCases, FormulaMatrix] + + def parsebit(self, pos): + "Parse the begin command" + command = self.parseliteral(pos) + bit = self.findbit(command) + ending = FormulaConfig.array['end'] + '{' + command + '}' + pos.pushending(ending) + bit.parsebit(pos) + self.add(bit) + self.original += pos.popending(ending) + self.size = bit.size + + def findbit(self, piece): + "Find the command bit corresponding to the \\begin{piece}" + for type in BeginCommand.types: + if piece.replace('*', '') == type.piece: + return self.factory.create(type) + bit = self.factory.create(EquationEnvironment) + bit.piece = piece + return bit + +FormulaCommand.types += [BeginCommand] + + + +class CombiningFunction(OneParamFunction): + + commandmap = FormulaConfig.combiningfunctions + + def parsebit(self, pos): + "Parse a combining function." + self.type = 'alpha' + combining = self.translated + parameter = self.parsesingleparameter(pos) + if not parameter: + Trace.error('Empty parameter for combining function ' + self.command) + elif len(parameter.extracttext()) != 1: + Trace.error('Applying combining function ' + self.command + ' to invalid string "' + parameter.extracttext() + '"') + self.contents.append(Constant(combining)) + + def parsesingleparameter(self, pos): + "Parse a parameter, or a single letter." + self.factory.clearskipped(pos) + if pos.finished(): + Trace.error('Error while parsing single parameter at ' + pos.identifier()) + return None + if self.factory.detecttype(Bracket, pos) \ + or self.factory.detecttype(FormulaCommand, pos): + return self.parseparameter(pos) + letter = FormulaConstant(pos.skipcurrent()) + self.add(letter) + return letter + +class DecoratingFunction(OneParamFunction): + "A function that decorates some bit of text" + + commandmap = FormulaConfig.decoratingfunctions + + def parsebit(self, pos): + "Parse a decorating function" + self.type = 'alpha' + symbol = self.translated + self.symbol = TaggedBit().constant(symbol, 'span class="symbolover"') + self.parameter = self.parseparameter(pos) + self.output = TaggedOutput().settag('span class="withsymbol"') + self.contents.insert(0, self.symbol) + self.parameter.output = TaggedOutput().settag('span class="undersymbol"') + self.simplifyifpossible() + +class LimitCommand(EmptyCommand): + "A command which accepts limits above and below, in display mode." + + commandmap = FormulaConfig.limitcommands + + def parsebit(self, pos): + "Parse a limit command." + pieces = BigSymbol(self.translated).getpieces() + self.output = TaggedOutput().settag('span class="limits"') + for piece in pieces: + self.contents.append(TaggedBit().constant(piece, 'span class="limit"')) + +class LimitPreviousCommand(LimitCommand): + "A command to limit the previous command." + + commandmap = None + + def parsebit(self, pos): + "Do nothing." + self.output = TaggedOutput().settag('span class="limits"') + self.factory.clearskipped(pos) + + def __unicode__(self): + "Return a printable representation." + return 'Limit previous command' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class LimitsProcessor(MathsProcessor): + "A processor for limits inside an element." + + def process(self, contents, index): + "Process the limits for an element." + if Options.simplemath: + return + if self.checklimits(contents, index): + self.modifylimits(contents, index) + if self.checkscript(contents, index) and self.checkscript(contents, index + 1): + self.modifyscripts(contents, index) + + def checklimits(self, contents, index): + "Check if the current position has a limits command." + if not DocumentParameters.displaymode: + return False + if self.checkcommand(contents, index + 1, LimitPreviousCommand): + self.limitsahead(contents, index) + return False + if not isinstance(contents[index], LimitCommand): + return False + return self.checkscript(contents, index + 1) + + def limitsahead(self, contents, index): + "Limit the current element based on the next." + contents[index + 1].add(contents[index].clone()) + contents[index].output = EmptyOutput() + + def modifylimits(self, contents, index): + "Modify a limits commands so that the limits appear above and below." + limited = contents[index] + subscript = self.getlimit(contents, index + 1) + limited.contents.append(subscript) + if self.checkscript(contents, index + 1): + superscript = self.getlimit(contents, index + 1) + else: + superscript = TaggedBit().constant(u' ', 'sup class="limit"') + limited.contents.insert(0, superscript) + + def getlimit(self, contents, index): + "Get the limit for a limits command." + limit = self.getscript(contents, index) + limit.output.tag = limit.output.tag.replace('script', 'limit') + return limit + + def modifyscripts(self, contents, index): + "Modify the super- and subscript to appear vertically aligned." + subscript = self.getscript(contents, index) + # subscript removed so instead of index + 1 we get index again + superscript = self.getscript(contents, index) + scripts = TaggedBit().complete([superscript, subscript], 'span class="scripts"') + contents.insert(index, scripts) + + def checkscript(self, contents, index): + "Check if the current element is a sub- or superscript." + return self.checkcommand(contents, index, SymbolFunction) + + def checkcommand(self, contents, index, type): + "Check for the given type as the current element." + if len(contents) <= index: + return False + return isinstance(contents[index], type) + + def getscript(self, contents, index): + "Get the sub- or superscript." + bit = contents[index] + bit.output.tag += ' class="script"' + del contents[index] + return bit + +class BracketCommand(OneParamFunction): + "A command which defines a bracket." + + commandmap = FormulaConfig.bracketcommands + + def parsebit(self, pos): + "Parse the bracket." + OneParamFunction.parsebit(self, pos) + + def create(self, direction, character): + "Create the bracket for the given character." + self.original = character + self.command = '\\' + direction + self.contents = [FormulaConstant(character)] + return self + +class BracketProcessor(MathsProcessor): + "A processor for bracket commands." + + def process(self, contents, index): + "Convert the bracket using Unicode pieces, if possible." + if Options.simplemath: + return + if self.checkleft(contents, index): + return self.processleft(contents, index) + + def processleft(self, contents, index): + "Process a left bracket." + rightindex = self.findright(contents, index + 1) + if not rightindex: + return + size = self.findmax(contents, index, rightindex) + self.resize(contents[index], size) + self.resize(contents[rightindex], size) + + def checkleft(self, contents, index): + "Check if the command at the given index is left." + return self.checkdirection(contents[index], '\\left') + + def checkright(self, contents, index): + "Check if the command at the given index is right." + return self.checkdirection(contents[index], '\\right') + + def checkdirection(self, bit, command): + "Check if the given bit is the desired bracket command." + if not isinstance(bit, BracketCommand): + return False + return bit.command == command + + def findright(self, contents, index): + "Find the right bracket starting at the given index, or 0." + depth = 1 + while index < len(contents): + if self.checkleft(contents, index): + depth += 1 + if self.checkright(contents, index): + depth -= 1 + if depth == 0: + return index + index += 1 + return None + + def findmax(self, contents, leftindex, rightindex): + "Find the max size of the contents between the two given indices." + sliced = contents[leftindex:rightindex] + return max([element.size for element in sliced]) + + def resize(self, command, size): + "Resize a bracket command to the given size." + character = command.extracttext() + alignment = command.command.replace('\\', '') + bracket = BigBracket(size, character, alignment) + command.output = ContentsOutput() + command.contents = bracket.getcontents() + +class TodayCommand(EmptyCommand): + "Shows today's date." + + commandmap = None + + def parsebit(self, pos): + "Parse a command without parameters" + self.output = FixedOutput() + self.html = [datetime.date.today().strftime('%b %d, %Y')] + + +FormulaCommand.types += [ + DecoratingFunction, CombiningFunction, LimitCommand, BracketCommand, + ] + +FormulaProcessor.processors += [ + LimitsProcessor(), BracketProcessor(), + ] + + + +class ParameterDefinition(object): + "The definition of a parameter in a hybrid function." + "[] parameters are optional, {} parameters are mandatory." + "Each parameter has a one-character name, like {$1} or {$p}." + "A parameter that ends in ! like {$p!} is a literal." + "Example: [$1]{$p!} reads an optional parameter $1 and a literal mandatory parameter p." + + parambrackets = [('[', ']'), ('{', '}')] + + def __init__(self): + self.name = None + self.literal = False + self.optional = False + self.value = None + self.literalvalue = None + + def parse(self, pos): + "Parse a parameter definition: [$0], {$x}, {$1!}..." + for (opening, closing) in ParameterDefinition.parambrackets: + if pos.checkskip(opening): + if opening == '[': + self.optional = True + if not pos.checkskip('$'): + Trace.error('Wrong parameter name, did you mean $' + pos.current() + '?') + return None + self.name = pos.skipcurrent() + if pos.checkskip('!'): + self.literal = True + if not pos.checkskip(closing): + Trace.error('Wrong parameter closing ' + pos.skipcurrent()) + return None + return self + Trace.error('Wrong character in parameter template: ' + pos.skipcurrent()) + return None + + def read(self, pos, function): + "Read the parameter itself using the definition." + if self.literal: + if self.optional: + self.literalvalue = function.parsesquareliteral(pos) + else: + self.literalvalue = function.parseliteral(pos) + if self.literalvalue: + self.value = FormulaConstant(self.literalvalue) + elif self.optional: + self.value = function.parsesquare(pos) + else: + self.value = function.parseparameter(pos) + + def __unicode__(self): + "Return a printable representation." + result = 'param ' + self.name + if self.value: + result += ': ' + unicode(self.value) + else: + result += ' (empty)' + return result + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +class ParameterFunction(CommandBit): + "A function with a variable number of parameters defined in a template." + "The parameters are defined as a parameter definition." + + def readparams(self, readtemplate, pos): + "Read the params according to the template." + self.params = dict() + for paramdef in self.paramdefs(readtemplate): + paramdef.read(pos, self) + self.params['$' + paramdef.name] = paramdef + + def paramdefs(self, readtemplate): + "Read each param definition in the template" + pos = TextPosition(readtemplate) + while not pos.finished(): + paramdef = ParameterDefinition().parse(pos) + if paramdef: + yield paramdef + + def getparam(self, name): + "Get a parameter as parsed." + if not name in self.params: + return None + return self.params[name] + + def getvalue(self, name): + "Get the value of a parameter." + return self.getparam(name).value + + def getliteralvalue(self, name): + "Get the literal value of a parameter." + param = self.getparam(name) + if not param or not param.literalvalue: + return None + return param.literalvalue + +class HybridFunction(ParameterFunction): + """ + A parameter function where the output is also defined using a template. + The template can use a number of functions; each function has an associated + tag. + Example: [f0{$1},span class="fbox"] defines a function f0 which corresponds + to a span of class fbox, yielding <span class="fbox">$1</span>. + Literal parameters can be used in tags definitions: + [f0{$1},span style="color: $p;"] + yields <span style="color: $p;">$1</span>, where $p is a literal parameter. + Sizes can be specified in hybridsizes, e.g. adding parameter sizes. By + default the resulting size is the max of all arguments. Sizes are used + to generate the right parameters. + A function followed by a single / is output as a self-closing XHTML tag: + [f0/,hr] + will generate <hr/>. + """ + + commandmap = FormulaConfig.hybridfunctions + + def parsebit(self, pos): + "Parse a function with [] and {} parameters" + readtemplate = self.translated[0] + writetemplate = self.translated[1] + self.readparams(readtemplate, pos) + self.contents = self.writeparams(writetemplate) + self.computehybridsize() + + def writeparams(self, writetemplate): + "Write all params according to the template" + return self.writepos(TextPosition(writetemplate)) + + def writepos(self, pos): + "Write all params as read in the parse position." + result = [] + while not pos.finished(): + if pos.checkskip('$'): + param = self.writeparam(pos) + if param: + result.append(param) + elif pos.checkskip('f'): + function = self.writefunction(pos) + if function: + function.type = None + result.append(function) + elif pos.checkskip('('): + result.append(self.writebracket('left', '(')) + elif pos.checkskip(')'): + result.append(self.writebracket('right', ')')) + else: + result.append(FormulaConstant(pos.skipcurrent())) + return result + + def writeparam(self, pos): + "Write a single param of the form $0, $x..." + name = '$' + pos.skipcurrent() + if not name in self.params: + Trace.error('Unknown parameter ' + name) + return None + if not self.params[name]: + return None + if pos.checkskip('.'): + self.params[name].value.type = pos.globalpha() + return self.params[name].value + + def writefunction(self, pos): + "Write a single function f0,...,fn." + tag = self.readtag(pos) + if not tag: + return None + if pos.checkskip('/'): + # self-closing XHTML tag, such as <hr/> + return TaggedBit().selfcomplete(tag) + if not pos.checkskip('{'): + Trace.error('Function should be defined in {}') + return None + pos.pushending('}') + contents = self.writepos(pos) + pos.popending() + if len(contents) == 0: + return None + return TaggedBit().complete(contents, tag) + + def readtag(self, pos): + "Get the tag corresponding to the given index. Does parameter substitution." + if not pos.current().isdigit(): + Trace.error('Function should be f0,...,f9: f' + pos.current()) + return None + index = int(pos.skipcurrent()) + if 2 + index > len(self.translated): + Trace.error('Function f' + unicode(index) + ' is not defined') + return None + tag = self.translated[2 + index] + if not '$' in tag: + return tag + for variable in self.params: + if variable in tag: + param = self.params[variable] + if not param.literal: + Trace.error('Parameters in tag ' + tag + ' should be literal: {' + variable + '!}') + continue + if param.literalvalue: + value = param.literalvalue + else: + value = '' + tag = tag.replace(variable, value) + return tag + + def writebracket(self, direction, character): + "Return a new bracket looking at the given direction." + return self.factory.create(BracketCommand).create(direction, character) + + def computehybridsize(self): + "Compute the size of the hybrid function." + if not self.command in HybridSize.configsizes: + self.computesize() + return + self.size = HybridSize().getsize(self) + # set the size in all elements at first level + for element in self.contents: + element.size = self.size + +class HybridSize(object): + "The size associated with a hybrid function." + + configsizes = FormulaConfig.hybridsizes + + def getsize(self, function): + "Read the size for a function and parse it." + sizestring = self.configsizes[function.command] + for name in function.params: + if name in sizestring: + size = function.params[name].value.computesize() + sizestring = sizestring.replace(name, unicode(size)) + if '$' in sizestring: + Trace.error('Unconverted variable in hybrid size: ' + sizestring) + return 1 + return eval(sizestring) + + +FormulaCommand.types += [HybridFunction] + + + + + + + + + +class HeaderParser(Parser): + "Parses the LyX header" + + def parse(self, reader): + "Parse header parameters into a dictionary, return the preamble." + contents = [] + self.parseending(reader, lambda: self.parseline(reader, contents)) + # skip last line + reader.nextline() + return contents + + def parseline(self, reader, contents): + "Parse a single line as a parameter or as a start" + line = reader.currentline() + if line.startswith(HeaderConfig.parameters['branch']): + self.parsebranch(reader) + return + elif line.startswith(HeaderConfig.parameters['lstset']): + LstParser().parselstset(reader) + return + elif line.startswith(HeaderConfig.parameters['beginpreamble']): + contents.append(self.factory.createcontainer(reader)) + return + # no match + self.parseparameter(reader) + + def parsebranch(self, reader): + "Parse all branch definitions." + branch = reader.currentline().split()[1] + reader.nextline() + subparser = HeaderParser().complete(HeaderConfig.parameters['endbranch']) + subparser.parse(reader) + options = BranchOptions(branch) + for key in subparser.parameters: + options.set(key, subparser.parameters[key]) + Options.branches[branch] = options + + def complete(self, ending): + "Complete the parser with the given ending." + self.ending = ending + return self + +class PreambleParser(Parser): + "A parser for the LyX preamble." + + preamble = [] + + def parse(self, reader): + "Parse the full preamble with all statements." + self.ending = HeaderConfig.parameters['endpreamble'] + self.parseending(reader, lambda: self.parsepreambleline(reader)) + return [] + + def parsepreambleline(self, reader): + "Parse a single preamble line." + PreambleParser.preamble.append(reader.currentline()) + reader.nextline() + +class LstParser(object): + "Parse global and local lstparams." + + globalparams = dict() + + def parselstset(self, reader): + "Parse a declaration of lstparams in lstset." + paramtext = self.extractlstset(reader) + if not '{' in paramtext: + Trace.error('Missing opening bracket in lstset: ' + paramtext) + return + lefttext = paramtext.split('{')[1] + croppedtext = lefttext[:-1] + LstParser.globalparams = self.parselstparams(croppedtext) + + def extractlstset(self, reader): + "Extract the global lstset parameters." + paramtext = '' + while not reader.finished(): + paramtext += reader.currentline() + reader.nextline() + if paramtext.endswith('}'): + return paramtext + Trace.error('Could not find end of \\lstset settings; aborting') + + def parsecontainer(self, container): + "Parse some lstparams from elyxer.a container." + container.lstparams = LstParser.globalparams.copy() + paramlist = container.getparameterlist('lstparams') + container.lstparams.update(self.parselstparams(paramlist)) + + def parselstparams(self, paramlist): + "Process a number of lstparams from elyxer.a list." + paramdict = dict() + for param in paramlist: + if not '=' in param: + if len(param.strip()) > 0: + Trace.error('Invalid listing parameter ' + param) + else: + key, value = param.split('=', 1) + paramdict[key] = value + return paramdict + + + + +class MacroDefinition(CommandBit): + "A function that defines a new command (a macro)." + + macros = dict() + + def parsebit(self, pos): + "Parse the function that defines the macro." + self.output = EmptyOutput() + self.parameternumber = 0 + self.defaults = [] + self.factory.defining = True + self.parseparameters(pos) + self.factory.defining = False + Trace.debug('New command ' + self.newcommand + ' (' + \ + unicode(self.parameternumber) + ' parameters)') + self.macros[self.newcommand] = self + + def parseparameters(self, pos): + "Parse all optional parameters (number of parameters, default values)" + "and the mandatory definition." + self.newcommand = self.parsenewcommand(pos) + # parse number of parameters + literal = self.parsesquareliteral(pos) + if literal: + self.parameternumber = int(literal) + # parse all default values + bracket = self.parsesquare(pos) + while bracket: + self.defaults.append(bracket) + bracket = self.parsesquare(pos) + # parse mandatory definition + self.definition = self.parseparameter(pos) + + def parsenewcommand(self, pos): + "Parse the name of the new command." + self.factory.clearskipped(pos) + if self.factory.detecttype(Bracket, pos): + return self.parseliteral(pos) + if self.factory.detecttype(FormulaCommand, pos): + return self.factory.create(FormulaCommand).extractcommand(pos) + Trace.error('Unknown formula bit in defining function at ' + pos.identifier()) + return 'unknown' + + def instantiate(self): + "Return an instance of the macro." + return self.definition.clone() + +class MacroParameter(FormulaBit): + "A parameter from elyxer.a macro." + + def detect(self, pos): + "Find a macro parameter: #n." + return pos.checkfor('#') + + def parsebit(self, pos): + "Parse the parameter: #n." + if not pos.checkskip('#'): + Trace.error('Missing parameter start #.') + return + self.number = int(pos.skipcurrent()) + self.original = '#' + unicode(self.number) + self.contents = [TaggedBit().constant('#' + unicode(self.number), 'span class="unknown"')] + +class MacroFunction(CommandBit): + "A function that was defined using a macro." + + commandmap = MacroDefinition.macros + + def parsebit(self, pos): + "Parse a number of input parameters." + self.output = FilteredOutput() + self.values = [] + macro = self.translated + self.parseparameters(pos, macro) + self.completemacro(macro) + + def parseparameters(self, pos, macro): + "Parse as many parameters as are needed." + self.parseoptional(pos, list(macro.defaults)) + self.parsemandatory(pos, macro.parameternumber - len(macro.defaults)) + if len(self.values) < macro.parameternumber: + Trace.error('Missing parameters in macro ' + unicode(self)) + + def parseoptional(self, pos, defaults): + "Parse optional parameters." + optional = [] + while self.factory.detecttype(SquareBracket, pos): + optional.append(self.parsesquare(pos)) + if len(optional) > len(defaults): + break + for value in optional: + default = defaults.pop() + if len(value.contents) > 0: + self.values.append(value) + else: + self.values.append(default) + self.values += defaults + + def parsemandatory(self, pos, number): + "Parse a number of mandatory parameters." + for index in range(number): + parameter = self.parsemacroparameter(pos, number - index) + if not parameter: + return + self.values.append(parameter) + + def parsemacroparameter(self, pos, remaining): + "Parse a macro parameter. Could be a bracket or a single letter." + "If there are just two values remaining and there is a running number," + "parse as two separater numbers." + self.factory.clearskipped(pos) + if pos.finished(): + return None + if self.factory.detecttype(FormulaNumber, pos): + return self.parsenumbers(pos, remaining) + return self.parseparameter(pos) + + def parsenumbers(self, pos, remaining): + "Parse the remaining parameters as a running number." + "For example, 12 would be {1}{2}." + number = self.factory.parsetype(FormulaNumber, pos) + if not len(number.original) == remaining: + return number + for digit in number.original: + value = self.factory.create(FormulaNumber) + value.add(FormulaConstant(digit)) + value.type = number + self.values.append(value) + return None + + def completemacro(self, macro): + "Complete the macro with the parameters read." + self.contents = [macro.instantiate()] + replaced = [False] * len(self.values) + for parameter in self.searchall(MacroParameter): + index = parameter.number - 1 + if index >= len(self.values): + Trace.error('Macro parameter index out of bounds: ' + unicode(index)) + return + replaced[index] = True + parameter.contents = [self.values[index].clone()] + for index in range(len(self.values)): + if not replaced[index]: + self.addfilter(index, self.values[index]) + + def addfilter(self, index, value): + "Add a filter for the given parameter number and parameter value." + original = '#' + unicode(index + 1) + value = ''.join(self.values[0].gethtml()) + self.output.addfilter(original, value) + +class FormulaMacro(Formula): + "A math macro defined in an inset." + + def __init__(self): + self.parser = MacroParser() + self.output = EmptyOutput() + + def __unicode__(self): + "Return a printable representation." + return 'Math macro' + + if sys.version_info >= (3, 0): + __str__ = __unicode__ + + +FormulaFactory.types += [ MacroParameter ] + +FormulaCommand.types += [ + MacroFunction, + ] + + + +def math2html(formula): + "Convert some TeX math to HTML." + factory = FormulaFactory() + whole = factory.parseformula(formula) + FormulaProcessor().process(whole) + whole.process() + return ''.join(whole.gethtml()) + +def main(): + "Main function, called if invoked from elyxer.the command line" + args = sys.argv + Options().parseoptions(args) + if len(args) != 1: + Trace.error('Usage: math2html.py escaped_string') + exit() + result = math2html(args[0]) + Trace.message(result) + +if __name__ == '__main__': + main() + diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/tex2mathml_extern.py b/env/lib/python3.8/site-packages/docutils/utils/math/tex2mathml_extern.py new file mode 100644 index 000000000..854589017 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/tex2mathml_extern.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# :Id: $Id: tex2mathml_extern.py 8376 2019-08-27 19:49:29Z milde $ +# :Copyright: © 2015 Günter Milde. +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + +# Wrappers for TeX->MathML conversion by external tools +# ===================================================== + +from __future__ import print_function +import subprocess + +document_template = r"""\documentclass{article} +\usepackage{amsmath} +\begin{document} +%s +\end{document} +""" + +def latexml(math_code, reporter=None): + """Convert LaTeX math code to MathML with LaTeXML_ + + .. _LaTeXML: http://dlmf.nist.gov/LaTeXML/ + """ + p = subprocess.Popen(['latexml', + '-', # read from stdin + # '--preload=amsmath', + '--inputencoding=utf8', + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + p.stdin.write((document_template % math_code).encode('utf8')) + p.stdin.close() + latexml_code = p.stdout.read() + latexml_err = p.stderr.read().decode('utf8') + if reporter and (latexml_err.find('Error') >= 0 or not latexml_code): + reporter.error(latexml_err) + + post_p = subprocess.Popen(['latexmlpost', + '-', + '--nonumbersections', + '--format=xhtml', + # '--linelength=78', # experimental + '--' + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + post_p.stdin.write(latexml_code) + post_p.stdin.close() + result = post_p.stdout.read().decode('utf8') + post_p_err = post_p.stderr.read().decode('utf8') + if reporter and (post_p_err.find('Error') >= 0 or not result): + reporter.error(post_p_err) + + # extract MathML code: + start, end = result.find('<math'), result.find('</math>')+7 + result = result[start:end] + if 'class="ltx_ERROR' in result: + raise SyntaxError(result) + return result + +def ttm(math_code, reporter=None): + """Convert LaTeX math code to MathML with TtM_ + + .. _TtM: http://hutchinson.belmont.ma.us/tth/mml/ + """ + p = subprocess.Popen(['ttm', + # '-i', # italic font for equations. Default roman. + '-u', # unicode character encoding. (Default iso-8859-1). + '-r', # output raw MathML (no preamble or postlude) + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + p.stdin.write((document_template % math_code).encode('utf8')) + p.stdin.close() + result = p.stdout.read() + err = p.stderr.read().decode('utf8') + if err.find('**** Unknown') >= 0: + msg = '\n'.join([line for line in err.splitlines() + if line.startswith('****')]) + raise SyntaxError('\nMessage from external converter TtM:\n'+ msg) + if reporter and err.find('**** Error') >= 0 or not result: + reporter.error(err) + start, end = result.find('<math'), result.find('</math>')+7 + result = result[start:end] + return result + +def blahtexml(math_code, inline=True, reporter=None): + """Convert LaTeX math code to MathML with blahtexml_ + + .. _blahtexml: http://gva.noekeon.org/blahtexml/ + """ + options = ['--mathml', + '--indented', + '--spacing', 'moderate', + '--mathml-encoding', 'raw', + '--other-encoding', 'raw', + '--doctype-xhtml+mathml', + '--annotate-TeX', + ] + if inline: + mathmode_arg = '' + else: + mathmode_arg = 'mode="display"' + options.append('--displaymath') + + p = subprocess.Popen(['blahtexml']+options, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + close_fds=True) + p.stdin.write(math_code.encode('utf8')) + p.stdin.close() + result = p.stdout.read().decode('utf8') + err = p.stderr.read().decode('utf8') + + if result.find('<error>') >= 0: + raise SyntaxError('\nMessage from external converter blahtexml:\n' + +result[result.find('<message>')+9:result.find('</message>')]) + if reporter and (err.find('**** Error') >= 0 or not result): + reporter.error(err) + start, end = result.find('<markup>')+9, result.find('</markup>') + result = ('<math xmlns="http://www.w3.org/1998/Math/MathML"%s>\n' + '%s</math>\n') % (mathmode_arg, result[start:end]) + return result + +# self-test + +if __name__ == "__main__": + example = (u'\\frac{\\partial \\sin^2(\\alpha)}{\\partial \\vec r}' + u'\\varpi \\, \\text{Grüße}') + # print(latexml(example).encode('utf8')) + # print(ttm(example)) + print(blahtexml(example).encode('utf8')) diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/tex2unichar.py b/env/lib/python3.8/site-packages/docutils/utils/math/tex2unichar.py new file mode 100644 index 000000000..434c0e8c3 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/tex2unichar.py @@ -0,0 +1,662 @@ +# -*- coding: utf-8 -*- + +# LaTeX math to Unicode symbols translation dictionaries. +# Generated with ``write_tex2unichar.py`` from the data in +# http://milde.users.sourceforge.net/LUCR/Math/ + +# Includes commands from: wasysym, stmaryrd, mathdots, mathabx, esint, bbold, amsxtra, amsmath, amssymb, standard LaTeX + +mathaccent = { + 'acute': u'\u0301', # x́ COMBINING ACUTE ACCENT + 'bar': u'\u0304', # x̄ COMBINING MACRON + 'breve': u'\u0306', # x̆ COMBINING BREVE + 'check': u'\u030c', # x̌ COMBINING CARON + 'ddddot': u'\u20dc', # x⃜ COMBINING FOUR DOTS ABOVE + 'dddot': u'\u20db', # x⃛ COMBINING THREE DOTS ABOVE + 'ddot': u'\u0308', # ẍ COMBINING DIAERESIS + 'dot': u'\u0307', # ẋ COMBINING DOT ABOVE + 'grave': u'\u0300', # x̀ COMBINING GRAVE ACCENT + 'hat': u'\u0302', # x̂ COMBINING CIRCUMFLEX ACCENT + 'mathring': u'\u030a', # x̊ COMBINING RING ABOVE + 'not': u'\u0338', # x̸ COMBINING LONG SOLIDUS OVERLAY + 'overleftarrow': u'\u20d6', # x⃖ COMBINING LEFT ARROW ABOVE + 'overleftrightarrow': u'\u20e1', # x⃡ COMBINING LEFT RIGHT ARROW ABOVE + 'overline': u'\u0305', # x̅ COMBINING OVERLINE + 'overrightarrow': u'\u20d7', # x⃗ COMBINING RIGHT ARROW ABOVE + 'tilde': u'\u0303', # x̃ COMBINING TILDE + 'underbar': u'\u0331', # x̱ COMBINING MACRON BELOW + 'underleftarrow': u'\u20ee', # x⃮ COMBINING LEFT ARROW BELOW + 'underline': u'\u0332', # x̲ COMBINING LOW LINE + 'underrightarrow': u'\u20ef', # x⃯ COMBINING RIGHT ARROW BELOW + 'vec': u'\u20d7', # x⃗ COMBINING RIGHT ARROW ABOVE + 'widehat': u'\u0302', # x̂ COMBINING CIRCUMFLEX ACCENT + 'widetilde': u'\u0303', # x̃ COMBINING TILDE + } +mathalpha = { + 'Bbbk': u'\U0001d55c', # 𝕜 MATHEMATICAL DOUBLE-STRUCK SMALL K + 'Delta': u'\u0394', # Δ GREEK CAPITAL LETTER DELTA + 'Gamma': u'\u0393', # Γ GREEK CAPITAL LETTER GAMMA + 'Im': u'\u2111', # ℑ BLACK-LETTER CAPITAL I + 'Lambda': u'\u039b', # Λ GREEK CAPITAL LETTER LAMDA + 'Omega': u'\u03a9', # Ω GREEK CAPITAL LETTER OMEGA + 'Phi': u'\u03a6', # Φ GREEK CAPITAL LETTER PHI + 'Pi': u'\u03a0', # Π GREEK CAPITAL LETTER PI + 'Psi': u'\u03a8', # Ψ GREEK CAPITAL LETTER PSI + 'Re': u'\u211c', # ℜ BLACK-LETTER CAPITAL R + 'Sigma': u'\u03a3', # Σ GREEK CAPITAL LETTER SIGMA + 'Theta': u'\u0398', # Θ GREEK CAPITAL LETTER THETA + 'Upsilon': u'\u03a5', # Υ GREEK CAPITAL LETTER UPSILON + 'Xi': u'\u039e', # Ξ GREEK CAPITAL LETTER XI + 'aleph': u'\u2135', # ℵ ALEF SYMBOL + 'alpha': u'\u03b1', # α GREEK SMALL LETTER ALPHA + 'beta': u'\u03b2', # β GREEK SMALL LETTER BETA + 'beth': u'\u2136', # ℶ BET SYMBOL + 'chi': u'\u03c7', # χ GREEK SMALL LETTER CHI + 'daleth': u'\u2138', # ℸ DALET SYMBOL + 'delta': u'\u03b4', # δ GREEK SMALL LETTER DELTA + 'digamma': u'\u03dc', # Ϝ GREEK LETTER DIGAMMA + 'ell': u'\u2113', # ℓ SCRIPT SMALL L + 'epsilon': u'\u03f5', # ϵ GREEK LUNATE EPSILON SYMBOL + 'eta': u'\u03b7', # η GREEK SMALL LETTER ETA + 'eth': u'\xf0', # ð LATIN SMALL LETTER ETH + 'gamma': u'\u03b3', # γ GREEK SMALL LETTER GAMMA + 'gimel': u'\u2137', # ℷ GIMEL SYMBOL + 'hbar': u'\u210f', # ℏ PLANCK CONSTANT OVER TWO PI + 'hslash': u'\u210f', # ℏ PLANCK CONSTANT OVER TWO PI + 'imath': u'\u0131', # ı LATIN SMALL LETTER DOTLESS I + 'iota': u'\u03b9', # ι GREEK SMALL LETTER IOTA + 'jmath': u'\u0237', # ȷ LATIN SMALL LETTER DOTLESS J + 'kappa': u'\u03ba', # κ GREEK SMALL LETTER KAPPA + 'lambda': u'\u03bb', # λ GREEK SMALL LETTER LAMDA + 'mu': u'\u03bc', # μ GREEK SMALL LETTER MU + 'nu': u'\u03bd', # ν GREEK SMALL LETTER NU + 'omega': u'\u03c9', # ω GREEK SMALL LETTER OMEGA + 'phi': u'\u03d5', # ϕ GREEK PHI SYMBOL + 'pi': u'\u03c0', # π GREEK SMALL LETTER PI + 'psi': u'\u03c8', # ψ GREEK SMALL LETTER PSI + 'rho': u'\u03c1', # ρ GREEK SMALL LETTER RHO + 'sigma': u'\u03c3', # σ GREEK SMALL LETTER SIGMA + 'tau': u'\u03c4', # τ GREEK SMALL LETTER TAU + 'theta': u'\u03b8', # θ GREEK SMALL LETTER THETA + 'upsilon': u'\u03c5', # υ GREEK SMALL LETTER UPSILON + 'varDelta': u'\U0001d6e5', # 𝛥 MATHEMATICAL ITALIC CAPITAL DELTA + 'varGamma': u'\U0001d6e4', # 𝛤 MATHEMATICAL ITALIC CAPITAL GAMMA + 'varLambda': u'\U0001d6ec', # 𝛬 MATHEMATICAL ITALIC CAPITAL LAMDA + 'varOmega': u'\U0001d6fa', # 𝛺 MATHEMATICAL ITALIC CAPITAL OMEGA + 'varPhi': u'\U0001d6f7', # 𝛷 MATHEMATICAL ITALIC CAPITAL PHI + 'varPi': u'\U0001d6f1', # 𝛱 MATHEMATICAL ITALIC CAPITAL PI + 'varPsi': u'\U0001d6f9', # 𝛹 MATHEMATICAL ITALIC CAPITAL PSI + 'varSigma': u'\U0001d6f4', # 𝛴 MATHEMATICAL ITALIC CAPITAL SIGMA + 'varTheta': u'\U0001d6e9', # 𝛩 MATHEMATICAL ITALIC CAPITAL THETA + 'varUpsilon': u'\U0001d6f6', # 𝛶 MATHEMATICAL ITALIC CAPITAL UPSILON + 'varXi': u'\U0001d6ef', # 𝛯 MATHEMATICAL ITALIC CAPITAL XI + 'varepsilon': u'\u03b5', # ε GREEK SMALL LETTER EPSILON + 'varkappa': u'\U0001d718', # 𝜘 MATHEMATICAL ITALIC KAPPA SYMBOL + 'varphi': u'\u03c6', # φ GREEK SMALL LETTER PHI + 'varpi': u'\u03d6', # ϖ GREEK PI SYMBOL + 'varrho': u'\u03f1', # ϱ GREEK RHO SYMBOL + 'varsigma': u'\u03c2', # ς GREEK SMALL LETTER FINAL SIGMA + 'vartheta': u'\u03d1', # ϑ GREEK THETA SYMBOL + 'wp': u'\u2118', # ℘ SCRIPT CAPITAL P + 'xi': u'\u03be', # ξ GREEK SMALL LETTER XI + 'zeta': u'\u03b6', # ζ GREEK SMALL LETTER ZETA + } +mathbin = { + 'Cap': u'\u22d2', # ⋒ DOUBLE INTERSECTION + 'Circle': u'\u25cb', # ○ WHITE CIRCLE + 'Cup': u'\u22d3', # ⋓ DOUBLE UNION + 'LHD': u'\u25c0', # ◀ BLACK LEFT-POINTING TRIANGLE + 'RHD': u'\u25b6', # ▶ BLACK RIGHT-POINTING TRIANGLE + 'amalg': u'\u2a3f', # ⨿ AMALGAMATION OR COPRODUCT + 'ast': u'\u2217', # ∗ ASTERISK OPERATOR + 'barwedge': u'\u22bc', # ⊼ NAND + 'bigtriangledown': u'\u25bd', # ▽ WHITE DOWN-POINTING TRIANGLE + 'bigtriangleup': u'\u25b3', # △ WHITE UP-POINTING TRIANGLE + 'bindnasrepma': u'\u214b', # ⅋ TURNED AMPERSAND + 'blacklozenge': u'\u29eb', # ⧫ BLACK LOZENGE + 'blacktriangledown': u'\u25be', # ▾ BLACK DOWN-POINTING SMALL TRIANGLE + 'blacktriangleleft': u'\u25c2', # ◂ BLACK LEFT-POINTING SMALL TRIANGLE + 'blacktriangleright': u'\u25b8', # ▸ BLACK RIGHT-POINTING SMALL TRIANGLE + 'blacktriangleup': u'\u25b4', # ▴ BLACK UP-POINTING SMALL TRIANGLE + 'boxast': u'\u29c6', # ⧆ SQUARED ASTERISK + 'boxbar': u'\u25eb', # ◫ WHITE SQUARE WITH VERTICAL BISECTING LINE + 'boxbox': u'\u29c8', # ⧈ SQUARED SQUARE + 'boxbslash': u'\u29c5', # ⧅ SQUARED FALLING DIAGONAL SLASH + 'boxcircle': u'\u29c7', # ⧇ SQUARED SMALL CIRCLE + 'boxdot': u'\u22a1', # ⊡ SQUARED DOT OPERATOR + 'boxminus': u'\u229f', # ⊟ SQUARED MINUS + 'boxplus': u'\u229e', # ⊞ SQUARED PLUS + 'boxslash': u'\u29c4', # ⧄ SQUARED RISING DIAGONAL SLASH + 'boxtimes': u'\u22a0', # ⊠ SQUARED TIMES + 'bullet': u'\u2219', # ∙ BULLET OPERATOR + 'cap': u'\u2229', # ∩ INTERSECTION + 'cdot': u'\u22c5', # ⋅ DOT OPERATOR + 'circ': u'\u2218', # ∘ RING OPERATOR + 'circledast': u'\u229b', # ⊛ CIRCLED ASTERISK OPERATOR + 'circledcirc': u'\u229a', # ⊚ CIRCLED RING OPERATOR + 'circleddash': u'\u229d', # ⊝ CIRCLED DASH + 'cup': u'\u222a', # ∪ UNION + 'curlyvee': u'\u22ce', # ⋎ CURLY LOGICAL OR + 'curlywedge': u'\u22cf', # ⋏ CURLY LOGICAL AND + 'dagger': u'\u2020', # † DAGGER + 'ddagger': u'\u2021', # ‡ DOUBLE DAGGER + 'diamond': u'\u22c4', # ⋄ DIAMOND OPERATOR + 'div': u'\xf7', # ÷ DIVISION SIGN + 'divideontimes': u'\u22c7', # ⋇ DIVISION TIMES + 'dotplus': u'\u2214', # ∔ DOT PLUS + 'doublebarwedge': u'\u2a5e', # ⩞ LOGICAL AND WITH DOUBLE OVERBAR + 'intercal': u'\u22ba', # ⊺ INTERCALATE + 'interleave': u'\u2af4', # ⫴ TRIPLE VERTICAL BAR BINARY RELATION + 'land': u'\u2227', # ∧ LOGICAL AND + 'leftthreetimes': u'\u22cb', # ⋋ LEFT SEMIDIRECT PRODUCT + 'lhd': u'\u25c1', # ◁ WHITE LEFT-POINTING TRIANGLE + 'lor': u'\u2228', # ∨ LOGICAL OR + 'ltimes': u'\u22c9', # ⋉ LEFT NORMAL FACTOR SEMIDIRECT PRODUCT + 'mp': u'\u2213', # ∓ MINUS-OR-PLUS SIGN + 'odot': u'\u2299', # ⊙ CIRCLED DOT OPERATOR + 'ominus': u'\u2296', # ⊖ CIRCLED MINUS + 'oplus': u'\u2295', # ⊕ CIRCLED PLUS + 'oslash': u'\u2298', # ⊘ CIRCLED DIVISION SLASH + 'otimes': u'\u2297', # ⊗ CIRCLED TIMES + 'pm': u'\xb1', # ± PLUS-MINUS SIGN + 'rhd': u'\u25b7', # ▷ WHITE RIGHT-POINTING TRIANGLE + 'rightthreetimes': u'\u22cc', # ⋌ RIGHT SEMIDIRECT PRODUCT + 'rtimes': u'\u22ca', # ⋊ RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT + 'setminus': u'\u29f5', # ⧵ REVERSE SOLIDUS OPERATOR + 'slash': u'\u2215', # ∕ DIVISION SLASH + 'smallsetminus': u'\u2216', # ∖ SET MINUS + 'smalltriangledown': u'\u25bf', # ▿ WHITE DOWN-POINTING SMALL TRIANGLE + 'smalltriangleleft': u'\u25c3', # ◃ WHITE LEFT-POINTING SMALL TRIANGLE + 'smalltriangleright': u'\u25b9', # ▹ WHITE RIGHT-POINTING SMALL TRIANGLE + 'smalltriangleup': u'\u25b5', # ▵ WHITE UP-POINTING SMALL TRIANGLE + 'sqcap': u'\u2293', # ⊓ SQUARE CAP + 'sqcup': u'\u2294', # ⊔ SQUARE CUP + 'sslash': u'\u2afd', # ⫽ DOUBLE SOLIDUS OPERATOR + 'star': u'\u22c6', # ⋆ STAR OPERATOR + 'talloblong': u'\u2afe', # ⫾ WHITE VERTICAL BAR + 'times': u'\xd7', # × MULTIPLICATION SIGN + 'triangle': u'\u25b3', # △ WHITE UP-POINTING TRIANGLE + 'triangledown': u'\u25bf', # ▿ WHITE DOWN-POINTING SMALL TRIANGLE + 'triangleleft': u'\u25c3', # ◃ WHITE LEFT-POINTING SMALL TRIANGLE + 'triangleright': u'\u25b9', # ▹ WHITE RIGHT-POINTING SMALL TRIANGLE + 'uplus': u'\u228e', # ⊎ MULTISET UNION + 'vartriangle': u'\u25b3', # △ WHITE UP-POINTING TRIANGLE + 'vee': u'\u2228', # ∨ LOGICAL OR + 'veebar': u'\u22bb', # ⊻ XOR + 'wedge': u'\u2227', # ∧ LOGICAL AND + 'wr': u'\u2240', # ≀ WREATH PRODUCT + } +mathclose = { + 'Rbag': u'\u27c6', # ⟆ RIGHT S-SHAPED BAG DELIMITER + 'lrcorner': u'\u231f', # ⌟ BOTTOM RIGHT CORNER + 'rangle': u'\u27e9', # ⟩ MATHEMATICAL RIGHT ANGLE BRACKET + 'rbag': u'\u27c6', # ⟆ RIGHT S-SHAPED BAG DELIMITER + 'rbrace': u'}', # } RIGHT CURLY BRACKET + 'rbrack': u']', # ] RIGHT SQUARE BRACKET + 'rceil': u'\u2309', # ⌉ RIGHT CEILING + 'rfloor': u'\u230b', # ⌋ RIGHT FLOOR + 'rgroup': u'\u27ef', # ⟯ MATHEMATICAL RIGHT FLATTENED PARENTHESIS + 'rrbracket': u'\u27e7', # ⟧ MATHEMATICAL RIGHT WHITE SQUARE BRACKET + 'rrparenthesis': u'\u2988', # ⦈ Z NOTATION RIGHT IMAGE BRACKET + 'urcorner': u'\u231d', # ⌝ TOP RIGHT CORNER + '}': u'}', # } RIGHT CURLY BRACKET + } +mathfence = { + 'Vert': u'\u2016', # ‖ DOUBLE VERTICAL LINE + 'vert': u'|', # | VERTICAL LINE + '|': u'\u2016', # ‖ DOUBLE VERTICAL LINE + } +mathop = { + 'Join': u'\u2a1d', # ⨝ JOIN + 'bigcap': u'\u22c2', # ⋂ N-ARY INTERSECTION + 'bigcup': u'\u22c3', # ⋃ N-ARY UNION + 'biginterleave': u'\u2afc', # ⫼ LARGE TRIPLE VERTICAL BAR OPERATOR + 'bigodot': u'\u2a00', # ⨀ N-ARY CIRCLED DOT OPERATOR + 'bigoplus': u'\u2a01', # ⨁ N-ARY CIRCLED PLUS OPERATOR + 'bigotimes': u'\u2a02', # ⨂ N-ARY CIRCLED TIMES OPERATOR + 'bigsqcup': u'\u2a06', # ⨆ N-ARY SQUARE UNION OPERATOR + 'biguplus': u'\u2a04', # ⨄ N-ARY UNION OPERATOR WITH PLUS + 'bigvee': u'\u22c1', # ⋁ N-ARY LOGICAL OR + 'bigwedge': u'\u22c0', # ⋀ N-ARY LOGICAL AND + 'coprod': u'\u2210', # ∐ N-ARY COPRODUCT + 'fatsemi': u'\u2a1f', # ⨟ Z NOTATION SCHEMA COMPOSITION + 'fint': u'\u2a0f', # ⨏ INTEGRAL AVERAGE WITH SLASH + 'iiiint': u'\u2a0c', # ⨌ QUADRUPLE INTEGRAL OPERATOR + 'iiint': u'\u222d', # ∭ TRIPLE INTEGRAL + 'iint': u'\u222c', # ∬ DOUBLE INTEGRAL + 'int': u'\u222b', # ∫ INTEGRAL + 'oiint': u'\u222f', # ∯ SURFACE INTEGRAL + 'oint': u'\u222e', # ∮ CONTOUR INTEGRAL + 'ointctrclockwise': u'\u2233', # ∳ ANTICLOCKWISE CONTOUR INTEGRAL + 'prod': u'\u220f', # ∏ N-ARY PRODUCT + 'sqint': u'\u2a16', # ⨖ QUATERNION INTEGRAL OPERATOR + 'sum': u'\u2211', # ∑ N-ARY SUMMATION + 'varointclockwise': u'\u2232', # ∲ CLOCKWISE CONTOUR INTEGRAL + } +mathopen = { + 'Lbag': u'\u27c5', # ⟅ LEFT S-SHAPED BAG DELIMITER + 'langle': u'\u27e8', # ⟨ MATHEMATICAL LEFT ANGLE BRACKET + 'lbag': u'\u27c5', # ⟅ LEFT S-SHAPED BAG DELIMITER + 'lbrace': u'{', # { LEFT CURLY BRACKET + 'lbrack': u'[', # [ LEFT SQUARE BRACKET + 'lceil': u'\u2308', # ⌈ LEFT CEILING + 'lfloor': u'\u230a', # ⌊ LEFT FLOOR + 'lgroup': u'\u27ee', # ⟮ MATHEMATICAL LEFT FLATTENED PARENTHESIS + 'llbracket': u'\u27e6', # ⟦ MATHEMATICAL LEFT WHITE SQUARE BRACKET + 'llcorner': u'\u231e', # ⌞ BOTTOM LEFT CORNER + 'llparenthesis': u'\u2987', # ⦇ Z NOTATION LEFT IMAGE BRACKET + 'ulcorner': u'\u231c', # ⌜ TOP LEFT CORNER + '{': u'{', # { LEFT CURLY BRACKET + } +mathord = { + '#': u'#', # # NUMBER SIGN + '$': u'$', # $ DOLLAR SIGN + '%': u'%', # % PERCENT SIGN + '&': u'&', # & AMPERSAND + 'AC': u'\u223f', # ∿ SINE WAVE + 'APLcomment': u'\u235d', # ⍝ APL FUNCTIONAL SYMBOL UP SHOE JOT + 'APLdownarrowbox': u'\u2357', # ⍗ APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW + 'APLinput': u'\u235e', # ⍞ APL FUNCTIONAL SYMBOL QUOTE QUAD + 'APLinv': u'\u2339', # ⌹ APL FUNCTIONAL SYMBOL QUAD DIVIDE + 'APLleftarrowbox': u'\u2347', # ⍇ APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW + 'APLlog': u'\u235f', # ⍟ APL FUNCTIONAL SYMBOL CIRCLE STAR + 'APLrightarrowbox': u'\u2348', # ⍈ APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW + 'APLuparrowbox': u'\u2350', # ⍐ APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW + 'Aries': u'\u2648', # ♈ ARIES + 'CIRCLE': u'\u25cf', # ● BLACK CIRCLE + 'CheckedBox': u'\u2611', # ☑ BALLOT BOX WITH CHECK + 'Diamond': u'\u25c7', # ◇ WHITE DIAMOND + 'Finv': u'\u2132', # Ⅎ TURNED CAPITAL F + 'Game': u'\u2141', # ⅁ TURNED SANS-SERIF CAPITAL G + 'Gemini': u'\u264a', # ♊ GEMINI + 'Jupiter': u'\u2643', # ♃ JUPITER + 'LEFTCIRCLE': u'\u25d6', # ◖ LEFT HALF BLACK CIRCLE + 'LEFTcircle': u'\u25d0', # ◐ CIRCLE WITH LEFT HALF BLACK + 'Leo': u'\u264c', # ♌ LEO + 'Libra': u'\u264e', # ♎ LIBRA + 'Mars': u'\u2642', # ♂ MALE SIGN + 'Mercury': u'\u263f', # ☿ MERCURY + 'Neptune': u'\u2646', # ♆ NEPTUNE + 'Pluto': u'\u2647', # ♇ PLUTO + 'RIGHTCIRCLE': u'\u25d7', # ◗ RIGHT HALF BLACK CIRCLE + 'RIGHTcircle': u'\u25d1', # ◑ CIRCLE WITH RIGHT HALF BLACK + 'Saturn': u'\u2644', # ♄ SATURN + 'Scorpio': u'\u264f', # ♏ SCORPIUS + 'Square': u'\u2610', # ☐ BALLOT BOX + 'Sun': u'\u2609', # ☉ SUN + 'Taurus': u'\u2649', # ♉ TAURUS + 'Uranus': u'\u2645', # ♅ URANUS + 'Venus': u'\u2640', # ♀ FEMALE SIGN + 'XBox': u'\u2612', # ☒ BALLOT BOX WITH X + 'Yup': u'\u2144', # ⅄ TURNED SANS-SERIF CAPITAL Y + '_': u'_', # _ LOW LINE + 'angle': u'\u2220', # ∠ ANGLE + 'aquarius': u'\u2652', # ♒ AQUARIUS + 'aries': u'\u2648', # ♈ ARIES + 'ast': u'*', # * ASTERISK + 'backepsilon': u'\u03f6', # ϶ GREEK REVERSED LUNATE EPSILON SYMBOL + 'backprime': u'\u2035', # ‵ REVERSED PRIME + 'backslash': u'\\', # \ REVERSE SOLIDUS + 'because': u'\u2235', # ∵ BECAUSE + 'bigstar': u'\u2605', # ★ BLACK STAR + 'binampersand': u'&', # & AMPERSAND + 'blacklozenge': u'\u2b27', # ⬧ BLACK MEDIUM LOZENGE + 'blacksmiley': u'\u263b', # ☻ BLACK SMILING FACE + 'blacksquare': u'\u25fc', # ◼ BLACK MEDIUM SQUARE + 'bot': u'\u22a5', # ⊥ UP TACK + 'boy': u'\u2642', # ♂ MALE SIGN + 'cancer': u'\u264b', # ♋ CANCER + 'capricornus': u'\u2651', # ♑ CAPRICORN + 'cdots': u'\u22ef', # ⋯ MIDLINE HORIZONTAL ELLIPSIS + 'cent': u'\xa2', # ¢ CENT SIGN + 'centerdot': u'\u2b1d', # ⬝ BLACK VERY SMALL SQUARE + 'checkmark': u'\u2713', # ✓ CHECK MARK + 'circlearrowleft': u'\u21ba', # ↺ ANTICLOCKWISE OPEN CIRCLE ARROW + 'circlearrowright': u'\u21bb', # ↻ CLOCKWISE OPEN CIRCLE ARROW + 'circledR': u'\xae', # ® REGISTERED SIGN + 'circledcirc': u'\u25ce', # ◎ BULLSEYE + 'clubsuit': u'\u2663', # ♣ BLACK CLUB SUIT + 'complement': u'\u2201', # ∁ COMPLEMENT + 'dasharrow': u'\u21e2', # ⇢ RIGHTWARDS DASHED ARROW + 'dashleftarrow': u'\u21e0', # ⇠ LEFTWARDS DASHED ARROW + 'dashrightarrow': u'\u21e2', # ⇢ RIGHTWARDS DASHED ARROW + 'diameter': u'\u2300', # ⌀ DIAMETER SIGN + 'diamondsuit': u'\u2662', # ♢ WHITE DIAMOND SUIT + 'earth': u'\u2641', # ♁ EARTH + 'exists': u'\u2203', # ∃ THERE EXISTS + 'female': u'\u2640', # ♀ FEMALE SIGN + 'flat': u'\u266d', # ♭ MUSIC FLAT SIGN + 'forall': u'\u2200', # ∀ FOR ALL + 'fourth': u'\u2057', # ⁗ QUADRUPLE PRIME + 'frownie': u'\u2639', # ☹ WHITE FROWNING FACE + 'gemini': u'\u264a', # ♊ GEMINI + 'girl': u'\u2640', # ♀ FEMALE SIGN + 'heartsuit': u'\u2661', # ♡ WHITE HEART SUIT + 'infty': u'\u221e', # ∞ INFINITY + 'invneg': u'\u2310', # ⌐ REVERSED NOT SIGN + 'jupiter': u'\u2643', # ♃ JUPITER + 'ldots': u'\u2026', # … HORIZONTAL ELLIPSIS + 'leftmoon': u'\u263e', # ☾ LAST QUARTER MOON + 'leftturn': u'\u21ba', # ↺ ANTICLOCKWISE OPEN CIRCLE ARROW + 'leo': u'\u264c', # ♌ LEO + 'libra': u'\u264e', # ♎ LIBRA + 'lnot': u'\xac', # ¬ NOT SIGN + 'lozenge': u'\u25ca', # ◊ LOZENGE + 'male': u'\u2642', # ♂ MALE SIGN + 'maltese': u'\u2720', # ✠ MALTESE CROSS + 'mathdollar': u'$', # $ DOLLAR SIGN + 'measuredangle': u'\u2221', # ∡ MEASURED ANGLE + 'mercury': u'\u263f', # ☿ MERCURY + 'mho': u'\u2127', # ℧ INVERTED OHM SIGN + 'nabla': u'\u2207', # ∇ NABLA + 'natural': u'\u266e', # ♮ MUSIC NATURAL SIGN + 'neg': u'\xac', # ¬ NOT SIGN + 'neptune': u'\u2646', # ♆ NEPTUNE + 'nexists': u'\u2204', # ∄ THERE DOES NOT EXIST + 'notbackslash': u'\u2340', # ⍀ APL FUNCTIONAL SYMBOL BACKSLASH BAR + 'partial': u'\u2202', # ∂ PARTIAL DIFFERENTIAL + 'pisces': u'\u2653', # ♓ PISCES + 'pluto': u'\u2647', # ♇ PLUTO + 'pounds': u'\xa3', # £ POUND SIGN + 'prime': u'\u2032', # ′ PRIME + 'quarternote': u'\u2669', # ♩ QUARTER NOTE + 'rightmoon': u'\u263d', # ☽ FIRST QUARTER MOON + 'rightturn': u'\u21bb', # ↻ CLOCKWISE OPEN CIRCLE ARROW + 'sagittarius': u'\u2650', # ♐ SAGITTARIUS + 'saturn': u'\u2644', # ♄ SATURN + 'scorpio': u'\u264f', # ♏ SCORPIUS + 'second': u'\u2033', # ″ DOUBLE PRIME + 'sharp': u'\u266f', # ♯ MUSIC SHARP SIGN + 'sim': u'~', # ~ TILDE + 'slash': u'/', # / SOLIDUS + 'smiley': u'\u263a', # ☺ WHITE SMILING FACE + 'spadesuit': u'\u2660', # ♠ BLACK SPADE SUIT + 'spddot': u'\xa8', # ¨ DIAERESIS + 'sphat': u'^', # ^ CIRCUMFLEX ACCENT + 'sphericalangle': u'\u2222', # ∢ SPHERICAL ANGLE + 'sptilde': u'~', # ~ TILDE + 'square': u'\u25fb', # ◻ WHITE MEDIUM SQUARE + 'sun': u'\u263c', # ☼ WHITE SUN WITH RAYS + 'taurus': u'\u2649', # ♉ TAURUS + 'therefore': u'\u2234', # ∴ THEREFORE + 'third': u'\u2034', # ‴ TRIPLE PRIME + 'top': u'\u22a4', # ⊤ DOWN TACK + 'triangleleft': u'\u25c5', # ◅ WHITE LEFT-POINTING POINTER + 'triangleright': u'\u25bb', # ▻ WHITE RIGHT-POINTING POINTER + 'twonotes': u'\u266b', # ♫ BEAMED EIGHTH NOTES + 'uranus': u'\u2645', # ♅ URANUS + 'varEarth': u'\u2641', # ♁ EARTH + 'varnothing': u'\u2205', # ∅ EMPTY SET + 'virgo': u'\u264d', # ♍ VIRGO + 'wasylozenge': u'\u2311', # ⌑ SQUARE LOZENGE + 'wasytherefore': u'\u2234', # ∴ THEREFORE + 'yen': u'\xa5', # ¥ YEN SIGN + } +mathover = { + 'overbrace': u'\u23de', # ⏞ TOP CURLY BRACKET + 'wideparen': u'\u23dc', # ⏜ TOP PARENTHESIS + } +mathradical = { + 'sqrt': u'\u221a', # √ SQUARE ROOT + 'sqrt[3]': u'\u221b', # ∛ CUBE ROOT + 'sqrt[4]': u'\u221c', # ∜ FOURTH ROOT + } +mathrel = { + 'Bumpeq': u'\u224e', # ≎ GEOMETRICALLY EQUIVALENT TO + 'Doteq': u'\u2251', # ≑ GEOMETRICALLY EQUAL TO + 'Downarrow': u'\u21d3', # ⇓ DOWNWARDS DOUBLE ARROW + 'Leftarrow': u'\u21d0', # ⇐ LEFTWARDS DOUBLE ARROW + 'Leftrightarrow': u'\u21d4', # ⇔ LEFT RIGHT DOUBLE ARROW + 'Lleftarrow': u'\u21da', # ⇚ LEFTWARDS TRIPLE ARROW + 'Longleftarrow': u'\u27f8', # ⟸ LONG LEFTWARDS DOUBLE ARROW + 'Longleftrightarrow': u'\u27fa', # ⟺ LONG LEFT RIGHT DOUBLE ARROW + 'Longmapsfrom': u'\u27fd', # ⟽ LONG LEFTWARDS DOUBLE ARROW FROM BAR + 'Longmapsto': u'\u27fe', # ⟾ LONG RIGHTWARDS DOUBLE ARROW FROM BAR + 'Longrightarrow': u'\u27f9', # ⟹ LONG RIGHTWARDS DOUBLE ARROW + 'Lsh': u'\u21b0', # ↰ UPWARDS ARROW WITH TIP LEFTWARDS + 'Mapsfrom': u'\u2906', # ⤆ LEFTWARDS DOUBLE ARROW FROM BAR + 'Mapsto': u'\u2907', # ⤇ RIGHTWARDS DOUBLE ARROW FROM BAR + 'Rightarrow': u'\u21d2', # ⇒ RIGHTWARDS DOUBLE ARROW + 'Rrightarrow': u'\u21db', # ⇛ RIGHTWARDS TRIPLE ARROW + 'Rsh': u'\u21b1', # ↱ UPWARDS ARROW WITH TIP RIGHTWARDS + 'Subset': u'\u22d0', # ⋐ DOUBLE SUBSET + 'Supset': u'\u22d1', # ⋑ DOUBLE SUPERSET + 'Uparrow': u'\u21d1', # ⇑ UPWARDS DOUBLE ARROW + 'Updownarrow': u'\u21d5', # ⇕ UP DOWN DOUBLE ARROW + 'VDash': u'\u22ab', # ⊫ DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + 'Vdash': u'\u22a9', # ⊩ FORCES + 'Vvdash': u'\u22aa', # ⊪ TRIPLE VERTICAL BAR RIGHT TURNSTILE + 'apprge': u'\u2273', # ≳ GREATER-THAN OR EQUIVALENT TO + 'apprle': u'\u2272', # ≲ LESS-THAN OR EQUIVALENT TO + 'approx': u'\u2248', # ≈ ALMOST EQUAL TO + 'approxeq': u'\u224a', # ≊ ALMOST EQUAL OR EQUAL TO + 'asymp': u'\u224d', # ≍ EQUIVALENT TO + 'backsim': u'\u223d', # ∽ REVERSED TILDE + 'backsimeq': u'\u22cd', # ⋍ REVERSED TILDE EQUALS + 'barin': u'\u22f6', # ⋶ ELEMENT OF WITH OVERBAR + 'barleftharpoon': u'\u296b', # ⥫ LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + 'barrightharpoon': u'\u296d', # ⥭ RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH + 'between': u'\u226c', # ≬ BETWEEN + 'bowtie': u'\u22c8', # ⋈ BOWTIE + 'bumpeq': u'\u224f', # ≏ DIFFERENCE BETWEEN + 'circeq': u'\u2257', # ≗ RING EQUAL TO + 'coloneq': u'\u2254', # ≔ COLON EQUALS + 'cong': u'\u2245', # ≅ APPROXIMATELY EQUAL TO + 'corresponds': u'\u2259', # ≙ ESTIMATES + 'curlyeqprec': u'\u22de', # ⋞ EQUAL TO OR PRECEDES + 'curlyeqsucc': u'\u22df', # ⋟ EQUAL TO OR SUCCEEDS + 'curvearrowleft': u'\u21b6', # ↶ ANTICLOCKWISE TOP SEMICIRCLE ARROW + 'curvearrowright': u'\u21b7', # ↷ CLOCKWISE TOP SEMICIRCLE ARROW + 'dashv': u'\u22a3', # ⊣ LEFT TACK + 'ddots': u'\u22f1', # ⋱ DOWN RIGHT DIAGONAL ELLIPSIS + 'dlsh': u'\u21b2', # ↲ DOWNWARDS ARROW WITH TIP LEFTWARDS + 'doteq': u'\u2250', # ≐ APPROACHES THE LIMIT + 'doteqdot': u'\u2251', # ≑ GEOMETRICALLY EQUAL TO + 'downarrow': u'\u2193', # ↓ DOWNWARDS ARROW + 'downdownarrows': u'\u21ca', # ⇊ DOWNWARDS PAIRED ARROWS + 'downdownharpoons': u'\u2965', # ⥥ DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + 'downharpoonleft': u'\u21c3', # ⇃ DOWNWARDS HARPOON WITH BARB LEFTWARDS + 'downharpoonright': u'\u21c2', # ⇂ DOWNWARDS HARPOON WITH BARB RIGHTWARDS + 'downuparrows': u'\u21f5', # ⇵ DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW + 'downupharpoons': u'\u296f', # ⥯ DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + 'drsh': u'\u21b3', # ↳ DOWNWARDS ARROW WITH TIP RIGHTWARDS + 'eqcirc': u'\u2256', # ≖ RING IN EQUAL TO + 'eqcolon': u'\u2255', # ≕ EQUALS COLON + 'eqsim': u'\u2242', # ≂ MINUS TILDE + 'eqslantgtr': u'\u2a96', # ⪖ SLANTED EQUAL TO OR GREATER-THAN + 'eqslantless': u'\u2a95', # ⪕ SLANTED EQUAL TO OR LESS-THAN + 'equiv': u'\u2261', # ≡ IDENTICAL TO + 'fallingdotseq': u'\u2252', # ≒ APPROXIMATELY EQUAL TO OR THE IMAGE OF + 'frown': u'\u2322', # ⌢ FROWN + 'ge': u'\u2265', # ≥ GREATER-THAN OR EQUAL TO + 'geq': u'\u2265', # ≥ GREATER-THAN OR EQUAL TO + 'geqq': u'\u2267', # ≧ GREATER-THAN OVER EQUAL TO + 'geqslant': u'\u2a7e', # ⩾ GREATER-THAN OR SLANTED EQUAL TO + 'gets': u'\u2190', # ← LEFTWARDS ARROW + 'gg': u'\u226b', # ≫ MUCH GREATER-THAN + 'ggcurly': u'\u2abc', # ⪼ DOUBLE SUCCEEDS + 'ggg': u'\u22d9', # ⋙ VERY MUCH GREATER-THAN + 'gnapprox': u'\u2a8a', # ⪊ GREATER-THAN AND NOT APPROXIMATE + 'gneq': u'\u2a88', # ⪈ GREATER-THAN AND SINGLE-LINE NOT EQUAL TO + 'gneqq': u'\u2269', # ≩ GREATER-THAN BUT NOT EQUAL TO + 'gnsim': u'\u22e7', # ⋧ GREATER-THAN BUT NOT EQUIVALENT TO + 'gtrapprox': u'\u2a86', # ⪆ GREATER-THAN OR APPROXIMATE + 'gtrdot': u'\u22d7', # ⋗ GREATER-THAN WITH DOT + 'gtreqless': u'\u22db', # ⋛ GREATER-THAN EQUAL TO OR LESS-THAN + 'gtreqqless': u'\u2a8c', # ⪌ GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN + 'gtrless': u'\u2277', # ≷ GREATER-THAN OR LESS-THAN + 'gtrsim': u'\u2273', # ≳ GREATER-THAN OR EQUIVALENT TO + 'hash': u'\u22d5', # ⋕ EQUAL AND PARALLEL TO + 'hookleftarrow': u'\u21a9', # ↩ LEFTWARDS ARROW WITH HOOK + 'hookrightarrow': u'\u21aa', # ↪ RIGHTWARDS ARROW WITH HOOK + 'iddots': u'\u22f0', # ⋰ UP RIGHT DIAGONAL ELLIPSIS + 'impliedby': u'\u27f8', # ⟸ LONG LEFTWARDS DOUBLE ARROW + 'implies': u'\u27f9', # ⟹ LONG RIGHTWARDS DOUBLE ARROW + 'in': u'\u2208', # ∈ ELEMENT OF + 'le': u'\u2264', # ≤ LESS-THAN OR EQUAL TO + 'leftarrow': u'\u2190', # ← LEFTWARDS ARROW + 'leftarrowtail': u'\u21a2', # ↢ LEFTWARDS ARROW WITH TAIL + 'leftarrowtriangle': u'\u21fd', # ⇽ LEFTWARDS OPEN-HEADED ARROW + 'leftbarharpoon': u'\u296a', # ⥪ LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + 'leftharpoondown': u'\u21bd', # ↽ LEFTWARDS HARPOON WITH BARB DOWNWARDS + 'leftharpoonup': u'\u21bc', # ↼ LEFTWARDS HARPOON WITH BARB UPWARDS + 'leftleftarrows': u'\u21c7', # ⇇ LEFTWARDS PAIRED ARROWS + 'leftleftharpoons': u'\u2962', # ⥢ LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN + 'leftrightarrow': u'\u2194', # ↔ LEFT RIGHT ARROW + 'leftrightarrows': u'\u21c6', # ⇆ LEFTWARDS ARROW OVER RIGHTWARDS ARROW + 'leftrightarrowtriangle': u'\u21ff', # ⇿ LEFT RIGHT OPEN-HEADED ARROW + 'leftrightharpoon': u'\u294a', # ⥊ LEFT BARB UP RIGHT BARB DOWN HARPOON + 'leftrightharpoons': u'\u21cb', # ⇋ LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON + 'leftrightsquigarrow': u'\u21ad', # ↭ LEFT RIGHT WAVE ARROW + 'leftslice': u'\u2aa6', # ⪦ LESS-THAN CLOSED BY CURVE + 'leftsquigarrow': u'\u21dc', # ⇜ LEFTWARDS SQUIGGLE ARROW + 'leq': u'\u2264', # ≤ LESS-THAN OR EQUAL TO + 'leqq': u'\u2266', # ≦ LESS-THAN OVER EQUAL TO + 'leqslant': u'\u2a7d', # ⩽ LESS-THAN OR SLANTED EQUAL TO + 'lessapprox': u'\u2a85', # ⪅ LESS-THAN OR APPROXIMATE + 'lessdot': u'\u22d6', # ⋖ LESS-THAN WITH DOT + 'lesseqgtr': u'\u22da', # ⋚ LESS-THAN EQUAL TO OR GREATER-THAN + 'lesseqqgtr': u'\u2a8b', # ⪋ LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN + 'lessgtr': u'\u2276', # ≶ LESS-THAN OR GREATER-THAN + 'lesssim': u'\u2272', # ≲ LESS-THAN OR EQUIVALENT TO + 'lightning': u'\u21af', # ↯ DOWNWARDS ZIGZAG ARROW + 'll': u'\u226a', # ≪ MUCH LESS-THAN + 'llcurly': u'\u2abb', # ⪻ DOUBLE PRECEDES + 'lll': u'\u22d8', # ⋘ VERY MUCH LESS-THAN + 'lnapprox': u'\u2a89', # ⪉ LESS-THAN AND NOT APPROXIMATE + 'lneq': u'\u2a87', # ⪇ LESS-THAN AND SINGLE-LINE NOT EQUAL TO + 'lneqq': u'\u2268', # ≨ LESS-THAN BUT NOT EQUAL TO + 'lnsim': u'\u22e6', # ⋦ LESS-THAN BUT NOT EQUIVALENT TO + 'longleftarrow': u'\u27f5', # ⟵ LONG LEFTWARDS ARROW + 'longleftrightarrow': u'\u27f7', # ⟷ LONG LEFT RIGHT ARROW + 'longmapsfrom': u'\u27fb', # ⟻ LONG LEFTWARDS ARROW FROM BAR + 'longmapsto': u'\u27fc', # ⟼ LONG RIGHTWARDS ARROW FROM BAR + 'longrightarrow': u'\u27f6', # ⟶ LONG RIGHTWARDS ARROW + 'looparrowleft': u'\u21ab', # ↫ LEFTWARDS ARROW WITH LOOP + 'looparrowright': u'\u21ac', # ↬ RIGHTWARDS ARROW WITH LOOP + 'mapsfrom': u'\u21a4', # ↤ LEFTWARDS ARROW FROM BAR + 'mapsto': u'\u21a6', # ↦ RIGHTWARDS ARROW FROM BAR + 'mid': u'\u2223', # ∣ DIVIDES + 'models': u'\u22a7', # ⊧ MODELS + 'multimap': u'\u22b8', # ⊸ MULTIMAP + 'nLeftarrow': u'\u21cd', # ⇍ LEFTWARDS DOUBLE ARROW WITH STROKE + 'nLeftrightarrow': u'\u21ce', # ⇎ LEFT RIGHT DOUBLE ARROW WITH STROKE + 'nRightarrow': u'\u21cf', # ⇏ RIGHTWARDS DOUBLE ARROW WITH STROKE + 'nVDash': u'\u22af', # ⊯ NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE + 'nVdash': u'\u22ae', # ⊮ DOES NOT FORCE + 'ncong': u'\u2247', # ≇ NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO + 'ne': u'\u2260', # ≠ NOT EQUAL TO + 'nearrow': u'\u2197', # ↗ NORTH EAST ARROW + 'neq': u'\u2260', # ≠ NOT EQUAL TO + 'ngeq': u'\u2271', # ≱ NEITHER GREATER-THAN NOR EQUAL TO + 'ngtr': u'\u226f', # ≯ NOT GREATER-THAN + 'ni': u'\u220b', # ∋ CONTAINS AS MEMBER + 'nleftarrow': u'\u219a', # ↚ LEFTWARDS ARROW WITH STROKE + 'nleftrightarrow': u'\u21ae', # ↮ LEFT RIGHT ARROW WITH STROKE + 'nleq': u'\u2270', # ≰ NEITHER LESS-THAN NOR EQUAL TO + 'nless': u'\u226e', # ≮ NOT LESS-THAN + 'nmid': u'\u2224', # ∤ DOES NOT DIVIDE + 'notasymp': u'\u226d', # ≭ NOT EQUIVALENT TO + 'notin': u'\u2209', # ∉ NOT AN ELEMENT OF + 'notowner': u'\u220c', # ∌ DOES NOT CONTAIN AS MEMBER + 'notslash': u'\u233f', # ⌿ APL FUNCTIONAL SYMBOL SLASH BAR + 'nparallel': u'\u2226', # ∦ NOT PARALLEL TO + 'nprec': u'\u2280', # ⊀ DOES NOT PRECEDE + 'npreceq': u'\u22e0', # ⋠ DOES NOT PRECEDE OR EQUAL + 'nrightarrow': u'\u219b', # ↛ RIGHTWARDS ARROW WITH STROKE + 'nsim': u'\u2241', # ≁ NOT TILDE + 'nsubseteq': u'\u2288', # ⊈ NEITHER A SUBSET OF NOR EQUAL TO + 'nsucc': u'\u2281', # ⊁ DOES NOT SUCCEED + 'nsucceq': u'\u22e1', # ⋡ DOES NOT SUCCEED OR EQUAL + 'nsupseteq': u'\u2289', # ⊉ NEITHER A SUPERSET OF NOR EQUAL TO + 'ntriangleleft': u'\u22ea', # ⋪ NOT NORMAL SUBGROUP OF + 'ntrianglelefteq': u'\u22ec', # ⋬ NOT NORMAL SUBGROUP OF OR EQUAL TO + 'ntriangleright': u'\u22eb', # ⋫ DOES NOT CONTAIN AS NORMAL SUBGROUP + 'ntrianglerighteq': u'\u22ed', # ⋭ DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL + 'nvDash': u'\u22ad', # ⊭ NOT TRUE + 'nvdash': u'\u22ac', # ⊬ DOES NOT PROVE + 'nwarrow': u'\u2196', # ↖ NORTH WEST ARROW + 'owns': u'\u220b', # ∋ CONTAINS AS MEMBER + 'parallel': u'\u2225', # ∥ PARALLEL TO + 'perp': u'\u27c2', # ⟂ PERPENDICULAR + 'pitchfork': u'\u22d4', # ⋔ PITCHFORK + 'prec': u'\u227a', # ≺ PRECEDES + 'precapprox': u'\u2ab7', # ⪷ PRECEDES ABOVE ALMOST EQUAL TO + 'preccurlyeq': u'\u227c', # ≼ PRECEDES OR EQUAL TO + 'preceq': u'\u2aaf', # ⪯ PRECEDES ABOVE SINGLE-LINE EQUALS SIGN + 'precnapprox': u'\u2ab9', # ⪹ PRECEDES ABOVE NOT ALMOST EQUAL TO + 'precnsim': u'\u22e8', # ⋨ PRECEDES BUT NOT EQUIVALENT TO + 'precsim': u'\u227e', # ≾ PRECEDES OR EQUIVALENT TO + 'propto': u'\u221d', # ∝ PROPORTIONAL TO + 'restriction': u'\u21be', # ↾ UPWARDS HARPOON WITH BARB RIGHTWARDS + 'rightarrow': u'\u2192', # → RIGHTWARDS ARROW + 'rightarrowtail': u'\u21a3', # ↣ RIGHTWARDS ARROW WITH TAIL + 'rightarrowtriangle': u'\u21fe', # ⇾ RIGHTWARDS OPEN-HEADED ARROW + 'rightbarharpoon': u'\u296c', # ⥬ RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH + 'rightharpoondown': u'\u21c1', # ⇁ RIGHTWARDS HARPOON WITH BARB DOWNWARDS + 'rightharpoonup': u'\u21c0', # ⇀ RIGHTWARDS HARPOON WITH BARB UPWARDS + 'rightleftarrows': u'\u21c4', # ⇄ RIGHTWARDS ARROW OVER LEFTWARDS ARROW + 'rightleftharpoon': u'\u294b', # ⥋ LEFT BARB DOWN RIGHT BARB UP HARPOON + 'rightleftharpoons': u'\u21cc', # ⇌ RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON + 'rightrightarrows': u'\u21c9', # ⇉ RIGHTWARDS PAIRED ARROWS + 'rightrightharpoons': u'\u2964', # ⥤ RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN + 'rightslice': u'\u2aa7', # ⪧ GREATER-THAN CLOSED BY CURVE + 'rightsquigarrow': u'\u21dd', # ⇝ RIGHTWARDS SQUIGGLE ARROW + 'risingdotseq': u'\u2253', # ≓ IMAGE OF OR APPROXIMATELY EQUAL TO + 'searrow': u'\u2198', # ↘ SOUTH EAST ARROW + 'sim': u'\u223c', # ∼ TILDE OPERATOR + 'simeq': u'\u2243', # ≃ ASYMPTOTICALLY EQUAL TO + 'smallfrown': u'\u2322', # ⌢ FROWN + 'smallsmile': u'\u2323', # ⌣ SMILE + 'smile': u'\u2323', # ⌣ SMILE + 'sqsubset': u'\u228f', # ⊏ SQUARE IMAGE OF + 'sqsubseteq': u'\u2291', # ⊑ SQUARE IMAGE OF OR EQUAL TO + 'sqsupset': u'\u2290', # ⊐ SQUARE ORIGINAL OF + 'sqsupseteq': u'\u2292', # ⊒ SQUARE ORIGINAL OF OR EQUAL TO + 'subset': u'\u2282', # ⊂ SUBSET OF + 'subseteq': u'\u2286', # ⊆ SUBSET OF OR EQUAL TO + 'subseteqq': u'\u2ac5', # ⫅ SUBSET OF ABOVE EQUALS SIGN + 'subsetneq': u'\u228a', # ⊊ SUBSET OF WITH NOT EQUAL TO + 'subsetneqq': u'\u2acb', # ⫋ SUBSET OF ABOVE NOT EQUAL TO + 'succ': u'\u227b', # ≻ SUCCEEDS + 'succapprox': u'\u2ab8', # ⪸ SUCCEEDS ABOVE ALMOST EQUAL TO + 'succcurlyeq': u'\u227d', # ≽ SUCCEEDS OR EQUAL TO + 'succeq': u'\u2ab0', # ⪰ SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN + 'succnapprox': u'\u2aba', # ⪺ SUCCEEDS ABOVE NOT ALMOST EQUAL TO + 'succnsim': u'\u22e9', # ⋩ SUCCEEDS BUT NOT EQUIVALENT TO + 'succsim': u'\u227f', # ≿ SUCCEEDS OR EQUIVALENT TO + 'supset': u'\u2283', # ⊃ SUPERSET OF + 'supseteq': u'\u2287', # ⊇ SUPERSET OF OR EQUAL TO + 'supseteqq': u'\u2ac6', # ⫆ SUPERSET OF ABOVE EQUALS SIGN + 'supsetneq': u'\u228b', # ⊋ SUPERSET OF WITH NOT EQUAL TO + 'supsetneqq': u'\u2acc', # ⫌ SUPERSET OF ABOVE NOT EQUAL TO + 'swarrow': u'\u2199', # ↙ SOUTH WEST ARROW + 'to': u'\u2192', # → RIGHTWARDS ARROW + 'trianglelefteq': u'\u22b4', # ⊴ NORMAL SUBGROUP OF OR EQUAL TO + 'triangleq': u'\u225c', # ≜ DELTA EQUAL TO + 'trianglerighteq': u'\u22b5', # ⊵ CONTAINS AS NORMAL SUBGROUP OR EQUAL TO + 'twoheadleftarrow': u'\u219e', # ↞ LEFTWARDS TWO HEADED ARROW + 'twoheadrightarrow': u'\u21a0', # ↠ RIGHTWARDS TWO HEADED ARROW + 'uparrow': u'\u2191', # ↑ UPWARDS ARROW + 'updownarrow': u'\u2195', # ↕ UP DOWN ARROW + 'updownarrows': u'\u21c5', # ⇅ UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW + 'updownharpoons': u'\u296e', # ⥮ UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT + 'upharpoonleft': u'\u21bf', # ↿ UPWARDS HARPOON WITH BARB LEFTWARDS + 'upharpoonright': u'\u21be', # ↾ UPWARDS HARPOON WITH BARB RIGHTWARDS + 'upuparrows': u'\u21c8', # ⇈ UPWARDS PAIRED ARROWS + 'upupharpoons': u'\u2963', # ⥣ UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT + 'vDash': u'\u22a8', # ⊨ TRUE + 'varpropto': u'\u221d', # ∝ PROPORTIONAL TO + 'vartriangleleft': u'\u22b2', # ⊲ NORMAL SUBGROUP OF + 'vartriangleright': u'\u22b3', # ⊳ CONTAINS AS NORMAL SUBGROUP + 'vdash': u'\u22a2', # ⊢ RIGHT TACK + 'vdots': u'\u22ee', # ⋮ VERTICAL ELLIPSIS + } +mathunder = { + 'underbrace': u'\u23df', # ⏟ BOTTOM CURLY BRACKET + } +space = { + ':': u'\u205f', #   MEDIUM MATHEMATICAL SPACE + 'medspace': u'\u205f', #   MEDIUM MATHEMATICAL SPACE + 'quad': u'\u2001', #   EM QUAD + } diff --git a/env/lib/python3.8/site-packages/docutils/utils/math/unichar2tex.py b/env/lib/python3.8/site-packages/docutils/utils/math/unichar2tex.py new file mode 100644 index 000000000..0e0b80809 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/math/unichar2tex.py @@ -0,0 +1,788 @@ +# LaTeX math to Unicode symbols translation table +# for use with the translate() method of unicode objects. +# Generated with ``write_unichar2tex.py`` from the data in +# http://milde.users.sourceforge.net/LUCR/Math/ + +# Includes commands from: standard LaTeX, amssymb, amsmath + +uni2tex_table = { +160: u'~', +163: u'\\pounds ', +165: u'\\yen ', +172: u'\\neg ', +174: u'\\circledR ', +177: u'\\pm ', +215: u'\\times ', +240: u'\\eth ', +247: u'\\div ', +305: u'\\imath ', +567: u'\\jmath ', +915: u'\\Gamma ', +916: u'\\Delta ', +920: u'\\Theta ', +923: u'\\Lambda ', +926: u'\\Xi ', +928: u'\\Pi ', +931: u'\\Sigma ', +933: u'\\Upsilon ', +934: u'\\Phi ', +936: u'\\Psi ', +937: u'\\Omega ', +945: u'\\alpha ', +946: u'\\beta ', +947: u'\\gamma ', +948: u'\\delta ', +949: u'\\varepsilon ', +950: u'\\zeta ', +951: u'\\eta ', +952: u'\\theta ', +953: u'\\iota ', +954: u'\\kappa ', +955: u'\\lambda ', +956: u'\\mu ', +957: u'\\nu ', +958: u'\\xi ', +960: u'\\pi ', +961: u'\\rho ', +962: u'\\varsigma ', +963: u'\\sigma ', +964: u'\\tau ', +965: u'\\upsilon ', +966: u'\\varphi ', +967: u'\\chi ', +968: u'\\psi ', +969: u'\\omega ', +977: u'\\vartheta ', +981: u'\\phi ', +982: u'\\varpi ', +989: u'\\digamma ', +1014: u'\\backepsilon ', +8193: u'\\quad ', +8214: u'\\| ', +8224: u'\\dagger ', +8225: u'\\ddagger ', +8230: u'\\ldots ', +8242: u'\\prime ', +8245: u'\\backprime ', +8287: u'\\: ', +8450: u'\\mathbb{C}', +8459: u'\\mathcal{H}', +8460: u'\\mathfrak{H}', +8461: u'\\mathbb{H}', +8463: u'\\hslash ', +8464: u'\\mathcal{I}', +8465: u'\\Im ', +8466: u'\\mathcal{L}', +8467: u'\\ell ', +8469: u'\\mathbb{N}', +8472: u'\\wp ', +8473: u'\\mathbb{P}', +8474: u'\\mathbb{Q}', +8475: u'\\mathcal{R}', +8476: u'\\Re ', +8477: u'\\mathbb{R}', +8484: u'\\mathbb{Z}', +8487: u'\\mho ', +8488: u'\\mathfrak{Z}', +8492: u'\\mathcal{B}', +8493: u'\\mathfrak{C}', +8496: u'\\mathcal{E}', +8497: u'\\mathcal{F}', +8498: u'\\Finv ', +8499: u'\\mathcal{M}', +8501: u'\\aleph ', +8502: u'\\beth ', +8503: u'\\gimel ', +8504: u'\\daleth ', +8592: u'\\leftarrow ', +8593: u'\\uparrow ', +8594: u'\\rightarrow ', +8595: u'\\downarrow ', +8596: u'\\leftrightarrow ', +8597: u'\\updownarrow ', +8598: u'\\nwarrow ', +8599: u'\\nearrow ', +8600: u'\\searrow ', +8601: u'\\swarrow ', +8602: u'\\nleftarrow ', +8603: u'\\nrightarrow ', +8606: u'\\twoheadleftarrow ', +8608: u'\\twoheadrightarrow ', +8610: u'\\leftarrowtail ', +8611: u'\\rightarrowtail ', +8614: u'\\mapsto ', +8617: u'\\hookleftarrow ', +8618: u'\\hookrightarrow ', +8619: u'\\looparrowleft ', +8620: u'\\looparrowright ', +8621: u'\\leftrightsquigarrow ', +8622: u'\\nleftrightarrow ', +8624: u'\\Lsh ', +8625: u'\\Rsh ', +8630: u'\\curvearrowleft ', +8631: u'\\curvearrowright ', +8634: u'\\circlearrowleft ', +8635: u'\\circlearrowright ', +8636: u'\\leftharpoonup ', +8637: u'\\leftharpoondown ', +8638: u'\\upharpoonright ', +8639: u'\\upharpoonleft ', +8640: u'\\rightharpoonup ', +8641: u'\\rightharpoondown ', +8642: u'\\downharpoonright ', +8643: u'\\downharpoonleft ', +8644: u'\\rightleftarrows ', +8646: u'\\leftrightarrows ', +8647: u'\\leftleftarrows ', +8648: u'\\upuparrows ', +8649: u'\\rightrightarrows ', +8650: u'\\downdownarrows ', +8651: u'\\leftrightharpoons ', +8652: u'\\rightleftharpoons ', +8653: u'\\nLeftarrow ', +8654: u'\\nLeftrightarrow ', +8655: u'\\nRightarrow ', +8656: u'\\Leftarrow ', +8657: u'\\Uparrow ', +8658: u'\\Rightarrow ', +8659: u'\\Downarrow ', +8660: u'\\Leftrightarrow ', +8661: u'\\Updownarrow ', +8666: u'\\Lleftarrow ', +8667: u'\\Rrightarrow ', +8669: u'\\rightsquigarrow ', +8672: u'\\dashleftarrow ', +8674: u'\\dashrightarrow ', +8704: u'\\forall ', +8705: u'\\complement ', +8706: u'\\partial ', +8707: u'\\exists ', +8708: u'\\nexists ', +8709: u'\\varnothing ', +8711: u'\\nabla ', +8712: u'\\in ', +8713: u'\\notin ', +8715: u'\\ni ', +8719: u'\\prod ', +8720: u'\\coprod ', +8721: u'\\sum ', +8722: u'-', +8723: u'\\mp ', +8724: u'\\dotplus ', +8725: u'\\slash ', +8726: u'\\smallsetminus ', +8727: u'\\ast ', +8728: u'\\circ ', +8729: u'\\bullet ', +8730: u'\\sqrt ', +8731: u'\\sqrt[3] ', +8732: u'\\sqrt[4] ', +8733: u'\\propto ', +8734: u'\\infty ', +8736: u'\\angle ', +8737: u'\\measuredangle ', +8738: u'\\sphericalangle ', +8739: u'\\mid ', +8740: u'\\nmid ', +8741: u'\\parallel ', +8742: u'\\nparallel ', +8743: u'\\wedge ', +8744: u'\\vee ', +8745: u'\\cap ', +8746: u'\\cup ', +8747: u'\\int ', +8748: u'\\iint ', +8749: u'\\iiint ', +8750: u'\\oint ', +8756: u'\\therefore ', +8757: u'\\because ', +8758: u':', +8764: u'\\sim ', +8765: u'\\backsim ', +8768: u'\\wr ', +8769: u'\\nsim ', +8770: u'\\eqsim ', +8771: u'\\simeq ', +8773: u'\\cong ', +8775: u'\\ncong ', +8776: u'\\approx ', +8778: u'\\approxeq ', +8781: u'\\asymp ', +8782: u'\\Bumpeq ', +8783: u'\\bumpeq ', +8784: u'\\doteq ', +8785: u'\\Doteq ', +8786: u'\\fallingdotseq ', +8787: u'\\risingdotseq ', +8790: u'\\eqcirc ', +8791: u'\\circeq ', +8796: u'\\triangleq ', +8800: u'\\neq ', +8801: u'\\equiv ', +8804: u'\\leq ', +8805: u'\\geq ', +8806: u'\\leqq ', +8807: u'\\geqq ', +8808: u'\\lneqq ', +8809: u'\\gneqq ', +8810: u'\\ll ', +8811: u'\\gg ', +8812: u'\\between ', +8814: u'\\nless ', +8815: u'\\ngtr ', +8816: u'\\nleq ', +8817: u'\\ngeq ', +8818: u'\\lesssim ', +8819: u'\\gtrsim ', +8822: u'\\lessgtr ', +8823: u'\\gtrless ', +8826: u'\\prec ', +8827: u'\\succ ', +8828: u'\\preccurlyeq ', +8829: u'\\succcurlyeq ', +8830: u'\\precsim ', +8831: u'\\succsim ', +8832: u'\\nprec ', +8833: u'\\nsucc ', +8834: u'\\subset ', +8835: u'\\supset ', +8838: u'\\subseteq ', +8839: u'\\supseteq ', +8840: u'\\nsubseteq ', +8841: u'\\nsupseteq ', +8842: u'\\subsetneq ', +8843: u'\\supsetneq ', +8846: u'\\uplus ', +8847: u'\\sqsubset ', +8848: u'\\sqsupset ', +8849: u'\\sqsubseteq ', +8850: u'\\sqsupseteq ', +8851: u'\\sqcap ', +8852: u'\\sqcup ', +8853: u'\\oplus ', +8854: u'\\ominus ', +8855: u'\\otimes ', +8856: u'\\oslash ', +8857: u'\\odot ', +8858: u'\\circledcirc ', +8859: u'\\circledast ', +8861: u'\\circleddash ', +8862: u'\\boxplus ', +8863: u'\\boxminus ', +8864: u'\\boxtimes ', +8865: u'\\boxdot ', +8866: u'\\vdash ', +8867: u'\\dashv ', +8868: u'\\top ', +8869: u'\\bot ', +8871: u'\\models ', +8872: u'\\vDash ', +8873: u'\\Vdash ', +8874: u'\\Vvdash ', +8876: u'\\nvdash ', +8877: u'\\nvDash ', +8878: u'\\nVdash ', +8879: u'\\nVDash ', +8882: u'\\vartriangleleft ', +8883: u'\\vartriangleright ', +8884: u'\\trianglelefteq ', +8885: u'\\trianglerighteq ', +8888: u'\\multimap ', +8890: u'\\intercal ', +8891: u'\\veebar ', +8892: u'\\barwedge ', +8896: u'\\bigwedge ', +8897: u'\\bigvee ', +8898: u'\\bigcap ', +8899: u'\\bigcup ', +8900: u'\\diamond ', +8901: u'\\cdot ', +8902: u'\\star ', +8903: u'\\divideontimes ', +8904: u'\\bowtie ', +8905: u'\\ltimes ', +8906: u'\\rtimes ', +8907: u'\\leftthreetimes ', +8908: u'\\rightthreetimes ', +8909: u'\\backsimeq ', +8910: u'\\curlyvee ', +8911: u'\\curlywedge ', +8912: u'\\Subset ', +8913: u'\\Supset ', +8914: u'\\Cap ', +8915: u'\\Cup ', +8916: u'\\pitchfork ', +8918: u'\\lessdot ', +8919: u'\\gtrdot ', +8920: u'\\lll ', +8921: u'\\ggg ', +8922: u'\\lesseqgtr ', +8923: u'\\gtreqless ', +8926: u'\\curlyeqprec ', +8927: u'\\curlyeqsucc ', +8928: u'\\npreceq ', +8929: u'\\nsucceq ', +8934: u'\\lnsim ', +8935: u'\\gnsim ', +8936: u'\\precnsim ', +8937: u'\\succnsim ', +8938: u'\\ntriangleleft ', +8939: u'\\ntriangleright ', +8940: u'\\ntrianglelefteq ', +8941: u'\\ntrianglerighteq ', +8942: u'\\vdots ', +8943: u'\\cdots ', +8945: u'\\ddots ', +8968: u'\\lceil ', +8969: u'\\rceil ', +8970: u'\\lfloor ', +8971: u'\\rfloor ', +8988: u'\\ulcorner ', +8989: u'\\urcorner ', +8990: u'\\llcorner ', +8991: u'\\lrcorner ', +8994: u'\\frown ', +8995: u'\\smile ', +9182: u'\\overbrace ', +9183: u'\\underbrace ', +9651: u'\\bigtriangleup ', +9655: u'\\rhd ', +9661: u'\\bigtriangledown ', +9665: u'\\lhd ', +9671: u'\\Diamond ', +9674: u'\\lozenge ', +9723: u'\\square ', +9724: u'\\blacksquare ', +9733: u'\\bigstar ', +9824: u'\\spadesuit ', +9825: u'\\heartsuit ', +9826: u'\\diamondsuit ', +9827: u'\\clubsuit ', +9837: u'\\flat ', +9838: u'\\natural ', +9839: u'\\sharp ', +10003: u'\\checkmark ', +10016: u'\\maltese ', +10178: u'\\perp ', +10216: u'\\langle ', +10217: u'\\rangle ', +10222: u'\\lgroup ', +10223: u'\\rgroup ', +10229: u'\\longleftarrow ', +10230: u'\\longrightarrow ', +10231: u'\\longleftrightarrow ', +10232: u'\\Longleftarrow ', +10233: u'\\Longrightarrow ', +10234: u'\\Longleftrightarrow ', +10236: u'\\longmapsto ', +10731: u'\\blacklozenge ', +10741: u'\\setminus ', +10752: u'\\bigodot ', +10753: u'\\bigoplus ', +10754: u'\\bigotimes ', +10756: u'\\biguplus ', +10758: u'\\bigsqcup ', +10764: u'\\iiiint ', +10781: u'\\Join ', +10815: u'\\amalg ', +10846: u'\\doublebarwedge ', +10877: u'\\leqslant ', +10878: u'\\geqslant ', +10885: u'\\lessapprox ', +10886: u'\\gtrapprox ', +10887: u'\\lneq ', +10888: u'\\gneq ', +10889: u'\\lnapprox ', +10890: u'\\gnapprox ', +10891: u'\\lesseqqgtr ', +10892: u'\\gtreqqless ', +10901: u'\\eqslantless ', +10902: u'\\eqslantgtr ', +10927: u'\\preceq ', +10928: u'\\succeq ', +10935: u'\\precapprox ', +10936: u'\\succapprox ', +10937: u'\\precnapprox ', +10938: u'\\succnapprox ', +10949: u'\\subseteqq ', +10950: u'\\supseteqq ', +10955: u'\\subsetneqq ', +10956: u'\\supsetneqq ', +119808: u'\\mathbf{A}', +119809: u'\\mathbf{B}', +119810: u'\\mathbf{C}', +119811: u'\\mathbf{D}', +119812: u'\\mathbf{E}', +119813: u'\\mathbf{F}', +119814: u'\\mathbf{G}', +119815: u'\\mathbf{H}', +119816: u'\\mathbf{I}', +119817: u'\\mathbf{J}', +119818: u'\\mathbf{K}', +119819: u'\\mathbf{L}', +119820: u'\\mathbf{M}', +119821: u'\\mathbf{N}', +119822: u'\\mathbf{O}', +119823: u'\\mathbf{P}', +119824: u'\\mathbf{Q}', +119825: u'\\mathbf{R}', +119826: u'\\mathbf{S}', +119827: u'\\mathbf{T}', +119828: u'\\mathbf{U}', +119829: u'\\mathbf{V}', +119830: u'\\mathbf{W}', +119831: u'\\mathbf{X}', +119832: u'\\mathbf{Y}', +119833: u'\\mathbf{Z}', +119834: u'\\mathbf{a}', +119835: u'\\mathbf{b}', +119836: u'\\mathbf{c}', +119837: u'\\mathbf{d}', +119838: u'\\mathbf{e}', +119839: u'\\mathbf{f}', +119840: u'\\mathbf{g}', +119841: u'\\mathbf{h}', +119842: u'\\mathbf{i}', +119843: u'\\mathbf{j}', +119844: u'\\mathbf{k}', +119845: u'\\mathbf{l}', +119846: u'\\mathbf{m}', +119847: u'\\mathbf{n}', +119848: u'\\mathbf{o}', +119849: u'\\mathbf{p}', +119850: u'\\mathbf{q}', +119851: u'\\mathbf{r}', +119852: u'\\mathbf{s}', +119853: u'\\mathbf{t}', +119854: u'\\mathbf{u}', +119855: u'\\mathbf{v}', +119856: u'\\mathbf{w}', +119857: u'\\mathbf{x}', +119858: u'\\mathbf{y}', +119859: u'\\mathbf{z}', +119860: u'A', +119861: u'B', +119862: u'C', +119863: u'D', +119864: u'E', +119865: u'F', +119866: u'G', +119867: u'H', +119868: u'I', +119869: u'J', +119870: u'K', +119871: u'L', +119872: u'M', +119873: u'N', +119874: u'O', +119875: u'P', +119876: u'Q', +119877: u'R', +119878: u'S', +119879: u'T', +119880: u'U', +119881: u'V', +119882: u'W', +119883: u'X', +119884: u'Y', +119885: u'Z', +119886: u'a', +119887: u'b', +119888: u'c', +119889: u'd', +119890: u'e', +119891: u'f', +119892: u'g', +119894: u'i', +119895: u'j', +119896: u'k', +119897: u'l', +119898: u'm', +119899: u'n', +119900: u'o', +119901: u'p', +119902: u'q', +119903: u'r', +119904: u's', +119905: u't', +119906: u'u', +119907: u'v', +119908: u'w', +119909: u'x', +119910: u'y', +119911: u'z', +119964: u'\\mathcal{A}', +119966: u'\\mathcal{C}', +119967: u'\\mathcal{D}', +119970: u'\\mathcal{G}', +119973: u'\\mathcal{J}', +119974: u'\\mathcal{K}', +119977: u'\\mathcal{N}', +119978: u'\\mathcal{O}', +119979: u'\\mathcal{P}', +119980: u'\\mathcal{Q}', +119982: u'\\mathcal{S}', +119983: u'\\mathcal{T}', +119984: u'\\mathcal{U}', +119985: u'\\mathcal{V}', +119986: u'\\mathcal{W}', +119987: u'\\mathcal{X}', +119988: u'\\mathcal{Y}', +119989: u'\\mathcal{Z}', +120068: u'\\mathfrak{A}', +120069: u'\\mathfrak{B}', +120071: u'\\mathfrak{D}', +120072: u'\\mathfrak{E}', +120073: u'\\mathfrak{F}', +120074: u'\\mathfrak{G}', +120077: u'\\mathfrak{J}', +120078: u'\\mathfrak{K}', +120079: u'\\mathfrak{L}', +120080: u'\\mathfrak{M}', +120081: u'\\mathfrak{N}', +120082: u'\\mathfrak{O}', +120083: u'\\mathfrak{P}', +120084: u'\\mathfrak{Q}', +120086: u'\\mathfrak{S}', +120087: u'\\mathfrak{T}', +120088: u'\\mathfrak{U}', +120089: u'\\mathfrak{V}', +120090: u'\\mathfrak{W}', +120091: u'\\mathfrak{X}', +120092: u'\\mathfrak{Y}', +120094: u'\\mathfrak{a}', +120095: u'\\mathfrak{b}', +120096: u'\\mathfrak{c}', +120097: u'\\mathfrak{d}', +120098: u'\\mathfrak{e}', +120099: u'\\mathfrak{f}', +120100: u'\\mathfrak{g}', +120101: u'\\mathfrak{h}', +120102: u'\\mathfrak{i}', +120103: u'\\mathfrak{j}', +120104: u'\\mathfrak{k}', +120105: u'\\mathfrak{l}', +120106: u'\\mathfrak{m}', +120107: u'\\mathfrak{n}', +120108: u'\\mathfrak{o}', +120109: u'\\mathfrak{p}', +120110: u'\\mathfrak{q}', +120111: u'\\mathfrak{r}', +120112: u'\\mathfrak{s}', +120113: u'\\mathfrak{t}', +120114: u'\\mathfrak{u}', +120115: u'\\mathfrak{v}', +120116: u'\\mathfrak{w}', +120117: u'\\mathfrak{x}', +120118: u'\\mathfrak{y}', +120119: u'\\mathfrak{z}', +120120: u'\\mathbb{A}', +120121: u'\\mathbb{B}', +120123: u'\\mathbb{D}', +120124: u'\\mathbb{E}', +120125: u'\\mathbb{F}', +120126: u'\\mathbb{G}', +120128: u'\\mathbb{I}', +120129: u'\\mathbb{J}', +120130: u'\\mathbb{K}', +120131: u'\\mathbb{L}', +120132: u'\\mathbb{M}', +120134: u'\\mathbb{O}', +120138: u'\\mathbb{S}', +120139: u'\\mathbb{T}', +120140: u'\\mathbb{U}', +120141: u'\\mathbb{V}', +120142: u'\\mathbb{W}', +120143: u'\\mathbb{X}', +120144: u'\\mathbb{Y}', +120156: u'\\Bbbk ', +120224: u'\\mathsf{A}', +120225: u'\\mathsf{B}', +120226: u'\\mathsf{C}', +120227: u'\\mathsf{D}', +120228: u'\\mathsf{E}', +120229: u'\\mathsf{F}', +120230: u'\\mathsf{G}', +120231: u'\\mathsf{H}', +120232: u'\\mathsf{I}', +120233: u'\\mathsf{J}', +120234: u'\\mathsf{K}', +120235: u'\\mathsf{L}', +120236: u'\\mathsf{M}', +120237: u'\\mathsf{N}', +120238: u'\\mathsf{O}', +120239: u'\\mathsf{P}', +120240: u'\\mathsf{Q}', +120241: u'\\mathsf{R}', +120242: u'\\mathsf{S}', +120243: u'\\mathsf{T}', +120244: u'\\mathsf{U}', +120245: u'\\mathsf{V}', +120246: u'\\mathsf{W}', +120247: u'\\mathsf{X}', +120248: u'\\mathsf{Y}', +120249: u'\\mathsf{Z}', +120250: u'\\mathsf{a}', +120251: u'\\mathsf{b}', +120252: u'\\mathsf{c}', +120253: u'\\mathsf{d}', +120254: u'\\mathsf{e}', +120255: u'\\mathsf{f}', +120256: u'\\mathsf{g}', +120257: u'\\mathsf{h}', +120258: u'\\mathsf{i}', +120259: u'\\mathsf{j}', +120260: u'\\mathsf{k}', +120261: u'\\mathsf{l}', +120262: u'\\mathsf{m}', +120263: u'\\mathsf{n}', +120264: u'\\mathsf{o}', +120265: u'\\mathsf{p}', +120266: u'\\mathsf{q}', +120267: u'\\mathsf{r}', +120268: u'\\mathsf{s}', +120269: u'\\mathsf{t}', +120270: u'\\mathsf{u}', +120271: u'\\mathsf{v}', +120272: u'\\mathsf{w}', +120273: u'\\mathsf{x}', +120274: u'\\mathsf{y}', +120275: u'\\mathsf{z}', +120432: u'\\mathtt{A}', +120433: u'\\mathtt{B}', +120434: u'\\mathtt{C}', +120435: u'\\mathtt{D}', +120436: u'\\mathtt{E}', +120437: u'\\mathtt{F}', +120438: u'\\mathtt{G}', +120439: u'\\mathtt{H}', +120440: u'\\mathtt{I}', +120441: u'\\mathtt{J}', +120442: u'\\mathtt{K}', +120443: u'\\mathtt{L}', +120444: u'\\mathtt{M}', +120445: u'\\mathtt{N}', +120446: u'\\mathtt{O}', +120447: u'\\mathtt{P}', +120448: u'\\mathtt{Q}', +120449: u'\\mathtt{R}', +120450: u'\\mathtt{S}', +120451: u'\\mathtt{T}', +120452: u'\\mathtt{U}', +120453: u'\\mathtt{V}', +120454: u'\\mathtt{W}', +120455: u'\\mathtt{X}', +120456: u'\\mathtt{Y}', +120457: u'\\mathtt{Z}', +120458: u'\\mathtt{a}', +120459: u'\\mathtt{b}', +120460: u'\\mathtt{c}', +120461: u'\\mathtt{d}', +120462: u'\\mathtt{e}', +120463: u'\\mathtt{f}', +120464: u'\\mathtt{g}', +120465: u'\\mathtt{h}', +120466: u'\\mathtt{i}', +120467: u'\\mathtt{j}', +120468: u'\\mathtt{k}', +120469: u'\\mathtt{l}', +120470: u'\\mathtt{m}', +120471: u'\\mathtt{n}', +120472: u'\\mathtt{o}', +120473: u'\\mathtt{p}', +120474: u'\\mathtt{q}', +120475: u'\\mathtt{r}', +120476: u'\\mathtt{s}', +120477: u'\\mathtt{t}', +120478: u'\\mathtt{u}', +120479: u'\\mathtt{v}', +120480: u'\\mathtt{w}', +120481: u'\\mathtt{x}', +120482: u'\\mathtt{y}', +120483: u'\\mathtt{z}', +120484: u'\\imath ', +120485: u'\\jmath ', +120490: u'\\mathbf{\\Gamma}', +120491: u'\\mathbf{\\Delta}', +120495: u'\\mathbf{\\Theta}', +120498: u'\\mathbf{\\Lambda}', +120501: u'\\mathbf{\\Xi}', +120503: u'\\mathbf{\\Pi}', +120506: u'\\mathbf{\\Sigma}', +120508: u'\\mathbf{\\Upsilon}', +120509: u'\\mathbf{\\Phi}', +120511: u'\\mathbf{\\Psi}', +120512: u'\\mathbf{\\Omega}', +120548: u'\\mathit{\\Gamma}', +120549: u'\\mathit{\\Delta}', +120553: u'\\mathit{\\Theta}', +120556: u'\\mathit{\\Lambda}', +120559: u'\\mathit{\\Xi}', +120561: u'\\mathit{\\Pi}', +120564: u'\\mathit{\\Sigma}', +120566: u'\\mathit{\\Upsilon}', +120567: u'\\mathit{\\Phi}', +120569: u'\\mathit{\\Psi}', +120570: u'\\mathit{\\Omega}', +120572: u'\\alpha ', +120573: u'\\beta ', +120574: u'\\gamma ', +120575: u'\\delta ', +120576: u'\\varepsilon ', +120577: u'\\zeta ', +120578: u'\\eta ', +120579: u'\\theta ', +120580: u'\\iota ', +120581: u'\\kappa ', +120582: u'\\lambda ', +120583: u'\\mu ', +120584: u'\\nu ', +120585: u'\\xi ', +120587: u'\\pi ', +120588: u'\\rho ', +120589: u'\\varsigma ', +120590: u'\\sigma ', +120591: u'\\tau ', +120592: u'\\upsilon ', +120593: u'\\varphi ', +120594: u'\\chi ', +120595: u'\\psi ', +120596: u'\\omega ', +120597: u'\\partial ', +120598: u'\\epsilon ', +120599: u'\\vartheta ', +120600: u'\\varkappa ', +120601: u'\\phi ', +120602: u'\\varrho ', +120603: u'\\varpi ', +120782: u'\\mathbf{0}', +120783: u'\\mathbf{1}', +120784: u'\\mathbf{2}', +120785: u'\\mathbf{3}', +120786: u'\\mathbf{4}', +120787: u'\\mathbf{5}', +120788: u'\\mathbf{6}', +120789: u'\\mathbf{7}', +120790: u'\\mathbf{8}', +120791: u'\\mathbf{9}', +120802: u'\\mathsf{0}', +120803: u'\\mathsf{1}', +120804: u'\\mathsf{2}', +120805: u'\\mathsf{3}', +120806: u'\\mathsf{4}', +120807: u'\\mathsf{5}', +120808: u'\\mathsf{6}', +120809: u'\\mathsf{7}', +120810: u'\\mathsf{8}', +120811: u'\\mathsf{9}', +120822: u'\\mathtt{0}', +120823: u'\\mathtt{1}', +120824: u'\\mathtt{2}', +120825: u'\\mathtt{3}', +120826: u'\\mathtt{4}', +120827: u'\\mathtt{5}', +120828: u'\\mathtt{6}', +120829: u'\\mathtt{7}', +120830: u'\\mathtt{8}', +120831: u'\\mathtt{9}', +} diff --git a/env/lib/python3.8/site-packages/docutils/utils/punctuation_chars.py b/env/lib/python3.8/site-packages/docutils/utils/punctuation_chars.py new file mode 100644 index 000000000..041cf9c1a --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/punctuation_chars.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# :Id: $Id: punctuation_chars.py 8016 2017-01-17 15:06:17Z milde $ +# :Copyright: © 2011, 2017 Günter Milde. +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause +# +# This file is generated by +# ``docutils/tools/dev/generate_punctuation_chars.py``. +# :: + +import sys, re +import unicodedata + +"""Docutils character category patterns. + + Patterns for the implementation of the `inline markup recognition rules`_ + in the reStructuredText parser `docutils.parsers.rst.states.py` based + on Unicode character categories. + The patterns are used inside ``[ ]`` in regular expressions. + + Rule (5) requires determination of matching open/close pairs. However, the + pairing of open/close quotes is ambiguous due to different typographic + conventions in different languages. The ``quote_pairs`` function tests + whether two characters form an open/close pair. + + The patterns are generated by + ``docutils/tools/dev/generate_punctuation_chars.py`` to prevent dependence + on the Python version and avoid the time-consuming generation with every + Docutils run. See there for motives and implementation details. + + The category of some characters changed with the development of the + Unicode standard. The current lists are generated with the help of the + "unicodedata" module of Python 2.7.13 (based on Unicode version 5.2.0). + + .. _inline markup recognition rules: + http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules +""" + +openers = (u'"\'(<\\[{\u0f3a\u0f3c\u169b\u2045\u207d\u208d\u2329\u2768' + u'\u276a\u276c\u276e\u2770\u2772\u2774\u27c5\u27e6\u27e8\u27ea' + u'\u27ec\u27ee\u2983\u2985\u2987\u2989\u298b\u298d\u298f\u2991' + u'\u2993\u2995\u2997\u29d8\u29da\u29fc\u2e22\u2e24\u2e26\u2e28' + u'\u3008\u300a\u300c\u300e\u3010\u3014\u3016\u3018\u301a\u301d' + u'\u301d\ufd3e\ufe17\ufe35\ufe37\ufe39\ufe3b\ufe3d\ufe3f\ufe41' + u'\ufe43\ufe47\ufe59\ufe5b\ufe5d\uff08\uff3b\uff5b\uff5f\uff62' + u'\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c\u2e1c\u2e20' + u'\u201a\u201e\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d' + u'\u2e1d\u2e21\u201b\u201f') +closers = (u'"\')>\\]}\u0f3b\u0f3d\u169c\u2046\u207e\u208e\u232a\u2769' + u'\u276b\u276d\u276f\u2771\u2773\u2775\u27c6\u27e7\u27e9\u27eb' + u'\u27ed\u27ef\u2984\u2986\u2988\u298a\u298c\u298e\u2990\u2992' + u'\u2994\u2996\u2998\u29d9\u29db\u29fd\u2e23\u2e25\u2e27\u2e29' + u'\u3009\u300b\u300d\u300f\u3011\u3015\u3017\u3019\u301b\u301e' + u'\u301f\ufd3f\ufe18\ufe36\ufe38\ufe3a\ufe3c\ufe3e\ufe40\ufe42' + u'\ufe44\ufe48\ufe5a\ufe5c\ufe5e\uff09\uff3d\uff5d\uff60\uff63' + u'\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d\u2e1d\u2e21' + u'\u201b\u201f\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c' + u'\u2e1c\u2e20\u201a\u201e') +delimiters = (u'\\-/:\u058a\xa1\xb7\xbf\u037e\u0387\u055a-\u055f\u0589' + u'\u05be\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c' + u'\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d' + u'\u07f7-\u07f9\u0830-\u083e\u0964\u0965\u0970\u0df4\u0e4f' + u'\u0e5a\u0e5b\u0f04-\u0f12\u0f85\u0fd0-\u0fd4\u104a-\u104f' + u'\u10fb\u1361-\u1368\u1400\u166d\u166e\u16eb-\u16ed\u1735' + u'\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944\u1945' + u'\u19de\u19df\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-' + u'\u1b60\u1c3b-\u1c3f\u1c7e\u1c7f\u1cd3\u2010-\u2017\u2020-' + u'\u2027\u2030-\u2038\u203b-\u203e\u2041-\u2043\u2047-' + u'\u2051\u2053\u2055-\u205e\u2cf9-\u2cfc\u2cfe\u2cff\u2e00' + u'\u2e01\u2e06-\u2e08\u2e0b\u2e0e-\u2e1b\u2e1e\u2e1f\u2e2a-' + u'\u2e2e\u2e30\u2e31\u3001-\u3003\u301c\u3030\u303d\u30a0' + u'\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7' + u'\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f' + u'\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uabeb' + u'\ufe10-\ufe16\ufe19\ufe30-\ufe32\ufe45\ufe46\ufe49-\ufe4c' + u'\ufe50-\ufe52\ufe54-\ufe58\ufe5f-\ufe61\ufe63\ufe68\ufe6a' + u'\ufe6b\uff01-\uff03\uff05-\uff07\uff0a\uff0c-\uff0f\uff1a' + u'\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65') +if sys.maxunicode >= 0x10FFFF: # "wide" build + delimiters += (u'\U00010100\U00010101\U0001039f\U000103d0\U00010857' + u'\U0001091f\U0001093f\U00010a50-\U00010a58\U00010a7f' + u'\U00010b39-\U00010b3f\U000110bb\U000110bc\U000110be-' + u'\U000110c1\U00012470-\U00012473') +closing_delimiters = u'\\\\.,;!?' + + +# Matching open/close quotes +# -------------------------- + +quote_pairs = {# open char: matching closing characters # usage example + u'\xbb': u'\xbb', # » » Swedish + u'\u2018': u'\u201a', # ‘ ‚ Albanian/Greek/Turkish + u'\u2019': u'\u2019', # ’ ’ Swedish + u'\u201a': u'\u2018\u2019', # ‚ ‘ German ‚ ’ Polish + u'\u201c': u'\u201e', # “ „ Albanian/Greek/Turkish + u'\u201e': u'\u201c\u201d', # „ “ German „ ” Polish + u'\u201d': u'\u201d', # ” ” Swedish + u'\u203a': u'\u203a', # › › Swedish + } +"""Additional open/close quote pairs.""" + +def match_chars(c1, c2): + """Test whether `c1` and `c2` are a matching open/close character pair. + + Matching open/close pairs are at the same position in + `punctuation_chars.openers` and `punctuation_chars.closers`. + The pairing of open/close quotes is ambiguous due to different + typographic conventions in different languages, + so we test for additional matches stored in `quote_pairs`. + """ + try: + i = openers.index(c1) + except ValueError: # c1 not in openers + return False + return c2 == closers[i] or c2 in quote_pairs.get(c1, u'') diff --git a/env/lib/python3.8/site-packages/docutils/utils/roman.py b/env/lib/python3.8/site-packages/docutils/utils/roman.py new file mode 100644 index 000000000..dce927fba --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/roman.py @@ -0,0 +1,82 @@ +"""Convert to and from Roman numerals""" + +__author__ = "Mark Pilgrim (f8dy@diveintopython.org)" +__version__ = "1.4" +__date__ = "8 August 2001" +__copyright__ = """Copyright (c) 2001 Mark Pilgrim + +This program is part of "Dive Into Python", a free Python tutorial for +experienced programmers. Visit http://diveintopython.org/ for the +latest version. + +This program is free software; you can redistribute it and/or modify +it under the terms of the Python 2.1.1 license, available at +http://www.python.org/2.1.1/license.html +""" + +import re + +#Define exceptions +class RomanError(Exception): pass +class OutOfRangeError(RomanError): pass +class NotIntegerError(RomanError): pass +class InvalidRomanNumeralError(RomanError): pass + +#Define digit mapping +romanNumeralMap = (('M', 1000), + ('CM', 900), + ('D', 500), + ('CD', 400), + ('C', 100), + ('XC', 90), + ('L', 50), + ('XL', 40), + ('X', 10), + ('IX', 9), + ('V', 5), + ('IV', 4), + ('I', 1)) + +def toRoman(n): + """convert integer to Roman numeral""" + if not (0 < n < 5000): + raise OutOfRangeError("number out of range (must be 1..4999)") + if int(n) != n: + raise NotIntegerError("decimals can not be converted") + + result = "" + for numeral, integer in romanNumeralMap: + while n >= integer: + result += numeral + n -= integer + return result + +#Define pattern to detect valid Roman numerals +romanNumeralPattern = re.compile(""" + ^ # beginning of string + M{0,4} # thousands - 0 to 4 M's + (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's), + # or 500-800 (D, followed by 0 to 3 C's) + (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's), + # or 50-80 (L, followed by 0 to 3 X's) + (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's), + # or 5-8 (V, followed by 0 to 3 I's) + $ # end of string + """, re.VERBOSE) + +def fromRoman(s): + """convert Roman numeral to integer""" + if not s: + raise InvalidRomanNumeralError('Input can not be blank') + + if not romanNumeralPattern.search(s): + raise InvalidRomanNumeralError('Invalid Roman numeral: %s' % s) + + result = 0 + index = 0 + for numeral, integer in romanNumeralMap: + while s[index:index+len(numeral)] == numeral: + result += integer + index += len(numeral) + return result + diff --git a/env/lib/python3.8/site-packages/docutils/utils/smartquotes.py b/env/lib/python3.8/site-packages/docutils/utils/smartquotes.py new file mode 100644 index 000000000..518ae09dc --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/smartquotes.py @@ -0,0 +1,1014 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# :Id: $Id: smartquotes.py 8376 2019-08-27 19:49:29Z milde $ +# :Copyright: © 2010 Günter Milde, +# original `SmartyPants`_: © 2003 John Gruber +# smartypants.py: © 2004, 2007 Chad Miller +# :Maintainer: docutils-develop@lists.sourceforge.net +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notices and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + + +r""" +========================= +Smart Quotes for Docutils +========================= + +Synopsis +======== + +"SmartyPants" is a free web publishing plug-in for Movable Type, Blosxom, and +BBEdit that easily translates plain ASCII punctuation characters into "smart" +typographic punctuation characters. + +``smartquotes.py`` is an adaption of "SmartyPants" to Docutils_. + +* Using Unicode instead of HTML entities for typographic punctuation + characters, it works for any output format that supports Unicode. +* Supports `language specific quote characters`__. + +__ http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks + + +Authors +======= + +`John Gruber`_ did all of the hard work of writing this software in Perl for +`Movable Type`_ and almost all of this useful documentation. `Chad Miller`_ +ported it to Python to use with Pyblosxom_. +Adapted to Docutils_ by Günter Milde. + +Additional Credits +================== + +Portions of the SmartyPants original work are based on Brad Choate's nifty +MTRegex plug-in. `Brad Choate`_ also contributed a few bits of source code to +this plug-in. Brad Choate is a fine hacker indeed. + +`Jeremy Hedley`_ and `Charles Wiltgen`_ deserve mention for exemplary beta +testing of the original SmartyPants. + +`Rael Dornfest`_ ported SmartyPants to Blosxom. + +.. _Brad Choate: http://bradchoate.com/ +.. _Jeremy Hedley: http://antipixel.com/ +.. _Charles Wiltgen: http://playbacktime.com/ +.. _Rael Dornfest: http://raelity.org/ + + +Copyright and License +===================== + +SmartyPants_ license (3-Clause BSD license): + + Copyright (c) 2003 John Gruber (http://daringfireball.net/) + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name "SmartyPants" 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 the copyright + owner 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. + +smartypants.py license (2-Clause BSD license): + + smartypants.py is a derivative work of SmartyPants. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + 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 the copyright + owner 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. + +.. _John Gruber: http://daringfireball.net/ +.. _Chad Miller: http://web.chad.org/ + +.. _Pyblosxom: http://pyblosxom.bluesock.org/ +.. _SmartyPants: http://daringfireball.net/projects/smartypants/ +.. _Movable Type: http://www.movabletype.org/ +.. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause +.. _Docutils: http://docutils.sf.net/ + +Description +=========== + +SmartyPants can perform the following transformations: + +- Straight quotes ( " and ' ) into "curly" quote characters +- Backticks-style quotes (\`\`like this'') into "curly" quote characters +- Dashes (``--`` and ``---``) into en- and em-dash entities +- Three consecutive dots (``...`` or ``. . .``) into an ellipsis entity + +This means you can write, edit, and save your posts using plain old +ASCII straight quotes, plain dashes, and plain dots, but your published +posts (and final HTML output) will appear with smart quotes, em-dashes, +and proper ellipses. + +SmartyPants does not modify characters within ``<pre>``, ``<code>``, ``<kbd>``, +``<math>`` or ``<script>`` tag blocks. Typically, these tags are used to +display text where smart quotes and other "smart punctuation" would not be +appropriate, such as source code or example markup. + + +Backslash Escapes +================= + +If you need to use literal straight quotes (or plain hyphens and periods), +`smartquotes` accepts the following backslash escape sequences to force +ASCII-punctuation. Mind, that you need two backslashes as Docutils expands it, +too. + +======== ========= +Escape Character +======== ========= +``\\`` \\ +``\\"`` \\" +``\\'`` \\' +``\\.`` \\. +``\\-`` \\- +``\\``` \\` +======== ========= + +This is useful, for example, when you want to use straight quotes as +foot and inch marks: 6\\'2\\" tall; a 17\\" iMac. + + +Caveats +======= + +Why You Might Not Want to Use Smart Quotes in Your Weblog +--------------------------------------------------------- + +For one thing, you might not care. + +Most normal, mentally stable individuals do not take notice of proper +typographic punctuation. Many design and typography nerds, however, break +out in a nasty rash when they encounter, say, a restaurant sign that uses +a straight apostrophe to spell "Joe's". + +If you're the sort of person who just doesn't care, you might well want to +continue not caring. Using straight quotes -- and sticking to the 7-bit +ASCII character set in general -- is certainly a simpler way to live. + +Even if you *do* care about accurate typography, you still might want to +think twice before educating the quote characters in your weblog. One side +effect of publishing curly quote characters is that it makes your +weblog a bit harder for others to quote from using copy-and-paste. What +happens is that when someone copies text from your blog, the copied text +contains the 8-bit curly quote characters (as well as the 8-bit characters +for em-dashes and ellipses, if you use these options). These characters +are not standard across different text encoding methods, which is why they +need to be encoded as characters. + +People copying text from your weblog, however, may not notice that you're +using curly quotes, and they'll go ahead and paste the unencoded 8-bit +characters copied from their browser into an email message or their own +weblog. When pasted as raw "smart quotes", these characters are likely to +get mangled beyond recognition. + +That said, my own opinion is that any decent text editor or email client +makes it easy to stupefy smart quote characters into their 7-bit +equivalents, and I don't consider it my problem if you're using an +indecent text editor or email client. + + +Algorithmic Shortcomings +------------------------ + +One situation in which quotes will get curled the wrong way is when +apostrophes are used at the start of leading contractions. For example:: + + 'Twas the night before Christmas. + +In the case above, SmartyPants will turn the apostrophe into an opening +single-quote, when in fact it should be the `right single quotation mark` +character which is also "the preferred character to use for apostrophe" +(Unicode). I don't think this problem can be solved in the general case -- +every word processor I've tried gets this wrong as well. In such cases, it's +best to use the proper character for closing single-quotes (’) by hand. + +In English, the same character is used for apostrophe and closing single +quote (both plain and "smart" ones). For other locales (French, Italean, +Swiss, ...) "smart" single closing quotes differ from the curly apostrophe. + + .. class:: language-fr + + Il dit : "C'est 'super' !" + +If the apostrophe is used at the end of a word, it cannot be distinguished +from a single quote by the algorithm. Therefore, a text like:: + + .. class:: language-de-CH + + "Er sagt: 'Ich fass' es nicht.'" + +will get a single closing guillemet instead of an apostrophe. + +This can be prevented by use use of the curly apostrophe character (’) in +the source:: + + - "Er sagt: 'Ich fass' es nicht.'" + + "Er sagt: 'Ich fass’ es nicht.'" + + +Version History +=============== + +1.8.1 2017-10-25 + - Use open quote after Unicode whitespace, ZWSP, and ZWNJ. + - Code cleanup. + +1.8: 2017-04-24 + - Command line front-end. + +1.7.1: 2017-03-19 + - Update and extend language-dependent quotes. + - Differentiate apostrophe from single quote. + +1.7: 2012-11-19 + - Internationalization: language-dependent quotes. + +1.6.1: 2012-11-06 + - Refactor code, code cleanup, + - `educate_tokens()` generator as interface for Docutils. + +1.6: 2010-08-26 + - Adaption to Docutils: + - Use Unicode instead of HTML entities, + - Remove code special to pyblosxom. + +1.5_1.6: Fri, 27 Jul 2007 07:06:40 -0400 + - Fixed bug where blocks of precious unalterable text was instead + interpreted. Thanks to Le Roux and Dirk van Oosterbosch. + +1.5_1.5: Sat, 13 Aug 2005 15:50:24 -0400 + - Fix bogus magical quotation when there is no hint that the + user wants it, e.g., in "21st century". Thanks to Nathan Hamblen. + - Be smarter about quotes before terminating numbers in an en-dash'ed + range. + +1.5_1.4: Thu, 10 Feb 2005 20:24:36 -0500 + - Fix a date-processing bug, as reported by jacob childress. + - Begin a test-suite for ensuring correct output. + - Removed import of "string", since I didn't really need it. + (This was my first every Python program. Sue me!) + +1.5_1.3: Wed, 15 Sep 2004 18:25:58 -0400 + - Abort processing if the flavour is in forbidden-list. Default of + [ "rss" ] (Idea of Wolfgang SCHNERRING.) + - Remove stray virgules from en-dashes. Patch by Wolfgang SCHNERRING. + +1.5_1.2: Mon, 24 May 2004 08:14:54 -0400 + - Some single quotes weren't replaced properly. Diff-tesuji played + by Benjamin GEIGER. + +1.5_1.1: Sun, 14 Mar 2004 14:38:28 -0500 + - Support upcoming pyblosxom 0.9 plugin verification feature. + +1.5_1.0: Tue, 09 Mar 2004 08:08:35 -0500 + - Initial release +""" +from __future__ import print_function + +options = r""" +Options +======= + +Numeric values are the easiest way to configure SmartyPants' behavior: + +:0: Suppress all transformations. (Do nothing.) + +:1: Performs default SmartyPants transformations: quotes (including + \`\`backticks'' -style), em-dashes, and ellipses. "``--``" (dash dash) + is used to signify an em-dash; there is no support for en-dashes + +:2: Same as smarty_pants="1", except that it uses the old-school typewriter + shorthand for dashes: "``--``" (dash dash) for en-dashes, "``---``" + (dash dash dash) + for em-dashes. + +:3: Same as smarty_pants="2", but inverts the shorthand for dashes: + "``--``" (dash dash) for em-dashes, and "``---``" (dash dash dash) for + en-dashes. + +:-1: Stupefy mode. Reverses the SmartyPants transformation process, turning + the characters produced by SmartyPants into their ASCII equivalents. + E.g. the LEFT DOUBLE QUOTATION MARK (“) is turned into a simple + double-quote (\"), "—" is turned into two dashes, etc. + + +The following single-character attribute values can be combined to toggle +individual transformations from within the smarty_pants attribute. For +example, ``"1"`` is equivalent to ``"qBde"``. + +:q: Educates normal quote characters: (") and ('). + +:b: Educates \`\`backticks'' -style double quotes. + +:B: Educates \`\`backticks'' -style double quotes and \`single' quotes. + +:d: Educates em-dashes. + +:D: Educates em-dashes and en-dashes, using old-school typewriter shorthand: + (dash dash) for en-dashes, (dash dash dash) for em-dashes. + +:i: Educates em-dashes and en-dashes, using inverted old-school typewriter + shorthand: (dash dash) for em-dashes, (dash dash dash) for en-dashes. + +:e: Educates ellipses. + +:w: Translates any instance of ``"`` into a normal double-quote character. + This should be of no interest to most people, but of particular interest + to anyone who writes their posts using Dreamweaver, as Dreamweaver + inexplicably uses this entity to represent a literal double-quote + character. SmartyPants only educates normal quotes, not entities (because + ordinarily, entities are used for the explicit purpose of representing the + specific character they represent). The "w" option must be used in + conjunction with one (or both) of the other quote options ("q" or "b"). + Thus, if you wish to apply all SmartyPants transformations (quotes, en- + and em-dashes, and ellipses) and also translate ``"`` entities into + regular quotes so SmartyPants can educate them, you should pass the + following to the smarty_pants attribute: +""" + + +default_smartypants_attr = "1" + + +import re, sys + +class smartchars(object): + """Smart quotes and dashes + """ + + endash = u'–' # "–" EN DASH + emdash = u'—' # "—" EM DASH + ellipsis = u'…' # "…" HORIZONTAL ELLIPSIS + apostrophe = u'’' # "’" RIGHT SINGLE QUOTATION MARK + + # quote characters (language-specific, set in __init__()) + # [1] http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks + # [2] http://de.wikipedia.org/wiki/Anf%C3%BChrungszeichen#Andere_Sprachen + # [3] https://fr.wikipedia.org/wiki/Guillemet + # [4] http://typographisme.net/post/Les-espaces-typographiques-et-le-web + # [5] http://www.btb.termiumplus.gc.ca/tpv2guides/guides/redac/index-fra.html + # [6] https://en.wikipedia.org/wiki/Hebrew_punctuation#Quotation_marks + # [7] http://www.tustep.uni-tuebingen.de/bi/bi00/bi001t1-anfuehrung.pdf + # [8] http://www.korrekturavdelingen.no/anforselstegn.htm + # [9] Typografisk håndbok. Oslo: Spartacus. 2000. s. 67. ISBN 8243001530. + # [10] http://www.typografi.org/sitat/sitatart.html + # + # See also configuration option "smartquote-locales". + quotes = {'af': u'“”‘’', + 'af-x-altquot': u'„”‚’', + 'bg': u'„“‚‘', # Bulgarian, https://bg.wikipedia.org/wiki/Кавички + 'ca': u'«»“”', + 'ca-x-altquot': u'“”‘’', + 'cs': u'„“‚‘', + 'cs-x-altquot': u'»«›‹', + 'da': u'»«›‹', + 'da-x-altquot': u'„“‚‘', + # 'da-x-altquot2': u'””’’', + 'de': u'„“‚‘', + 'de-x-altquot': u'»«›‹', + 'de-ch': u'«»‹›', + 'el': u'«»“”', + 'en': u'“”‘’', + 'en-uk-x-altquot': u'‘’“”', # Attention: " → ‘ and ' → “ ! + 'eo': u'“”‘’', + 'es': u'«»“”', + 'es-x-altquot': u'“”‘’', + 'et': u'„“‚‘', # no secondary quote listed in + 'et-x-altquot': u'«»‹›', # the sources above (wikipedia.org) + 'eu': u'«»‹›', + 'fi': u'””’’', + 'fi-x-altquot': u'»»››', + 'fr': (u'« ', u' »', u'“', u'”'), # full no-break space + 'fr-x-altquot': (u'« ', u' »', u'“', u'”'), # narrow no-break space + 'fr-ch': u'«»‹›', + 'fr-ch-x-altquot': (u'« ', u' »', u'‹ ', u' ›'), # narrow no-break space, http://typoguide.ch/ + 'gl': u'«»“”', + 'he': u'”“»«', # Hebrew is RTL, test position: + 'he-x-altquot': u'„”‚’', # low quotation marks are opening. + # 'he-x-altquot': u'“„‘‚', # RTL: low quotation marks opening + 'hr': u'„”‘’', # http://hrvatska-tipografija.com/polunavodnici/ + 'hr-x-altquot': u'»«›‹', + 'hsb': u'„“‚‘', + 'hsb-x-altquot': u'»«›‹', + 'hu': u'„”«»', + 'is': u'„“‚‘', + 'it': u'«»“”', + 'it-ch': u'«»‹›', + 'it-x-altquot': u'“”‘’', + # 'it-x-altquot2': u'“„‘‚', # [7] in headlines + 'ja': u'「」『』', + 'ko': u'《》〈〉', + 'lt': u'„“‚‘', + 'lv': u'„“‚‘', + 'mk': u'„“‚‘', # Macedonian, https://mk.wikipedia.org/wiki/Правопис_и_правоговор_на_македонскиот_јазик + 'nl': u'“”‘’', + 'nl-x-altquot': u'„”‚’', + # 'nl-x-altquot2': u'””’’', + 'nb': u'«»’’', # Norsk bokmål (canonical form 'no') + 'nn': u'«»’’', # Nynorsk [10] + 'nn-x-altquot': u'«»‘’', # [8], [10] + # 'nn-x-altquot2': u'«»«»', # [9], [10 + # 'nn-x-altquot3': u'„“‚‘', # [10] + 'no': u'«»’’', # Norsk bokmål [10] + 'no-x-altquot': u'«»‘’', # [8], [10] + # 'no-x-altquot2': u'«»«»', # [9], [10 + # 'no-x-altquot3': u'„“‚‘', # [10] + 'pl': u'„”«»', + 'pl-x-altquot': u'«»‚’', + # 'pl-x-altquot2': u'„”‚’', # https://pl.wikipedia.org/wiki/Cudzys%C5%82%C3%B3w + 'pt': u'«»“”', + 'pt-br': u'“”‘’', + 'ro': u'„”«»', + 'ru': u'«»„“', + 'sh': u'„”‚’', # Serbo-Croatian + 'sh-x-altquot': u'»«›‹', + 'sk': u'„“‚‘', # Slovak + 'sk-x-altquot': u'»«›‹', + 'sl': u'„“‚‘', # Slovenian + 'sl-x-altquot': u'»«›‹', + 'sq': u'«»‹›', # Albanian + 'sq-x-altquot': u'“„‘‚', + 'sr': u'„”’’', + 'sr-x-altquot': u'»«›‹', + 'sv': u'””’’', + 'sv-x-altquot': u'»»››', + 'tr': u'“”‘’', + 'tr-x-altquot': u'«»‹›', + # 'tr-x-altquot2': u'“„‘‚', # [7] antiquated? + 'uk': u'«»„“', + 'uk-x-altquot': u'„“‚‘', + 'zh-cn': u'“”‘’', + 'zh-tw': u'「」『』', + } + + def __init__(self, language='en'): + self.language = language + try: + (self.opquote, self.cpquote, + self.osquote, self.csquote) = self.quotes[language.lower()] + except KeyError: + self.opquote, self.cpquote, self.osquote, self.csquote = u'""\'\'' + + +def smartyPants(text, attr=default_smartypants_attr, language='en'): + """Main function for "traditional" use.""" + + return "".join([t for t in educate_tokens(tokenize(text), + attr, language)]) + + +def educate_tokens(text_tokens, attr=default_smartypants_attr, language='en'): + """Return iterator that "educates" the items of `text_tokens`. + """ + + # Parse attributes: + # 0 : do nothing + # 1 : set all + # 2 : set all, using old school en- and em- dash shortcuts + # 3 : set all, using inverted old school en and em- dash shortcuts + # + # q : quotes + # b : backtick quotes (``double'' only) + # B : backtick quotes (``double'' and `single') + # d : dashes + # D : old school dashes + # i : inverted old school dashes + # e : ellipses + # w : convert " entities to " for Dreamweaver users + + convert_quot = False # translate " entities into normal quotes? + do_dashes = False + do_backticks = False + do_quotes = False + do_ellipses = False + do_stupefy = False + + # if attr == "0": # pass tokens unchanged (see below). + if attr == "1": # Do everything, turn all options on. + do_quotes = True + do_backticks = True + do_dashes = 1 + do_ellipses = True + elif attr == "2": + # Do everything, turn all options on, use old school dash shorthand. + do_quotes = True + do_backticks = True + do_dashes = 2 + do_ellipses = True + elif attr == "3": + # Do everything, use inverted old school dash shorthand. + do_quotes = True + do_backticks = True + do_dashes = 3 + do_ellipses = True + elif attr == "-1": # Special "stupefy" mode. + do_stupefy = True + else: + if "q" in attr: do_quotes = True + if "b" in attr: do_backticks = True + if "B" in attr: do_backticks = 2 + if "d" in attr: do_dashes = 1 + if "D" in attr: do_dashes = 2 + if "i" in attr: do_dashes = 3 + if "e" in attr: do_ellipses = True + if "w" in attr: convert_quot = True + + prev_token_last_char = " " + # Last character of the previous text token. Used as + # context to curl leading quote characters correctly. + + for (ttype, text) in text_tokens: + + # skip HTML and/or XML tags as well as emtpy text tokens + # without updating the last character + if ttype == 'tag' or not text: + yield text + continue + + # skip literal text (math, literal, raw, ...) + if ttype == 'literal': + prev_token_last_char = text[-1:] + yield text + continue + + last_char = text[-1:] # Remember last char before processing. + + text = processEscapes(text) + + if convert_quot: + text = re.sub('"', '"', text) + + if do_dashes == 1: + text = educateDashes(text) + elif do_dashes == 2: + text = educateDashesOldSchool(text) + elif do_dashes == 3: + text = educateDashesOldSchoolInverted(text) + + if do_ellipses: + text = educateEllipses(text) + + # Note: backticks need to be processed before quotes. + if do_backticks: + text = educateBackticks(text, language) + + if do_backticks == 2: + text = educateSingleBackticks(text, language) + + if do_quotes: + # Replace plain quotes in context to prevent converstion to + # 2-character sequence in French. + context = prev_token_last_char.replace('"', ';').replace("'", ';') + text = educateQuotes(context+text, language)[1:] + + if do_stupefy: + text = stupefyEntities(text, language) + + # Remember last char as context for the next token + prev_token_last_char = last_char + + text = processEscapes(text, restore=True) + + yield text + + + +def educateQuotes(text, language='en'): + """ + Parameter: - text string (unicode or bytes). + - language (`BCP 47` language tag.) + Returns: The `text`, with "educated" curly quote characters. + + Example input: "Isn't this fun?" + Example output: “Isn’t this fun?“; + """ + + smart = smartchars(language) + + punct_class = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]""" + close_class = r"""[^\ \t\r\n\[\{\(\-]""" + open_class = u'[\u200B\u200C]' # ZWSP, ZWNJ + dec_dashes = r"""–|—""" + + # Special case if the very first character is a quote + # followed by punctuation at a non-word-break. + # Close the quotes by brute force: + text = re.sub(r"^'(?=%s\\B)" % (punct_class,), smart.csquote, text) + text = re.sub(r'^"(?=%s\\B)' % (punct_class,), smart.cpquote, text) + + # Special case for double sets of quotes, e.g.: + # <p>He said, "'Quoted' words in a larger quote."</p> + text = re.sub(r""""'(?=\w)""", smart.opquote+smart.osquote, text) + text = re.sub(r"""'"(?=\w)""", smart.osquote+smart.opquote, text) + + # Special case for decade abbreviations (the '80s): + if language.startswith('en'): # TODO similar cases in other languages? + text = re.sub(r"'(?=\d{2}s)", smart.apostrophe, text) + + # Get most opening single quotes: + opening_single_quotes_regex = re.compile(u""" + (# ?<= # look behind fails: requires fixed-width pattern + \\s | # a whitespace char, or + %s | # another separating char, or +   | # a non-breaking space entity, or + [\u2013 \u2014 ] | # literal dashes, or + -- | # dumb dashes, or + &[mn]dash; | # dash entities (named or + %s | # decimal or + &\\#x201[34]; # hex) + ) + ' # the quote + (?=\\w) # followed by a word character + """ % (open_class, dec_dashes), re.VERBOSE | re.UNICODE) + + text = opening_single_quotes_regex.sub(r'\1'+smart.osquote, text) + + # In many locales, single closing quotes are different from apostrophe: + if smart.csquote != smart.apostrophe: + apostrophe_regex = re.compile(r"(?<=(\w|\d))'(?=\w)", re.UNICODE) + text = apostrophe_regex.sub(smart.apostrophe, text) + # TODO: keep track of quoting level to recognize apostrophe in, e.g., + # "Ich fass' es nicht." + + closing_single_quotes_regex = re.compile(r""" + (?<=%s) + ' + """ % close_class, re.VERBOSE) + text = closing_single_quotes_regex.sub(smart.csquote, text) + + # Any remaining single quotes should be opening ones: + text = re.sub(r"""'""", smart.osquote, text) + + # Get most opening double quotes: + opening_double_quotes_regex = re.compile(u""" + ( + \\s | # a whitespace char, or + %s | # another separating char, or +   | # a non-breaking space entity, or + [\u2013 \u2014 ] | # literal dashes, or + -- | # dumb dashes, or + &[mn]dash; | # dash entities (named or + %s | # decimal or + &\\#x201[34]; # hex) + ) + " # the quote + (?=\\w) # followed by a word character + """ % (open_class, dec_dashes), re.VERBOSE | re.UNICODE) + + text = opening_double_quotes_regex.sub(r'\1'+smart.opquote, text) + + # Double closing quotes: + closing_double_quotes_regex = re.compile(r""" + ( + (?<=%s)" | # char indicating the quote should be closing + "(?=\s) # whitespace behind + ) + """ % (close_class,), re.VERBOSE | re.UNICODE) + text = closing_double_quotes_regex.sub(smart.cpquote, text) + + # Any remaining quotes should be opening ones. + text = re.sub(r'"', smart.opquote, text) + + return text + + +def educateBackticks(text, language='en'): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with ``backticks'' -style double quotes + translated into HTML curly quote entities. + Example input: ``Isn't this fun?'' + Example output: “Isn't this fun?“; + """ + smart = smartchars(language) + + text = re.sub(r"""``""", smart.opquote, text) + text = re.sub(r"""''""", smart.cpquote, text) + return text + + +def educateSingleBackticks(text, language='en'): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with `backticks' -style single quotes + translated into HTML curly quote entities. + + Example input: `Isn't this fun?' + Example output: ‘Isn’t this fun?’ + """ + smart = smartchars(language) + + text = re.sub(r"""`""", smart.osquote, text) + text = re.sub(r"""'""", smart.csquote, text) + return text + + +def educateDashes(text): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with each instance of "--" translated to + an em-dash character. + """ + + text = re.sub(r"""---""", smartchars.endash, text) # en (yes, backwards) + text = re.sub(r"""--""", smartchars.emdash, text) # em (yes, backwards) + return text + + +def educateDashesOldSchool(text): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with each instance of "--" translated to + an en-dash character, and each "---" translated to + an em-dash character. + """ + + text = re.sub(r"""---""", smartchars.emdash, text) + text = re.sub(r"""--""", smartchars.endash, text) + return text + + +def educateDashesOldSchoolInverted(text): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with each instance of "--" translated to + an em-dash character, and each "---" translated to + an en-dash character. Two reasons why: First, unlike the + en- and em-dash syntax supported by + EducateDashesOldSchool(), it's compatible with existing + entries written before SmartyPants 1.1, back when "--" was + only used for em-dashes. Second, em-dashes are more + common than en-dashes, and so it sort of makes sense that + the shortcut should be shorter to type. (Thanks to Aaron + Swartz for the idea.) + """ + text = re.sub(r"""---""", smartchars.endash, text) # em + text = re.sub(r"""--""", smartchars.emdash, text) # en + return text + + + +def educateEllipses(text): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with each instance of "..." translated to + an ellipsis character. + + Example input: Huh...? + Example output: Huh…? + """ + + text = re.sub(r"""\.\.\.""", smartchars.ellipsis, text) + text = re.sub(r"""\. \. \.""", smartchars.ellipsis, text) + return text + + +def stupefyEntities(text, language='en'): + """ + Parameter: String (unicode or bytes). + Returns: The `text`, with each SmartyPants character translated to + its ASCII counterpart. + + Example input: “Hello — world.” + Example output: "Hello -- world." + """ + smart = smartchars(language) + + text = re.sub(smart.endash, "-", text) # en-dash + text = re.sub(smart.emdash, "--", text) # em-dash + + text = re.sub(smart.osquote, "'", text) # open single quote + text = re.sub(smart.csquote, "'", text) # close single quote + + text = re.sub(smart.opquote, '"', text) # open double quote + text = re.sub(smart.cpquote, '"', text) # close double quote + + text = re.sub(smart.ellipsis, '...', text)# ellipsis + + return text + + +def processEscapes(text, restore=False): + r""" + Parameter: String (unicode or bytes). + Returns: The `text`, with after processing the following backslash + escape sequences. This is useful if you want to force a "dumb" + quote or other character to appear. + + Escape Value + ------ ----- + \\ \ + \" " + \' ' + \. . + \- - + \` ` + """ + replacements = ((r'\\', r'\'), + (r'\"', r'"'), + (r"\'", r'''), + (r'\.', r'.'), + (r'\-', r'-'), + (r'\`', r'`')) + if restore: + for (ch, rep) in replacements: + text = text.replace(rep, ch[1]) + else: + for (ch, rep) in replacements: + text = text.replace(ch, rep) + + return text + + +def tokenize(text): + """ + Parameter: String containing HTML markup. + Returns: An iterator that yields the tokens comprising the input + string. Each token is either a tag (possibly with nested, + tags contained therein, such as <a href="http://github.com/%3CMTFoo%3E">, or a + run of text between tags. Each yielded element is a + two-element tuple; the first is either 'tag' or 'text'; + the second is the actual value. + + Based on the _tokenize() subroutine from Brad Choate's MTRegex plugin. + <http://www.bradchoate.com/past/mtregex.php> + """ + + pos = 0 + length = len(text) + # tokens = [] + + depth = 6 + nested_tags = "|".join(['(?:<(?:[^<>]',] * depth) + (')*>)' * depth) + #match = r"""(?: <! ( -- .*? -- \s* )+ > ) | # comments + # (?: <\? .*? \?> ) | # directives + # %s # nested tags """ % (nested_tags,) + tag_soup = re.compile(r"""([^<]*)(<[^>]*>)""") + + token_match = tag_soup.search(text) + + previous_end = 0 + while token_match is not None: + if token_match.group(1): + yield ('text', token_match.group(1)) + + yield ('tag', token_match.group(2)) + + previous_end = token_match.end() + token_match = tag_soup.search(text, token_match.end()) + + if previous_end < len(text): + yield ('text', text[previous_end:]) + + + +if __name__ == "__main__": + + import itertools + try: + import locale # module missing in Jython + locale.setlocale(locale.LC_ALL, '') # set to user defaults + defaultlanguage = locale.getdefaultlocale()[0] + except: + defaultlanguage = 'en' + + # Normalize and drop unsupported subtags: + defaultlanguage = defaultlanguage.lower().replace('-', '_') + # split (except singletons, which mark the following tag as non-standard): + defaultlanguage = re.sub(r'_([a-zA-Z0-9])_', r'_\1-', defaultlanguage) + _subtags = [subtag for subtag in defaultlanguage.split('_')] + _basetag = _subtags.pop(0) + # find all combinations of subtags + for n in range(len(_subtags), 0, -1): + for tags in itertools.combinations(_subtags, n): + _tag = '-'.join((_basetag,)+tags) + if _tag in smartchars.quotes: + defaultlanguage = _tag + break + else: + if _basetag in smartchars.quotes: + defaultlanguage = _basetag + else: + defaultlanguage = 'en' + + + import argparse + parser = argparse.ArgumentParser( + description='Filter stdin making ASCII punctuation "smart".') + # parser.add_argument("text", help="text to be acted on") + parser.add_argument("-a", "--action", default="1", + help="what to do with the input (see --actionhelp)") + parser.add_argument("-e", "--encoding", default="utf8", + help="text encoding") + parser.add_argument("-l", "--language", default=defaultlanguage, + help="text language (BCP47 tag), " + "Default: %s"% defaultlanguage) + parser.add_argument("-q", "--alternative-quotes", action="http://github.com/store_true", + help="use alternative quote style") + parser.add_argument("--doc", action="http://github.com/store_true", + help="print documentation") + parser.add_argument("--actionhelp", action="http://github.com/store_true", + help="list available actions") + parser.add_argument("--stylehelp", action="http://github.com/store_true", + help="list available quote styles") + parser.add_argument("--test", action="http://github.com/store_true", + help="perform short self-test") + args = parser.parse_args() + + if args.doc: + print(__doc__) + elif args.actionhelp: + print(options) + elif args.stylehelp: + print() + print("Available styles (primary open/close, secondary open/close)") + print("language tag quotes") + print("============ ======") + for key in sorted(smartchars.quotes.keys()): + print("%-14s %s" % (key, smartchars.quotes[key])) + elif args.test: + # Unit test output goes to stderr. + import unittest + + class TestSmartypantsAllAttributes(unittest.TestCase): + # the default attribute is "1", which means "all". + def test_dates(self): + self.assertEqual(smartyPants("1440-80's"), u"1440-80’s") + self.assertEqual(smartyPants("1440-'80s"), u"1440-’80s") + self.assertEqual(smartyPants("1440---'80s"), u"1440–’80s") + self.assertEqual(smartyPants("1960's"), u"1960’s") + self.assertEqual(smartyPants("one two '60s"), u"one two ’60s") + self.assertEqual(smartyPants("'60s"), u"’60s") + + def test_educated_quotes(self): + self.assertEqual(smartyPants('"Isn\'t this fun?"'), u'“Isn’t this fun?”') + + def test_html_tags(self): + text = '<a src="http://github.com/foo">more</a>' + self.assertEqual(smartyPants(text), text) + + suite = unittest.TestLoader().loadTestsFromTestCase( + TestSmartypantsAllAttributes) + unittest.TextTestRunner().run(suite) + + else: + if args.alternative_quotes: + if '-x-altquot' in args.language: + args.language = args.language.replace('-x-altquot', '') + else: + args.language += '-x-altquot' + text = sys.stdin.read().decode(args.encoding) + print(smartyPants(text, attr=args.action, + language=args.language).encode(args.encoding)) diff --git a/env/lib/python3.8/site-packages/docutils/utils/urischemes.py b/env/lib/python3.8/site-packages/docutils/utils/urischemes.py new file mode 100644 index 000000000..d9309eded --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/utils/urischemes.py @@ -0,0 +1,136 @@ +# $Id: urischemes.py 8376 2019-08-27 19:49:29Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +`schemes` is a dictionary with lowercase URI addressing schemes as +keys and descriptions as values. It was compiled from the index at +http://www.iana.org/assignments/uri-schemes (revised 2005-11-28) +and an older list at http://www.w3.org/Addressing/schemes.html. +""" + +# Many values are blank and should be filled in with useful descriptions. + +schemes = { + 'about': 'provides information on Navigator', + 'acap': 'Application Configuration Access Protocol; RFC 2244', + 'addbook': "To add vCard entries to Communicator's Address Book", + 'afp': 'Apple Filing Protocol', + 'afs': 'Andrew File System global file names', + 'aim': 'AOL Instant Messenger', + 'callto': 'for NetMeeting links', + 'castanet': 'Castanet Tuner URLs for Netcaster', + 'chttp': 'cached HTTP supported by RealPlayer', + 'cid': 'content identifier; RFC 2392', + 'crid': 'TV-Anytime Content Reference Identifier; RFC 4078', + 'data': ('allows inclusion of small data items as "immediate" data; ' + 'RFC 2397'), + 'dav': 'Distributed Authoring and Versioning Protocol; RFC 2518', + 'dict': 'dictionary service protocol; RFC 2229', + 'dns': 'Domain Name System resources', + 'eid': ('External ID; non-URL data; general escape mechanism to allow ' + 'access to information for applications that are too ' + 'specialized to justify their own schemes'), + 'fax': ('a connection to a terminal that can handle telefaxes ' + '(facsimiles); RFC 2806'), + 'feed': 'NetNewsWire feed', + 'file': 'Host-specific file names; RFC 1738', + 'finger': '', + 'freenet': '', + 'ftp': 'File Transfer Protocol; RFC 1738', + 'go': 'go; RFC 3368', + 'gopher': 'The Gopher Protocol', + 'gsm-sms': ('Global System for Mobile Communications Short Message ' + 'Service'), + 'h323': ('video (audiovisual) communication on local area networks; ' + 'RFC 3508'), + 'h324': ('video and audio communications over low bitrate connections ' + 'such as POTS modem connections'), + 'hdl': 'CNRI handle system', + 'hnews': 'an HTTP-tunneling variant of the NNTP news protocol', + 'http': 'Hypertext Transfer Protocol; RFC 2616', + 'https': 'HTTP over SSL; RFC 2818', + 'hydra': 'SubEthaEdit URI. See http://www.codingmonkeys.de/subethaedit.', + 'iioploc': 'Internet Inter-ORB Protocol Location?', + 'ilu': 'Inter-Language Unification', + 'im': 'Instant Messaging; RFC 3860', + 'imap': 'Internet Message Access Protocol; RFC 2192', + 'info': 'Information Assets with Identifiers in Public Namespaces', + 'ior': 'CORBA interoperable object reference', + 'ipp': 'Internet Printing Protocol; RFC 3510', + 'irc': 'Internet Relay Chat', + 'iris.beep': 'iris.beep; RFC 3983', + 'iseek': 'See www.ambrosiasw.com; a little util for OS X.', + 'jar': 'Java archive', + 'javascript': ('JavaScript code; evaluates the expression after the ' + 'colon'), + 'jdbc': 'JDBC connection URI.', + 'ldap': 'Lightweight Directory Access Protocol', + 'lifn': '', + 'livescript': '', + 'lrq': '', + 'mailbox': 'Mail folder access', + 'mailserver': 'Access to data available from mail servers', + 'mailto': 'Electronic mail address; RFC 2368', + 'md5': '', + 'mid': 'message identifier; RFC 2392', + 'mocha': '', + 'modem': ('a connection to a terminal that can handle incoming data ' + 'calls; RFC 2806'), + 'mtqp': 'Message Tracking Query Protocol; RFC 3887', + 'mupdate': 'Mailbox Update (MUPDATE) Protocol; RFC 3656', + 'news': 'USENET news; RFC 1738', + 'nfs': 'Network File System protocol; RFC 2224', + 'nntp': 'USENET news using NNTP access; RFC 1738', + 'opaquelocktoken': 'RFC 2518', + 'phone': '', + 'pop': 'Post Office Protocol; RFC 2384', + 'pop3': 'Post Office Protocol v3', + 'pres': 'Presence; RFC 3859', + 'printer': '', + 'prospero': 'Prospero Directory Service; RFC 4157', + 'rdar': ('URLs found in Darwin source ' + '(http://www.opensource.apple.com/darwinsource/).'), + 'res': '', + 'rtsp': 'real time streaming protocol; RFC 2326', + 'rvp': '', + 'rwhois': '', + 'rx': 'Remote Execution', + 'sdp': '', + 'service': 'service location; RFC 2609', + 'shttp': 'secure hypertext transfer protocol', + 'sip': 'Session Initiation Protocol; RFC 3261', + 'sips': 'secure session intitiaion protocol; RFC 3261', + 'smb': 'SAMBA filesystems.', + 'snews': 'For NNTP postings via SSL', + 'snmp': 'Simple Network Management Protocol; RFC 4088', + 'soap.beep': 'RFC 3288', + 'soap.beeps': 'RFC 3288', + 'ssh': 'Reference to interactive sessions via ssh.', + 't120': 'real time data conferencing (audiographics)', + 'tag': 'RFC 4151', + 'tcp': '', + 'tel': ('a connection to a terminal that handles normal voice ' + 'telephone calls, a voice mailbox or another voice messaging ' + 'system or a service that can be operated using DTMF tones; ' + 'RFC 3966.'), + 'telephone': 'telephone', + 'telnet': 'Reference to interactive sessions; RFC 4248', + 'tftp': 'Trivial File Transfer Protocol; RFC 3617', + 'tip': 'Transaction Internet Protocol; RFC 2371', + 'tn3270': 'Interactive 3270 emulation sessions', + 'tv': '', + 'urn': 'Uniform Resource Name; RFC 2141', + 'uuid': '', + 'vemmi': 'versatile multimedia interface; RFC 2122', + 'videotex': '', + 'view-source': 'displays HTML code that was generated with JavaScript', + 'wais': 'Wide Area Information Servers; RFC 4156', + 'whodp': '', + 'whois++': 'Distributed directory service.', + 'x-man-page': ('Opens man page in Terminal.app on OS X ' + '(see macosxhints.com)'), + 'xmlrpc.beep': 'RFC 3529', + 'xmlrpc.beeps': 'RFC 3529', + 'z39.50r': 'Z39.50 Retrieval; RFC 2056', + 'z39.50s': 'Z39.50 Session; RFC 2056',} diff --git a/env/lib/python3.8/site-packages/docutils/writers/__init__.py b/env/lib/python3.8/site-packages/docutils/writers/__init__.py new file mode 100644 index 000000000..a29bd8ca4 --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/writers/__init__.py @@ -0,0 +1,143 @@ +# $Id: __init__.py 8239 2018-11-21 21:46:00Z milde $ +# Author: David Goodger <goodger@python.org> +# Copyright: This module has been placed in the public domain. + +""" +This package contains Docutils Writer modules. +""" + +__docformat__ = 'reStructuredText' + +import os.path +import sys + +import docutils +from docutils import languages, Component +from docutils.transforms import universal + + +class Writer(Component): + + """ + Abstract base class for docutils Writers. + + Each writer module or package must export a subclass also called 'Writer'. + Each writer must support all standard node types listed in + `docutils.nodes.node_class_names`. + + The `write()` method is the main entry point. + """ + + component_type = 'writer' + config_section = 'writers' + + def get_transforms(self): + return Component.get_transforms(self) + [ + universal.Messages, + universal.FilterMessages, + universal.StripClassesAndElements,] + + document = None + """The document to write (Docutils doctree); set by `write`.""" + + output = None + """Final translated form of `document` (Unicode string for text, binary + string for other forms); set by `translate`.""" + + language = None + """Language module for the document; set by `write`.""" + + destination = None + """`docutils.io` Output object; where to write the document. + Set by `write`.""" + + def __init__(self): + + # Used by HTML and LaTeX writer for output fragments: + self.parts = {} + """Mapping of document part names to fragments of `self.output`. + Values are Unicode strings; encoding is up to the client. The 'whole' + key should contain the entire document output. + """ + + def write(self, document, destination): + """ + Process a document into its final form. + + Translate `document` (a Docutils document tree) into the Writer's + native format, and write it out to its `destination` (a + `docutils.io.Output` subclass object). + + Normally not overridden or extended in subclasses. + """ + self.document = document + self.language = languages.get_language( + document.settings.language_code, + document.reporter) + self.destination = destination + self.translate() + output = self.destination.write(self.output) + return output + + def translate(self): + """ + Do final translation of `self.document` into `self.output`. Called + from `write`. Override in subclasses. + + Usually done with a `docutils.nodes.NodeVisitor` subclass, in + combination with a call to `docutils.nodes.Node.walk()` or + `docutils.nodes.Node.walkabout()`. The ``NodeVisitor`` subclass must + support all standard elements (listed in + `docutils.nodes.node_class_names`) and possibly non-standard elements + used by the current Reader as well. + """ + raise NotImplementedError('subclass must override this method') + + def assemble_parts(self): + """Assemble the `self.parts` dictionary. Extend in subclasses.""" + self.parts['whole'] = self.output + self.parts['encoding'] = self.document.settings.output_encoding + self.parts['version'] = docutils.__version__ + + +class UnfilteredWriter(Writer): + + """ + A writer that passes the document tree on unchanged (e.g. a + serializer.) + + Documents written by UnfilteredWriters are typically reused at a + later date using a subclass of `readers.ReReader`. + """ + + def get_transforms(self): + # Do not add any transforms. When the document is reused + # later, the then-used writer will add the appropriate + # transforms. + return Component.get_transforms(self) + + +_writer_aliases = { + 'html': 'html4css1', # may change to html5 some day + 'html4': 'html4css1', + 'html5': 'html5_polyglot', + 'latex': 'latex2e', + 'pprint': 'pseudoxml', + 'pformat': 'pseudoxml', + 'pdf': 'rlpdf', + 's5': 's5_html', + 'xelatex': 'xetex', + 'xhtml': 'html5_polyglot', + 'xhtml10': 'html4css1', + 'xml': 'docutils_xml'} + +def get_writer_class(writer_name): + """Return the Writer class from the `writer_name` module.""" + writer_name = writer_name.lower() + if writer_name in _writer_aliases: + writer_name = _writer_aliases[writer_name] + try: + module = __import__(writer_name, globals(), locals(), level=1) + except ImportError: + module = __import__(writer_name, globals(), locals(), level=0) + return module.Writer diff --git a/env/lib/python3.8/site-packages/docutils/writers/_html_base.py b/env/lib/python3.8/site-packages/docutils/writers/_html_base.py new file mode 100644 index 000000000..c58aef78e --- /dev/null +++ b/env/lib/python3.8/site-packages/docutils/writers/_html_base.py @@ -0,0 +1,1670 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# :Author: David Goodger, Günter Milde +# Based on the html4css1 writer by David Goodger. +# :Maintainer: docutils-develop@lists.sourceforge.net +# :Revision: $Revision: 8412 $ +# :Date: $Date: 2005-06-28$ +# :Copyright: © 2016 David Goodger, Günter Milde +# :License: Released under the terms of the `2-Clause BSD license`_, in short: +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +# This file is offered as-is, without any warranty. +# +# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause + +"""common definitions for Docutils HTML writers""" + +import sys +import os.path +import re + +try: # check for the Python Imaging Library + import PIL.Image +except ImportError: + try: # sometimes PIL modules are put in PYTHONPATH's root + import Image + class PIL(object): pass # dummy wrapper + PIL.Image = Image + except ImportError: + PIL = None + +import docutils +from docutils import nodes, utils, writers, languages, io +from docutils.utils.error_reporting import SafeString +from docutils.transforms import writer_aux +from docutils.utils.math import (unichar2tex, pick_math_environment, + math2html, latex2mathml, tex2mathml_extern) + +if sys.version_info >= (3, 0): + from urllib.request import url2pathname +else: + from urllib import url2pathname + +if sys.version_info >= (3, 0): + unicode = str # noqa + + +class Writer(writers.Writer): + + supported = ('html', 'xhtml') # update in subclass + """Formats this writer supports.""" + + # default_stylesheets = [] # set in subclass! + # default_stylesheet_dirs = ['.'] # set in subclass! + default_template = 'template.txt' + # default_template_path = ... # set in subclass! + # settings_spec = ... # set in subclass! + + settings_defaults = {'output_encoding_error_handler': 'xmlcharrefreplace'} + + # config_section = ... # set in subclass! + config_section_dependencies = ('writers', 'html writers') + + visitor_attributes = ( + 'head_prefix', 'head', 'stylesheet', 'body_prefix', + 'body_pre_docinfo', 'docinfo', 'body', 'body_suffix', + 'title', 'subtitle', 'header', 'footer', 'meta', 'fragment', + 'html_prolog', 'html_head', 'html_title', 'html_subtitle', + 'html_body') + + def get_transforms(self): + return writers.Writer.get_transforms(self) + [writer_aux.Admonitions] + + def translate(self): + self.visitor = visitor = self.translator_class(self.document) + self.document.walkabout(visitor) + for attr in self.visitor_attributes: + setattr(self, attr, getattr(visitor, attr)) + self.output = self.apply_template() + + def apply_template(self): + template_file = open(self.document.settings.template, 'rb') + template = unicode(template_file.read(), 'utf-8') + template_file.close() + subs = self.interpolation_dict() + return template % subs + + def interpolation_dict(self): + subs = {} + settings = self.document.settings + for attr in self.visitor_attributes: + subs[attr] = ''.join(getattr(self, attr)).rstrip('\n') + subs['encoding'] = settings.output_encoding + subs['version'] = docutils.__version__ + return subs + + def assemble_parts(self): + writers.Writer.assemble_parts(self) + for part in self.visitor_attributes: + self.parts[part] = ''.join(getattr(self, part)) + + +class HTMLTranslator(nodes.NodeVisitor): + + """ + Generic Docutils to HTML translator. + + See the `html4css1` and `html5_polyglot` writers for full featured + HTML writers. + + .. IMPORTANT:: + The `visit_*` and `depart_*` methods use a + heterogeneous stack, `self.context`. + When subclassing, make sure to be consistent in its use! + + Examples for robust coding: + + a) Override both `visit_*` and `depart_*` methods, don't call the + parent functions. + + b) Extend both and unconditionally call the parent functions:: + + def visit_example(self, node): + if foo: + self.body.append('<div class="foo">') + html4css1.HTMLTranslator.visit_example(self, node) + + def depart_example(self, node): + html4css1.HTMLTranslator.depart_example(self, node) + if foo: + self.body.append('</div>') + + c) Extend both, calling the parent functions under the same + conditions:: + + def visit_example(self, node): + if foo: + self.body.append('<div class="foo">\n') + else: # call the parent method + _html_base.HTMLTranslator.visit_example(self, node) + + def depart_example(self, node): + if foo: + self.body.append('</div>\n') + else: # call the parent method + _html_base.HTMLTranslator.depart_example(self, node) + + d) Extend one method (call the parent), but don't otherwise use the + `self.context` stack:: + + def depart_example(self, node): + _html_base.HTMLTranslator.depart_example(self, node) + if foo: + # implementation-specific code + # that does not use `self.context` + self.body.append('</div>\n') + + This way, changes in stack use will not bite you. + """ + + xml_declaration = '<?xml version="1.0" encoding="%s" ?>\n' + doctype = '<!DOCTYPE html>\n' + doctype_mathml = doctype + + head_prefix_template = ('<html xmlns="http://www.w3.org/1999/xhtml"' + ' xml:lang="%(lang)s" lang="%(lang)s">\n<head>\n') + content_type = ('<meta charset="%s"/>\n') + generator = ('<meta name="generator" content="Docutils %s: ' + 'http://docutils.sourceforge.net/" />\n') + + # Template for the MathJax script in the header: + mathjax_script = '<script type="text/javascript" src="http://github.com/%s"></script>\n' + + mathjax_url = 'file:/usr/share/javascript/mathjax/MathJax.js' + """ + URL of the MathJax javascript library. + + The MathJax library ought to be installed on the same + server as the rest of the deployed site files and specified + in the `math-output` setting appended to "mathjax". + See `Docutils Configuration`__. + + __ http://docutils.sourceforge.net/docs/user/config.html#math-output + + The fallback tries a local MathJax installation at + ``/usr/share/javascript/mathjax/MathJax.js``. + """ + + stylesheet_link = '<link rel="stylesheet" href="http://github.com/%s" type="text/css" />\n' + embedded_stylesheet = '<style type="text/css">\n\n%s\n</style>\n' + words_and_spaces = re.compile(r'[^ \n]+| +|\n') + # wrap point inside word: + in_word_wrap_point = re.compile(r'.+\W\W.+|[-?].+', re.U) + lang_attribute = 'lang' # name changes to 'xml:lang' in XHTML 1.1 + + special_characters = {ord('&'): u'&', + ord('<'): u'<', + ord('"'): u'"', + ord('>'): u'>', + ord('@'): u'@', # may thwart address harvesters + } + """Character references for characters with a special meaning in HTML.""" + + + def __init__(self, document): + nodes.NodeVisitor.__init__(self, document) + self.settings = settings = document.settings + lcode = settings.language_code + self.language = languages.get_language(lcode, document.reporter) + self.meta = [self.generator % docutils.__version__] + self.head_prefix = [] + self.html_prolog = [] + if settings.xml_declaration: + self.head_prefix.append(self.xml_declaration + % settings.output_encoding) + # self.content_type = "" + # encoding not interpolated: + self.html_prolog.append(self.xml_declaration) + self.head = self.meta[:] + self.stylesheet = [self.stylesheet_call(path) + for path in utils.get_stylesheet_list(settings)] + self.body_prefix = ['</head>\n<body>\n'] + # document title, subtitle display + self.body_pre_docinfo = [] + # author, date, etc. + self.docinfo = [] + self.body = [] + self.fragment = [] + self.body_suffix = ['</body>\n</html>\n'] + self.section_level = 0 + self.initial_header_level = int(settings.initial_header_level) + + self.math_output = settings.math_output.split() + self.math_output_options = self.math_output[1:] + self.math_output = self.math_output[0].lower() + + self.context = [] + """Heterogeneous stack. + + Used by visit_* and depart_* functions in conjunction with the tree + traversal. Make sure that the pops correspond to the pushes.""" + + self.topic_classes = [] # TODO: replace with self_in_contents + self.colspecs = [] + self.compact_p = True + self.compact_simple = False + self.compact_field_list = False + self.in_docinfo = False + self.in_sidebar = False + self.in_footnote_list = False + self.title = [] + self.subtitle = [] + self.header = [] + self.footer = [] + self.html_head = [self.content_type] # charset not interpolated + self.html_title = [] + self.html_subtitle = [] + self.html_body = [] + self.in_document_title = 0 # len(self.body) or 0 + self.in_mailto = False + self.author_in_authors = False # for html4css1 + self.math_header = [] + + def astext(self): + return ''.join(self.head_prefix + self.head + + self.stylesheet + self.body_prefix + + self.body_pre_docinfo + self.docinfo + + self.body + self.body_suffix) + + def encode(self, text): + """Encode special characters in `text` & return.""" + # Use only named entities known in both XML and HTML + # other characters are automatically encoded "by number" if required. + # @@@ A codec to do these and all other HTML entities would be nice. + text = unicode(text) + return text.translate(self.special_characters) + + def cloak_mailto(self, uri): + """Try to hide a mailto: URL from harvesters.""" + # Encode "@" using a URL octet reference (see RFC 1738). + # Further cloaking with HTML entities will be done in the + # `attval` function. + return uri.replace('@', '%40') + + def cloak_email(self, addr): + """Try to hide the link text of a email link from harversters.""" + # Surround at-signs and periods with <span> tags. ("@" has + # already been encoded to "@" by the `encode` method.) + addr = addr.replace('@', '<span>@</span>') + addr = addr.replace('.', '<span>.</span>') + return addr + + def attval(self, text, + whitespace=re.compile('[\n\r\t\v\f]')): + """Cleanse, HTML encode, and return attribute value text.""" + encoded = self.encode(whitespace.sub(' ', text)) + if self.in_mailto and self.settings.cloak_email_addresses: + # Cloak at-signs ("%40") and periods with HTML entities. + encoded = encoded.replace('%40', '%40') + encoded = encoded.replace('.', '.') + return encoded + + def stylesheet_call(self, path): + """Return code to reference or embed stylesheet file `path`""" + if self.settings.embed_stylesheet: + try: + content = io.FileInput(source_path=path, + encoding='utf-8').read() + self.settings.record_dependencies.add(path) + except IOError as err: + msg = u"Cannot embed stylesheet '%s': %s." % ( + path, SafeString(err.strerror)) + self.document.reporter.error(msg) + return '<--- %s --->\n' % msg + return self.embedded_stylesheet % content + # else link to style file: + if self.settings.stylesheet_path: + # adapt path relative to output (cf. config.html#stylesheet-path) + path = utils.relative_path(self.settings._destination, path) + return self.stylesheet_link % self.encode(path) + + def starttag(self, node, tagname, suffix='\n', empty=False, **attributes): + """ + Construct and return a start tag given a node (id & class attributes + are extracted), tag name, and optional attributes. + """ + tagname = tagname.lower() + prefix = [] + atts = {} + ids = [] + for (name, value) in attributes.items(): + atts[name.lower()] = value + classes = [] + languages = [] + # unify class arguments and move language specification + for cls in node.get('classes', []) + atts.pop('class', '').split(): + if cls.startswith('language-'): + languages.append(cls[9:]) + elif cls.strip() and cls not in classes: + classes.append(cls) + if languages: + # attribute name is 'lang' in XHTML 1.0 but 'xml:lang' in 1.1 + atts[self.lang_attribute] = languages[0] + if classes: + atts['class'] = ' '.join(classes) + assert 'id' not in atts + ids.extend(node.get('ids', [])) + if 'ids' in atts: + ids.extend(atts['ids']) + del atts['ids'] + if ids: + atts['id'] = ids[0] + for id in ids[1:]: + # Add empty "span" elements for additional IDs. Note + # that we cannot use empty "a" elements because there + # may be targets inside of references, but nested "a" + # elements aren't allowed in XHTML (even if they do + # not all have a "href" attribute). + if empty or isinstance(node, + (nodes.bullet_list, nodes.docinfo, + nodes.definition_list, nodes.enumerated_list, + nodes.field_list, nodes.option_list, + nodes.table)): + # Insert target right in front of element. + prefix.append('<span id="%s"></span>' % id) + else: + # Non-empty tag. Place the auxiliary <span> tag + # *inside* the element, as the first child. + suffix += '<span id="%s"></span>' % id + attlist = sorted(atts.items()) + parts = [tagname] + for name, value in attlist: + # value=None was used for boolean attributes without + # value, but this isn't supported by XHTML. + assert value is not None + if isinstance(value, list): + values = [unicode(v) for v in value] + parts.append('%s="%s"' % (name.lower(), + self.attval(' '.join(values)))) + else: + parts.append('%s="%s"' % (name.lower(), + self.attval(unicode(value)))) + if empty: + infix = ' /' + else: + infix = '' + return ''.join(prefix) + '<%s%s>' % (' '.join(parts), infix) + suffix + + def emptytag(self, node, tagname, suffix='\n', **attributes): + """Construct and return an XML-compatible empty tag.""" + return self.starttag(node, tagname, suffix, empty=True, **attributes) + + def set_class_on_child(self, node, class_, index=0): + """ + Set class `class_` on the visible child no. index of `node`. + Do nothing if node has fewer children than `index`. + """ + children = [n for n in node if not isinstance(n, nodes.Invisible)] + try: + child = children[index] + except IndexError: + return + child['classes'].append(class_) + + def visit_Text(self, node): + text = node.astext() + encoded = self.encode(text) + if self.in_mailto and self.settings.cloak_email_addresses: + encoded = self.cloak_email(encoded) + self.body.append(encoded) + + def depart_Text(self, node): + pass + + def visit_abbreviation(self, node): + # @@@ implementation incomplete ("title" attribute) + self.body.append(self.starttag(node, 'abbr', '')) + + def depart_abbreviation(self, node): + self.body.append('</abbr>') + + def visit_acronym(self, node): + # @@@ implementation incomplete ("title" attribute) + self.body.append(self.starttag(node, 'acronym', '')) + + def depart_acronym(self, node): + self.body.append('</acronym>') + + def visit_address(self, node): + self.visit_docinfo_item(node, 'address', meta=False) + self.body.append(self.starttag(node, 'pre', + suffix= '', CLASS='address')) + + def depart_address(self, node): + self.body.append('\n</pre>\n') + self.depart_docinfo_item() + + def visit_admonition(self, node): + node['classes'].insert(0, 'admonition') + self.body.append(self.starttag(node, 'div')) + + def depart_admonition(self, node=None): + self.body.append('</div>\n') + + attribution_formats = {'dash': (u'\u2014', ''), + 'parentheses': ('(', ')'), + 'parens': ('(', ')'), + 'none': ('', '')} + + def visit_attribution(self, node): + prefix, suffix = self.attribution_formats[self.settings.attribution] + self.context.append(suffix) + self.body.append( + self.starttag(node, 'p', prefix, CLASS='attribution')) + + def depart_attribution(self, node): + self.body.append(self.context.pop() + '</p>\n') + + def visit_author(self, node): + if not(isinstance(node.parent, nodes.authors)): + self.visit_docinfo_item(node, 'author') + self.body.append('<p>') + + def depart_author(self, node): + self.body.append('</p>') + if isinstance(node.parent, nodes.authors): + self.body.append('\n') + else: + self.depart_docinfo_item() + + def visit_authors(self, node): + self.visit_docinfo_item(node, 'authors') + + def depart_authors(self, node): + self.depart_docinfo_item() + + def visit_block_quote(self, node): + self.body.append(self.starttag(node, 'blockquote')) + + def depart_block_quote(self, node): + self.body.append('</blockquote>\n') + + def check_simple_list(self, node): + """Check for a simple list that can be rendered compactly.""" + visitor = SimpleListChecker(self.document) + try: + node.walk(visitor) + except nodes.NodeFound: + return False + else: + return True + + # Compact lists + # ------------ + # Include definition lists and field lists (in addition to ordered + # and unordered lists) in the test if a list is "simple" (cf. the + # html4css1.HTMLTranslator docstring and the SimpleListChecker class at + # the end of this file). + + def is_compactable(self, node): + # explicite class arguments have precedence + if 'compact' in node['classes']: + return True + if 'open' in node['classes']: + return False + # check config setting: + if (isinstance(node, (nodes.field_list, nodes.definition_list)) + and not self.settings.compact_field_lists): + return False + if (isinstance(node, (nodes.enumerated_list, nodes.bullet_list)) + and not self.settings.compact_lists): + return False + # more special cases: + if (self.topic_classes == ['contents']): # TODO: self.in_contents + return True + # check the list items: + return self.check_simple_list(node) + + def visit_bullet_list(self, node): + atts = {} + old_compact_simple = self.compact_simple + self.context.append((self.compact_simple, self.compact_p)) + self.compact_p = None + self.compact_simple = self.is_compactable(node) + if self.compact_simple and not old_compact_simple: + atts['class'] = 'simple' + self.body.append(self.starttag(node, 'ul', **atts)) + + def depart_bullet_list(self, node): + self.compact_simple, self.compact_p = self.context.pop() + self.body.append('</ul>\n') + + def visit_caption(self, node): + self.body.append(self.starttag(node, 'p', '', CLASS='caption')) + + def depart_caption(self, node): + self.body.append('</p>\n') + + # citations + # --------- + # Use definition list instead of table for bibliographic references. + # Join adjacent citation entries. + + def visit_citation(self, node): + if not self.in_footnote_list: + self.body.append('<dl class="citation">\n') + self.in_footnote_list = True + + def depart_citation(self, node): + self.body.append('</dd>\n') + if not isinstance(node.next_node(descend=False, siblings=True), + nodes.citation): + self.body.append('</dl>\n') + self.in_footnote_list = False + + def visit_citation_reference(self, node): + href = '#' + if 'refid' in node: + href += node['refid'] + elif 'refname' in node: + href += self.document.nameids[node['refname']] + # else: # TODO system message (or already in the transform)? + # 'Citation reference missing.' + self.body.append(self.starttag( + node, 'a', '[', CLASS='citation-reference', href=href)) + + def depart_citation_reference(self, node): + self.body.append(']</a>') + + # classifier + # ---------- + # don't insert classifier-delimiter here (done by CSS) + + def visit_classifier(self, node): + self.body.append(self.starttag(node, 'span', '', CLASS='classifier')) + + def depart_classifier(self, node): + self.body.append('</span>') + + def visit_colspec(self, node): + self.colspecs.append(node) + # "stubs" list is an attribute of the tgroup element: + node.parent.stubs.append(node.attributes.get('stub')) + + def depart_colspec(self, node): + # write out <colgroup> when all colspecs are processed + if isinstance(node.next_node(descend=False, siblings=True), + nodes.colspec): + return + if 'colwidths-auto' in node.parent.parent['classes'] or ( + 'colwidths-auto' in self.settings.table_style and + ('colwidths-given' not in node.parent.parent['classes'])): + return + total_width = sum(node['colwidth'] for node in self.colspecs) + self.body.append(self.starttag(node, 'colgroup')) + for node in self.colspecs: + colwidth = int(node['colwidth'] * 100.0 / total_width + 0.5) + self.body.append(self.emptytag(node, 'col', + style='width: %i%%' % colwidth)) + self.body.append('</colgroup>\n') + + def visit_comment(self, node, + sub=re.compile('-(?=-)').sub): + """Escape double-dashes in comment text.""" + self.body.append('<!-- %s -->\n' % sub('- ', node.astext())) + # Content already processed: + raise nodes.SkipNode + + def visit_compound(self, node): + self.body.append(self.starttag(node, 'div', CLASS='compound')) + if len(node) > 1: + node[0]['classes'].append('compound-first') + node[-1]['classes'].append('compound-last') + for child in node[1:-1]: + child['classes'].append('compound-middle') + + def depart_compound(self, node): + self.body.append('</div>\n') + + def visit_container(self, node): + self.body.append(self.starttag(node, 'div', CLASS='docutils container')) + + def depart_container(self, node): + self.body.append('</div>\n') + + def visit_contact(self, node): + self.visit_docinfo_item(node, 'contact', meta=False) + + def depart_contact(self, node): + self.depart_docinfo_item() + + def visit_copyright(self, node): + self.visit_docinfo_item(node, 'copyright') + + def depart_copyright(self, node): + self.depart_docinfo_item() + + def visit_date(self, node): + self.visit_docinfo_item(node, 'date') + + def depart_date(self, node): + self.depart_docinfo_item() + + def visit_decoration(self, node): + pass + + def depart_decoration(self, node): + pass + + def visit_definition(self, node): + self.body.append('</dt>\n') + self.body.append(self.starttag(node, 'dd', '')) + + def depart_definition(self, node): + self.body.append('</dd>\n') + + def visit_definition_list(self, node): + classes = node.setdefault('classes', []) + if self.is_compactable(node): + classes.append('simple') + self.body.append(self.starttag(node, 'dl')) + + def depart_definition_list(self, node): + self.body.append('</dl>\n') + + def visit_definition_list_item(self, node): + # pass class arguments, ids and names to definition term: + node.children[0]['classes'] = ( + node.get('classes', []) + node.children[0].get('classes', [])) + node.children[0]['ids'] = ( + node.get('ids', []) + node.children[0].get('ids', [])) + node.children[0]['names'] = ( + node.get('names', []) + node.children[0].get('names', [])) + + def depart_definition_list_item(self, node): + pass + + def visit_description(self, node): + self.body.append(self.starttag(node, 'dd', '')) + + def depart_description(self, node): + self.body.append('</dd>\n') + + def visit_docinfo(self, node): + self.context.append(len(self.body)) + classes = 'docinfo' + if (self.is_compactable(node)): + classes += ' simple' + self.body.append(self.starttag(node, 'dl', CLASS=classes)) + + def depart_docinfo(self, node): + self.body.append('</dl>\n') + start = self.context.pop() + self.docinfo = self.body[start:] + self.body = [] + + def visit_docinfo_item(self, node, name, meta=True): + if meta: + meta_tag = '<meta name="%s" content="%s" />\n' \ + % (name, self.attval(node.astext())) + self.add_meta(meta_tag) + self.body.append('<dt class="%s">%s</dt>\n' + % (name, self.language.labels[name])) + self.body.append(self.starttag(node, 'dd', '', CLASS=name)) + + def depart_docinfo_item(self): + self.body.append('</dd>\n') + + def visit_doctest_block(self, node): + self.body.append(self.starttag(node, 'pre', suffix='', + CLASS='code python doctest')) + + def depart_doctest_block(self, node): + self.body.append('\n</pre>\n') + + def visit_document(self, node): + title = (node.get('title', '') or os.path.basename(node['source']) + or 'docutils document without title') + self.head.append('<title>%s\n' % self.encode(title)) + + def depart_document(self, node): + self.head_prefix.extend([self.doctype, + self.head_prefix_template % + {'lang': self.settings.language_code}]) + self.html_prolog.append(self.doctype) + self.meta.insert(0, self.content_type % self.settings.output_encoding) + self.head.insert(0, self.content_type % self.settings.output_encoding) + if 'name="dcterms.' in ''.join(self.meta): + self.head.append( + '') + if self.math_header: + if self.math_output == 'mathjax': + self.head.extend(self.math_header) + else: + self.stylesheet.extend(self.math_header) + # skip content-type meta tag with interpolated charset value: + self.html_head.extend(self.head[1:]) + self.body_prefix.append(self.starttag(node, 'div', CLASS='document')) + self.body_suffix.insert(0, '\n') + self.fragment.extend(self.body) # self.fragment is the "naked" body + self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo + + self.docinfo + self.body + + self.body_suffix[:-1]) + assert not self.context, 'len(context) = %s' % len(self.context) + + def visit_emphasis(self, node): + self.body.append(self.starttag(node, 'em', '')) + + def depart_emphasis(self, node): + self.body.append('') + + def visit_entry(self, node): + atts = {'class': []} + if isinstance(node.parent.parent, nodes.thead): + atts['class'].append('head') + if node.parent.parent.parent.stubs[node.parent.column]: + # "stubs" list is an attribute of the tgroup element + atts['class'].append('stub') + if atts['class']: + tagname = 'th' + atts['class'] = ' '.join(atts['class']) + else: + tagname = 'td' + del atts['class'] + node.parent.column += 1 + if 'morerows' in node: + atts['rowspan'] = node['morerows'] + 1 + if 'morecols' in node: + atts['colspan'] = node['morecols'] + 1 + node.parent.column += node['morecols'] + self.body.append(self.starttag(node, tagname, '', **atts)) + self.context.append('\n' % tagname.lower()) + # TODO: why does the html4css1 writer insert an NBSP into empty cells? + # if len(node) == 0: # empty cell + # self.body.append(' ') # no-break space + + def depart_entry(self, node): + self.body.append(self.context.pop()) + + def visit_enumerated_list(self, node): + atts = {} + if 'start' in node: + atts['start'] = node['start'] + if 'enumtype' in node: + atts['class'] = node['enumtype'] + if self.is_compactable(node): + atts['class'] = (atts.get('class', '') + ' simple').strip() + self.body.append(self.starttag(node, 'ol', **atts)) + + def depart_enumerated_list(self, node): + self.body.append('\n') + + def visit_field_list(self, node): + # Keep simple paragraphs in the field_body to enable CSS + # rule to start body on new line if the label is too long + classes = 'field-list' + if (self.is_compactable(node)): + classes += ' simple' + self.body.append(self.starttag(node, 'dl', CLASS=classes)) + + def depart_field_list(self, node): + self.body.append('\n') + + def visit_field(self, node): + pass + + def depart_field(self, node): + pass + + # as field is ignored, pass class arguments to field-name and field-body: + + def visit_field_name(self, node): + self.body.append(self.starttag(node, 'dt', '', + CLASS=''.join(node.parent['classes']))) + + def depart_field_name(self, node): + self.body.append('\n') + + def visit_field_body(self, node): + self.body.append(self.starttag(node, 'dd', '', + CLASS=''.join(node.parent['classes']))) + # prevent misalignment of following content if the field is empty: + if not node.children: + self.body.append('

') + + def depart_field_body(self, node): + self.body.append('\n') + + def visit_figure(self, node): + atts = {'class': 'figure'} + if node.get('width'): + atts['style'] = 'width: %s' % node['width'] + if node.get('align'): + atts['class'] += " align-" + node['align'] + self.body.append(self.starttag(node, 'div', **atts)) + + def depart_figure(self, node): + self.body.append('\n') + + # use HTML 5