10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 |
2 | ==============
3 | ACBrLib Python
4 | ==============
5 |
6 | |PyPI pyversions| |PyPI version fury.io| |PyPI license|
7 |
8 | Camada de abstração para acesso à `ACBrLib`_ em Python.
9 |
10 | ----
11 |
12 | `ACBrLib`_ é um conjunto de bibliotecas voltadas para o mercado de
13 | automação comercial que oferece acesso à um conjunto rico de abstrações
14 | que facilitam o desenvolvimento de aplicações como pontos-de-venda (PDV) e
15 | aplicações relacionadas. Esta biblioteca fornece uma camada que torna
16 | trivial a utilização da `ACBrLib`_ em seus próprios aplicativos escritos em
17 | `linguagem Python `_.
18 |
19 | .. note::
20 |
21 | Esta biblioteca está em seus primeiros estágios de desenvolvimento,
22 | portanto, não espere encontrar toda a riqueza que os componentes
23 | `ACBr`_ possuem, por enquanto. Mas estamos totalmente abertos a
24 | `sujestões`_ e estamos aceitando `pull-requests`_.
25 |
26 |
27 | Instalação
28 | ----------
29 |
30 | Instale, preferencialmente em um ambiente virtual, usando ``pip``:
31 |
32 | .. code-block:: shell
33 |
34 | pip install acbrlib-python
35 |
36 |
37 | ACBrLibCEP
38 | ----------
39 |
40 | Dá acesso a consultas de CEP utilizando dezenas de serviços de consulta
41 | disponíveis. Alguns desses serviços podem ser gratuítos ou gratuítos para
42 | desenvolvimento. Veja `este link `_
43 | para ter uma ideia dos serviços que podem ser utilizados.
44 |
45 | Para fazer uma consulta baseada no CEP:
46 |
47 | .. code-block:: python
48 |
49 | from acbrlib_python import ACBrLibCEP
50 |
51 | with ACBrLibCEP.usando('/caminho/para/libacbrcep64.so') as cep:
52 | enderecos = cep.buscar_por_cep('18270170')
53 | for endereco in enderecos:
54 | print(endereco)
55 |
56 | O trecho acima resultará em uma lista de objetos ``Endereco`` como resultado
57 | da busca, prontos para serem usados. A consulta acima trará um único resultado
58 | (usando o serviço `ViaCEP `_):
59 |
60 | .. code-block:: python
61 |
62 | Endereco(
63 | tipo_logradouro='',
64 | logradouro='Rua Coronel Aureliano de Camargo',
65 | complemento='',
66 | bairro='Centro',
67 | municipio='Tatuí',
68 | uf='SP',
69 | cep='18270-170',
70 | ibge_municipio='3554003',
71 | ibge_uf='35'
72 | )
73 |
74 | Para mais exemplos de uso, veja a pasta ``exemplos`` neste repositório.
75 |
76 |
77 | Sobre Nomenclatura e Estilo de Código
78 | =====================================
79 |
80 | Uma questão muito relevante é a maneira como esta abstração se refere aos
81 | nomes dos métodos disponíveis na biblioteca `ACBrLib`_ que utiliza uma
82 | convenção de nomenclatura para variáveis e nomes de argumentos ou
83 | parâmetros de funções conhecida como `Notação Húngara `_.
84 | Porém, em Python é utilizada a convenção `snake case `_
85 | tal como descrito na `PEP8 `_.
86 |
87 | Assim, para manter o estilo de Python, os nomes de variáveis e argumentos de
88 | função deverão descartar o prefixo que indica o tipo de dado e converter o
89 | restante para snake case, assim como nomes de métodos e funções também,
90 | por exemplo:
91 |
92 | * `eArqConfig` para `arq_config`;
93 | * `ConfigLerValor` para `config_ler_valor`;
94 | * `eArquivoXmlEvento` para `arquivo_xml_evento`;
95 | * etc…
96 |
97 | Métodos de bibliotecas que são prefixados com o nome da lib, será descartado o
98 | prefixo e o restante do nome do método convertido para snake case, por exemplo:
99 |
100 | * (ACBrLibNFe) `NFE_CarregarINI` para `carregar_ini`;
101 | * (ACBrLibNFe) `NFE_ValidarRegrasdeNegocios` para `validar_regras_de_negocios`
102 | (note a correção do conector `de` que está em minúsculo no original);
103 | * (ACBrLibCEP) `CEP_BuscarPorLogradouro` para `buscar_por_logradouro`;
104 | * etc…
105 |
106 | Esperamos que essa explicação faça sentido, senão, envia suas `sujestões`_.
107 |
108 |
109 | Desenvolvimento
110 | ===============
111 |
112 | Você é bem-vindo para ajudar no desenvolvimento desta biblioteca enviando
113 | suas contribuições através de `pull-requests`_. Faça um *fork* deste
114 | repositório e execute os testes antes de começar a implementar alguma
115 | coisa. A gestão de dependências é feita via `Poetry`_ e recomendamos a
116 | utilização de `pyenv`_
117 |
118 | .. code-block:: shell
119 |
120 | $ git clone https://github.com/base4sistemas/acbrlib-python.git
121 | $ cd acbrlib-python
122 | $ poetry install
123 | $ poetry run pytest
124 |
125 |
126 | .. _`sujestões`: https://github.com/base4sistemas/acbrlib-python/issues
127 | .. _`pull-requests`: https://github.com/base4sistemas/acbrlib-python/pulls
128 | .. _`ACBr`: https://projetoacbr.com.br/
129 | .. _`ACBrLib`: https://projetoacbr.com.br/downloads/#acbrlib
130 | .. _`pyenv`: https://github.com/pyenv/pyenv
131 | .. _`Poetry`: https://python-poetry.org/
132 |
133 | .. |PyPI pyversions| image:: https://img.shields.io/pypi/pyversions/acbrlib-python.svg
134 | :target: https://pypi.python.org/pypi/acbrlib-python/
135 |
136 | .. |PyPI version fury.io| image:: https://badge.fury.io/py/acbrlib-python.svg
137 | :target: https://pypi.python.org/pypi/acbrlib-python/
138 |
139 | .. |PyPI license| image:: https://img.shields.io/pypi/l/acbrlib-python.svg
140 | :target: https://pypi.python.org/pypi/acbrlib-python/
141 |
--------------------------------------------------------------------------------
/acbrlib_python/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/__init__.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from .cep import * # noqa:
21 |
22 | __version__ = '0.1.0'
23 |
--------------------------------------------------------------------------------
/acbrlib_python/cep/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/__init__.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from .impl import ACBrLibCEP # noqa:
21 |
22 | __all__ = ['ACBrLibCEP']
23 |
--------------------------------------------------------------------------------
/acbrlib_python/cep/constantes.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/constantes.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | CEP_WS_NENHUM = 0
21 | CEP_WS_BUSCARCEP = 1
22 | CEP_WS_CEPLIVRE = 2
23 | CEP_WS_REPUBLICAVIRTUAL = 3
24 | CEP_WS_BASES4YOU = 4
25 | CEP_WS_RNSOLUCOES = 5
26 | CEP_WS_KINGHOST = 6
27 | CEP_WS_BYJG = 7
28 | CEP_WS_CORREIOS = 8
29 | CEP_WS_DEVMEDIA = 9
30 | CEP_WS_VIACEP = 10
31 | CEP_WS_CORREIOSSIGEP = 11
32 | CEP_WS_CEPABERTO = 12
33 | CEP_WS_WSCEP = 13
34 |
35 | CEP_WEBSERVICES = (
36 | (CEP_WS_NENHUM, 'Nenhum'),
37 | (CEP_WS_BUSCARCEP, 'BuscarCEP'),
38 | (CEP_WS_CEPLIVRE, 'CEP Livre'),
39 | (CEP_WS_REPUBLICAVIRTUAL, 'República Virtual'),
40 | (CEP_WS_BASES4YOU, 'Bases4You'),
41 | (CEP_WS_RNSOLUCOES, 'RN Soluções'),
42 | (CEP_WS_KINGHOST, 'King Host'),
43 | (CEP_WS_BYJG, 'By JG'),
44 | (CEP_WS_CORREIOS, 'Correios'),
45 | (CEP_WS_DEVMEDIA, 'DevMedia'),
46 | (CEP_WS_VIACEP, 'ViaCEP'),
47 | (CEP_WS_CORREIOSSIGEP, 'Correios SIGEP'),
48 | (CEP_WS_CEPABERTO, 'CEP Aberto'),
49 | (CEP_WS_WSCEP, 'WS CEP'),
50 | )
51 |
--------------------------------------------------------------------------------
/acbrlib_python/cep/excecoes.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/excecoes.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from ..excecoes import ACBrLibException
21 |
22 |
23 | class ACBrLibCEPException(ACBrLibException):
24 | pass
25 |
26 |
27 | class ACBrLibCEPErro(Exception):
28 | pass
29 |
30 |
31 | class ACBrLibCEPErroResposta(ACBrLibCEPErro):
32 | pass
33 |
--------------------------------------------------------------------------------
/acbrlib_python/cep/impl.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/impl.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | import configparser
21 | import io
22 |
23 | from contextlib import contextmanager
24 | from ctypes import POINTER
25 | from ctypes import c_char_p
26 | from ctypes import c_int
27 | from typing import List
28 | from typing import Mapping
29 | from typing import Type
30 |
31 | from ..constantes import AUTO
32 | from ..excecoes import ACBrLibException
33 | from ..mixins import ACBrLibCommonMixin
34 | from ..mixins import ACBrLibConfigMixin
35 | from ..proto import ACBrLibReferencia
36 | from ..proto import ReferenceLibrary
37 | from ..proto import Signature
38 | from ..proto import common_method_prototypes
39 | from ..proto import config_method_prototypes
40 | from ..proto import read_string_buffer
41 |
42 | from .excecoes import ACBrLibCEPException
43 | from .excecoes import ACBrLibCEPErroResposta
44 | from .modelos import Endereco
45 |
46 |
47 | class ACBrLibCEP(ACBrLibReferencia, ACBrLibCommonMixin, ACBrLibConfigMixin):
48 |
49 | def __init__(
50 | self,
51 | prefixo: str,
52 | biblioteca: ReferenceLibrary,
53 | prototipos: Mapping[str, Signature],
54 | base_exception: Type[ACBrLibException]):
55 | super().__init__(prefixo, biblioteca, prototipos, base_exception)
56 |
57 | @staticmethod
58 | def usar(caminho_biblioteca, convencao_chamada=AUTO):
59 | prototypes = {
60 | **common_method_prototypes('CEP'),
61 | **config_method_prototypes('CEP'),
62 | 'CEP_BuscarPorCEP': Signature([c_char_p, c_char_p, POINTER(c_int)]), # eCEP, sResposta, esTamanho,
63 | 'CEP_BuscarPorLogradouro': Signature([
64 | c_char_p, # eCidade
65 | c_char_p, # eTipo_Logradouro
66 | c_char_p, # eLogradouro
67 | c_char_p, # eUF
68 | c_char_p, # eBairro
69 | c_char_p, # sResposta
70 | POINTER(c_int), # esTamanho
71 | ])
72 | }
73 | instancia = ACBrLibCEP(
74 | 'CEP',
75 | ReferenceLibrary(
76 | caminho_biblioteca,
77 | calling_convention=convencao_chamada
78 | ),
79 | prototypes,
80 | ACBrLibCEPException
81 | )
82 | return instancia
83 |
84 | @classmethod
85 | @contextmanager
86 | def usando(
87 | cls,
88 | caminho_biblioteca,
89 | convencao_chamada=AUTO,
90 | arq_config='',
91 | chave_crypt=''):
92 | cep = cls.usar(caminho_biblioteca, convencao_chamada=convencao_chamada)
93 | cep.inicializar(arq_config, chave_crypt)
94 | try:
95 | yield cep
96 | finally:
97 | cep.finalizar()
98 |
99 | def buscar_por_cep(self, numero: str) -> List[Endereco]:
100 | """
101 | Faz uma busca pelo número do CEP.
102 | :param numero: Número do CEP. Deve possuir exatamente oito digitos e
103 | pode ou não estar formatado (qualquer caracter que não seja um
104 | digito, será ignorado).
105 | :return: Retorna uma lista de :class:`~acbrlib_python.cep.Endereco`.
106 | :raise ValueError: Se o argumento não possuir oito digitos, após
107 | todos os caracteres não-digito terem sido removidos.
108 | """
109 | cep = ''.join([c for c in numero if c.isdigit()])
110 | if len(cep) != 8:
111 | raise ValueError(
112 | f'CEP informado nao possui nove digitos: {numero!r}'
113 | )
114 | metodo = f'{self._prefixo}_BuscarPorCEP'
115 | resposta = read_string_buffer(self, metodo, self._b(cep))
116 | return processar_resposta(resposta)
117 |
118 | def buscar_por_logradouro(
119 | self,
120 | tipo_logradouro='',
121 | logradouro='',
122 | bairro='',
123 | municipio='',
124 | uf='') -> List[Endereco]:
125 | """
126 | Faz uma busca por determinados atributos de um endereço. Embora,
127 | todos os parâmetros sejam opcionais, para que você obtenha um
128 | resultado mais próximo do que procura, especifique o maior número de
129 | atributos que conheçer do endereço.
130 |
131 | A precisão do resultado irá depender da qualidade dos valores dos
132 | atributos informados e do serviço de busca de CEP que estiver usando.
133 |
134 | :param str tipo_logradouro: Opcional. O tipo do logradouro (rua,
135 | avenida, etc).
136 | :param str logradouro: Opcional. O nome do logradouro.
137 | :param str bairro: Opcional. O nome do bairro.
138 | :param str municipio: Opcional. O nome do município.
139 | :param str uf: Opcional. A sigla do Estado do município.
140 |
141 | :return: Retorna uma lista de :class:`~acbrlib_python.cep.Endereco`.
142 | """
143 | metodo = f'{self._prefixo}_BuscarPorLogradouro'
144 | resposta = read_string_buffer(
145 | self,
146 | metodo,
147 | self._b(municipio),
148 | self._b(tipo_logradouro),
149 | self._b(logradouro),
150 | self._b(uf),
151 | self._b(bairro),
152 | )
153 | return processar_resposta(resposta)
154 |
155 |
156 | def processar_resposta(resposta: str) -> List[Endereco]:
157 | buf = io.StringIO(resposta)
158 | parser = configparser.ConfigParser()
159 | parser.read_file(buf)
160 | section, option = 'CEP', 'Quantidade'
161 | if not parser.has_option(section, option):
162 | raise ACBrLibCEPErroResposta(
163 | 'Resposta mal formada; a resposta nao possui a '
164 | 'informacao da quantidade de enderecos encontrados; '
165 | f'resposta={resposta!r}'
166 | )
167 | enderecos = []
168 | for i in range(parser.getint(section, option)):
169 | enderecos.append(_endereco(i, parser))
170 | return enderecos
171 |
172 |
173 | def _endereco(i: int, parser: configparser.ConfigParser) -> Endereco:
174 | section = f'Endereco{i + 1}'
175 | options = [
176 | 'Tipo_Logradouro',
177 | 'Logradouro',
178 | 'Complemento',
179 | 'Bairro',
180 | 'Municipio',
181 | 'UF',
182 | 'CEP',
183 | 'IBGE_Municipio',
184 | 'IBGE_UF',
185 | ]
186 | kwargs = {}
187 | for option in options:
188 | if not parser.has_option(section, option):
189 | raise ACBrLibCEPErroResposta(
190 | 'Resposta mal formada; a resposta nao possui a '
191 | f'informacao {option!r} na secao {section!r}'
192 | )
193 | kwargs[option.lower()] = parser.get(section, option)
194 | return Endereco(**kwargs)
195 |
--------------------------------------------------------------------------------
/acbrlib_python/cep/modelos.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/modelos.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from dataclasses import dataclass
21 |
22 |
23 | @dataclass(frozen=True)
24 | class Endereco:
25 | tipo_logradouro: str
26 | logradouro: str
27 | complemento: str
28 | bairro: str
29 | municipio: str
30 | uf: str
31 | cep: str
32 | ibge_municipio: str
33 | ibge_uf: str
34 |
--------------------------------------------------------------------------------
/acbrlib_python/constantes.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/constantes.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from .cep.constantes import * # noqa:
21 |
22 | AUTO = 'auto'
23 | STANDARD_C = 'cdecl'
24 | WINDOWS_STDCALL = 'stdcall'
25 |
26 | CALLING_CONVENTIONS = (
27 | (AUTO, 'Automático (pela extensão)'),
28 | (STANDARD_C, 'C Padrão (Cdecl)'),
29 | (WINDOWS_STDCALL, 'Windows Padrão (StdCall)'),
30 | )
31 |
32 |
33 | CONVENCOES_CHAMADA = CALLING_CONVENTIONS
34 |
35 | BUFFER_LENGTH = 1024
36 |
--------------------------------------------------------------------------------
/acbrlib_python/excecoes.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/excecoes.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from unidecode import unidecode
21 |
22 |
23 | class ACBrLibException(Exception):
24 | def __init__(self, metodo=None, retorno=None, mensagem=None):
25 | if not mensagem:
26 | mensagem = f'Código de retorno inesperado: {retorno!r}'
27 | mensagem = f'{mensagem} (método {metodo!r} retornou {retorno!r})'
28 | self._metodo = metodo
29 | self._retorno = retorno
30 | super().__init__(unidecode(mensagem))
31 |
32 | @property
33 | def metodo(self):
34 | return self._metodo
35 |
36 | @property
37 | def retorno(self):
38 | return self._retorno
39 |
--------------------------------------------------------------------------------
/acbrlib_python/mixins.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/mixins.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from ctypes import byref
21 | from ctypes import c_int
22 | from ctypes import create_string_buffer
23 |
24 | from .constantes import BUFFER_LENGTH
25 | from .proto import ACBrLibMixin
26 | from .proto import read_string_buffer
27 |
28 |
29 | class ACBrLibCommonMixin(ACBrLibMixin):
30 | """
31 | Fornece os "métodos da biblioteca" comuns a todos os sabores de
32 | bibliotecas ACBrLib:
33 |
34 | * ``XXX_Inicializar``
35 | * ``XXX_Finalizar``
36 | * ``XXX_UltimoRetorno``
37 | * ``XXX_Nome``
38 | * ``XXX_Versao``
39 |
40 | Este mixin requer que a classe herde de
41 | :class:`~acbrlib_python.base.ACBrLibReferencia`.
42 | """
43 |
44 | def inicializar(self, arq_config: str, chave_crypt: str) -> None:
45 | metodo = f'{self._prefixo}_Inicializar'
46 | retorno = self._invocar(metodo)(self._b(arq_config), self._b(chave_crypt))
47 | if retorno == 0:
48 | return
49 | else:
50 | codigos_erro = {
51 | -1: 'Falha na inicialização da biblioteca',
52 | -5: 'Não foi possível localizar o arquivo INI informado',
53 | -6: 'Não foi possível encontrar o diretório do arquivo INI',
54 | }
55 | raise self._base_exception(
56 | metodo=metodo,
57 | retorno=retorno,
58 | mensagem=codigos_erro.get(retorno)
59 | )
60 |
61 | def finalizar(self) -> None:
62 | metodo = f'{self._prefixo}_Finalizar'
63 | retorno = self._invocar(metodo)()
64 | if retorno == 0:
65 | return
66 | else:
67 | codigos_erro = {
68 | -2: 'Falha na finalização da biblioteca'
69 | }
70 | raise self._base_exception(
71 | metodo=metodo,
72 | retorno=retorno,
73 | mensagem=codigos_erro.get(retorno)
74 | )
75 |
76 | def ultimo_retorno(self, buffer_len=BUFFER_LENGTH) -> str:
77 | metodo = f'{self._prefixo}_UltimoRetorno'
78 | resposta = create_string_buffer(buffer_len)
79 | tamanho = c_int(buffer_len)
80 | retorno = self._invocar(metodo)(resposta, byref(tamanho))
81 | if retorno == 0:
82 | return self._s(resposta.value)
83 | else:
84 | codigos_erro = {
85 | -10: 'Falha na execução do método'
86 | }
87 | raise self._base_exception(
88 | metodo=metodo,
89 | retorno=retorno,
90 | mensagem=codigos_erro.get(retorno)
91 | )
92 |
93 | def nome(self) -> str:
94 | metodo = f'{self._prefixo}_Nome'
95 | return read_string_buffer(self, metodo, buffer_len=1)
96 |
97 | def versao(self) -> str:
98 | metodo = f'{self._prefixo}_Versao'
99 | return read_string_buffer(self, metodo)
100 |
101 |
102 | class ACBrLibConfigMixin(ACBrLibMixin):
103 | """
104 | Fornece os "métodos de configuração" comuns a todos os sabores de
105 | bibliotecas ACBrLib:
106 |
107 | * ``XXX_ConfigLer``
108 | * ``XXX_ConfigGravar``
109 | * ``XXX_ConfigLerValor``
110 | * ``XXX_ConfigGravarValor``
111 | * ``XXX_ConfigImportar``
112 | * ``XXX_ConfigExportar``
113 |
114 | Este mixin requer que a classe herde de
115 | :class:`~acbrlib_python.base.ACBrLibReferencia`.
116 | """
117 |
118 | def config_ler(self, arq_config: str) -> None:
119 | metodo = f'{self._prefixo}_ConfigLer'
120 | retorno = self._invocar(metodo)(self._b(arq_config))
121 | if retorno != 0:
122 | codigos_erro = {
123 | -5: 'Não foi possível localizar o arquivo INI informado',
124 | -6: 'Não foi possível encontrar o diretório do arquivo INI',
125 | -10: 'Houve uma falha na execução do método'
126 | }
127 | raise self._base_exception(
128 | metodo=metodo,
129 | retorno=retorno,
130 | mensagem=codigos_erro.get(retorno)
131 | )
132 |
133 | def config_gravar(self, arq_config: str) -> None:
134 | metodo = f'{self._prefixo}_ConfigGravar'
135 | retorno = self._invocar(metodo)(self._b(arq_config))
136 | if retorno != 0:
137 | codigos_erro = {
138 | -5: 'Não foi possível localizar o arquivo INI informado',
139 | -6: 'Não foi possível encontrar o diretório do arquivo INI',
140 | -10: 'Houve uma falha na execução do método'
141 | }
142 | raise self._base_exception(
143 | metodo=metodo,
144 | retorno=retorno,
145 | mensagem=codigos_erro.get(retorno)
146 | )
147 |
148 | def config_ler_valor(self, sessao: str, chave: str) -> str:
149 | metodo = f'{self._prefixo}_ConfigLerValor'
150 | resposta = create_string_buffer(BUFFER_LENGTH)
151 | tamanho = c_int(BUFFER_LENGTH)
152 | retorno = self._invocar(metodo)(
153 | self._b(sessao),
154 | self._b(chave),
155 | resposta,
156 | byref(tamanho)
157 | )
158 | if retorno == 0:
159 | return self._s(resposta.value)
160 | else:
161 | codigos_erro = {
162 | -1: 'A biblioteca não foi inicializada',
163 | -3: 'Erro ao ler a configuração informada',
164 | }
165 | raise self._base_exception(
166 | metodo=metodo,
167 | retorno=retorno,
168 | mensagem=codigos_erro.get(retorno)
169 | )
170 |
171 | def config_gravar_valor(self, sessao: str, chave: str, valor: str) -> None:
172 | metodo = f'{self._prefixo}_ConfigGravarValor'
173 | retorno = self._invocar(metodo)(self._b(sessao), self._b(chave), self._b(valor))
174 | if retorno != 0:
175 | codigos_erro = {
176 | -1: 'A biblioteca não foi inicializada',
177 | -3: 'Erro ao ler a configuração informada',
178 | }
179 | raise self._base_exception(
180 | metodo=metodo,
181 | retorno=retorno,
182 | mensagem=codigos_erro.get(retorno)
183 | )
184 |
185 | def config_importar(self, arq_config: str) -> None:
186 | metodo = f'{self._prefixo}_ConfigImportar'
187 | retorno = self._invocar(metodo)(self._b(arq_config))
188 | if retorno != 0:
189 | codigos_erro = {
190 | -5: 'Não foi possível localizar o arquivo INI informado',
191 | -6: 'Não foi possível encontrar o diretório do arquivo INI',
192 | -10: 'Houve uma falha na execução do método'
193 | }
194 | raise self._base_exception(
195 | metodo=metodo,
196 | retorno=retorno,
197 | mensagem=codigos_erro.get(retorno)
198 | )
199 |
200 | def config_exportar(self) -> str:
201 | metodo = f'{self._prefixo}_ConfigExportar'
202 | resposta = create_string_buffer(BUFFER_LENGTH)
203 | tamanho = c_int(BUFFER_LENGTH)
204 | retorno = self._invocar(metodo)(resposta, byref(tamanho))
205 | if retorno == 0:
206 | return self._s(resposta.value)
207 | else:
208 | codigos_erro = {
209 | -10: 'Houve uma falha na execução do método'
210 | }
211 | raise self._base_exception(
212 | metodo=metodo,
213 | retorno=retorno,
214 | mensagem=codigos_erro.get(retorno)
215 | )
216 |
--------------------------------------------------------------------------------
/acbrlib_python/proto.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # acbrlib_python/cep/proto.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | import sys
21 |
22 | from ctypes import CDLL
23 | from ctypes import POINTER
24 | from ctypes import byref
25 | from ctypes import c_char_p
26 | from ctypes import c_int
27 | from ctypes import create_string_buffer
28 |
29 | from typing import Any
30 | from typing import List
31 | from typing import Mapping
32 | from typing import Optional
33 | from typing import Type
34 | from typing import Union
35 |
36 | from .constantes import AUTO
37 | from .constantes import BUFFER_LENGTH
38 | from .excecoes import ACBrLibException
39 |
40 |
41 | class Signature(object):
42 | """Descreve uma assinatura de função e o tipo de retorno."""
43 |
44 | __slots__ = ('_argtypes', '_restype')
45 |
46 | def __init__(
47 | self,
48 | argtypes: List[Any],
49 | restype: Optional[Any] = None):
50 | self._argtypes = argtypes[:]
51 | self._restype = restype or c_int
52 |
53 | @property
54 | def argtypes(self):
55 | return self._argtypes[:]
56 |
57 | @property
58 | def restype(self):
59 | return self._restype
60 |
61 |
62 | class ReferenceLibrary(object):
63 |
64 | def __init__(self, library_path, calling_convention=AUTO, lazy_load=True):
65 | self._path = library_path
66 | self._calling_convention = calling_convention
67 | self._lazy_load = lazy_load
68 | self._ref = None if self._lazy_load else self._load_library()
69 |
70 | @property
71 | def ref(self):
72 | if self._ref is None:
73 | self._load_library()
74 | return self._ref
75 |
76 | def _load_library(self):
77 | self._ref = loader(self._path, self._calling_convention)
78 |
79 |
80 | class ACBrLibMixin:
81 | pass
82 |
83 |
84 | class ACBrLibReferencia(object):
85 |
86 | def __init__(
87 | self,
88 | prefixo: str,
89 | biblioteca: ReferenceLibrary,
90 | prototipos: Mapping[str, Signature],
91 | base_exception: Type[ACBrLibException],
92 | encoding: str = 'utf-8'):
93 | self._prefixo = prefixo
94 | self._biblioteca = biblioteca
95 | self._prototipos = prototipos
96 | self._base_exception = base_exception
97 | self._encoding = encoding
98 |
99 | def _invocar(self, metodo: str):
100 | if metodo not in self._prototipos:
101 | raise ValueError(f'Metodo/funcao desconhecido: {metodo}')
102 | proto = self._prototipos.get(metodo)
103 | fptr = getattr(self._biblioteca.ref, metodo)
104 | fptr.argtypes = proto.argtypes
105 | fptr.restype = proto.restype
106 | return fptr
107 |
108 | def _b(self, value: str) -> bytes:
109 | return value.encode(self._encoding)
110 |
111 | def _s(self, value: bytes) -> str:
112 | return value.decode(self._encoding)
113 |
114 |
115 | def read_string_buffer(
116 | impl: Union[ACBrLibReferencia, ACBrLibMixin],
117 | method_name: str,
118 | *args,
119 | **kwargs):
120 | """
121 | Faz uma leitura de um buffer string considerando que o tamanho inicial do
122 | buffer possa ser insuficiente. Se for o caso, esta função invocará a
123 | leitura dos dados do último retorno, considerando o tamanho ideal do
124 | buffer que é indicado durante a primeira tentativa.
125 |
126 | O código usuário desta biblioteca não deveria ter que acessar diretamente
127 | esta função.
128 |
129 | :param impl: Instância da :class:`ACBrLibReferencia`.
130 | :param method_name: Nome do método a ser invocado.
131 | :param args: Os parâmetros posicionais a serem passados para o método.
132 | :param kwargs: Os parâmetros nomeados a serem passados parao método.
133 | Se houver um parâmetro chamado ``buffer_len`` (*int*), ele será
134 | utilizado como referência para o tamanho do buffer a ser lido.
135 | Se não for informado será usado o valor da constante
136 | :attr:`acbrlib_python.constantes.BUFFER_LENGTH`.
137 |
138 | :return: Retorna o buffer string já convertido para o encoding da
139 | implementação definido em :class:`ACBrLibReferencia`.
140 | """
141 | buffer_len = kwargs.pop('buffer_len', BUFFER_LENGTH)
142 | str_buffer = create_string_buffer(buffer_len)
143 | int_size = c_int(buffer_len)
144 | mod_args = list(args) + [str_buffer, byref(int_size)]
145 | retval = getattr(impl, '_invocar')(method_name)(*mod_args, **kwargs)
146 | if retval == 0:
147 | if int_size.value > buffer_len:
148 | return impl.ultimo_retorno(buffer_len=int_size.value)
149 | else:
150 | return getattr(impl, '_s')(str_buffer.value)
151 | else:
152 | exc = getattr(impl, '_base_exception')
153 | raise exc(metodo=method_name, retorno=retval)
154 |
155 |
156 | def common_method_prototypes(
157 | prefix: str,
158 | excludes: Optional[List[str]] = None) -> Mapping[str, Signature]:
159 | """
160 | Retorna o conjunto dos métodos que aparecem na documentação da
161 | ACBrLib como "Métodos da Biblioteca". O código usuário desta
162 | biblioteca não deveria ter que acessar diretamente esta função.
163 |
164 | :param prefix: Prefixo de três letras que identifica a biblioteca,
165 | como "CEP" ou "NFE" por exemplo.
166 |
167 | :param excludes: Nomes de métodos que devem ser removidos do
168 | resultado. Deve ser uma lista especificando o nome completo,
169 | incluindo o prefixo, por exemplo "CEP_UltimoRetorno" para
170 | que esse protótipo de função seja excluído do resultado.
171 |
172 | :return: Um dicionário contendo os nomes de função e suas
173 | assinaturas de parâmetros (protótipos de funções).
174 | """
175 | prototypes = {
176 | f'{prefix}_Inicializar': Signature([c_char_p, c_char_p]), # eArqConfig, eChaveCrypt
177 | f'{prefix}_Finalizar': Signature([]),
178 | f'{prefix}_UltimoRetorno': Signature([c_char_p, POINTER(c_int)]), # sMensagem, esTamanho
179 | f'{prefix}_Nome': Signature([c_char_p, POINTER(c_int)]), # sNome, esTamanho
180 | f'{prefix}_Versao': Signature([c_char_p, POINTER(c_int)]), # sVersao, esTamanho
181 | }
182 | if excludes:
183 | for name in excludes:
184 | prototypes.pop(name)
185 | return prototypes
186 |
187 |
188 | def config_method_prototypes(
189 | prefix: str,
190 | excludes: Optional[List[str]] = None) -> Mapping[str, Signature]:
191 | """
192 | Retorna o conjunto dos métodos que aparecem na documentação da
193 | ACBrLib como "Métodos da Configuração". O código usuário desta
194 | biblioteca não deveria ter que acessar diretamente esta função.
195 |
196 | :param prefix: Prefixo de três letras que identifica a biblioteca,
197 | como "CEP" ou "NFE" por exemplo.
198 |
199 | :param excludes: Nomes de métodos que devem ser removidos do
200 | resultado. Deve ser uma lista especificando o nome completo,
201 | incluindo o prefixo, por exemplo "DIS_ConfigImportar" para
202 | que esse protótipo de função seja excluído do resultado.
203 |
204 | :return: Um dicionário contendo os nomes de função e suas
205 | assinaturas de parâmetros (protótipos de funções).
206 | """
207 | prototypes = {
208 | f'{prefix}_ConfigLer': Signature([c_char_p]), # eArqConfig
209 | f'{prefix}_ConfigGravar': Signature([c_char_p]), # eArqConfig
210 | f'{prefix}_ConfigLerValor': Signature([
211 | c_char_p, # eSessao
212 | c_char_p, # eChave
213 | c_char_p, # sValor
214 | POINTER(c_int) # esTamanho
215 | ]),
216 | f'{prefix}_ConfigGravarValor': Signature([c_char_p, c_char_p, c_char_p]), # eSessao, eChave, sValor
217 | f'{prefix}_ConfigImportar': Signature([c_char_p]), # eArqConfig
218 | f'{prefix}_ConfigExportar': Signature([c_char_p, POINTER(c_int)]), # sMensagem, esTamanho
219 | }
220 | if excludes:
221 | for name in excludes:
222 | prototypes.pop(name)
223 | return prototypes
224 |
225 |
226 | def loader(path: str, calling_convention: str) -> CDLL:
227 | """
228 | Carrega uma biblioteca (DLL/shared object) no caminho indicado.
229 |
230 | :param path: Caminho completo para biblioteca.
231 |
232 | :param calling_convention: Convenção de chamada.
233 | Veja as constantes definidas em
234 | :attr:`acbrlib_python.constantes.CONVENCOES_CHAMADA`.
235 |
236 | :return: Uma referência para ``ctypes.CDLL`` carregada,
237 | conforme a convenção de chamada (*CDECL* ou *StdCall*).
238 |
239 | """
240 | name = f'_loader_{calling_convention}'
241 | loader_func = getattr(sys.modules[__name__], name, None)
242 | if not loader_func:
243 | raise ValueError(
244 | f'Unexpected calling convention; got {calling_convention!r}'
245 | )
246 | return loader_func(path, calling_convention)
247 |
248 |
249 | def _loader_auto(path: str, calling_convention: str) -> CDLL:
250 | if path.endswith(('.DLL', '.dll')):
251 | return _loader_stdcall(path, calling_convention)
252 | else:
253 | return _loader_cdecl(path, calling_convention)
254 |
255 |
256 | def _loader_stdcall(path: str, calling_convention: str) -> CDLL:
257 | from ctypes import WinDLL
258 | return WinDLL(path)
259 |
260 |
261 | def _loader_cdecl(path: str, calling_convention: str) -> CDLL:
262 | return CDLL(path)
263 |
--------------------------------------------------------------------------------
/exemplos/cep.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # exemplos/cep.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | """
21 | Invoque este exemplo, modificando os valores padrão das variáveis
22 | diretamente neste código ou modificando os valores das variáveis de
23 | ambiente na chamada, por exemplo:
24 |
25 | $ ACBRLIB_INI_PATH=/home/user/ACBR.INI python exemplos/cep.py
26 |
27 | Não considere este exemplo completo ou definitivo. Dê uma boa olhada
28 | antes de executá-lo. Sempre tomamos o cuidado de
29 | não fazer nada que possa causar problemas.
30 | """
31 |
32 | import os
33 |
34 | from acbrlib_python import ACBrLibCEP
35 |
36 |
37 | ACBRLIB_PATH = os.getenv('ACBRLIB_PATH', '/usr/lib/libacbrcep64.so')
38 | ACBRLIB_INI_PATH = os.getenv('ACBRLIB_INI_PATH', '')
39 | ACBRLIB_CHAVE_CRYPT = os.getenv('ACBRLIB_CHAVE_CRYPT', '')
40 |
41 |
42 | def iniciacao_simples():
43 | cep = ACBrLibCEP.usar(ACBRLIB_PATH)
44 | cep.inicializar(ACBRLIB_INI_PATH, ACBRLIB_CHAVE_CRYPT)
45 | print(f'CEP_Nome: {cep.nome()}')
46 | print(f'CEP_Versao: {cep.versao()}')
47 | print(f'CEP_UltimoRetorno: {cep.ultimo_retorno()}')
48 | cep.finalizar()
49 |
50 |
51 | def iniciacao_simples_e_segura():
52 | # o context manager garante a finalização
53 | with ACBrLibCEP.usando(
54 | ACBRLIB_PATH,
55 | arq_config=ACBRLIB_INI_PATH,
56 | chave_crypt=ACBRLIB_CHAVE_CRYPT) as cep:
57 | print(f'{cep.nome()}, versao {cep.versao()}')
58 | print(f'Último retorno: {cep.ultimo_retorno()}')
59 |
60 |
61 | def consultar_por_cep():
62 | with ACBrLibCEP.usando(
63 | ACBRLIB_PATH,
64 | arq_config=ACBRLIB_INI_PATH,
65 | chave_crypt=ACBRLIB_CHAVE_CRYPT) as cep:
66 | enderecos = cep.buscar_por_cep('18270170')
67 | for endereco in enderecos:
68 | print(endereco)
69 |
70 |
71 | def consultar_por_logradouro():
72 | with ACBrLibCEP.usando(
73 | ACBRLIB_PATH,
74 | arq_config=ACBRLIB_INI_PATH,
75 | chave_crypt=ACBRLIB_CHAVE_CRYPT) as cep:
76 | enderecos = cep.buscar_por_logradouro(
77 | logradouro='Rua Brasil',
78 | municipio='Catanduva',
79 | uf='SP'
80 | )
81 | for ender in enderecos:
82 | print(ender)
83 |
84 |
85 | def manipulacao_de_configuracao():
86 | with ACBrLibCEP.usando(ACBRLIB_PATH) as cep:
87 | cep.config_ler(ACBRLIB_INI_PATH)
88 | # valor = cep.config_ler_valor('CEP', 'WebService')
89 | # print(f'CEP/WebService: {valor!r}')
90 | valor = cep.config_ler_valor('Principal', 'LogPath')
91 | print(f'Principal/LogPath: {valor!r}')
92 |
93 |
94 | if __name__ == '__main__':
95 | # iniciacao_simples()
96 | # iniciacao_simples_e_segura()
97 | # consultar_por_cep()
98 | consultar_por_logradouro()
99 | # manipulacao_de_configuracao()
100 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | [[package]]
2 | name = "appnope"
3 | version = "0.1.2"
4 | description = "Disable App Nap on macOS >= 10.9"
5 | category = "dev"
6 | optional = false
7 | python-versions = "*"
8 |
9 | [[package]]
10 | name = "atomicwrites"
11 | version = "1.4.0"
12 | description = "Atomic file writes."
13 | category = "dev"
14 | optional = false
15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
16 |
17 | [[package]]
18 | name = "attrs"
19 | version = "21.2.0"
20 | description = "Classes Without Boilerplate"
21 | category = "dev"
22 | optional = false
23 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
24 |
25 | [package.extras]
26 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
27 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
28 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
29 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
30 |
31 | [[package]]
32 | name = "backcall"
33 | version = "0.2.0"
34 | description = "Specifications for callback functions passed in to an API"
35 | category = "dev"
36 | optional = false
37 | python-versions = "*"
38 |
39 | [[package]]
40 | name = "colorama"
41 | version = "0.4.4"
42 | description = "Cross-platform colored terminal text."
43 | category = "dev"
44 | optional = false
45 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
46 |
47 | [[package]]
48 | name = "decorator"
49 | version = "5.1.0"
50 | description = "Decorators for Humans"
51 | category = "dev"
52 | optional = false
53 | python-versions = ">=3.5"
54 |
55 | [[package]]
56 | name = "iniconfig"
57 | version = "1.1.1"
58 | description = "iniconfig: brain-dead simple config-ini parsing"
59 | category = "dev"
60 | optional = false
61 | python-versions = "*"
62 |
63 | [[package]]
64 | name = "ipython"
65 | version = "7.28.0"
66 | description = "IPython: Productive Interactive Computing"
67 | category = "dev"
68 | optional = false
69 | python-versions = ">=3.7"
70 |
71 | [package.dependencies]
72 | appnope = {version = "*", markers = "sys_platform == \"darwin\""}
73 | backcall = "*"
74 | colorama = {version = "*", markers = "sys_platform == \"win32\""}
75 | decorator = "*"
76 | jedi = ">=0.16"
77 | matplotlib-inline = "*"
78 | pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
79 | pickleshare = "*"
80 | prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0"
81 | pygments = "*"
82 | traitlets = ">=4.2"
83 |
84 | [package.extras]
85 | all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"]
86 | doc = ["Sphinx (>=1.3)"]
87 | kernel = ["ipykernel"]
88 | nbconvert = ["nbconvert"]
89 | nbformat = ["nbformat"]
90 | notebook = ["notebook", "ipywidgets"]
91 | parallel = ["ipyparallel"]
92 | qtconsole = ["qtconsole"]
93 | test = ["nose (>=0.10.1)", "requests", "testpath", "pygments", "nbformat", "ipykernel", "numpy (>=1.17)"]
94 |
95 | [[package]]
96 | name = "jedi"
97 | version = "0.18.0"
98 | description = "An autocompletion tool for Python that can be used for text editors."
99 | category = "dev"
100 | optional = false
101 | python-versions = ">=3.6"
102 |
103 | [package.dependencies]
104 | parso = ">=0.8.0,<0.9.0"
105 |
106 | [package.extras]
107 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
108 | testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<6.0.0)"]
109 |
110 | [[package]]
111 | name = "matplotlib-inline"
112 | version = "0.1.3"
113 | description = "Inline Matplotlib backend for Jupyter"
114 | category = "dev"
115 | optional = false
116 | python-versions = ">=3.5"
117 |
118 | [package.dependencies]
119 | traitlets = "*"
120 |
121 | [[package]]
122 | name = "packaging"
123 | version = "21.0"
124 | description = "Core utilities for Python packages"
125 | category = "dev"
126 | optional = false
127 | python-versions = ">=3.6"
128 |
129 | [package.dependencies]
130 | pyparsing = ">=2.0.2"
131 |
132 | [[package]]
133 | name = "parso"
134 | version = "0.8.2"
135 | description = "A Python Parser"
136 | category = "dev"
137 | optional = false
138 | python-versions = ">=3.6"
139 |
140 | [package.extras]
141 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
142 | testing = ["docopt", "pytest (<6.0.0)"]
143 |
144 | [[package]]
145 | name = "pexpect"
146 | version = "4.8.0"
147 | description = "Pexpect allows easy control of interactive console applications."
148 | category = "dev"
149 | optional = false
150 | python-versions = "*"
151 |
152 | [package.dependencies]
153 | ptyprocess = ">=0.5"
154 |
155 | [[package]]
156 | name = "pickleshare"
157 | version = "0.7.5"
158 | description = "Tiny 'shelve'-like database with concurrency support"
159 | category = "dev"
160 | optional = false
161 | python-versions = "*"
162 |
163 | [[package]]
164 | name = "pluggy"
165 | version = "1.0.0"
166 | description = "plugin and hook calling mechanisms for python"
167 | category = "dev"
168 | optional = false
169 | python-versions = ">=3.6"
170 |
171 | [package.extras]
172 | dev = ["pre-commit", "tox"]
173 | testing = ["pytest", "pytest-benchmark"]
174 |
175 | [[package]]
176 | name = "prompt-toolkit"
177 | version = "3.0.20"
178 | description = "Library for building powerful interactive command lines in Python"
179 | category = "dev"
180 | optional = false
181 | python-versions = ">=3.6.2"
182 |
183 | [package.dependencies]
184 | wcwidth = "*"
185 |
186 | [[package]]
187 | name = "ptyprocess"
188 | version = "0.7.0"
189 | description = "Run a subprocess in a pseudo terminal"
190 | category = "dev"
191 | optional = false
192 | python-versions = "*"
193 |
194 | [[package]]
195 | name = "py"
196 | version = "1.10.0"
197 | description = "library with cross-python path, ini-parsing, io, code, log facilities"
198 | category = "dev"
199 | optional = false
200 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
201 |
202 | [[package]]
203 | name = "pygments"
204 | version = "2.10.0"
205 | description = "Pygments is a syntax highlighting package written in Python."
206 | category = "dev"
207 | optional = false
208 | python-versions = ">=3.5"
209 |
210 | [[package]]
211 | name = "pyparsing"
212 | version = "2.4.7"
213 | description = "Python parsing module"
214 | category = "dev"
215 | optional = false
216 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
217 |
218 | [[package]]
219 | name = "pytest"
220 | version = "6.2.5"
221 | description = "pytest: simple powerful testing with Python"
222 | category = "dev"
223 | optional = false
224 | python-versions = ">=3.6"
225 |
226 | [package.dependencies]
227 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
228 | attrs = ">=19.2.0"
229 | colorama = {version = "*", markers = "sys_platform == \"win32\""}
230 | iniconfig = "*"
231 | packaging = "*"
232 | pluggy = ">=0.12,<2.0"
233 | py = ">=1.8.2"
234 | toml = "*"
235 |
236 | [package.extras]
237 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
238 |
239 | [[package]]
240 | name = "toml"
241 | version = "0.10.2"
242 | description = "Python Library for Tom's Obvious, Minimal Language"
243 | category = "dev"
244 | optional = false
245 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
246 |
247 | [[package]]
248 | name = "traitlets"
249 | version = "5.1.0"
250 | description = "Traitlets Python configuration system"
251 | category = "dev"
252 | optional = false
253 | python-versions = ">=3.7"
254 |
255 | [package.extras]
256 | test = ["pytest"]
257 |
258 | [[package]]
259 | name = "unidecode"
260 | version = "1.3.2"
261 | description = "ASCII transliterations of Unicode text"
262 | category = "main"
263 | optional = false
264 | python-versions = ">=3.5"
265 |
266 | [[package]]
267 | name = "wcwidth"
268 | version = "0.2.5"
269 | description = "Measures the displayed width of unicode strings in a terminal"
270 | category = "dev"
271 | optional = false
272 | python-versions = "*"
273 |
274 | [metadata]
275 | lock-version = "1.1"
276 | python-versions = "^3.9"
277 | content-hash = "047b6d30629dc03ed9c9656e19ce04dad9bcbd619f04f161e7a40a93f6e12cb6"
278 |
279 | [metadata.files]
280 | appnope = [
281 | {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"},
282 | {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"},
283 | ]
284 | atomicwrites = [
285 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
286 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
287 | ]
288 | attrs = [
289 | {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
290 | {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
291 | ]
292 | backcall = [
293 | {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
294 | {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
295 | ]
296 | colorama = [
297 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
298 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
299 | ]
300 | decorator = [
301 | {file = "decorator-5.1.0-py3-none-any.whl", hash = "sha256:7b12e7c3c6ab203a29e157335e9122cb03de9ab7264b137594103fd4a683b374"},
302 | {file = "decorator-5.1.0.tar.gz", hash = "sha256:e59913af105b9860aa2c8d3272d9de5a56a4e608db9a2f167a8480b323d529a7"},
303 | ]
304 | iniconfig = [
305 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
306 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
307 | ]
308 | ipython = [
309 | {file = "ipython-7.28.0-py3-none-any.whl", hash = "sha256:f16148f9163e1e526f1008d7c8d966d9c15600ca20d1a754287cf96d00ba6f1d"},
310 | {file = "ipython-7.28.0.tar.gz", hash = "sha256:2097be5c814d1b974aea57673176a924c4c8c9583890e7a5f082f547b9975b11"},
311 | ]
312 | jedi = [
313 | {file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"},
314 | {file = "jedi-0.18.0.tar.gz", hash = "sha256:92550a404bad8afed881a137ec9a461fed49eca661414be45059329614ed0707"},
315 | ]
316 | matplotlib-inline = [
317 | {file = "matplotlib-inline-0.1.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"},
318 | {file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"},
319 | ]
320 | packaging = [
321 | {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
322 | {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
323 | ]
324 | parso = [
325 | {file = "parso-0.8.2-py2.py3-none-any.whl", hash = "sha256:a8c4922db71e4fdb90e0d0bc6e50f9b273d3397925e5e60a717e719201778d22"},
326 | {file = "parso-0.8.2.tar.gz", hash = "sha256:12b83492c6239ce32ff5eed6d3639d6a536170723c6f3f1506869f1ace413398"},
327 | ]
328 | pexpect = [
329 | {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
330 | {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
331 | ]
332 | pickleshare = [
333 | {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
334 | {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
335 | ]
336 | pluggy = [
337 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
338 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
339 | ]
340 | prompt-toolkit = [
341 | {file = "prompt_toolkit-3.0.20-py3-none-any.whl", hash = "sha256:6076e46efae19b1e0ca1ec003ed37a933dc94b4d20f486235d436e64771dcd5c"},
342 | {file = "prompt_toolkit-3.0.20.tar.gz", hash = "sha256:eb71d5a6b72ce6db177af4a7d4d7085b99756bf656d98ffcc4fecd36850eea6c"},
343 | ]
344 | ptyprocess = [
345 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
346 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
347 | ]
348 | py = [
349 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
350 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
351 | ]
352 | pygments = [
353 | {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"},
354 | {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"},
355 | ]
356 | pyparsing = [
357 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
358 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
359 | ]
360 | pytest = [
361 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
362 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
363 | ]
364 | toml = [
365 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
366 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
367 | ]
368 | traitlets = [
369 | {file = "traitlets-5.1.0-py3-none-any.whl", hash = "sha256:03f172516916220b58c9f19d7f854734136dd9528103d04e9bf139a92c9f54c4"},
370 | {file = "traitlets-5.1.0.tar.gz", hash = "sha256:bd382d7ea181fbbcce157c133db9a829ce06edffe097bcf3ab945b435452b46d"},
371 | ]
372 | unidecode = [
373 | {file = "Unidecode-1.3.2-py3-none-any.whl", hash = "sha256:215fe33c9d1c889fa823ccb66df91b02524eb8cc8c9c80f9c5b8129754d27829"},
374 | {file = "Unidecode-1.3.2.tar.gz", hash = "sha256:669898c1528912bcf07f9819dc60df18d057f7528271e31f8ec28cc88ef27504"},
375 | ]
376 | wcwidth = [
377 | {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
378 | {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
379 | ]
380 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "acbrlib-python"
3 | version = "0.1.0"
4 | description = "Camada de abstração para acesso à ACBrLib em Python"
5 | license = "Apache-2.0"
6 | repository = "https://github.com/base4sistemas/acbrlib-python"
7 | authors = ["Daniel Gonçalves "]
8 | readme = "README.rst"
9 | classifiers = [
10 | "Development Status :: 1 - Planning",
11 | "Environment :: Other Environment",
12 | "Intended Audience :: Developers",
13 | "License :: OSI Approved :: Apache Software License",
14 | "Natural Language :: Portuguese (Brazilian)",
15 | "Operating System :: OS Independent",
16 | "Programming Language :: Python",
17 | "Programming Language :: Python :: 3",
18 | "Topic :: Office/Business",
19 | "Topic :: Office/Business :: Financial",
20 | "Topic :: Office/Business :: Financial :: Point-Of-Sale",
21 | "Topic :: Printing",
22 | "Topic :: Software Development",
23 | "Topic :: Software Development :: Libraries",
24 | ]
25 |
26 | [tool.poetry.dependencies]
27 | python = "^3.9"
28 | Unidecode = "^1.3.2"
29 |
30 | [tool.poetry.dev-dependencies]
31 | pytest = "*"
32 | ipython = "^7.28.0"
33 |
34 | [tool.poetry.urls]
35 | "Bug Tracker" = "https://github.com/base4sistemas/acbrlib-python/issues"
36 |
37 | [build-system]
38 | requires = ["poetry-core>=1.0.0"]
39 | build-backend = "poetry.core.masonry.api"
40 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # tests/__init__.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
--------------------------------------------------------------------------------
/tests/cep/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # tests/cep/__init__.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
--------------------------------------------------------------------------------
/tests/cep/test_resposta.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # tests/cep/test_resposta.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | import pytest
21 |
22 | from acbrlib_python.cep.impl import processar_resposta
23 | from acbrlib_python.cep.excecoes import ACBrLibCEPErroResposta
24 |
25 |
26 | def test_resposta_sem_resultados():
27 | """Uma resposta sem resultados deve resultar uma lista vazia."""
28 | conteudo = [
29 | '[CEP]',
30 | 'Quantidade=0',
31 | ]
32 | enderecos = processar_resposta('\n'.join(conteudo))
33 | assert len(enderecos) == 0
34 |
35 |
36 | def test_resposta_com_um_resultado():
37 | """Resposta normal, contendo um resultado."""
38 | conteudo = [
39 | '[Endereco1]',
40 | 'Bairro = Centro',
41 | 'CEP = 18270-170',
42 | 'Complemento =',
43 | 'IBGE_Municipio = 3554003',
44 | 'IBGE_UF = 35',
45 | 'Logradouro = Rua Coronel Aureliano de Camargo',
46 | 'Municipio = Tatuí',
47 | 'Tipo_Logradouro =',
48 | 'UF = SP',
49 | '',
50 | '[CEP]',
51 | 'Quantidade = 1',
52 | ]
53 | enderecos = processar_resposta('\n'.join(conteudo))
54 | assert len(enderecos) == 1
55 |
56 | e = enderecos[0]
57 | assert e.tipo_logradouro == ''
58 | assert e.logradouro == 'Rua Coronel Aureliano de Camargo'
59 | assert e.complemento == ''
60 | assert e.bairro == 'Centro'
61 | assert e.municipio == 'Tatuí'
62 | assert e.uf == 'SP'
63 | assert e.cep == '18270-170'
64 | assert e.ibge_municipio == '3554003'
65 | assert e.ibge_uf == '35'
66 |
67 |
68 | def test_resposta_mal_formada_sem_quantidade():
69 | """
70 | Testa uma resposta que não possui a seção que indica a quantidade de
71 | endereços encontrados.
72 | """
73 | conteudo = [
74 | '[Endereco1]',
75 | 'Tipo_Logradouro = Rua',
76 | ]
77 | with pytest.raises(ACBrLibCEPErroResposta):
78 | processar_resposta('\n'.join(conteudo))
79 |
80 |
81 | def test_resposta_mal_formada_sem_enderecos():
82 | """
83 | Testa uma resposta que indica a existência de 1 endereço, mas que não
84 | possui nenhuma seção ``EnderecoN``.
85 | """
86 | conteudo = [
87 | '[CEP]',
88 | 'Quantidade=1',
89 | ]
90 | with pytest.raises(ACBrLibCEPErroResposta):
91 | processar_resposta('\n'.join(conteudo))
92 |
--------------------------------------------------------------------------------
/tests/test_acbrlib_python.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # tests/test_acbrlib_python.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from acbrlib_python import __version__
21 |
22 |
23 | def test_version():
24 | assert __version__ == '0.1.0'
25 |
--------------------------------------------------------------------------------
/tests/test_proto.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | #
3 | # tests/test_proto.py
4 | #
5 | # Copyright 2021 Base4 Sistemas
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | from acbrlib_python import proto
21 | from acbrlib_python.constantes import AUTO
22 | from acbrlib_python.proto import ReferenceLibrary
23 | from acbrlib_python.proto import Signature
24 | from acbrlib_python.proto import common_method_prototypes
25 | from acbrlib_python.proto import config_method_prototypes
26 |
27 |
28 | class _FakeCDLL:
29 |
30 | def __init__(self, path, calling_convention):
31 | self._path = path
32 | self._calling_convention = calling_convention
33 |
34 |
35 | def test_referencelibrary_class_auto_cdecl(monkeypatch):
36 | def mockreturn(path, calling_convention):
37 | return _FakeCDLL(path, calling_convention)
38 | monkeypatch.setattr(proto, 'loader', mockreturn)
39 | lib = ReferenceLibrary('/var/lib.so')
40 | assert isinstance(lib.ref, _FakeCDLL)
41 | assert lib._path == '/var/lib.so'
42 | assert lib._calling_convention == AUTO
43 | assert lib._lazy_load is True
44 |
45 |
46 | def test_signature_class():
47 | original_args = ['a', 'b', 'c']
48 | s = Signature(original_args, restype='t')
49 | assert 'a' in s.argtypes
50 | assert 'b' in s.argtypes
51 | assert 'c' in s.argtypes
52 | assert 't' == s.restype
53 |
54 | # a lista em argtypes deve ser uma cópia da lista de
55 | # argumentos informada e, portanto, imutável externamente
56 | original_args.append('x')
57 | assert 'x' not in s.argtypes
58 |
59 | ext_args = s.argtypes
60 | ext_args.append('x')
61 | assert 'x' not in s.argtypes
62 |
63 |
64 | def test_common_method_prototypes_all():
65 | res = common_method_prototypes('CEP')
66 | assert 'CEP_Inicializar' in res
67 | assert 'CEP_Finalizar' in res
68 | assert 'CEP_UltimoRetorno' in res
69 | assert 'CEP_Nome' in res
70 | assert 'CEP_Versao' in res
71 |
72 |
73 | def test_common_method_prototypes_excluded():
74 | res = common_method_prototypes('CEP', excludes=['CEP_Finalizar'])
75 | assert 'CEP_Finalizar' not in res
76 |
77 |
78 | def test_config_method_prototypes_all():
79 | res = config_method_prototypes('NFE')
80 | assert 'NFE_ConfigLer' in res
81 | assert 'NFE_ConfigGravar' in res
82 | assert 'NFE_ConfigLerValor' in res
83 | assert 'NFE_ConfigGravarValor' in res
84 | assert 'NFE_ConfigImportar' in res
85 | assert 'NFE_ConfigExportar' in res
86 |
87 |
88 | def test_config_method_prototypes_excluded():
89 | res = config_method_prototypes(
90 | 'DIS',
91 | excludes=['DIS_ConfigImportar', 'DIS_ConfigExportar']
92 | )
93 | assert 'DIS_ConfigImportar' not in res
94 | assert 'DIS_ConfigExportar' not in res
95 |
--------------------------------------------------------------------------------