Skip to content

Commit

Permalink
Calendar API cleanup (deephaven#4201)
Browse files Browse the repository at this point in the history
* First refactoring.

* First refactoring.

* Add local date chronology methods.

* Calendar refactoring and cleanup.

* Calendar refactoring and cleanup.

* Calendar refactoring and cleanup.

* Calendar refactoring and cleanup.

* BusinessCalendar refactoring and cleanup.

* BusinessCalendar refactoring and cleanup.

* BusinessPeriod BusinessSchedule refactoring and cleanup.

* BusinessCalendar refactoring and cleanup:
* Exceptions

* BusinessCalendar refactoring and cleanup:
* Business Schedule

* BusinessCalendar refactoring and cleanup:
* Business Day

* BusinessCalendar refactoring and cleanup:
* Business Time

* BusinessCalendar refactoring and cleanup:
* Arithmetic

* BusinessCalendar refactoring and cleanup:
* Misc

* BusinessCalendar refactoring and cleanup:
* BusinessCalendarParser

* BusinessCalendar refactoring and cleanup:
* BusinessCalendarParser

* BusinessCalendar refactoring and cleanup:
* DefaultBusinessCalendar

* BusinessCalendar refactoring and cleanup:
* Calendars

* BusinessCalendar refactoring and cleanup:
* DateStringUtils

* BusinessCalendar refactoring and cleanup:
* DefaultNoHolidayBusinessCalendar

* BusinessCalendar refactoring and cleanup:
* Ranges

* BusinessCalendar refactoring and cleanup:
* Differences

* Calendar refactoring and cleanup:
* Plus/Minus

* DateTimeUtils added todayDate plus formatting LocalDate.

* Todo cleanup:
* Calendar

* Todo and docs cleanup:
* Calendar
* BusinessCalendar

* Todo and docs and formatting cleanup:
* Calendar
* BusinessCalendar

* Todo and docs and formatting cleanup:
* Calendar
* BusinessCalendar

* Todo and docs and formatting cleanup:
* Calendar
* BusinessCalendar

* Todo and docs and formatting cleanup:
* BusinessPeriod
* Calendars

* Unit test:
* BusinessPeriod

* Unit test:
* BusinessSchedule

* Unit test:
* Calendar

* Unit test:
* BusinessPeriod
* BusinessSchedule

* Unit test:
* BusinessCalendar - Schedule

* Unit test:
* BusinessCalendar - Schedule

* Unit test:
* BusinessCalendar - Business Day

* Unit test:
* BusinessCalendar - Business Time

* Unit test:
* BusinessCalendar - Ranges

* Unit test:
* BusinessCalendar - Differences

* Unit test:
* BusinessCalendar - Arithmetic

* Unit test:
* BusinessCalendar - Getters

* Committing to rebase

* Committing to rebase

* Updated doc string.

* Updated doc string.  Added a weekendDays getter.

* Updated doc string.  Added a weekendDays getter.

* Renamed todayDate to todayLocalDate.  (partial commit)

* Add LocalDate arithmetic.

* Updating calendar configs.

* Updating calendar configs.

* Refactoring code gen

* Refactoring code gen

* Make axis transforms compile

* Refactoring code gen.  Not fully working.

* Updated GroovyStaticImports

* Refactoring code gen.  Not fully working.

* Figure interface

* Figure interface

* FigureImpl

* Refactoring code gen.

* Refactoring code gen.

* Refactoring code gen.

* Refactoring code gen.

* Refactoring code gen.

* Refactoring code gen.

* StaticCalendarMethods

* Refactoring code gen.

* Renamed currentDate to calendarDate

* Add calendar methods to groovy.

* Add calendar methods to ColumnExpressionValidator.

* Working on tests.

* Working on tests.

* StaticCalendarMethods

* Spotless

* Update calendar files

* Addressing tests.

* Automatically test all static calendar methods in query strings and automatically test static calendar methods.

* Improve test coverage.

* Improve test coverage.

* spotless

* Python API and unit tests.

* Spotless

* Create a numpy business calendar.

* Create a BusinessCalendar dtype.

* Fixed figure.py

* Fixed unit tests

* Fixed unit tests

* Fixed unit tests

* Addressing code review.

* Addressing code review.

* Addressing code review.

* Addressing code review.

* Addressing code review.

* Elijah's updated calendars, only from authoritative sources.

* Spotless

* Reduce logging level.

* Function rename

* Function/Class rename

* Addressing review comments.

* Fixed broken unit test.

* Added a new calendar integration test and fix test failures.

* Test numpy calendars with a bus calendar with no business time.

* Update engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendarParser.java

Co-authored-by: Alex Peters <80283343+alexpeters1208@users.noreply.github.com>

* Update engine/time/src/main/java/io/deephaven/time/calendar/BusinessDay.java

Co-authored-by: Alex Peters <80283343+alexpeters1208@users.noreply.github.com>

* Update engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java

Co-authored-by: Charles P. Wright <cpwright@gmail.com>

* Update py/server/deephaven/calendar.py

Co-authored-by: Jianfeng Mao <4297243+jmao-denver@users.noreply.github.com>

* Update py/server/deephaven/calendar.py

Co-authored-by: Jianfeng Mao <4297243+jmao-denver@users.noreply.github.com>

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.

* Address review comments.  Name changes.

* Address review comments.  Name changes.

* Address review comments.  Regenerate and format.

* Address review comments.  Regenerate and format.

* Address review comments.  Improve multi-threaded performance.

* Address review comments.  Corrected sources list.

* Address review comments.  Improved documentation.

* Address review comments.  Compute time range nanos on demand and support returning durations.

* Address review comments.  More explicitly handle open vs closed ranges.

* Address review comments.  More explicitly handle open vs closed ranges.

* Address review comments.  Update calendar parsing for 24:00.

* Spotless

* Addressing review comments.  Add methods that return durations.

* Addressing review comments.  Add methods that return durations.

* Fixed error message.

* Addressing reviewer comments.  Making the calendar API null tolerant, like the rest of the time API.

* Addressing review comments.  Make the entire API null tolerant for consistency.

* Addressing review comments.  Defer calendar initialization to make finding errors easier.

* Spotless

* Address review comments.  Rename DateTimeUtils.plus to DateTimeUtils.plusDays for long args.

* Update py/server/deephaven/calendar.py

Co-authored-by: JJ Brosnan <84038776+jjbrosnan@users.noreply.github.com>

* Address review comments.  Rename DateTimeUtils.minus to DateTimeUtils.minusDays for long args.

* Address review comments.  Docstring cleanup.

* Address review comments.  BusinessCalendarXMLParser not public.

* Address review comments.  Made BusinessCalendar and Calendar constructors package so that they can be converted to interfaces in the future.

* Address review comments.  Shrink the UTC calendar to save memory.

* Address review comments.  Rename dayOfWeek to dayOfWeekValue and add dayOfWeek.

* Address review comments.  Compromise on publishing business calendars that may not be accurate.

* Address review comments.  Fix javadocs.

* Address review comments.  Spotless

* Python unit test fixes.

---------

Co-authored-by: Alex Peters <80283343+alexpeters1208@users.noreply.github.com>
Co-authored-by: Charles P. Wright <cpwright@gmail.com>
Co-authored-by: Jianfeng Mao <4297243+jmao-denver@users.noreply.github.com>
Co-authored-by: JJ Brosnan <84038776+jjbrosnan@users.noreply.github.com>
  • Loading branch information
5 people authored Jan 9, 2024
1 parent 07e22f0 commit ef44435
Show file tree
Hide file tree
Showing 97 changed files with 13,926 additions and 12,709 deletions.
20 changes: 20 additions & 0 deletions Generators/Generators.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,25 @@ task groovyStaticImportGeneratorAssert(type: JavaExec, dependsOn: 'classes') {
classpath = sourceSets.main.runtimeClasspath
workingDir = workDir
onlyIf { System.getenv('NO_ASSERT') != 'true' }
}

task generateStaticCalendarMethods(type: JavaExec, dependsOn: 'classes') {
description 'Run StaticCalendarMethodsGenerator'

main = 'io.deephaven.libs.StaticCalendarMethodsGenerator'
args devRoot, 'false'
classpath = sourceSets.main.runtimeClasspath
workingDir = workDir
}

task generateStaticCalendarMethodsAssert(type: JavaExec, dependsOn: 'classes') {
description 'Run StaticCalendarMethodsGenerator to assert that the generated code has not changed'

main = 'io.deephaven.libs.StaticCalendarMethodsGenerator'
args devRoot, 'true'
classpath = sourceSets.main.runtimeClasspath
workingDir = workDir
onlyIf { System.getenv('NO_ASSERT') != 'true' }
}

task generateAxesPlotMethods(type: JavaExec, dependsOn: 'classes') {
Expand Down Expand Up @@ -190,6 +208,7 @@ tasks.register 'generateAllPythonAssert', {

tasks.register 'generateAll', {
Task t -> t.dependsOn ':Generators:groovyStaticImportGenerator',
':Generators:generateStaticCalendarMethods',
':Generators:generateAxesPlotMethods',
':Generators:generateMultiSeries',
':Generators:generateFigureImmutable',
Expand All @@ -201,6 +220,7 @@ tasks.register 'generateAll', {
}

project.tasks.getByName('quick').dependsOn groovyStaticImportGeneratorAssert,
generateStaticCalendarMethodsAssert,
generateAxesPlotMethodsAssert,
generateMultiSeriesAssert,
generateFigureImmutableAssert,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending
*/
package io.deephaven.gen;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Abstract class for generating Java code from methods of one or more classes.
*
* {@link #generateCode()} must be called to generate the code.
*/
public abstract class AbstractBasicJavaGenerator {
private static final Logger log = Logger.getLogger(AbstractBasicJavaGenerator.class.toString());

private final String gradleTask;
private final String packageName;
private final String className;
private final Map<JavaFunction, JavaFunction> functions = new TreeMap<>();
private final Collection<Predicate<JavaFunction>> skipsGen;

/**
* Constructor.
*
* @param gradleTask Gradle task to generate the code.
* @param packageName Package name for the generated class.
* @param className Class name for the generated class.
* @param imports Array of fully qualified class names to process.
* @param includeMethod a predicate to determine if a method should be considered for code generation.
* @param skipsGen Collection of predicates to determine if a function should be skipped when generating code.
* @throws ClassNotFoundException If a class in the imports array cannot be found.
*/
public AbstractBasicJavaGenerator(final String gradleTask, final String packageName, final String className,
final String[] imports, Predicate<Method> includeMethod, Collection<Predicate<JavaFunction>> skipsGen)
throws ClassNotFoundException {
this.gradleTask = gradleTask;
this.packageName = packageName;
this.className = className;
this.skipsGen = skipsGen;

for (String imp : imports) {
Class<?> c = Class.forName(imp, false, Thread.currentThread().getContextClassLoader());
log.info("Processing class: " + c);

for (Method m : c.getMethods()) {
log.info("Processing method (" + c + "): " + m);
if (includeMethod.test(m)) {
addMethod(m);
}
}
}
}

private void addMethod(Method m) {
log.info("Processing public static method: " + m);

JavaFunction f = new JavaFunction(m);
// System.out.println(f);

if (functions.containsKey(f)) {
JavaFunction fAlready = functions.get(f);
final String message = "Signature Already Present: " + fAlready + "\t" + f;
log.severe(message);
throw new RuntimeException(message);
} else {
log.info("Added method: " + f);
functions.put(f, f);
}
}

/**
* Generate Javadoc for the output class.
*
* @return The Javadoc.
*/
abstract public String generateClassJavadoc();

/**
* Generate the Java code for a function.
*
* @param f The function.
* @return The Java code.
*/
abstract public String generateFunction(JavaFunction f);

/**
* Generate the code.
*
* @return The generated code.
*/
@SuppressWarnings("StringConcatenationInLoop")
public String generateCode() {

String code = GenUtils.javaHeader(this.getClass(), gradleTask);
code += "package " + packageName + ";\n\n";

Set<String> imports = GenUtils.typesToImport(functions.keySet());

for (String imp : imports) {
code += "import " + imp + ";\n";
}

code += "\n";
code += generateClassJavadoc();
code += "public class " + className + " {\n";

for (JavaFunction f : functions.keySet()) {
boolean skip = false;
for (Predicate<JavaFunction> skipCheck : skipsGen) {
skip = skip || skipCheck.test(f);
}

if (skip) {
log.warning("*** Skipping function: " + f);
continue;
}

code += generateFunction(f);
code += "\n";
}

code += "}\n\n";

return code;
}

/**
* Run a generator from the command line.
*
* @param gen The generator to run.
* @param relativeFilePath The relative file path to write the generated code to.
* @param args The command line arguments.
* @throws IOException If there is an IO error.
*/
public static void runCommandLine(final AbstractBasicJavaGenerator gen, final String relativeFilePath,
final String[] args) throws IOException {

String devroot = null;
boolean assertNoChange = false;
if (args.length == 1) {
devroot = args[0];
} else if (args.length == 2) {
devroot = args[0];
assertNoChange = Boolean.parseBoolean(args[1]);
} else {
System.out.println("Usage: <devroot> [assertNoChange]");
System.exit(-1);
}

log.setLevel(Level.WARNING);
log.warning("Running " + gen.getClass().getSimpleName() + " assertNoChange=" + assertNoChange);

final String code = gen.generateCode();
log.info("\n\n**************************************\n\n");
log.info(code);

String file = devroot + relativeFilePath;

if (assertNoChange) {
String oldCode = new String(Files.readAllBytes(Paths.get(file)));
GenUtils.assertGeneratedCodeSame(AbstractBasicJavaGenerator.class, gen.gradleTask, oldCode, code);
} else {

PrintWriter out = new PrintWriter(file);
out.print(code);
out.close();

log.warning("Class file written to: " + file);
}
}

}
Loading

0 comments on commit ef44435

Please sign in to comment.