diff --git a/README.md b/README.md new file mode 100644 index 0000000..d821af1 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +![pyreportjasperbytesUVV logo](https://acesseonline-arquivos-publicos.s3.us-east-2.amazonaws.com/logo-pyreportjasper.png) + +# pyreportjasperbytesUVV + + +[![Python Versions](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue.svg)](#) +[![Java Versions](https://img.shields.io/badge/java-%3E=9%20and%20%3C=20-blue.svg)](#) +[![JVM](https://img.shields.io/badge/jvm-OpenJDK%20%7C%20Oracle%20%7C%20Corretto%20%7C%20Temurin-blue.svg)](#) +[![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20Mac-blue)](#) +[![License](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/EduardoSFReis/pyreportjasper/blob/master/LICENSE) + +Este pacote tem como objetivo compilar e processar relatórios **JasperReports** +(`.jrxml` e `.jasper`). Ele permite gerar relatórios complexos, prontos para +uso em produção, sem precisar escrever manualmente layout em HTML ou CSS. + +Com **JasperReports**, você pode criar relatórios em vários formatos: +PDF, HTML, Excel, OpenOffice e Word — tudo isso de forma simples e rápida. + +### Destaques do JasperReports +- Engine de relatórios poderoso, escrito em Java. +- Funciona com diversas fontes de dados (bancos, CSV, XML, JSON etc.). +- Possui grande comunidade e documentação. +- Altamente customizável, permitindo layouts avançados. + +### Sobre este fork +Este repositório é um **fork** de [PyReportJasper (acesseonline/pyreportjasper)](https://github.com/acesseonline/pyreportjasper). +A grande alteração nesta versão é que **todas as saídas são retornadas em bytes**. + +### Links Úteis +- **Code**: [GitHub](https://github.com/EduardoSFReis/pyreportjasper) +- **Issue tracker**: [GitHub Issues](https://github.com/EduardoSFReis/pyreportjasper/issues) +- **Documentation**: [Python Docs](https://pyreportjasper.readthedocs.io/en/latest/) +- **License**: [GNU GENERAL PUBLIC LICENSE](https://github.com/EduardoSFReis/pyreportjasper/blob/master/LICENSE) +- **Build status**: [![TestsCI](https://github.com/EduardoSFReis/pyreportjasper/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/EduardoSFReis/pyreportjasper/actions?query=workflow%3ATests) +- **Version**: [![PyPI version](https://img.shields.io/pypi/v/pyreportjasper?style=flat-square)](https://pypi.org/project/pyreportjasper/) + diff --git a/README.rst b/README.rst deleted file mode 100755 index b6bdcb8..0000000 --- a/README.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. image:: https://acesseonline-arquivos-publicos.s3.us-east-2.amazonaws.com/logo-pyreportjasper.png - :scale: 50 % - :alt: PyReportJasper logo - :align: center - -PyReportJasper -============== - -|pyversions| |javaversions| |jvm| |platform| |license| - -This package aims to be a solution to compile and process JasperReports -(.jrxml & .jasper files). - -Did you ever had to create a good looking Invoice with a lot of fields -for your great web app or desktop? - -I had to, and the solutions out there were not perfect. Generating -*HTML* + *CSS* to make a *PDF*? WTF? That doesn't make any sense! :) - -Then I found **JasperReports** the best open source solution for -reporting. - -**From their website:** - - The JasperReports Library is the world's most popular open source - reporting engine. It is entirely written in Java and it is able to - use data coming from any kind of data source and produce - pixel-perfect documents that can be viewed, printed or exported in a - variety of document formats including HTML, PDF, Excel, OpenOffice - and Word. - - -:Code: `GitHub - `_ -:Issue tracker: `GitHub Issues - `_ -:Documentation: `Python Docs`_ -:License: `GNU GENERAL PUBLIC LICENSE`_ -:Build status: |TestsCI|_ -:Version: |PypiVersion|_ |Conda|_ - - -.. |PypiVersion| image:: https://img.shields.io/pypi/v/pyreportjasper?style=flat-square -.. _PypiVersion: https://pypi.org/project/pyreportjasper/ - - -.. |TestsCI| image:: https://github.com/EduardoSFReis/pyreportjasper/actions/workflows/tests.yml/badge.svg?branch=master -.. _TestsCI: https://github.com/EduardoSFReis/pyreportjasper/actions?query=workflow%3ATests -.. |pyversions| image:: https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue.svg -.. |javaversions| image:: https://img.shields.io/badge/java-%3E=9%20and%20%3C=20-blue.svg -.. |jvm| image:: https://img.shields.io/badge/jvm-OpenJDK%20%7C%20Oracle%20%7C%20Corretto%20%7C%20Temurin-blue.svg -.. |platform| image:: https://img.shields.io/badge/platform-Linux%20%7C%20Windows%20%7C%20Mac-blue -.. _GNU GENERAL PUBLIC LICENSE: https://github.com/EduardoSFReis/pyreportjasper/blob/master/LICENSE -.. _Python Docs: https://pyreportjasper.readthedocs.io/en/latest/ -.. |license| image:: https://img.shields.io/badge/License-GPLv3-blue.svg - :target: https://github.com/EduardoSFReis/pyreportjasper/blob/master/LICENSE \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 8fe2f47..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,3 +0,0 @@ -[build-system] -requires = ["setuptools>=42", "wheel"] -build-backend = "setuptools.build_meta" diff --git a/pyreportjasper/__init__.py b/pyreportjasper/__init__.py index 341ed6c..a488350 100755 --- a/pyreportjasper/__init__.py +++ b/pyreportjasper/__init__.py @@ -2,7 +2,8 @@ # GNU GENERAL PUBLIC LICENSE # # 2023 Jadson Bonfim Ribeiro -# +## Versão alterada 2024 Eduardo Soares + from .pyreportjasper import PyReportJasper diff --git a/pyreportjasper/application_class_path.py b/pyreportjasper/application_class_path.py index 967c08d..d4b882b 100644 --- a/pyreportjasper/application_class_path.py +++ b/pyreportjasper/application_class_path.py @@ -2,7 +2,8 @@ # GNU GENERAL PUBLIC LICENSE # # 2023 Jadson Bonfim Ribeiro -# +## Versão alterada 2024 Eduardo Soares + class ApplicationClassPath: pass \ No newline at end of file diff --git a/pyreportjasper/config.py b/pyreportjasper/config.py index 0a8e98e..4e6d686 100644 --- a/pyreportjasper/config.py +++ b/pyreportjasper/config.py @@ -2,7 +2,8 @@ # GNU GENERAL PUBLIC LICENSE # # 2023 Jadson Bonfim Ribeiro -# +## Versão alterada 2024 Eduardo Soares + class Config: askFilter = None diff --git a/pyreportjasper/db.py b/pyreportjasper/db.py index 67bb5a1..2a8c39b 100644 --- a/pyreportjasper/db.py +++ b/pyreportjasper/db.py @@ -2,7 +2,8 @@ # GNU GENERAL PUBLIC LICENSE # # 2023 Jadson Bonfim Ribeiro -# +## Versão alterada 2024 Eduardo Soares + import os import jpype diff --git a/pyreportjasper/pyreportjasper.py b/pyreportjasper/pyreportjasper.py index 79ee54a..49b60dc 100644 --- a/pyreportjasper/pyreportjasper.py +++ b/pyreportjasper/pyreportjasper.py @@ -2,7 +2,8 @@ # GNU GENERAL PUBLIC LICENSE # # 2024 Jadson Bonfim Ribeiro -# +## Versão alterada 2024 Eduardo Soares + import os import warnings diff --git a/pyreportjasper/report.py b/pyreportjasper/report.py index 04218f7..3f53638 100644 --- a/pyreportjasper/report.py +++ b/pyreportjasper/report.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- # GNU GENERAL PUBLIC LICENSE # -# 2024 Jadson Bonfim Ribeiro -# +# 2023 Jadson Bonfim Ribeiro +## Versão alterada 2024 Eduardo Soares + import os import jpype import pathlib @@ -29,16 +29,6 @@ class Report: ('Boolean', 'java.lang.Boolean'), ('Float', 'java.lang.Float'), ('Date', 'java.util.Date'), - #TODO: Not yet implemented - # ('List', 'java.util.List'), - # ('Currency', 'java.util.Currency'), - # ('Image', 'java.awt.Image'), - # ('Byte', 'java.lang.Byte'), - # ('Character', 'java.lang.Character'), - # ('Short', 'java.lang.Short'), - # ('Long', 'java.lang.Long'), - # ('Float', 'java.lang.Float'), - # ('Double', 'java.lang.Double'), ]) @@ -119,40 +109,44 @@ def __init__(self, config: Config, input_file): if self.config.useJaxen: self.DefaultJasperReportsContext = jpype.JPackage('net').sf.jasperreports.engine.DefaultJasperReportsContext - self.context = self.DefaultJasperReportsContext.getInstance(); + self.context = self.DefaultJasperReportsContext.getInstance() self.JRPropertiesUtil = jpype.JPackage('net').sf.jasperreports.engine.JRPropertiesUtil - self.JRPropertiesUtil.getInstance(self.context).setProperty("net.sf.jasperreports.xpath.executer.factory", - "net.sf.jasperreports.engine.util.xml.JaxenXPathExecuterFactory"); + self.JRPropertiesUtil.getInstance(self.context).setProperty( + "net.sf.jasperreports.xpath.executer.factory", + "net.sf.jasperreports.engine.util.xml.JaxenXPathExecuterFactory" + ) + # Lendo o arquivo de entrada (bytes ou caminho) if isinstance(input_file, str) or isinstance(input_file, pathlib.PurePath): if not os.path.isfile(input_file): raise NameError('input_file is not file.') with open(input_file, 'rb') as file: - self.input_file = file.read() + self.input_file = file.read() elif isinstance(input_file, bytes): self.input_file = input_file else: raise NameError('input_file does not have a valid type. Please enter the file path or its bytes') - - # self.input_file = input_file + self.defaultLocale = self.Locale.getDefault() + if self.config.has_resource(): self.add_jar_class_path(self.config.resource) - if self.config.has_resource(): + if os.path.isdir(self.config.resource): try: res = self.File(self.config.resource) self.ApplicationClasspath.add(res) except Exception as ex: raise NameError( - 'It was not possible to add the path {0} to the Class Path: ERROR: {1}'\ - .format(self.config.resource, str(ex))) + 'It was not possible to add the path {0} to the Class Path: ERROR: {1}' \ + .format(self.config.resource, str(ex)) + ) if self.config.has_jdbc_dir(): self.add_jar_class_path(self.config.jdbcDir) + # Tenta carregar como .jasper ou .jrprint try: - # This fails in case of an jrxml file j_object = self.jvJRLoader.loadObject(self.ByteArrayInputStream(self.input_file)) cast_error = True try: @@ -160,19 +154,18 @@ def __init__(self, config: Config, input_file): cast_error = False self.initial_input_type = 'JASPER_REPORT' except: - # nothing to do here pass try: self.jasper_print = jpype.JObject(j_object, self.JasperPrint) cast_error = False self.initial_input_type = 'JASPER_PRINT' except: - # nothing to do here pass if cast_error: raise NameError('input file: {0} is not of a valid type'.format(self.input_file)) except Exception: + # Se não for .jasper/.jrprint, tenta compilar .jrxml try: self.jasper_design = self.JRXmlLoader.load(self.ByteArrayInputStream(self.input_file)) self.initial_input_type = 'JASPER_DESIGN' @@ -180,6 +173,7 @@ def __init__(self, config: Config, input_file): except Exception as ex: raise NameError('input file: {0} is not a valid jrxml file:'.format(str(ex))) + # Prepara subreports self.jasper_subreports = {} for subreport_name, subreport_file in self.config.subreports.items(): try: @@ -190,15 +184,12 @@ def __init__(self, config: Config, input_file): jasper_file_subreport = str(sub_report_without_ext) + '.jasper' if ext_sub_report == '.jrxml': print("Compiling: {}".format(subreport_file)) - self.jvJasperCompileManager.compileReportToFile(subreport_file, jasper_file_subreport) + self.jvJasperCompileManager.compileReportToFile(subreport_file, jasper_file_subreport) self.jasper_subreports[subreport_name] = self.jvJasperCompileManager.compileReport(subreport_jasper_design) except Exception: - raise NameError('input file: {0} is not a valid jrxml file'.format(subreport_name)) + raise NameError('input file: {0} is not a valid jrxml file'.format(subreport_name)) def compile(self): - # TODO: Avoid WARNING at first loading when compiling design into report. - # Illegal reflective access by net.sf.jasperreports.engine.util.ClassUtils - # to constructor com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl() self.jasper_report = self.jvJasperCompileManager.compileReport(self.jasper_design) if self.config.is_write_jasper(): if self.config.output: @@ -210,10 +201,6 @@ def compile(self): self.config.input = new_input def compile_to_file(self): - """ - Emit a .jasper compiled version of the report definition .jrxml file. - :return: - """ if self.initial_input_type == "JASPER_DESIGN": try: base = os.path.splitext(self.config.output)[0] @@ -228,75 +215,77 @@ def fill(self): def fill_internal(self): parameters = self.HashMap() - for key in self.config.params: - if isinstance(self.config.params[key], dict): - param_dict = self.config.params[key] - type_var = param_dict.get('type') + + # Converte params para tipos Java (quando configurado) + for key, value in self.config.params.items(): + if isinstance(value, dict): + type_var = value.get('type') if isinstance(type_var, self.TypeJava): type_instance_java = type_var.value type_name = type_var.name if type_instance_java: if type_name == 'BigInteger': - value_java = jpype.JClass(type_instance_java)(str(param_dict.get('value'))) - + val = str(value.get('value')) + value_java = jpype.JClass(type_instance_java)(val) elif type_name == 'Array': - list_values = param_dict.get('value') + list_values = value.get('value') first_val = list_values[0] - if type(first_val) == int: + if isinstance(first_val, int): IntArrayCls = JArray(JInt) - int_array = IntArrayCls(list_values) - value_java = int_array - elif type(first_val) == str: + value_java = IntArrayCls(list_values) + elif isinstance(first_val, str): StrArrayCls = JArray(JString) - str_array = StrArrayCls(list_values) - value_java = str_array + value_java = StrArrayCls(list_values) else: raise NameError('Array type only accepts Int and Str') elif type_name == 'ArrayList': - from java.util import ArrayList # pyright: ignore[reportMissingImports] + from java.util import ArrayList value_java = ArrayList() - list_values = param_dict.get('value') - for itm in list_values: - if type(itm) == int: + for itm in value.get('value'): + if isinstance(itm, int): value_java.add(JInt(itm)) - elif type(itm) == str: + elif isinstance(itm, str): value_java.add(JString(itm)) - elif type(itm) == bool: + elif isinstance(itm, bool): value_java.add(JBoolean(itm)) - elif type(itm) == float: + elif isinstance(itm, float): value_java.add(JFloat(itm)) else: - raise NameError('ArrayList type only accepts int, str, bool and float') + raise NameError('ArrayList type only accepts int, str, bool or float') elif type_name == 'String': - value_java = jpype.JClass(type_instance_java)(param_dict.get('value')) + value_java = jpype.JClass(type_instance_java)(value.get('value')) elif type_name == 'Integer': - value_java = jpype.JClass(type_instance_java)(str(param_dict.get('value'))) + val = str(value.get('value')) + value_java = jpype.JClass(type_instance_java)(val) elif type_name == 'Boolean': - if not isinstance(param_dict.get('value'), bool): - raise NameError('The value of the name parameter {} is not of type bool'.format(key)) - value_java = jpype.JClass(type_instance_java)(param_dict.get('value')) + if not isinstance(value.get('value'), bool): + raise NameError('Parameter {} is not of type bool'.format(key)) + value_java = jpype.JClass(type_instance_java)(value.get('value')) elif type_name == 'Float': - if not isinstance(param_dict.get('value'), float): - raise NameError('The value of the name parameter {} is not of type float'.format(key)) - value_java = jpype.JClass(type_instance_java)(param_dict.get('value')) - elif type_name == 'Date': - from java.util import Calendar, Date # pyright: ignore[reportMissingImports] - from java.text import DateFormat, SimpleDateFormat # pyright: ignore[reportMissingImports] - - format_in = param_dict.get('format_input', 'yyyy-MM-dd') # Ex.: "dd/MM/yyyy" + if not isinstance(value.get('value'), float): + raise NameError('Parameter {} is not float'.format(key)) + value_java = jpype.JClass(type_instance_java)(value.get('value')) + elif type_name == 'Date': + from java.util import Calendar, Date + from java.text import SimpleDateFormat + format_in = value.get('format_input', 'yyyy-MM-dd') sdf = SimpleDateFormat(format_in) - value_java = sdf.parse(param_dict.get('value')) # Output of type: java.util.Date + value_java = sdf.parse(value.get('value')) + else: + raise NameError('Unknown TypeJava: {}'.format(type_name)) parameters.put(key, value_java) else: - raise NameError('Instance JAVA not locate') + raise NameError('Instance JAVA not locate') else: - print('{} parameter does not have an TypeJava type'.format(key)) + # Se não é TypeJava, insere do jeito que veio + parameters.put(key, value) else: - parameters.put(key, self.config.params[key]) - - # /!\ NOTE: Sub-reports are loaded after params to avoid them to be override + parameters.put(key, value) + + # Carrega subreports for subreport_key, subreport in self.jasper_subreports.items(): parameters.put(subreport_key, subreport) + try: if self.config.locale: self.config.locale = self.LocaleUtils.toLocale(self.config.locale) @@ -304,8 +293,9 @@ def fill_internal(self): if self.config.dbType is None: empty_data_source = self.JREmptyDataSource() - self.jasper_print = self.jvJasperFillManager.fillReport(self.jasper_report, parameters, - empty_data_source) + self.jasper_print = self.jvJasperFillManager.fillReport( + self.jasper_report, parameters, empty_data_source + ) elif self.config.dbType == 'csv': db = Db() ds = db.get_csv_datasource(self.config) @@ -318,7 +308,6 @@ def fill_internal(self): self.jasper_print = self.jvJasperFillManager.fillReport(self.jasper_report, parameters, ds) elif self.config.dbType == 'json': if self.config.jsonQuery is None: - # try to get json query stored in the report self.config.jsonQuery = self.get_main_dataset_query() db = Db() ds = db.get_json_datasource(self.config) @@ -327,7 +316,6 @@ def fill_internal(self): self.jasper_print = self.jvJasperFillManager.fillReport(self.jasper_report, parameters, ds) elif self.config.dbType == 'jsonql': if self.config.jsonQLQuery is None: - # try to get jsonql query stored in the report self.config.jsonQuery = self.get_main_dataset_query() db = Db() ds = db.get_jsonql_datasource(self.config) @@ -340,154 +328,192 @@ def fill_internal(self): except Exception as ex: raise NameError('Erro fill internal: {}'.format(str(ex))) - def get_output_stream(self, suffix): - """ - Return a file-based output stream with the given suffix - :param suffix: - :return: FileOutputStream - """ - if os.path.isdir(self.config.output): - base = os.path.basename(self.input_file) - name_file = os.path.splitext(base)[0] - output_path = os.path.splitext(self.config.output)[0] + name_file + suffix - else: - output_path = os.path.splitext(self.config.output)[0] + suffix - try: - output_stream = self.FileOutputStream(self.File(output_path)) - return output_stream - except Exception as ex: - raise NameError('Unable to create outputStream to {}: {}'.format(output_path, str(ex))) + # ========================================================================= + # Métodos de exportação - todos retornam bytes + # ========================================================================= - def get_output_stream_pdf(self): + def export_pdf(self): + """Retorna o arquivo PDF em bytes.""" output_stream = self.ByteArrayOutputStream() self.JasperExportManager.exportReportToPdfStream(self.jasper_print, output_stream) - return output_stream - - def fetch_pdf_report(self): - output_stream_pdf = self.get_output_stream_pdf() - res = self.String(output_stream_pdf.toByteArray(), 'UTF-8') - return bytes(str(res), 'UTF-8') - - def export_pdf_bytes(self): - output_stream_pdf = self.get_output_stream_pdf() - pdf_bytes = output_stream_pdf.toByteArray() - return pdf_bytes - - def export_pdf(self): - output_stream = self.get_output_stream('.pdf') - output_stream_pdf = self.get_output_stream_pdf() - output_stream_pdf.writeTo(output_stream) - output_stream_pdf.flush() # if no buffer used, it can be ignored. - output_stream_pdf.close() + return output_stream.toByteArray() def export_html(self): + """Retorna o relatório em HTML (string codificada em bytes).""" exporter = self.HtmlExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - output_stream = self.SimpleHtmlExporterOutput(self.get_output_stream(".html")) - exporter.setExporterOutput(output_stream) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleHtmlExporterOutput(byte_out)) + exporter.exportReport() + return byte_out.toByteArray() def export_rtf(self): + """Retorna o relatório em RTF (bytes).""" exporter = self.JRRtfExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleWriterExporterOutput(self.get_output_stream('.rtf'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleWriterExporterOutput(byte_out)) + exporter.exportReport() + return byte_out.toByteArray() def export_docx(self): + """Retorna o relatório em DOCX (bytes).""" exporter = self.JRDocxExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.docx'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) exporter.exportReport() + return byte_out.toByteArray() + def export_odt(self): + """Retorna o relatório em ODT (bytes).""" exporter = self.JROdtExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.odt'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) exporter.exportReport() + return byte_out.toByteArray() + def export_xml(self): + """Retorna o relatório em XML (bytes).""" exporter = self.JRXmlExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - output_stream = self.SimpleXmlExporterOutput(self.get_output_stream(".xml")) - output_stream.setEmbeddingImages(False) - exporter.setExporterOutput(output_stream) + + byte_out = self.ByteArrayOutputStream() + out_xml = self.SimpleXmlExporterOutput(byte_out) + out_xml.setEmbeddingImages(False) + exporter.setExporterOutput(out_xml) exporter.exportReport() + return byte_out.toByteArray() + def export_xls(self): + """Retorna o relatório em XLS (bytes).""" date_formats = self.HashMap() date_formats.put("EEE, MMM d, yyyy", "ddd, mmm d, yyyy") + exporter = self.JRXlsExporter() rep_config = self.SimpleXlsReportConfiguration() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.xls'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) + rep_config.setDetectCellType(True) rep_config.setFormatPatternsMap(date_formats) exporter.setConfiguration(rep_config) exporter.exportReport() + return byte_out.toByteArray() + def export_xls_meta(self): + """Retorna o relatório em XLS (com metadata) (bytes).""" date_formats = self.HashMap() date_formats.put("EEE, MMM d, yyyy", "ddd, mmm d, yyyy") + exporter = self.JRXlsMetadataExporter() rep_config = self.SimpleXlsMetadataReportConfiguration() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.xls'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) + rep_config.setDetectCellType(True) rep_config.setFormatPatternsMap(date_formats) exporter.setConfiguration(rep_config) exporter.exportReport() + return byte_out.toByteArray() + def export_xlsx(self): + """Retorna o relatório em XLSX (bytes).""" date_formats = self.HashMap() date_formats.put("EEE, MMM d, yyyy", "ddd, mmm d, yyyy") + exporter = self.JRXlsxExporter() rep_config = self.SimpleXlsxReportConfiguration() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.xlsx'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) + rep_config.setDetectCellType(True) rep_config.setFormatPatternsMap(date_formats) exporter.setConfiguration(rep_config) exporter.exportReport() + return byte_out.toByteArray() + def export_csv(self): + """Retorna o relatório em CSV (bytes).""" exporter = self.JRCsvExporter() configuration = self.SimpleCsvExporterConfiguration() configuration.setFieldDelimiter(self.config.outFieldDel) + exporter.setConfiguration(configuration) exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput( - self.SimpleWriterExporterOutput(self.get_output_stream(".csv"), self.config.outCharset)) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleWriterExporterOutput(byte_out, self.config.outCharset)) + exporter.exportReport() + return byte_out.toByteArray() def export_csv_meta(self): + """Retorna o relatório em CSV (com metadata) (bytes).""" exporter = self.JRCsvMetadataExporter() configuration = self.SimpleCsvMetadataExporterConfiguration() configuration.setFieldDelimiter(self.config.outFieldDel) + exporter.setConfiguration(configuration) exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput( - self.SimpleWriterExporterOutput(self.get_output_stream(".csv"), self.config.outCharset)) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleWriterExporterOutput(byte_out, self.config.outCharset)) + exporter.exportReport() + return byte_out.toByteArray() def export_ods(self): + """Retorna o relatório em ODS (bytes).""" exporter = self.JROdsExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.ods'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) exporter.exportReport() + return byte_out.toByteArray() + def export_pptx(self): + """Retorna o relatório em PPTX (bytes).""" exporter = self.JRPptxExporter() exporter.setExporterInput(self.SimpleExporterInput(self.jasper_print)) - exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(self.get_output_stream('.pptx'))) + + byte_out = self.ByteArrayOutputStream() + exporter.setExporterOutput(self.SimpleOutputStreamExporterOutput(byte_out)) exporter.exportReport() + return byte_out.toByteArray() + def export_jrprint(self): - self.JRSaver.saveObject(self.jasper_print, self.get_output_stream('.jrprint')) + """Retorna o relatório em JRPRINT (bytes).""" + byte_out = self.ByteArrayOutputStream() + self.JRSaver.saveObject(self.jasper_print, byte_out) + return byte_out.toByteArray() + def get_report_parameters(self): """ - getReportParameters - :return: an List of {@link net.sf.jasperreports.engine.JRParameter} objects + Retorna uma lista de objetos JRParameter do report. """ if self.jasper_report is not None: return_val = self.jasper_report.getParameters() @@ -497,11 +523,8 @@ def get_report_parameters(self): def get_main_dataset_query(self): """ - For JSON, JSONQL and any other data types that need a query to be provided, - an obvious default is to use the one written into the report, since that is - likely what the report designer debugged/intended to be used. This provides - access to the value so it can be used as needed. - :return: str of main dataset query + Para JSON, JSONQL e outros data types que precisam de query, + usar a query principal contida no próprio relatório. """ if self.initial_input_type == "JASPER_DESIGN": return self.jasper_design.getMainDesignDataset().getQuery().getText() @@ -518,4 +541,3 @@ def add_jar_class_path(self, dir_or_jar): jpype.addClassPath(dir_or_jar) except Exception as ex: raise NameError("Error adding class path: {}".format(ex)) - diff --git a/setup.cfg b/setup.cfg deleted file mode 100755 index dbfbbee..0000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[metadata] -description-file = README.rst -long-description-content-type = text/x-rst; charset=UTF-8 diff --git a/setup.py b/setup.py index 6f4ae19..56291c8 100755 --- a/setup.py +++ b/setup.py @@ -1,101 +1,60 @@ -# -*- coding: utf-8 -*- -# GNU GENERAL PUBLIC LICENSE -# -# 2023 Jadson Bonfim Ribeiro -# Versão alterada 2024 Eduardo Soares -# -from setuptools import setup, find_packages import io import os import re +from setuptools import setup, find_packages from collections import OrderedDict import subprocess - -def version_available(cmd): - try: - output = subprocess.call([cmd, "-version"]) - return output == 0 - except OSError as e: - # handle file not found error. - if e.errno == os.errno.ENOENT: - print("error please install " + cmd) - return False - else: - # Something else went wrong, raise the exception - raise - - -with io.open('README.rst', 'rt', encoding='utf8') as f: - readme = f.read() - - def get_version(package): - init_py = open(os.path.join(package, '__init__.py')).read() + with open(os.path.join(package, '__init__.py')) as f: + init_py = f.read() return re.search("__version__ = ['\"]([^'\"]+)['\"]", init_py).group(1) +with io.open("README.md", "rt", encoding="utf-8") as f: + long_description = f.read() setup( - name='pyreportjasperbytes', - version=get_version('pyreportjasper'), - url='https://github.com/acesseonline/pyreportjasper', - download_url='https://pypi.python.org/pypi/pyreportjasper/' + get_version('pyreportjasper'), + name="pyreportjasperbytesUVV", + version=get_version("pyreportjasper"), + url="https://github.com/EduardoSFReis/pyreportjasper", + download_url="https://pypi.org/project/pyreportjasperbytesUVV/" + get_version("pyreportjasper"), project_urls=OrderedDict(( - ('Documentation', 'https://pyreportjasper.readthedocs.io/en/master/'), - ('Code', 'https://github.com/acesseonline/pyreportjasper'), - ('Issue tracker', 'https://github.com/acesseonline/pyreportjasper/issues'), + ("Documentation", "https://pyreportjasper.readthedocs.io/en/master/"), + ("Code", "https://github.com/EduardoSFReis/pyreportjasper"), + ("Issue tracker", "https://github.com/EduardoSFReis/pyreportjasper/issues"), )), - license='GPLv3', - author='Eduardo Soares Franco Reis', - author_email='edufrancoreis@hotmail.com', - maintainer='Eduardo Soares Franco Reis', - maintainer_email='edufrancoreis@hotmail.com', - keywords='report jasper python', - description='This package aims to be a solution to compile and process ' - 'JasperReports (.jrxml & .jasper files).', - long_description=open('README.rst').read(), - long_description_content_type="text/x-rst", - zip_safe=False, - platforms=[ - 'Operating System :: Microsoft :: Windows', - 'Operating System :: POSIX', - 'Operating System :: Unix', - 'Operating System :: MacOS', - ], - python_requires=">=3.7", + license="GPLv3", + author="Eduardo Soares Franco Reis", + author_email="edufrancoreis@hotmail.com", + maintainer="Eduardo Soares Franco Reis", + maintainer_email="edufrancoreis@hotmail.com", + keywords="report jasper python", + description="This package aims to be a solution to compile and process JasperReports (.jrxml & .jasper files).", + long_description=long_description, + long_description_content_type="text/markdown", # <- IMPORTANTE packages=find_packages(), - install_requires=[ - 'jpype1' - ], + install_requires=["jpype1"], extras_require={ - # 'tests': [ - # 'pytest', - # ], - 'docs': [ - 'readthedocs-sphinx-ext', - 'sphinx', - 'sphinx-rtd-theme', - 'recommonmark', - 'commonmark', - 'mock', - 'docutils', - 'Pygments' + "docs": [ + "readthedocs-sphinx-ext", + "sphinx", + "sphinx-rtd-theme", + "recommonmark", + "commonmark", + "mock", + "docutils", + "Pygments", ], - }, - test_suite='tests', - package_data={ - 'package': ['libs/*'], }, - include_package_data=True, - has_ext_modules=lambda : True, + python_requires=">=3.7", classifiers=[ - 'Intended Audience :: Developers', - 'Operating System :: OS Independent', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], )