355 '",{0}{1}"'.format(os.linesep, i1string).join(modules), |
404 '",{0}{1}"'.format(os.linesep, i1string).join(modules), |
356 os.linesep) |
405 os.linesep) |
357 sourceCode += '{0}],{1}'.format(istring, os.linesep) |
406 sourceCode += '{0}],{1}'.format(istring, os.linesep) |
358 del modules |
407 del modules |
359 |
408 |
360 scripts = [] |
409 if self.entryPointsList.topLevelItemCount(): |
361 for row in range(self.scriptsList.count()): |
410 entryPoints = { |
362 scripts.append(self.scriptsList.item(row).text()) |
411 "console_scripts": [], |
363 if scripts: |
412 "gui_scripts": [], |
364 sourceCode += '{0}scripts=[{1}'.format(istring, os.linesep) |
413 } |
365 sourceCode += '{0}"{1}"{2}'.format( |
414 for row in range(self.entryPointsList.topLevelItemCount()): |
366 i1string, |
415 itm = self.entryPointsList.topLevelItem(row) |
367 '",{0}{1}"'.format(os.linesep, i1string).join(scripts), |
416 entryPoints[itm.data(0, Qt.ItemDataRole.UserRole)].append( |
368 os.linesep) |
417 "{0} = {1}".format(itm.text(1), itm.text(2)) |
369 sourceCode += '{0}],{1}'.format(istring, os.linesep) |
418 ) |
370 del scripts |
419 sourceCode += '{0}entry_points={{{1}'.format(istring, os.linesep) |
|
420 for epCategory in entryPoints: |
|
421 if entryPoints[epCategory]: |
|
422 sourceCode += '{0}"{1}": [{2}'.format( |
|
423 i1string, epCategory, os.linesep) |
|
424 for entryPoint in entryPoints[epCategory]: |
|
425 sourceCode += '{0}"{1}",{2}'.format( |
|
426 i2string, entryPoint, os.linesep) |
|
427 sourceCode += '{0}],{1}'.format(i1string, os.linesep) |
|
428 sourceCode += '{0}}},{1}'.format(istring, os.linesep) |
371 |
429 |
372 sourceCode += "){0}".format(estring) |
430 sourceCode += "){0}".format(estring) |
373 return sourceCode |
431 return sourceCode |
|
432 |
|
433 def __getSetupCfgCode(self): |
|
434 """ |
|
435 Private method to get the source code for a 'setup.cfg' file. |
|
436 |
|
437 @return generated code |
|
438 @rtype str |
|
439 """ |
|
440 from . import SetupCfgUtilities |
|
441 metadata = { |
|
442 "name": self.nameEdit.text(), |
|
443 "version": self.versionEdit.text(), |
|
444 } |
|
445 |
|
446 if self.summaryEdit.text(): |
|
447 metadata["description"] = self.summaryEdit.text() |
|
448 |
|
449 if self.descriptionEdit.toPlainText(): |
|
450 metadata["long_description"] = ( |
|
451 "file: {0}".format( |
|
452 ", ".join(self.descriptionEdit.toPlainText().splitlines()) |
|
453 ) |
|
454 if self.descriptionFromFilesCheckBox.isChecked() else |
|
455 self.descriptionEdit.toPlainText() |
|
456 ) |
|
457 |
|
458 if self.descriptionContentTypeComboBox.currentData(): |
|
459 metadata["long_description_content_type"] = ( |
|
460 self.descriptionContentTypeComboBox.currentData() |
|
461 ) |
|
462 |
|
463 if self.authorEdit.text(): |
|
464 metadata["author"] = self.authorEdit.text() |
|
465 metadata["author_email"] = self.authorEmailEdit.text() |
|
466 |
|
467 if self.maintainerEdit.text(): |
|
468 metadata["maintainer"] = self.maintainerEdit.text() |
|
469 metadata["maintainer_email"] = self.maintainerEmailEdit.text() |
|
470 |
|
471 metadata["url"] = self.homePageUrlEdit.text() |
|
472 if self.downloadUrlEdit.text(): |
|
473 metadata["download_url"] = self.downloadUrlEdit.text() |
|
474 |
|
475 if self.projectUrlsList.topLevelItemCount(): |
|
476 projectURLs = {} |
|
477 for row in range(self.projectUrlsList.topLevelItemCount()): |
|
478 urlItem = self.projectUrlsList.topLevelItem(row) |
|
479 projectURLs[urlItem.text(0)] = urlItem.text(1) |
|
480 metadata["project_urls"] = SetupCfgUtilities.toString(projectURLs) |
|
481 |
|
482 classifiers = [] |
|
483 if not self.licenseClassifierCheckBox.isChecked(): |
|
484 metadata["license"] = self.licenseEdit.text() |
|
485 else: |
|
486 classifiers.append( |
|
487 self.licenseClassifierComboBox.itemData( |
|
488 self.licenseClassifierComboBox.currentIndex())) |
|
489 |
|
490 platforms = self.platformsEdit.toPlainText().splitlines() |
|
491 if platforms: |
|
492 metadata["platforms"] = SetupCfgUtilities.toString(platforms) |
|
493 |
|
494 if self.developmentStatusComboBox.currentIndex() != 0: |
|
495 classifiers.append(self.developmentStatusComboBox.currentData()) |
|
496 |
|
497 itm = self.classifiersList.topLevelItem(0) |
|
498 while itm: |
|
499 itm.setExpanded(True) |
|
500 if itm.checkState(0) == Qt.CheckState.Checked: |
|
501 classifiers.append(itm.data(0, Qt.ItemDataRole.UserRole)) |
|
502 itm = self.classifiersList.itemBelow(itm) |
|
503 |
|
504 # cleanup classifiers list - remove all invalid entries |
|
505 classifiers = [c for c in classifiers if bool(c)] |
|
506 if classifiers: |
|
507 metadata["classifiers"] = SetupCfgUtilities.toString(classifiers) |
|
508 |
|
509 if self.keywordsEdit.text(): |
|
510 metadata["keywords"] = SetupCfgUtilities.toString( |
|
511 self.keywordsEdit.text().split()) |
|
512 |
|
513 options = { |
|
514 "packages": "find:" |
|
515 } |
|
516 |
|
517 if self.pyVersionEdit.text(): |
|
518 options["python_requires"] = self.pyVersionEdit.text() |
|
519 |
|
520 findOptions = {} |
|
521 src = Utilities.fromNativeSeparators(self.sourceDirectoryPicker.text()) |
|
522 excludePatterns = [] |
|
523 for row in range(self.excludePatternList.count()): |
|
524 excludePatterns.append( |
|
525 self.excludePatternList.item(row).text()) |
|
526 if src: |
|
527 options["package_dir"] = SetupCfgUtilities.toString({"": src}) |
|
528 findOptions["where"] = src |
|
529 if excludePatterns: |
|
530 findOptions["exclude"] = SetupCfgUtilities.toString(excludePatterns) |
|
531 |
|
532 if self.includePackageDataCheckBox.isChecked(): |
|
533 options["include_package_data"] = SetupCfgUtilities.toString(True) |
|
534 packageData = {} # placeholder section |
|
535 else: |
|
536 packageData = None |
|
537 |
|
538 modules = [] |
|
539 for row in range(self.modulesList.count()): |
|
540 modules.append(self.modulesList.item(row).text()) |
|
541 if modules: |
|
542 options["py_modules"] = SetupCfgUtilities.toString(modules) |
|
543 |
|
544 if self.entryPointsList.topLevelItemCount(): |
|
545 entryPoints = { |
|
546 "console_scripts": {}, |
|
547 "gui_scripts": {}, |
|
548 } |
|
549 for row in range(self.entryPointsList.topLevelItemCount()): |
|
550 itm = self.entryPointsList.topLevelItem(row) |
|
551 entryPoints[itm.data(0, Qt.ItemDataRole.UserRole)][ |
|
552 itm.text(1)] = itm.text(2) |
|
553 for epType in list(entryPoints.keys()): |
|
554 if entryPoints[epType]: |
|
555 entryPoints[epType] = SetupCfgUtilities.toString( |
|
556 entryPoints[epType]) |
|
557 else: |
|
558 del entryPoints[epType] |
|
559 else: |
|
560 entryPoints = {} |
|
561 |
|
562 configDict = { |
|
563 "metadata": metadata, |
|
564 "options": options, |
|
565 "options.packages.find": findOptions, |
|
566 } |
|
567 if packageData is not None: |
|
568 configDict["options.package_data"] = packageData |
|
569 if entryPoints: |
|
570 configDict["options.entry_points"] = entryPoints |
|
571 |
|
572 cparser = configparser.ConfigParser() |
|
573 cparser.read_dict(configDict) |
|
574 sio = io.StringIO() |
|
575 cparser.write(sio) |
|
576 sourceCode = sio.getvalue() |
|
577 return sourceCode |
|
578 |
|
579 def __getPyprojectCode(self): |
|
580 """ |
|
581 Private method to get the source code for a 'pyproject.toml' file. |
|
582 |
|
583 @return generated code |
|
584 @rtype str |
|
585 """ |
|
586 doc = tomlkit.document() |
|
587 |
|
588 buildSystem = tomlkit.table() |
|
589 buildSystem["requires"] = ["setuptools>=61.0.0", "wheel"] |
|
590 buildSystem["build-backend"] = "setuptools.build_meta" |
|
591 doc["build-system"] = buildSystem |
|
592 |
|
593 project = tomlkit.table() |
|
594 project["name"] = self.nameEdit.text() |
|
595 project["version"] = self.versionEdit.text() |
|
596 |
|
597 if self.summaryEdit.text(): |
|
598 project["description"] = self.summaryEdit.text() |
|
599 |
|
600 if self.descriptionEdit.toPlainText(): |
|
601 if self.descriptionFromFilesCheckBox.isChecked(): |
|
602 project["readme"] = self.descriptionEdit.toPlainText().splitlines()[0] |
|
603 else: |
|
604 readme = tomlkit.table() |
|
605 readme["text"] = self.descriptionEdit.toPlainText() |
|
606 readme["content-type"] = ( |
|
607 self.descriptionContentTypeComboBox.currentData() |
|
608 ) |
|
609 project["readme"] = readme |
|
610 |
|
611 if self.authorEdit.text(): |
|
612 authors = tomlkit.array() |
|
613 author = tomlkit.inline_table() |
|
614 author["name"] = self.authorEdit.text() |
|
615 author["email"] = self.authorEmailEdit.text() |
|
616 authors.append(author) |
|
617 project["authors"] = authors |
|
618 |
|
619 if self.maintainerEdit.text(): |
|
620 maintainers = tomlkit.array() |
|
621 maintainer = tomlkit.inline_table() |
|
622 maintainer["name"] = self.maintainerEdit.text() |
|
623 maintainer["email"] = self.maintainerEmailEdit.text() |
|
624 maintainers.append(maintainer) |
|
625 project["maintainers"] = maintainers |
|
626 |
|
627 urls = tomlkit.table() |
|
628 urls["Homepage"] = self.homePageUrlEdit.text() |
|
629 if self.downloadUrlEdit.text(): |
|
630 urls["Download"] = self.downloadUrlEdit.text() |
|
631 |
|
632 if self.projectUrlsList.topLevelItemCount(): |
|
633 for row in range(self.projectUrlsList.topLevelItemCount()): |
|
634 urlItem = self.projectUrlsList.topLevelItem(row) |
|
635 urls[urlItem.text(0)] = urlItem.text(1) |
|
636 project["urls"] = urls |
|
637 |
|
638 classifiers = [] |
|
639 if not self.licenseClassifierCheckBox.isChecked(): |
|
640 license = tomlkit.table() |
|
641 license["text"] = self.licenseEdit.text() |
|
642 project["license"] = license |
|
643 else: |
|
644 classifiers.append( |
|
645 self.licenseClassifierComboBox.itemData( |
|
646 self.licenseClassifierComboBox.currentIndex())) |
|
647 |
|
648 if self.developmentStatusComboBox.currentIndex() != 0: |
|
649 classifiers.append(self.developmentStatusComboBox.currentData()) |
|
650 |
|
651 itm = self.classifiersList.topLevelItem(0) |
|
652 while itm: |
|
653 itm.setExpanded(True) |
|
654 if itm.checkState(0) == Qt.CheckState.Checked: |
|
655 classifiers.append(itm.data(0, Qt.ItemDataRole.UserRole)) |
|
656 itm = self.classifiersList.itemBelow(itm) |
|
657 |
|
658 # cleanup classifiers list - remove all invalid entries |
|
659 classifiers = [c for c in classifiers if bool(c)] |
|
660 if classifiers: |
|
661 classifiersArray = tomlkit.array() |
|
662 for classifier in classifiers: |
|
663 classifiersArray.add_line(classifier) |
|
664 classifiersArray.append(tomlkit.nl()) |
|
665 project["classifiers"] = classifiersArray |
|
666 |
|
667 if self.keywordsEdit.text(): |
|
668 keywords = tomlkit.array() |
|
669 for kw in self.keywordsEdit.text().split(): |
|
670 keywords.add_line(kw) |
|
671 keywords.append(tomlkit.nl()) |
|
672 project["keywords"] = keywords |
|
673 |
|
674 if self.pyVersionEdit.text(): |
|
675 project["requires-python"] = self.pyVersionEdit.text() |
|
676 |
|
677 if self.entryPointsList.topLevelItemCount(): |
|
678 entryPoints = { |
|
679 "console_scripts": {}, |
|
680 "gui_scripts": {}, |
|
681 } |
|
682 for row in range(self.entryPointsList.topLevelItemCount()): |
|
683 itm = self.entryPointsList.topLevelItem(row) |
|
684 entryPoints[itm.data(0, Qt.ItemDataRole.UserRole)][ |
|
685 itm.text(1)] = itm.text(2) |
|
686 |
|
687 if entryPoints["console_scripts"]: |
|
688 scripts = tomlkit.table() |
|
689 for name, function in entryPoints["console_scripts"].items(): |
|
690 scripts[name] = function |
|
691 project["scripts"] = scripts |
|
692 |
|
693 if entryPoints["gui_scripts"]: |
|
694 guiScripts = tomlkit.table() |
|
695 for name, function in entryPoints["gui_scripts"].items(): |
|
696 guiScripts[name] = function |
|
697 project["gui-scripts"] = guiScripts |
|
698 |
|
699 # placeholder |
|
700 dependencies = tomlkit.array() |
|
701 dependencies.append(tomlkit.comment( |
|
702 "TODO: enter project dependencies " # __NO-TASK__ |
|
703 )) |
|
704 project["dependencies"] = dependencies |
|
705 |
|
706 doc["project"] = project |
|
707 |
|
708 setuptools = tomlkit.table() |
|
709 |
|
710 platforms = self.platformsEdit.toPlainText().splitlines() |
|
711 if platforms: |
|
712 platformsArray = tomlkit.array() |
|
713 for plt in platforms: |
|
714 platformsArray.add_line(plt) |
|
715 platformsArray.append(tomlkit.nl()) |
|
716 setuptools["platforms"] = platformsArray |
|
717 |
|
718 setuptools["include-package-data"] = self.includePackageDataCheckBox.isChecked() |
|
719 if self.includePackageDataCheckBox.isChecked(): |
|
720 # placeholder |
|
721 setuptools["package-data"] = tomlkit.table() |
|
722 setuptools["package-data"].add(tomlkit.comment( |
|
723 "TODO: enter package data patterns" # __NO-TASK__ |
|
724 )) |
|
725 |
|
726 if self.modulesList.count(): |
|
727 modulesArray = tomlkit.array() |
|
728 for row in range(self.modulesList.count()): |
|
729 modulesArray.add_line(self.modulesList.item(row).text()) |
|
730 modulesArray.append(tomlkit.nl()) |
|
731 setuptools["py-modules"] = modulesArray |
|
732 |
|
733 findspec = tomlkit.table() |
|
734 src = Utilities.fromNativeSeparators(self.sourceDirectoryPicker.text()) |
|
735 excludePatterns = [] |
|
736 for row in range(self.excludePatternList.count()): |
|
737 excludePatterns.append( |
|
738 self.excludePatternList.item(row).text()) |
|
739 if src: |
|
740 findspec["where"] = [ericApp().getObject("Project").getRelativePath(src)] |
|
741 if excludePatterns: |
|
742 excludePatternsArray = tomlkit.array() |
|
743 for pattern in excludePatterns: |
|
744 excludePatternsArray.add_line(pattern) |
|
745 excludePatternsArray.append(tomlkit.nl()) |
|
746 findspec["exclude"] = excludePatternsArray |
|
747 |
|
748 if bool(findspec): |
|
749 setuptools["packages"] = tomlkit.table(is_super_table=True) |
|
750 setuptools["packages"]["find"] = findspec |
|
751 |
|
752 doc["tool"] = tomlkit.table(is_super_table=True) |
|
753 doc["tool"]["setuptools"] = setuptools |
|
754 |
|
755 sourceCode = tomlkit.dumps(doc) |
|
756 return sourceCode |
|
757 |
|
758 def getCode(self, indLevel, indString): |
|
759 """ |
|
760 Public method to get the source code. |
|
761 |
|
762 @param indLevel indentation level |
|
763 @type int |
|
764 @param indString string used for indentation (space or tab) |
|
765 @type str |
|
766 @return generated code |
|
767 @rtype str |
|
768 """ |
|
769 if self.__category == "setup.py": |
|
770 return self.__getSetupPyCode(indLevel, indString) |
|
771 elif self.__category == "setup.cfg": |
|
772 return self.__getSetupCfgCode() |
|
773 elif self.__category == "pyproject.toml": |
|
774 return self.__getPyprojectCode() |
|
775 else: |
|
776 # should not happen, but play it safe |
|
777 return "" |
374 |
778 |
375 @pyqtSlot() |
779 @pyqtSlot() |
376 def on_projectButton_clicked(self): |
780 def on_projectButton_clicked(self): |
377 """ |
781 """ |
378 Private slot to populate some fields with data retrieved from the |
782 Private slot to populate some fields with data retrieved from the |
413 """ |
817 """ |
414 return (Preferences.getMultiProject("Workspace") or |
818 return (Preferences.getMultiProject("Workspace") or |
415 Utilities.getHomeDir()) |
819 Utilities.getHomeDir()) |
416 |
820 |
417 @pyqtSlot() |
821 @pyqtSlot() |
418 def on_scriptsList_itemSelectionChanged(self): |
822 def on_entryPointsList_itemSelectionChanged(self): |
419 """ |
823 """ |
420 Private slot to handle a change of selected items of the |
824 Private slot to handle a change of selected items of the |
421 scripts list. |
825 entry points list. |
422 """ |
826 """ |
423 self.deleteScriptButton.setEnabled( |
827 self.deleteEntryPointButton.setEnabled( |
424 len(self.scriptsList.selectedItems()) > 0) |
828 bool(self.entryPointsList.selectedItems())) |
425 |
829 self.editEntryPointButton.setEnabled( |
426 @pyqtSlot() |
830 len(self.entryPointsList.selectedItems()) == 1) |
427 def on_deleteScriptButton_clicked(self): |
831 |
428 """ |
832 @pyqtSlot() |
429 Private slot to delete the selected script items. |
833 def on_deleteEntryPointButton_clicked(self): |
430 """ |
834 """ |
431 for itm in self.scriptsList.selectedItems(): |
835 Private slot to delete the selected entry point items. |
432 self.scriptsList.takeItem( |
836 """ |
433 self.scriptsList.row(itm)) |
837 for itm in self.entryPointsList.selectedItems(): |
|
838 self.entryPointsList.takeTopLevelItem(self.entryPointsList.row(itm)) |
434 del itm |
839 del itm |
435 |
840 |
436 @pyqtSlot() |
841 @pyqtSlot() |
437 def on_addScriptButton_clicked(self): |
842 def on_addEntryPointButton_clicked(self): |
438 """ |
843 """ |
439 Private slot to add scripts to the list. |
844 Private slot to add an entry point to the list. |
440 """ |
845 """ |
441 startDir = self.packageRootPicker.text() or self.__getStartDir() |
846 project = ericApp().getObject("Project") |
442 scriptsList = EricFileDialog.getOpenFileNames( |
847 rootDir = ( |
443 self, |
848 project.getProjectPath() |
444 self.tr("Add Scripts"), |
849 if project.isOpen() else |
445 startDir, |
850 "" |
446 self.tr("Python Files (*.py);;All Files(*)")) |
851 ) |
447 for script in scriptsList: |
852 dlg = AddEntryPointDialog(rootDir, parent=self) |
448 script = script.replace( |
853 if dlg.exec() == QDialog.DialogCode.Accepted: |
449 Utilities.toNativeSeparators(startDir), "") |
854 epType, epCategory, name, script = dlg.getEntryPoint() |
450 if script.startswith(("\\", "/")): |
855 itm = QTreeWidgetItem(self.entryPointsList, [epType, name, script]) |
451 script = script[1:] |
856 itm.setData(0, Qt.ItemDataRole.UserRole, epCategory) |
452 if script: |
857 |
453 QListWidgetItem(Utilities.fromNativeSeparators(script), |
858 @pyqtSlot() |
454 self.scriptsList) |
859 def on_editEntryPointButton_clicked(self): |
|
860 """ |
|
861 Private slot to edit the selected entry point. |
|
862 """ |
|
863 project = ericApp().getObject("Project") |
|
864 rootDir = ( |
|
865 project.getProjectPath() |
|
866 if project.isOpen() else |
|
867 "" |
|
868 ) |
|
869 itm = self.entryPointsList.selectedItems()[0] |
|
870 dlg = AddEntryPointDialog(rootDir, epType=itm.text(0), name=itm.text(1), |
|
871 script=itm.text(2), parent=self) |
|
872 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
873 epType, epCategory, name, script = dlg.getEntryPoint() |
|
874 itm.setText(0, epType) |
|
875 itm.setText(1, name) |
|
876 itm.setText(2, script) |
|
877 itm.setData(0, Qt.ItemDataRole.UserRole, epCategory) |
455 |
878 |
456 @pyqtSlot() |
879 @pyqtSlot() |
457 def on_modulesList_itemSelectionChanged(self): |
880 def on_modulesList_itemSelectionChanged(self): |
458 """ |
881 """ |
459 Private slot to handle a change of selected items of the |
882 Private slot to handle a change of selected items of the |
460 modules list. |
883 modules list. |
461 """ |
884 """ |
462 self.deleteModuleButton.setEnabled( |
885 self.deleteModuleButton.setEnabled( |
463 len(self.modulesList.selectedItems()) > 0) |
886 bool(self.modulesList.selectedItems())) |
464 |
887 |
465 @pyqtSlot() |
888 @pyqtSlot() |
466 def on_deleteModuleButton_clicked(self): |
889 def on_deleteModuleButton_clicked(self): |
467 """ |
890 """ |
468 Private slot to delete the selected script items. |
891 Private slot to delete the selected module items. |
469 """ |
892 """ |
470 for itm in self.modulesList.selectedItems(): |
893 for itm in self.modulesList.selectedItems(): |
471 self.modulesList.takeItem( |
894 self.modulesList.takeItem(self.modulesList.row(itm)) |
472 self.modulesList.row(itm)) |
|
473 del itm |
895 del itm |
474 |
896 |
475 @pyqtSlot() |
897 @pyqtSlot() |
476 def on_addModuleButton_clicked(self): |
898 def on_addModuleButton_clicked(self): |
477 """ |
899 """ |